/** * AriaSessionManager - Singleton class for global session management * * This class manages the WebSocket connection, Anam client, and session state * outside of React's lifecycle, ensuring session continuity across page navigation. * * Key features: * - Singleton pattern ensures only one instance exists globally * - Session persists across React component unmounts/remounts * - Proactive session refresh before expiration * - Tab visibility awareness for resource optimization * - Error recovery with exponential backoff */ import type { AriaSDKConfig, SessionState, SessionManagerStatus, SessionManagerEventType, SessionManagerListener, ChatMessage, WebSocketTriggerEvent } from '@/types'; export declare class AriaSessionManager { private static instance; private config; private refreshConfig; private ws; private anamClient; private videoStream; private audioInputStream; private hiddenVideoElement; private hiddenAudioElement; private sessionState; private status; private chatMessages; private liveTranscript; private lastMessageHistory; private listeners; private refreshTimer; private retryCount; private retryTimer; private isTabVisible; private pendingRefresh; private onWebSocketTrigger; private isPaused; private beforeUnloadHandler; private deferAnamInit; private isAnamInitializing; private isToolCallActive; private activeToolCall; private autoReconnectEnabled; private reconnectAttempts; private maxReconnectAttempts; private reconnectTimer; private isIntentionalDisconnect; private isReconnecting; private autoReconnectOnAnamDisconnect; private hasHadSessionBefore; private constructor(); /** * Get or create the singleton instance * * If instance already exists and config has meaningful values (websocketUrl), * the config will be updated. Otherwise, existing config is preserved. */ static getInstance(config: AriaSDKConfig): AriaSessionManager; /** * Check if an instance exists */ static hasInstance(): boolean; /** * Destroy the singleton instance (for testing or cleanup) */ static destroyInstance(): void; private updateConfig; getConfig(): AriaSDKConfig; /** * Check if the manager is properly configured for message storage * Returns true if both userId and WebSocket are available */ canStoreMessages(): boolean; /** * Get the current userId from config */ getUserId(): string | undefined; addEventListener(type: SessionManagerEventType, listener: SessionManagerListener): void; removeEventListener(type: SessionManagerEventType, listener: SessionManagerListener): void; private emit; private setStatus; getStatus(): SessionManagerStatus; getSessionState(): SessionState; private updateSessionState; connect(): void; disconnect(): void; isConnected(): boolean; /** * Enable or disable auto-reconnect functionality */ setAutoReconnect(enabled: boolean): void; /** * Schedule a reconnection attempt with exponential backoff */ private scheduleReconnect; /** * Attempt to reconnect the WebSocket */ private reconnect; /** * Check if the current session token is expired */ private isTokenExpired; /** * Check if the session token is valid and can be used * Public method for external checks */ isSessionValid(): boolean; /** * Get time until token expires in milliseconds * Returns -1 if no expiry or already expired */ getTimeUntilExpiry(): number; /** * Clear the reconnect timer */ private clearReconnectTimer; /** * Reset reconnect state (call when intentionally connecting) */ private resetReconnectState; private handleWebSocketMessage; private handleSessionResponse; private handleSessionError; /** * Request a session token from the backend with user_trigger=true * This is called automatically when WebSocket connects * The token is stored and used when user opens the widget for the first time * * If user has had a session before (in this app lifecycle), skip_greeting is sent * to prevent the greeting from playing again on subsequent sessions. */ private requestSessionToken; /** * Manually trigger a session (for user-initiated actions) * * NOTE: With global session management, this is typically not needed. * The session token is automatically requested when the provider mounts. * This method will request a new token if one doesn't exist or is expired. */ triggerSession(userTrigger?: boolean): void; /** * Check if Anam client is initialized */ isAnamClientInitialized(): boolean; /** * Check if session token is available (ready for on-demand initialization) */ hasSessionToken(): boolean; /** * Initialize the Anam client on demand (called when widget opens) * This is the lazy initialization entry point - ensures greeting plays when user opens widget */ initializeSessionOnDemand(): Promise; private initializeAnamClient; /** * Clear tool call state */ private clearToolCallState; /** * Get current tool call state */ getToolCallState(): { isActive: boolean; toolName: string | null; toolData: Record | null; }; private createHiddenVideoElement; private createHiddenAudioElement; private removeHiddenVideoElement; private removeHiddenAudioElement; /** * Get the current video stream */ getVideoStream(): MediaStream | null; /** * Attach the video stream to a visible video element * Audio is handled by the hidden audio element if available, otherwise through video element */ attachToVideoElement(element: HTMLVideoElement): void; /** * Detach video stream from visible element (when widget closes) */ detachFromVideoElement(element: HTMLVideoElement): void; getChatMessages(): ChatMessage[]; getLiveTranscript(): string; clearLiveTranscript(): void; private sendMessageHistory; private sendMessageStream; sendSessionEnd(): void; sendMessage(message: string): Promise; toggleMute(): boolean; isMuted(): boolean; stopStreaming(): Promise; private scheduleRefresh; refreshSession(): Promise; private scheduleRetry; private setupVisibilityListener; private handleVisibilityChange; private setupBeforeUnloadHandler; private removeBeforeUnloadHandler; /** * Check if session persistence is enabled * Returns FALSE - sessions are ended when widget closes to save Anam resources * A new session with skip_greeting is created when widget reopens */ isPersistSessionEnabled(): boolean; /** * Check if WebSocket should stay alive when paused */ shouldKeepWebSocketAlive(): boolean; /** * Check if widget is closed (session was ended on close) * Note: With the new behavior, sessions are ended when widget closes, * not paused. This returns true if the widget was closed. */ isSessionPaused(): boolean; /** * Pause the session (called when widget closes / user hangs up) * * NEW BEHAVIOR: Ends the Anam session to save resources. * When widget reopens, a new session is created with skip_greeting: true * so the greeting doesn't play again. * * This is more resource-efficient than keeping the session alive. */ pauseSession(): Promise; /** * Resume the session (called when widget reopens) * * Since we end the session on pause (to free Anam resources), this requests a new * session token with skip_greeting: true, then initializes the Anam client. * * @returns true if session is ready or initialization started, false if waiting for token */ resumeSession(): Promise; /** * Reset session state (used when session expires or needs to be recreated) */ private resetSessionState; /** * Force end the session (explicit user action or logout) * This always ends the session regardless of persistSession setting * * @param resetGreeting - If true, resets the greeting state so next session shows greeting (useful for logout) */ forceEndSession(resetGreeting?: boolean): Promise; /** * Reset the greeting state so the next session will show the greeting * Call this when user logs out or you want to show greeting again */ resetGreetingState(): void; /** * Check if greeting will be skipped on next session */ willSkipGreeting(): boolean; /** * Check if the session is currently reconnecting */ isSessionReconnecting(): boolean; /** * Enable or disable auto-reconnect when Anam disconnects (e.g., due to inactivity) */ setAutoReconnectOnAnamDisconnect(enabled: boolean): void; /** * Auto-reconnect the session after Anam disconnects (e.g., due to inactivity timeout) * This creates a new session seamlessly without user intervention */ private autoReconnectSession; /** * Clean up resources for reconnection (without sending session_end) */ private cleanupForReconnect; /** * Clear stale session data when Anam disconnects while paused * This ensures a fresh session is created when the widget reopens */ private clearStaleSessionForResume; /** * End the current session but keep WebSocket connected for new session creation * This is called when widget closes without persistSession enabled * The next time the widget opens, a new session will be created */ endCurrentSession(): Promise; private clearTimers; private clearRefreshTimer; private clearRetryTimer; /** * Set callback for WebSocket trigger events */ setWebSocketTriggerCallback(callback: ((event: WebSocketTriggerEvent) => void) | null): void; /** * Destroy the session manager and clean up all resources */ destroy(): void; } export default AriaSessionManager; //# sourceMappingURL=AriaSessionManager.d.ts.map