Skip to content

Commit 6bf57b0

Browse files
committed
doc: minor doc update
1 parent 58548e7 commit 6bf57b0

File tree

1 file changed

+219
-3
lines changed

1 file changed

+219
-3
lines changed

README.md

Lines changed: 219 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ suspend fun login(email: String, password: String) {
9797
}
9898

9999
onTwoFactorRequired = { context ->
100-
// Handle 2FA requirement
100+
// Handle TFA requirement
101101
navigateToTwoFactorScreen(context)
102102
}
103103
}
@@ -394,7 +394,7 @@ Context update callbacks are specifically designed to handle **interrupted authe
394394

395395
**Common interrupted flows:**
396396
- **Account Linking:** When a social login conflicts with an existing account
397-
- **Two-Factor Authentication:** When 2FA is required for login/registration
397+
- **Two-Factor Authentication:** When TFA is required for login/registration
398398
- **Registration Missing Fields:** When required profile fields are missing during registration
399399

400400
**How it works:**
@@ -416,7 +416,7 @@ authenticationService.authenticate().login()
416416
// Handle enriched context - enhanced data for flow completion
417417
onTwoFactorContextUpdated = { enrichedContext ->
418418
// SDK-enriched context with additional data:
419-
// - Available email addresses for 2FA
419+
// - Available email addresses for TFA
420420
// - Phone numbers registered for SMS
421421
// - QR codes for authenticator apps
422422
// - Tokens needed for flow continuation
@@ -503,6 +503,222 @@ This powerful DSL system allows you to:
503503
- **Handle complex flows** with enriched context data
504504
- **Maintain clean separation** between business logic and UI logic
505505

506+
# Session Event Bus
507+
508+
The SDK provides a lifecycle-aware event bus for session and messaging events. This allows your app to react to session changes (expiration, refresh, verification) and push notifications across your entire application in a decoupled, type-safe manner.
509+
510+
## Event Types
511+
512+
### Session Events
513+
514+
**Core Session Events (Always Available):**
515+
- `SessionEvent.SessionExpired` - Session has expired
516+
- `SessionEvent.SessionRefreshed` - Session was successfully refreshed
517+
- `SessionEvent.VerifySession` - Session verification requested
518+
519+
**Session Validation Events (Opt-In):**
520+
521+
These events only fire if you enable session validation when initializing the AuthenticationService:
522+
523+
```kotlin
524+
val authenticationService = AuthenticationService(siteConfig)
525+
.registerForSessionValidation(
526+
config = SessionValidationConfig(
527+
intervalMinutes = 20L, // Check session every 20 minutes
528+
enabled = true // Enable validation
529+
)
530+
)
531+
```
532+
533+
**Validation Events:**
534+
- `SessionEvent.ValidationStarted` - Session validation has started
535+
- `SessionEvent.ValidationSucceeded` - Session validation succeeded
536+
- `SessionEvent.ValidationFailed` - Session validation failed (includes reason)
537+
538+
⚠️ **Note:** Session validation adds periodic background checks to ensure session validity. Only enable if your app requires this level of session monitoring.
539+
540+
### Message Events
541+
542+
Push notification and Firebase messaging events:
543+
- `MessageEvent.TokenReceived` - FCM token received
544+
- `MessageEvent.RemoteMessageReceived` - Push notification received
545+
- `MessageEvent.NotificationActionReceived` - Notification action triggered
546+
547+
## Usage
548+
549+
### Lifecycle-Aware Subscription (Activities/Fragments)
550+
551+
For UI components that implement `LifecycleOwner` (Activities, Fragments), use lifecycle-aware subscriptions that automatically clean up:
552+
553+
```kotlin
554+
class MainActivity : FragmentActivity() {
555+
override fun onCreate(savedInstanceState: Bundle?) {
556+
super.onCreate(savedInstanceState)
557+
558+
// Initialize event bus (only needed once in your app)
559+
if (!CDCEventBusProvider.isInitialized()) {
560+
CDCEventBusProvider.initialize()
561+
}
562+
563+
// Subscribe with automatic lifecycle management
564+
subscribeToSessionEvents { event ->
565+
when (event) {
566+
is SessionEvent.SessionExpired -> {
567+
// Handle session expiration
568+
navigateToLogin()
569+
}
570+
is SessionEvent.SessionRefreshed -> {
571+
// Handle session refresh
572+
updateSessionUI()
573+
}
574+
is SessionEvent.ValidationFailed -> {
575+
// Handle validation failure
576+
showSessionWarning(event.reason)
577+
}
578+
else -> { /* Handle other events */ }
579+
}
580+
}
581+
}
582+
583+
// No cleanup needed - automatically unsubscribes when lifecycle ends
584+
}
585+
```
586+
587+
### Manual Subscription (ViewModels/Services)
588+
589+
For components without lifecycle support (ViewModels, Services), use manual subscriptions with explicit cleanup:
590+
591+
```kotlin
592+
class MainActivityViewModel(
593+
private val authenticationFlowDelegate: AuthenticationFlowDelegate
594+
) : ViewModel() {
595+
596+
private var sessionEventSubscription: EventSubscription? = null
597+
598+
init {
599+
// Initialize event bus
600+
if (!CDCEventBusProvider.isInitialized()) {
601+
CDCEventBusProvider.initialize()
602+
}
603+
604+
// Manual subscription requires explicit cleanup
605+
sessionEventSubscription = subscribeToSessionEventsManual { event ->
606+
when (event) {
607+
is SessionEvent.SessionExpired -> handleSessionExpired()
608+
is SessionEvent.SessionRefreshed -> handleSessionRefreshed()
609+
is SessionEvent.ValidationSucceeded -> handleValidationSucceeded()
610+
else -> { /* Handle other events */ }
611+
}
612+
}
613+
}
614+
615+
private fun handleSessionExpired() {
616+
authenticationFlowDelegate.handleSessionExpired()
617+
// Navigate to login screen
618+
}
619+
620+
override fun onCleared() {
621+
// Important: Unsubscribe to prevent memory leaks
622+
sessionEventSubscription?.unsubscribe()
623+
sessionEventSubscription = null
624+
super.onCleared()
625+
}
626+
}
627+
```
628+
629+
## Event Scopes
630+
631+
Events can be scoped for targeted distribution:
632+
633+
- `EventScope.GLOBAL` - All subscribers receive the event (default)
634+
- `EventScope.SCOPED` - Only subscribers in a specific scope receive the event
635+
636+
```kotlin
637+
// Emit to all subscribers (default)
638+
emitSessionExpired(sessionId)
639+
640+
// Emit to specific scope
641+
emitSessionExpired(sessionId, scope = EventScope.SCOPED)
642+
```
643+
644+
## Benefits
645+
646+
**Decoupled Architecture** - Components don't need direct references to each other
647+
**Lifecycle-Aware** - Automatic cleanup prevents memory leaks in Activities/Fragments
648+
**Type-Safe** - Compile-time event type checking with sealed classes
649+
**Flexible** - Works with Activities, Fragments, ViewModels, and Services
650+
**Testable** - Easy to mock and test event handling
651+
**Thread-Safe** - Events dispatched on appropriate coroutine dispatchers
652+
653+
## Common Use Cases
654+
655+
### 1. Global Session Expiration Handling
656+
657+
Handle session expiration across your entire app from a single ViewModel:
658+
659+
```kotlin
660+
class MainActivityViewModel : ViewModel() {
661+
init {
662+
subscribeToSessionEventsManual { event ->
663+
if (event is SessionEvent.SessionExpired) {
664+
// Clear app state
665+
clearUserData()
666+
// Navigate to login
667+
navigateToLogin()
668+
}
669+
}
670+
}
671+
}
672+
```
673+
674+
### 2. Push Notification Handling
675+
676+
React to push notifications throughout your app:
677+
678+
```kotlin
679+
subscribeToMessageEvents { event ->
680+
when (event) {
681+
is MessageEvent.RemoteMessageReceived -> {
682+
// Show in-app notification
683+
showInAppNotification(event.data)
684+
}
685+
is MessageEvent.NotificationActionReceived -> {
686+
// Handle notification action
687+
handleNotificationAction(event.action, event.data)
688+
}
689+
else -> { /* Handle other events */ }
690+
}
691+
}
692+
```
693+
694+
### 3. Session Monitoring
695+
696+
Monitor session health with validation events:
697+
698+
```kotlin
699+
subscribeToSessionEvents { event ->
700+
when (event) {
701+
is SessionEvent.ValidationStarted -> showLoadingIndicator()
702+
is SessionEvent.ValidationSucceeded -> hideLoadingIndicator()
703+
is SessionEvent.ValidationFailed -> {
704+
hideLoadingIndicator()
705+
showSessionWarning("Session validation failed: ${event.reason}")
706+
}
707+
else -> { /* Handle other events */ }
708+
}
709+
}
710+
```
711+
712+
## Important Notes
713+
714+
⚠️ **Initialization:** Call `CDCEventBusProvider.initialize()` once in your app (e.g., in MainActivity or Application class)
715+
716+
⚠️ **Manual Subscriptions:** Always call `unsubscribe()` on manual subscriptions to prevent memory leaks
717+
718+
⚠️ **Thread Safety:** Event handlers run on background threads (IO dispatcher) for manual subscriptions. Use appropriate dispatchers for UI updates.
719+
720+
⚠️ **Validation Events:** Only subscribe to validation events if you've enabled session validation via `registerForSessionValidation()`
721+
506722
# Social Provider Authentication
507723

508724
The SDK provides a flexible system for integrating social login providers (Google, Facebook, WeChat, Line, etc.) through the `IAuthenticationProvider` interface. The SDK is **intentionally decoupled** from third-party social SDKs, allowing you to use any version of social provider SDKs without compatibility issues.

0 commit comments

Comments
 (0)