Lifecycle Hooks
Three primary hooks control your app's integration with the marketplace session lifecycle. An optional fourth hook handles session extensions.
onSessionStart
Purpose: Provision user and initialize app state.
When called: After JWT validation, before timer starts.
Common tasks:
- Create user account in your system
- Generate app authentication token
- Store session data
- Initialize user preferences
- Load user data
Example
onSessionStart: async (context: SessionStartContext) => {
console.log('[Session] Starting for user:', context.userId);
// 1. Check if user exists
let user = await getUser(context.userId);
// 2. Create if new user
if (!user) {
user = await createUser({
id: context.userId,
email: context.email,
source: 'marketplace',
createdAt: new Date(),
});
console.log('[Session] Created new user:', user.id);
}
// 3. Generate session token
const token = await generateSessionToken({
userId: user.id,
sessionId: context.sessionId,
expiresAt: context.expiresAt,
});
// 4. Store in app state
appState.setAuth({
token,
user,
expiresAt: context.expiresAt,
source: 'marketplace',
});
// 5. Load user data
await loadUserPreferences(user.id);
await loadUserContent(user.id);
console.log('[Session] User authenticated and initialized');
},
Error Handling
If onSessionStart throws an error, the session will not start:
onSessionStart: async (context: SessionStartContext) => {
try {
await authenticateUser(context);
} catch (error) {
console.error('[Session] Failed to start:', error);
showError('Failed to initialize session. Please try again.');
throw new Error('Session initialization failed');
}
},
onSessionWarning
Purpose: Alert user before session expires.
When called: At warning threshold (default: 5 minutes remaining).
Common tasks:
- Show warning modal/notification
- Offer session extension
- Auto-save user work
- Prompt to save changes
Example
onSessionWarning: async (context: SessionWarningContext) => {
console.log('[Session] Warning! Only', context.minutesRemaining, 'minutes left');
// 1. Auto-save user work
await autoSaveUserWork();
// 2. Show warning modal
showModal({
title: 'Session Expiring Soon',
message: `Your session will expire in ${context.minutesRemaining} minutes.`,
buttons: [
{
label: 'Extend Session',
action: async () => {
try {
await sdk.extendSession(30);
showNotification('Session extended!');
} catch (error) {
showError('Failed to extend session');
}
},
},
{
label: 'Save & Exit',
action: async () => {
await saveAllChanges();
sdk.endSession('manual');
},
},
{
label: 'Continue',
action: () => {
// Dismiss modal, continue working
},
},
],
});
},
Customizing Warning Threshold
const sdk = new MarketplaceSDK({
// ... other options
warningThresholdMinutes: 10, // Warn 10 minutes before expiration
});
onSessionEnd
Purpose: Clean up app state when session ends.
When called: When session expires or user manually ends.
Common tasks:
- Clear authentication state
- Log user out
- Save analytics
- Clear cached data
- Redirect to marketplace (optional)
Example
onSessionEnd: async (context: SessionEndContext) => {
console.log('[Session] Ending. Reason:', context.reason);
console.log('[Session] Duration:', context.actualDurationMinutes, 'minutes');
// 1. Save analytics
await logSessionEnd({
userId: context.userId,
sessionId: context.sessionId,
duration: context.actualDurationMinutes,
reason: context.reason,
timestamp: Date.now(),
});
// 2. Clear authentication
localStorage.removeItem('auth_token');
localStorage.removeItem('user_data');
appState.clearAuth();
// 3. Clear any cached data
await clearUserCache();
// 4. Show farewell message
if (context.reason === 'manual') {
showNotification('Session ended. Thank you for using our app!');
} else if (context.reason === 'expired') {
showNotification('Session expired. Please return via marketplace to continue.');
}
console.log('[Session] Cleanup complete');
},
Preventing Redirect
By default, SDK redirects to marketplace after session ends. To prevent this:
const sdk = new MarketplaceSDK({
// ... other options
marketplaceUrl: undefined, // Disable redirect
});
// Or handle redirect manually in onSessionEnd:
onSessionEnd: async (context: SessionEndContext) => {
await cleanup();
if (context.reason === 'expired') {
window.location.href = 'https://platform.generalwisdom.com?session=expired';
} else {
window.location.href = 'https://platform.generalwisdom.com';
}
},
onSessionExtend
Purpose: Handle session extension requests.
When called: After successful session extension.
Common tasks:
- Update stored expiration time
- Refresh auth tokens
- Show confirmation
- Update UI timer
Example
onSessionExtend: async (context: SessionExtendContext) => {
console.log('[Session] Extended by', context.extensionMinutes, 'minutes');
console.log('[Session] New expiration:', new Date(context.newExpiresAt * 1000));
// 1. Update stored expiration
const auth = appState.getAuth();
auth.expiresAt = context.newExpiresAt;
appState.setAuth(auth);
// 2. Refresh app auth token if needed
if (needsTokenRefresh(auth)) {
const newToken = await refreshAppToken(auth.token);
auth.token = newToken;
appState.setAuth(auth);
}
// 3. Show confirmation
showNotification(`Session extended! You have ${context.extensionMinutes} more minutes.`);
// 4. Log analytics
await logSessionExtension({
userId: context.userId,
sessionId: context.sessionId,
extensionMinutes: context.extensionMinutes,
timestamp: Date.now(),
});
},
Context Types
interface SessionStartContext {
sessionId: string;
applicationId: string;
userId: string;
orgId?: string;
email?: string;
startTime: number; // Unix timestamp
expiresAt: number; // Unix timestamp
durationMinutes: number;
jwt: string; // Original JWT token
}
interface SessionEndContext {
sessionId: string;
userId: string;
reason: 'expired' | 'manual' | 'error';
actualDurationMinutes: number;
}
interface SessionWarningContext {
sessionId: string;
userId: string;
minutesRemaining: number;
expiresAt: number;
}
interface SessionExtendContext {
sessionId: string;
userId: string;
extensionMinutes: number;
newExpiresAt: number;
previousExpiresAt: number;
}