cevro-messenger-sdk 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +145 -19
- package/dist/esm/index.js.map +1 -1
- package/dist/types/core/CevroMessenger.d.ts +7 -0
- package/dist/types/core/CevroMessenger.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +2 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/ui/ChatWindow.d.ts +6 -0
- package/dist/types/ui/ChatWindow.d.ts.map +1 -1
- package/dist/types/ui/MessageList.d.ts +17 -0
- package/dist/types/ui/MessageList.d.ts.map +1 -1
- package/dist/types/ui/PastConversation.d.ts +10 -1
- package/dist/types/ui/PastConversation.d.ts.map +1 -1
- package/dist/umd/cevro-messenger.min.js +1 -1
- package/dist/umd/cevro-messenger.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cevro-messenger.min.js","sources":["../../src/core/EventEmitter.ts","../../src/utils/session.ts","../../src/utils/file-validation.ts","../../src/core/ApiClient.ts","../../node_modules/centrifuge/build/index.mjs","../../src/core/WebSocketClient.ts","../../src/utils/dom.ts","../../src/ui/Launcher.ts","../../src/i18n/strings.ts","../../src/ui/MessageList.ts","../../src/ui/ChatWindow.ts","../../src/ui/ConversationList.ts","../../src/ui/PastConversation.ts","../../src/core/CevroMessenger.ts","../../src/index.ts"],"sourcesContent":["import type { EventType, EventHandler } from '../types';\n\n/**\n * Simple event emitter for SDK events\n */\nexport class EventEmitter {\n private listeners: Map<EventType, Set<EventHandler>> = new Map();\n private onceHandlers: Map<EventHandler, EventHandler> = new Map(); // Maps wrapper -> original\n\n /**\n * Subscribe to an event\n */\n on<T = any>(event: EventType, handler: EventHandler<T>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler);\n\n // Return unsubscribe function\n return () => this.off(event, handler);\n }\n\n /**\n * Subscribe to an event (fires only once)\n */\n once<T = any>(event: EventType, handler: EventHandler<T>): () => void {\n const onceHandler: EventHandler<T> = (data) => {\n this.onceHandlers.delete(onceHandler);\n this.off(event, onceHandler);\n handler(data);\n };\n this.onceHandlers.set(onceHandler, handler);\n return this.on(event, onceHandler);\n }\n\n /**\n * Unsubscribe from an event\n */\n off(event: EventType, handler: EventHandler): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n // Also clean up from onceHandlers if it was a once handler\n this.onceHandlers.delete(handler);\n }\n }\n\n /**\n * Emit an event\n */\n emit<T = any>(event: EventType, data?: T): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch {\n // Silently ignore handler errors\n }\n });\n }\n }\n\n /**\n * Remove all listeners for an event (or all events if no event specified)\n */\n removeAllListeners(event?: EventType): void {\n if (event) {\n // Clean up once handlers for this event\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n this.onceHandlers.delete(handler);\n });\n }\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n this.onceHandlers.clear();\n }\n }\n\n /**\n * Get listener count for an event\n */\n listenerCount(event: EventType): number {\n return this.listeners.get(event)?.size || 0;\n }\n}\n","import type { SessionData } from '../types';\n\n// ============================================\n// Multi-layer identity persistence\n// Stores visitor token in localStorage + cookie + indexedDB\n// so clearing one doesn't lose the visitor identity.\n// ============================================\n\nconst VISITOR_TOKEN_KEY = 'cevro_visitor_token';\nconst SESSION_KEY = 'cevro_session';\nconst COOKIE_MAX_AGE_SECONDS = 270 * 24 * 60 * 60; // 9 months (same as Intercom)\nconst IDB_DB_NAME = 'cevro_sdk';\nconst IDB_STORE_NAME = 'identity';\n\n// --- Cookie helpers ---\n\nfunction setCookie(name: string, value: string): void {\n try {\n document.cookie = `${name}=${encodeURIComponent(value)};max-age=${COOKIE_MAX_AGE_SECONDS};path=/;SameSite=Lax`;\n } catch {\n // Cookies may be blocked\n }\n}\n\nfunction getCookie(name: string): string | null {\n try {\n const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));\n return match ? decodeURIComponent(match[1]) : null;\n } catch {\n return null;\n }\n}\n\nfunction deleteCookie(name: string): void {\n try {\n document.cookie = `${name}=;max-age=0;path=/;SameSite=Lax`;\n } catch {\n // Ignore\n }\n}\n\n// --- IndexedDB helpers (async, fire-and-forget for writes) ---\n\nfunction openIDB(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(IDB_DB_NAME, 1);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(IDB_STORE_NAME)) {\n db.createObjectStore(IDB_STORE_NAME);\n }\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n}\n\nfunction idbSet(key: string, value: string): void {\n // Fire-and-forget — don't block on write\n openIDB()\n .then(db => {\n const tx = db.transaction(IDB_STORE_NAME, 'readwrite');\n tx.objectStore(IDB_STORE_NAME).put(value, key);\n tx.oncomplete = () => db.close();\n tx.onerror = () => db.close();\n })\n .catch(() => {});\n}\n\nfunction idbGet(key: string): Promise<string | null> {\n return openIDB()\n .then(db => {\n return new Promise<string | null>((resolve) => {\n const tx = db.transaction(IDB_STORE_NAME, 'readonly');\n const req = tx.objectStore(IDB_STORE_NAME).get(key);\n req.onsuccess = () => resolve(req.result ?? null);\n req.onerror = () => resolve(null);\n tx.oncomplete = () => db.close();\n tx.onerror = () => db.close();\n });\n })\n .catch(() => null);\n}\n\nfunction idbDelete(key: string): void {\n openIDB()\n .then(db => {\n const tx = db.transaction(IDB_STORE_NAME, 'readwrite');\n tx.objectStore(IDB_STORE_NAME).delete(key);\n tx.oncomplete = () => db.close();\n tx.onerror = () => db.close();\n })\n .catch(() => {});\n}\n\n/**\n * Collect browser session data\n */\nexport function collectSessionData(): SessionData {\n const session: SessionData = {};\n\n if (typeof window === 'undefined' || typeof navigator === 'undefined') {\n return session;\n }\n\n try {\n // Browser info\n session.userAgent = navigator.userAgent;\n session.language = navigator.language;\n session.platform = navigator.platform;\n session.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n // Page context\n session.currentPage = window.location.href;\n session.pageTitle = document.title;\n session.referrer = document.referrer;\n\n // Screen dimensions\n session.screenWidth = window.screen.width;\n session.screenHeight = window.screen.height;\n session.viewportWidth = window.innerWidth;\n session.viewportHeight = window.innerHeight;\n session.devicePixelRatio = window.devicePixelRatio;\n\n // UTM parameters from URL\n const urlParams = new URLSearchParams(window.location.search);\n session.utmSource = urlParams.get('utm_source') || undefined;\n session.utmMedium = urlParams.get('utm_medium') || undefined;\n session.utmCampaign = urlParams.get('utm_campaign') || undefined;\n session.utmContent = urlParams.get('utm_content') || undefined;\n session.utmTerm = urlParams.get('utm_term') || undefined;\n\n // Capabilities\n session.cookiesEnabled = navigator.cookieEnabled;\n session.touchSupport = 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n session.online = navigator.onLine;\n\n // Connection info (if available)\n const connection = (navigator as any).connection;\n if (connection) {\n session.connectionType = connection.effectiveType;\n }\n } catch (e) {\n // Silently ignore errors in session collection\n }\n\n return session;\n}\n\n/**\n * Get stored visitor token (signed by server)\n * Checks localStorage first, then cookie fallback.\n * IndexedDB is checked asynchronously via recoverVisitorToken().\n */\nexport function getStoredVisitorToken(): string | null {\n // Layer 1: localStorage (fastest, synchronous)\n try {\n const fromLS = localStorage.getItem(VISITOR_TOKEN_KEY);\n if (fromLS) return fromLS;\n } catch {\n // localStorage unavailable\n }\n\n // Layer 2: cookie fallback\n const fromCookie = getCookie(VISITOR_TOKEN_KEY);\n if (fromCookie) {\n // Restore to localStorage\n try { localStorage.setItem(VISITOR_TOKEN_KEY, fromCookie); } catch {}\n return fromCookie;\n }\n\n return null;\n}\n\n/**\n * Async recovery: check IndexedDB if synchronous stores are empty.\n * Call once at boot — if a token is recovered, it's written back to all layers.\n */\nexport async function recoverVisitorToken(): Promise<string | null> {\n // If synchronous stores already have it, nothing to recover\n const sync = getStoredVisitorToken();\n if (sync) return sync;\n\n // Layer 3: IndexedDB\n try {\n const fromIDB = await idbGet(VISITOR_TOKEN_KEY);\n if (fromIDB) {\n // Restore to all synchronous layers\n try { localStorage.setItem(VISITOR_TOKEN_KEY, fromIDB); } catch {}\n setCookie(VISITOR_TOKEN_KEY, fromIDB);\n return fromIDB;\n }\n } catch {\n // IndexedDB unavailable\n }\n\n return null;\n}\n\n/**\n * Store visitor token received from server.\n * Writes to all three layers for maximum persistence.\n */\nexport function storeVisitorToken(token: string): void {\n // Layer 1: localStorage\n try { localStorage.setItem(VISITOR_TOKEN_KEY, token); } catch {}\n\n // Layer 2: cookie (9 months)\n setCookie(VISITOR_TOKEN_KEY, token);\n\n // Layer 3: indexedDB (async, fire-and-forget)\n idbSet(VISITOR_TOKEN_KEY, token);\n}\n\n/**\n * Extract visitorId from visitorToken\n * Token format: visitorId.signature\n */\nexport function extractVisitorIdFromToken(token: string): string | null {\n if (!token) return null;\n const lastDotIndex = token.lastIndexOf('.');\n if (lastDotIndex <= 0) return null;\n return token.substring(0, lastDotIndex);\n}\n\n/**\n * Get visitorId from stored token (or null if not available)\n */\nexport function getStoredVisitorId(): string | null {\n const token = getStoredVisitorToken();\n return token ? extractVisitorIdFromToken(token) : null;\n}\n\n/**\n * Get visitor ID from stored token, or null if not yet available.\n * The visitor ID is assigned by the server and stored in the visitor token.\n */\nexport function generateVisitorId(): string | null {\n return getStoredVisitorId();\n}\n\n/**\n * Stored session data\n */\nexport interface StoredSessionData {\n sessionId?: string;\n contactId?: string;\n ticketId?: string;\n}\n\n// --- Account-switch detection ---\n//\n// Storage keys are always plain (`cevro_session`, `cevro_visitor_token`).\n// We track the last identified playerId in `cevro_active_player`.\n//\n// On first identify(): store the player hash, keep existing session/visitor\n// data intact. The anonymous→identified merge happens server-side (backend\n// links the visitorId to the playerId in initSession).\n//\n// On subsequent identify() with a DIFFERENT playerId: account switch detected.\n// Clear session + visitor data so the new identity starts fresh, then store\n// the new player hash.\n//\n// This optimizes for the 99% case (single account) with zero disruption,\n// and only pays the reset cost on actual account switches.\n\nconst ACTIVE_PLAYER_KEY = 'cevro_active_player';\n\n/**\n * Simple hash to avoid storing raw playerIds in localStorage.\n */\nfunction hashForKey(input: string): string {\n let hash = 0;\n for (let i = 0; i < input.length; i++) {\n hash = ((hash << 5) - hash + input.charCodeAt(i)) | 0;\n }\n return Math.abs(hash).toString(36);\n}\n\n/**\n * Check if identify() is being called for a different player than the\n * one currently stored. Returns true if this is an account switch that\n * requires clearing session data.\n *\n * Also stores the new player hash so subsequent calls detect correctly.\n * First-time identify (no previous player) returns false — the anonymous\n * session should be preserved for server-side merge.\n */\nexport function detectAndRecordPlayerSwitch(playerId: string): boolean {\n const playerHash = hashForKey(playerId);\n try {\n const stored = localStorage.getItem(ACTIVE_PLAYER_KEY);\n localStorage.setItem(ACTIVE_PLAYER_KEY, playerHash);\n\n // First identify — no previous player, not a switch\n if (!stored) return false;\n\n // Same player — not a switch\n if (stored === playerHash) return false;\n\n // Different player — account switch\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Clear the active player record (e.g. on shutdown with clearVisitorData).\n */\nexport function clearActivePlayer(): void {\n try {\n localStorage.removeItem(ACTIVE_PLAYER_KEY);\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Get stored session data\n */\nexport function getStoredSession(): StoredSessionData | null {\n try {\n const stored = localStorage.getItem(SESSION_KEY);\n return stored ? JSON.parse(stored) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Store session data\n */\nexport function storeSession(sessionId: string, contactId: string, ticketId: string): void {\n try {\n localStorage.setItem(SESSION_KEY, JSON.stringify({ sessionId, contactId, ticketId }));\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Clear stored session data\n */\nexport function clearStoredSession(): void {\n try {\n localStorage.removeItem(SESSION_KEY);\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Clear stored visitor token from all layers.\n */\nexport function clearStoredVisitorToken(): void {\n try { localStorage.removeItem(VISITOR_TOKEN_KEY); } catch {}\n deleteCookie(VISITOR_TOKEN_KEY);\n idbDelete(VISITOR_TOKEN_KEY);\n}\n\n/**\n * Clear all stored data (session + visitor token + active player)\n */\nexport function clearAllStoredData(): void {\n clearStoredSession();\n clearStoredVisitorToken();\n clearActivePlayer();\n}\n","/**\n * File validation utilities for secure file uploads\n * Provides client-side validation as first line of defense\n */\n\n/**\n * Allowed MIME types for file uploads\n * This whitelist prevents potentially dangerous file types\n */\nexport const ALLOWED_MIME_TYPES: ReadonlySet<string> = new Set([\n // Images\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'image/svg+xml',\n // Documents\n 'application/pdf',\n 'text/plain',\n 'text/csv',\n // Microsoft Office\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'application/vnd.ms-excel',\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'application/vnd.ms-powerpoint',\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n // Audio/Video\n 'audio/mpeg',\n 'audio/wav',\n 'audio/ogg',\n 'video/mp4',\n 'video/webm',\n // Archives (optional - can be disabled)\n 'application/zip',\n 'application/x-rar-compressed',\n]);\n\n/**\n * Dangerous file extensions that should always be blocked\n * Even if MIME type looks safe, these extensions are risky\n */\nexport const BLOCKED_EXTENSIONS: ReadonlySet<string> = new Set([\n '.exe', '.dll', '.bat', '.cmd', '.sh', '.bash',\n '.ps1', '.psm1', '.psd1', // PowerShell\n '.vbs', '.vbe', '.js', '.jse', '.ws', '.wsf', '.wsc', '.wsh', // Scripts\n '.msi', '.msp', '.mst', // Windows installers\n '.scr', '.pif', '.com', // Executables\n '.hta', '.cpl', '.msc', // Control panel/settings\n '.jar', '.class', // Java\n '.php', '.php3', '.php4', '.php5', '.phtml', // PHP\n '.asp', '.aspx', '.ashx', '.asmx', // ASP.NET\n '.jsp', '.jspx', // JSP\n '.py', '.pyc', '.pyw', // Python\n '.rb', '.rbw', // Ruby\n '.pl', '.pm', '.cgi', // Perl/CGI\n '.htaccess', '.htpasswd', // Apache config\n]);\n\n/**\n * Default file upload constraints\n */\nexport const DEFAULT_FILE_CONSTRAINTS = {\n maxSizeBytes: 25 * 1024 * 1024, // 25MB\n minSizeBytes: 1, // At least 1 byte\n maxFilenameLength: 255,\n} as const;\n\n/**\n * File validation configuration\n */\nexport interface FileValidationConfig {\n maxSizeBytes?: number;\n minSizeBytes?: number;\n allowedMimeTypes?: ReadonlySet<string> | Set<string>;\n blockedExtensions?: ReadonlySet<string> | Set<string>;\n maxFilenameLength?: number;\n}\n\n/**\n * File validation result\n */\nexport interface FileValidationResult {\n valid: boolean;\n error?: string;\n errorCode?: 'FILE_TOO_LARGE' | 'FILE_TOO_SMALL' | 'INVALID_TYPE' | 'BLOCKED_EXTENSION' | 'FILENAME_TOO_LONG' | 'EMPTY_FILE';\n}\n\n/**\n * Get file extension from filename (lowercase)\n */\nexport function getFileExtension(filename: string): string {\n const lastDot = filename.lastIndexOf('.');\n if (lastDot === -1 || lastDot === filename.length - 1) {\n return '';\n }\n return filename.substring(lastDot).toLowerCase();\n}\n\n/**\n * Sanitize filename for safe storage\n * Removes path traversal attempts and dangerous characters\n */\nexport function sanitizeFilename(filename: string): string {\n // Remove path components\n let sanitized = filename.replace(/^.*[\\\\/]/, '');\n\n // Remove null bytes and other control characters\n sanitized = sanitized.replace(/[\\x00-\\x1f\\x7f]/g, '');\n\n // Replace problematic characters\n sanitized = sanitized.replace(/[<>:\"/\\\\|?*]/g, '_');\n\n // Trim whitespace and dots from start/end\n sanitized = sanitized.replace(/^[\\s.]+|[\\s.]+$/g, '');\n\n // If empty after sanitization, use default name\n if (!sanitized) {\n sanitized = 'unnamed_file';\n }\n\n // Limit length\n if (sanitized.length > DEFAULT_FILE_CONSTRAINTS.maxFilenameLength) {\n const ext = getFileExtension(sanitized);\n const nameWithoutExt = sanitized.slice(0, -ext.length || undefined);\n const maxNameLength = DEFAULT_FILE_CONSTRAINTS.maxFilenameLength - ext.length;\n sanitized = nameWithoutExt.slice(0, maxNameLength) + ext;\n }\n\n return sanitized;\n}\n\n/**\n * Validate a file before upload\n * Returns validation result with error details if invalid\n */\nexport function validateFile(\n file: File,\n config: FileValidationConfig = {}\n): FileValidationResult {\n const {\n maxSizeBytes = DEFAULT_FILE_CONSTRAINTS.maxSizeBytes,\n minSizeBytes = DEFAULT_FILE_CONSTRAINTS.minSizeBytes,\n allowedMimeTypes = ALLOWED_MIME_TYPES,\n blockedExtensions = BLOCKED_EXTENSIONS,\n maxFilenameLength = DEFAULT_FILE_CONSTRAINTS.maxFilenameLength,\n } = config;\n\n // Check file size\n if (file.size === 0) {\n return {\n valid: false,\n error: 'File is empty',\n errorCode: 'EMPTY_FILE',\n };\n }\n\n if (file.size < minSizeBytes) {\n return {\n valid: false,\n error: `File is too small. Minimum size is ${formatFileSize(minSizeBytes)}`,\n errorCode: 'FILE_TOO_SMALL',\n };\n }\n\n if (file.size > maxSizeBytes) {\n return {\n valid: false,\n error: `File is too large. Maximum size is ${formatFileSize(maxSizeBytes)}`,\n errorCode: 'FILE_TOO_LARGE',\n };\n }\n\n // Check filename length\n if (file.name.length > maxFilenameLength) {\n return {\n valid: false,\n error: `Filename is too long. Maximum length is ${maxFilenameLength} characters`,\n errorCode: 'FILENAME_TOO_LONG',\n };\n }\n\n // Check for blocked extensions\n const extension = getFileExtension(file.name);\n if (extension && blockedExtensions.has(extension)) {\n return {\n valid: false,\n error: `File type \"${extension}\" is not allowed for security reasons`,\n errorCode: 'BLOCKED_EXTENSION',\n };\n }\n\n // Check MIME type\n const mimeType = file.type || 'application/octet-stream';\n if (!allowedMimeTypes.has(mimeType)) {\n // Allow files without explicit type if extension is safe\n if (mimeType === 'application/octet-stream' && extension && !blockedExtensions.has(extension)) {\n // Let it pass - backend will verify\n } else {\n return {\n valid: false,\n error: `File type \"${mimeType}\" is not allowed. Allowed types: images, documents, audio, video`,\n errorCode: 'INVALID_TYPE',\n };\n }\n }\n\n return { valid: true };\n}\n\n/**\n * Format file size to human-readable string\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];\n}\n\n/**\n * Generate accept attribute string from ALLOWED_MIME_TYPES\n * Used to sync file input accept with validation rules\n */\nexport function generateAcceptAttribute(allowedMimeTypes: ReadonlySet<string> = ALLOWED_MIME_TYPES): string {\n const accepts: string[] = [];\n\n allowedMimeTypes.forEach((mimeType) => {\n accepts.push(mimeType);\n });\n\n return accepts.join(',');\n}\n\n/**\n * Rate limiter for file uploads\n * Prevents rapid successive uploads\n */\nexport class UploadRateLimiter {\n private uploadTimestamps: number[] = [];\n private readonly maxUploads: number;\n private readonly windowMs: number;\n\n constructor(maxUploads = 5, windowMs = 60000) {\n this.maxUploads = maxUploads;\n this.windowMs = windowMs;\n }\n\n /**\n * Check if upload is allowed\n * Returns true if allowed, false if rate limited\n */\n canUpload(): boolean {\n const now = Date.now();\n // Remove timestamps outside the window\n this.uploadTimestamps = this.uploadTimestamps.filter(\n (timestamp) => now - timestamp < this.windowMs\n );\n return this.uploadTimestamps.length < this.maxUploads;\n }\n\n /**\n * Record an upload attempt\n */\n recordUpload(): void {\n this.uploadTimestamps.push(Date.now());\n }\n\n /**\n * Get remaining uploads in current window\n */\n getRemainingUploads(): number {\n const now = Date.now();\n this.uploadTimestamps = this.uploadTimestamps.filter(\n (timestamp) => now - timestamp < this.windowMs\n );\n return Math.max(0, this.maxUploads - this.uploadTimestamps.length);\n }\n\n /**\n * Get time until next upload is allowed (in ms)\n * Returns 0 if upload is allowed now\n */\n getTimeUntilNextUpload(): number {\n if (this.canUpload()) return 0;\n const oldestTimestamp = Math.min(...this.uploadTimestamps);\n return Math.max(0, this.windowMs - (Date.now() - oldestTimestamp));\n }\n\n /**\n * Reset the rate limiter\n */\n reset(): void {\n this.uploadTimestamps = [];\n }\n}\n","import type {\n CevroMessengerConfig,\n SendMessageRequest,\n Message,\n Conversation,\n ConversationHistoryItem,\n ConversationHistoryResponse,\n ConversationMessagesResponse,\n Agent,\n LocaleStrings,\n WidgetAppearanceConfig,\n} from '../types';\nimport { collectSessionData } from '../utils/session';\nimport {\n validateFile,\n sanitizeFilename,\n UploadRateLimiter,\n} from '../utils/file-validation';\n\n/**\n * API client for communicating with Cevro backend\n */\nexport class ApiClient {\n private config: CevroMessengerConfig;\n private accessToken: string | null = null;\n private contactId: string | null = null;\n private currentTicketId: string | null = null;\n private visitorToken: string | null = null;\n private currentAgent: Agent | null = null;\n private uploadRateLimiter: UploadRateLimiter;\n private visitorId: string | null = null;\n\n constructor(config: CevroMessengerConfig) {\n this.config = config;\n this.uploadRateLimiter = new UploadRateLimiter();\n }\n\n /**\n * Update config reference (used when config object is replaced)\n */\n updateConfig(config: CevroMessengerConfig): void {\n this.config = config;\n }\n\n /**\n * Set visitor token for authenticated requests\n */\n setVisitorToken(token: string): void {\n this.visitorToken = token;\n }\n\n /**\n * Get visitor token\n */\n getVisitorToken(): string | null {\n return this.visitorToken;\n }\n\n /**\n * Set access token for authenticated requests\n */\n setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n /**\n * Get current contact ID\n */\n getContactId(): string | null {\n return this.contactId;\n }\n\n /**\n * Get current ticket ID\n */\n getCurrentTicketId(): string | null {\n return this.currentTicketId;\n }\n\n /**\n * Set current ticket ID\n */\n setCurrentTicketId(ticketId: string): void {\n this.currentTicketId = ticketId;\n }\n\n /**\n * Get current agent info\n */\n getCurrentAgent(): Agent | null {\n return this.currentAgent;\n }\n\n /**\n * Make API request\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.config.apiBase}${endpoint}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(options.headers as Record<string, string> || {}),\n };\n\n // Add workspace headers for gateway auth\n if (this.config.workspaceId) {\n headers['X-Workspace-Id'] = this.config.workspaceId;\n }\n if (this.config.brandId) {\n headers['X-Brand-Id'] = this.config.brandId;\n }\n if (this.visitorToken) {\n headers['X-Visitor-Token'] = this.visitorToken;\n }\n if (this.config.player?.playerId) {\n headers['X-Player-Id'] = this.config.player.playerId;\n }\n if (this.config.player?.playerHash) {\n headers['X-Player-Hash'] = this.config.player.playerHash;\n }\n if (this.visitorId) {\n headers['X-Visitor-Id'] = this.visitorId;\n }\n\n if (this.accessToken) {\n headers['Authorization'] = `Bearer ${this.accessToken}`;\n }\n\n const response = await fetch(url, {\n ...options,\n headers,\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: response.statusText }));\n throw new Error(error.message || `Request failed: ${response.status}`);\n }\n\n return response.json();\n }\n\n /**\n * Initialize a chat session\n * Called when chat opens to create/restore session\n */\n async initSession(\n visitorId: string | null,\n visitorContactInfo?: { firstName: string; email: string } | null,\n options?: { forceNewTicket?: boolean }\n ): Promise<{\n sessionId: string;\n contactId: string;\n ticketId: string;\n visitorId: string;\n isNewSession: boolean;\n isNewTicket: boolean;\n ticketClosed?: boolean;\n ticketClosedReason?: string;\n agent?: Agent;\n typingConfig?: {\n onDurationMs: number;\n offDurationMs: number;\n };\n messages?: Message[];\n hasMoreMessages?: boolean;\n cursor?: string;\n locale?: Partial<LocaleStrings>;\n requireContactInfo?: boolean;\n missingFields?: ('firstName' | 'email')[];\n }> {\n const session = collectSessionData();\n\n const payload: any = {\n visitorId,\n session,\n brandId: this.config.brandId,\n // Use visitor contact info if provided, otherwise fall back to player config\n firstName: visitorContactInfo?.firstName || this.config.player?.firstName,\n lastName: this.config.player?.lastName,\n email: (visitorContactInfo?.email || this.config.player?.email) || undefined,\n phone: this.config.player?.phone,\n customAttributes: this.config.player?.customAttributes,\n forceNewTicket: options?.forceNewTicket,\n };\n\n // Add player data for authenticated users (for merge logic)\n if (this.config.player?.playerId) {\n payload.playerId = this.config.player.playerId;\n payload.playerHash = this.config.player.playerHash;\n }\n\n const result = await this.request<any>('/api/v1/sdk/session', {\n method: 'POST',\n body: JSON.stringify(payload),\n headers: visitorId ? { 'X-Visitor-Id': visitorId } : undefined,\n });\n\n // If contact info is required, return early without storing session\n if (result.requireContactInfo && result.missingFields?.length > 0) {\n return {\n sessionId: '',\n contactId: '',\n ticketId: '',\n visitorId: result.visitorId || '',\n isNewSession: false,\n isNewTicket: false,\n requireContactInfo: result.requireContactInfo,\n missingFields: result.missingFields,\n };\n }\n\n // Store contact, ticket IDs and agent info\n this.contactId = result.contactId;\n this.currentTicketId = result.ticketId;\n if (result.agent) {\n this.currentAgent = result.agent;\n }\n\n return {\n sessionId: result.sessionId,\n contactId: result.contactId,\n ticketId: result.ticketId,\n visitorId: result.visitorId,\n isNewSession: result.isNewSession,\n isNewTicket: result.isNewTicket,\n ticketClosed: result.ticketClosed,\n ticketClosedReason: result.ticketClosedReason,\n agent: result.agent,\n typingConfig: result.typingConfig,\n messages: result.messages?.map((msg: any) => this.normalizeMessage(msg)),\n hasMoreMessages: result.hasMoreMessages,\n cursor: result.cursor,\n locale: result.locale,\n requireContactInfo: result.requireContactInfo,\n };\n }\n\n /**\n * Send a message to an existing conversation\n */\n async sendMessage(message: string, assetId?: string): Promise<Message> {\n if (!this.contactId || !this.currentTicketId) {\n throw new Error('No active session. Call initSession first.');\n }\n\n const payload: SendMessageRequest = {\n contactId: this.contactId,\n ticketId: this.currentTicketId,\n message,\n assetId,\n };\n\n const result = await this.request<any>('/api/v1/sdk/send', {\n method: 'POST',\n body: JSON.stringify(payload),\n });\n\n // Server returns {success: true, message: {...}}, extract the message\n return this.normalizeMessage(result.message || result);\n }\n\n /**\n * Get messages for the current ticket (for authenticated users)\n */\n async getMessages(ticketId?: string): Promise<Message[]> {\n const targetTicketId = ticketId || this.currentTicketId;\n if (!targetTicketId) {\n throw new Error('No ticket ID available');\n }\n\n const result = await this.request<any>(\n `/api/v1/messages/my-tickets?supportTicketId=${targetTicketId}`\n );\n\n const messages = result.results || result.messages || result || [];\n return messages.map((msg: any) => this.normalizeMessage(msg));\n }\n\n /**\n * Get user's support tickets (for authenticated users)\n */\n async getMyTickets(): Promise<Conversation[]> {\n const result = await this.request<any>('/api/v1/messages/my-tickets');\n\n const tickets = result.results || result.tickets || result || [];\n return tickets.map((ticket: any) => this.normalizeConversation(ticket));\n }\n\n /**\n * Upload a file using presigned S3 URL for better performance.\n * The file is uploaded directly to S3, bypassing the backend.\n *\n * Security features:\n * - File size validation (client-side)\n * - MIME type whitelist validation\n * - Blocked extension check\n * - Rate limiting (uploads per minute)\n * - Filename sanitization\n *\n * @param file - The file to upload\n * @param onProgress - Optional callback for upload progress (0-100)\n * @returns The asset ID to use when sending messages\n * @throws Error if validation fails or rate limited\n */\n async uploadFile(\n file: File,\n onProgress?: (progress: number) => void\n ): Promise<string> {\n // Step 0: Rate limiting check\n if (!this.uploadRateLimiter.canUpload()) {\n const waitTime = Math.ceil(this.uploadRateLimiter.getTimeUntilNextUpload() / 1000);\n throw new Error(`Too many uploads. Please wait ${waitTime} seconds before uploading again.`);\n }\n\n // Step 1: Validate file (size, type, extension)\n const validation = validateFile(file);\n if (!validation.valid) {\n throw new Error(validation.error || 'File validation failed');\n }\n\n // Step 2: Sanitize filename\n const sanitizedFilename = sanitizeFilename(file.name);\n\n // Step 3: Record upload attempt for rate limiting\n this.uploadRateLimiter.recordUpload();\n\n // Step 4: Get presigned URL from backend\n const { uploadUrl, assetId } = await this.request<{\n uploadUrl: string;\n assetId: string;\n expiresIn: number;\n }>('/api/v1/sdk/upload-url', {\n method: 'POST',\n body: JSON.stringify({\n filename: sanitizedFilename,\n contentType: file.type || 'application/octet-stream',\n size: file.size,\n }),\n });\n\n // Step 5: Upload file directly to S3\n await this.uploadToS3(uploadUrl, file, onProgress);\n\n return assetId;\n }\n\n /**\n * Upload file directly to S3 using presigned URL\n */\n private async uploadToS3(\n uploadUrl: string,\n file: File,\n onProgress?: (progress: number) => void\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable && onProgress) {\n const progress = Math.round((event.loaded / event.total) * 100);\n onProgress(progress);\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Upload failed'));\n });\n\n xhr.open('PUT', uploadUrl);\n xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');\n xhr.send(file);\n });\n }\n\n /**\n * Normalize message object from API response\n */\n private normalizeMessage(data: any): Message {\n return {\n id: data.objectId || data.id,\n body: data.body || '',\n inbound: data.inbound || false,\n outbound: data.outbound || !data.inbound,\n createdAt: data.createdAt || new Date().toISOString(),\n type: data.type || 'text',\n mediaUrl: data.mediaUrl,\n mediaType: data.mediaType,\n status: data.status || 'sent',\n richContent: data.richContent,\n };\n }\n\n /**\n * Normalize conversation object from API response\n */\n private normalizeConversation(data: any): Conversation {\n return {\n id: data.objectId || data.id,\n conversationId: data.conversationId || data.objectId || data.id,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n status: data.resolved ? 'resolved' : data.escalated ? 'escalated' : 'open',\n unreadCount: data.unreadCount || 0,\n lastMessage: data.latestMessage ? this.normalizeMessage(data.latestMessage) : undefined,\n };\n }\n\n /**\n * Get Centrifugo connection token for real-time messaging\n *\n * For authenticated players: uses playerHash for identity verification\n * For visitors: uses server-signed visitorToken for security\n *\n * @param visitorToken - Server-signed visitor token (optional, server generates if not provided)\n */\n async getConnectionToken(visitorToken?: string | null): Promise<{\n token: string;\n visitorId: string;\n visitorToken: string;\n expiresAt: number;\n }> {\n const payload: any = {\n workspaceId: this.config.workspaceId,\n brandId: this.config.brandId,\n };\n\n if (visitorToken) {\n payload.visitorToken = visitorToken;\n }\n\n // Add player data for authenticated users\n if (this.config.player?.playerId) {\n payload.playerId = this.config.player.playerId;\n payload.playerHash = this.config.player.playerHash;\n payload.email = this.config.player.email || undefined;\n payload.firstName = this.config.player.firstName;\n }\n\n const result = await this.request<{\n token: string;\n visitorId: string;\n visitorToken: string;\n expiresAt: number;\n }>('/api/v1/sdk/token', {\n method: 'POST',\n body: JSON.stringify(payload),\n });\n\n return result;\n }\n\n /**\n * Refresh Centrifugo token before expiration\n */\n async refreshConnectionToken(visitorToken?: string | null): Promise<{\n token: string;\n visitorToken: string;\n expiresAt: number;\n }> {\n return this.getConnectionToken(visitorToken);\n }\n\n /**\n * Submit CSAT rating for a closed conversation\n */\n async submitCSAT(\n ticketId: string,\n contactId: string,\n rating: number,\n feedback?: string\n ): Promise<void> {\n await this.request('/api/v1/sdk/csat', {\n method: 'POST',\n body: JSON.stringify({\n ticketId,\n contactId,\n rating,\n feedback,\n }),\n });\n }\n\n /**\n * Get past conversations for the current contact\n */\n async getConversations(cursor?: string): Promise<{\n conversations: ConversationHistoryItem[];\n hasMore: boolean;\n cursor?: string;\n }> {\n const params = new URLSearchParams();\n if (cursor) params.set('cursor', cursor);\n\n const url = params.toString()\n ? `/api/v1/sdk/conversations?${params.toString()}`\n : '/api/v1/sdk/conversations';\n\n const result = await this.request<ConversationHistoryResponse>(url);\n\n return {\n conversations: result.conversations || [],\n hasMore: result.hasMore || false,\n cursor: result.cursor,\n };\n }\n\n /**\n * Get messages for a past conversation (paginated)\n */\n async getConversationMessages(ticketId: string, cursor?: string): Promise<{\n messages: Message[];\n hasMore: boolean;\n cursor?: string;\n }> {\n const params = new URLSearchParams();\n if (cursor) params.set('cursor', cursor);\n\n const base = `/api/v1/sdk/conversations/${ticketId}/messages`;\n const url = params.toString() ? `${base}?${params.toString()}` : base;\n\n const result = await this.request<ConversationMessagesResponse>(url);\n\n return {\n messages: (result.messages || []).map((msg: any) => this.normalizeMessage(msg)),\n hasMore: result.hasMore || false,\n cursor: result.cursor,\n };\n }\n\n /**\n * Set visitor ID (sent as X-Visitor-Id header on all requests)\n */\n setVisitorId(id: string): void {\n this.visitorId = id;\n }\n\n async getWidgetConfig(): Promise<WidgetAppearanceConfig> {\n try {\n const result = await this.request<WidgetAppearanceConfig>('/api/v1/sdk/widget-config', {\n method: 'GET',\n });\n return result;\n } catch (error) {\n // Return empty config on error - widget will use defaults\n return {};\n }\n }\n\n /**\n * Clear stored data (on shutdown)\n */\n clear(): void {\n this.accessToken = null;\n this.contactId = null;\n this.currentTicketId = null;\n this.visitorToken = null;\n this.visitorId = null;\n this.currentAgent = null;\n }\n}\n","/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise, SuppressedError, Symbol */\r\n\r\n\r\nfunction __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\ntypeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\n\nfunction getDefaultExportFromCjs (x) {\n\treturn x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;\n}\n\nvar events = {exports: {}};\n\nvar R = typeof Reflect === 'object' ? Reflect : null;\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n };\n\nvar ReflectOwnKeys;\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys;\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n};\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nevents.exports = EventEmitter;\nevents.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction _getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the `throw` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n checkListener(listener);\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = _getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n if (arguments.length === 0)\n return this.listener.call(this.target);\n return this.listener.apply(this.target, arguments);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n checkListener(listener);\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n checkListener(listener);\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n checkListener(listener);\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n\nfunction once(emitter, name) {\n return new Promise(function (resolve, reject) {\n function errorListener(err) {\n emitter.removeListener(name, resolver);\n reject(err);\n }\n\n function resolver() {\n if (typeof emitter.removeListener === 'function') {\n emitter.removeListener('error', errorListener);\n }\n resolve([].slice.call(arguments));\n }\n eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n if (name !== 'error') {\n addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n }\n });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n if (typeof emitter.on === 'function') {\n eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n if (typeof emitter.on === 'function') {\n if (flags.once) {\n emitter.once(name, listener);\n } else {\n emitter.on(name, listener);\n }\n } else if (typeof emitter.addEventListener === 'function') {\n // EventTarget does not have `error` event semantics like Node\n // EventEmitters, we do not listen for `error` events here.\n emitter.addEventListener(name, function wrapListener(arg) {\n // IE does not have builtin `{ once: true }` support so we\n // have to do it manually.\n if (flags.once) {\n emitter.removeEventListener(name, wrapListener);\n }\n listener(arg);\n });\n } else {\n throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n }\n}\n\nvar eventsExports = events.exports;\nvar EventEmitter$1 = /*@__PURE__*/getDefaultExportFromCjs(eventsExports);\n\nvar errorCodes;\n(function (errorCodes) {\n errorCodes[errorCodes[\"timeout\"] = 1] = \"timeout\";\n errorCodes[errorCodes[\"transportClosed\"] = 2] = \"transportClosed\";\n errorCodes[errorCodes[\"clientDisconnected\"] = 3] = \"clientDisconnected\";\n errorCodes[errorCodes[\"clientClosed\"] = 4] = \"clientClosed\";\n errorCodes[errorCodes[\"clientConnectToken\"] = 5] = \"clientConnectToken\";\n errorCodes[errorCodes[\"clientRefreshToken\"] = 6] = \"clientRefreshToken\";\n errorCodes[errorCodes[\"subscriptionUnsubscribed\"] = 7] = \"subscriptionUnsubscribed\";\n errorCodes[errorCodes[\"subscriptionSubscribeToken\"] = 8] = \"subscriptionSubscribeToken\";\n errorCodes[errorCodes[\"subscriptionRefreshToken\"] = 9] = \"subscriptionRefreshToken\";\n errorCodes[errorCodes[\"transportWriteError\"] = 10] = \"transportWriteError\";\n errorCodes[errorCodes[\"connectionClosed\"] = 11] = \"connectionClosed\";\n errorCodes[errorCodes[\"badConfiguration\"] = 12] = \"badConfiguration\";\n})(errorCodes || (errorCodes = {}));\nvar connectingCodes;\n(function (connectingCodes) {\n connectingCodes[connectingCodes[\"connectCalled\"] = 0] = \"connectCalled\";\n connectingCodes[connectingCodes[\"transportClosed\"] = 1] = \"transportClosed\";\n connectingCodes[connectingCodes[\"noPing\"] = 2] = \"noPing\";\n connectingCodes[connectingCodes[\"subscribeTimeout\"] = 3] = \"subscribeTimeout\";\n connectingCodes[connectingCodes[\"unsubscribeError\"] = 4] = \"unsubscribeError\";\n})(connectingCodes || (connectingCodes = {}));\nvar disconnectedCodes;\n(function (disconnectedCodes) {\n disconnectedCodes[disconnectedCodes[\"disconnectCalled\"] = 0] = \"disconnectCalled\";\n disconnectedCodes[disconnectedCodes[\"unauthorized\"] = 1] = \"unauthorized\";\n disconnectedCodes[disconnectedCodes[\"badProtocol\"] = 2] = \"badProtocol\";\n disconnectedCodes[disconnectedCodes[\"messageSizeLimit\"] = 3] = \"messageSizeLimit\";\n})(disconnectedCodes || (disconnectedCodes = {}));\nvar subscribingCodes;\n(function (subscribingCodes) {\n subscribingCodes[subscribingCodes[\"subscribeCalled\"] = 0] = \"subscribeCalled\";\n subscribingCodes[subscribingCodes[\"transportClosed\"] = 1] = \"transportClosed\";\n})(subscribingCodes || (subscribingCodes = {}));\nvar unsubscribedCodes;\n(function (unsubscribedCodes) {\n unsubscribedCodes[unsubscribedCodes[\"unsubscribeCalled\"] = 0] = \"unsubscribeCalled\";\n unsubscribedCodes[unsubscribedCodes[\"unauthorized\"] = 1] = \"unauthorized\";\n unsubscribedCodes[unsubscribedCodes[\"clientClosed\"] = 2] = \"clientClosed\";\n})(unsubscribedCodes || (unsubscribedCodes = {}));\nvar subscriptionFlags;\n(function (subscriptionFlags) {\n subscriptionFlags[subscriptionFlags[\"channelCompaction\"] = 1] = \"channelCompaction\";\n})(subscriptionFlags || (subscriptionFlags = {}));\n\n/** State of client. */\nvar State;\n(function (State) {\n State[\"Disconnected\"] = \"disconnected\";\n State[\"Connecting\"] = \"connecting\";\n State[\"Connected\"] = \"connected\";\n})(State || (State = {}));\n/** State of Subscription */\nvar SubscriptionState;\n(function (SubscriptionState) {\n SubscriptionState[\"Unsubscribed\"] = \"unsubscribed\";\n SubscriptionState[\"Subscribing\"] = \"subscribing\";\n SubscriptionState[\"Subscribed\"] = \"subscribed\";\n})(SubscriptionState || (SubscriptionState = {}));\n\n/** @internal */\nfunction startsWith(value, prefix) {\n return value.lastIndexOf(prefix, 0) === 0;\n}\n/** @internal */\nfunction isFunction(value) {\n if (value === undefined || value === null) {\n return false;\n }\n return typeof value === 'function';\n}\n/** @internal */\nfunction log(level, args) {\n if (globalThis.console) {\n const logger = globalThis.console[level];\n if (isFunction(logger)) {\n logger.apply(globalThis.console, args);\n }\n }\n}\nfunction randomInt(min, max) {\n return Math.floor(Math.random() * (max - min + 1) + min);\n}\n/** @internal */\nfunction backoff(step, min, max) {\n // Full jitter technique, see:\n // https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/\n if (step > 31) {\n step = 31;\n }\n const interval = randomInt(0, Math.min(max, min * Math.pow(2, step)));\n return Math.min(max, min + interval);\n}\n/** @internal */\nfunction errorExists(data) {\n return 'error' in data && data.error !== null;\n}\n/** @internal */\nfunction ttlMilliseconds(ttl) {\n // https://stackoverflow.com/questions/12633405/what-is-the-maximum-delay-for-setinterval\n return Math.min(ttl * 1000, 2147483647);\n}\n\n/** Subscription to a channel */\nclass Subscription extends EventEmitter$1 {\n /** Subscription constructor should not be used directly, create subscriptions using Client method. */\n constructor(centrifuge, channel, options) {\n super();\n this._resubscribeTimeout = null;\n this._refreshTimeout = null;\n this.channel = channel;\n this.state = SubscriptionState.Unsubscribed;\n this._centrifuge = centrifuge;\n this._token = '';\n this._getToken = null;\n this._data = null;\n this._getData = null;\n this._recover = false;\n this._offset = null;\n this._epoch = null;\n this._id = 0;\n this._recoverable = false;\n this._positioned = false;\n this._joinLeave = false;\n this._minResubscribeDelay = 500;\n this._maxResubscribeDelay = 20000;\n this._resubscribeTimeout = null;\n this._resubscribeAttempts = 0;\n this._promises = {};\n this._promiseId = 0;\n this._inflight = false;\n this._refreshTimeout = null;\n this._delta = '';\n this._delta_negotiated = false;\n this._tagsFilter = null;\n this._prevValue = null;\n this._unsubPromise = Promise.resolve();\n this._setOptions(options);\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n if (this._centrifuge._debugEnabled) {\n this.on('state', (ctx) => {\n this._debug('subscription state', channel, ctx.oldState, '->', ctx.newState);\n });\n this.on('error', (ctx) => {\n this._debug('subscription error', channel, ctx);\n });\n }\n else {\n // Avoid unhandled exception in EventEmitter for non-set error handler.\n this.on('error', function () { Function.prototype(); });\n }\n }\n /** ready returns a Promise which resolves upon subscription goes to Subscribed\n * state and rejects in case of subscription goes to Unsubscribed state.\n * Optional timeout can be passed.*/\n ready(timeout) {\n if (this.state === SubscriptionState.Unsubscribed) {\n return Promise.reject({ code: errorCodes.subscriptionUnsubscribed, message: this.state });\n }\n if (this.state === SubscriptionState.Subscribed) {\n return Promise.resolve();\n }\n return new Promise((res, rej) => {\n const ctx = {\n resolve: res,\n reject: rej\n };\n if (timeout) {\n ctx.timeout = setTimeout(function () {\n rej({ code: errorCodes.timeout, message: 'timeout' });\n }, timeout);\n }\n this._promises[this._nextPromiseId()] = ctx;\n });\n }\n /** subscribe to a channel.*/\n subscribe() {\n if (this._isSubscribed()) {\n return;\n }\n this._resubscribeAttempts = 0;\n this._setSubscribing(subscribingCodes.subscribeCalled, 'subscribe called');\n }\n /** unsubscribe from a channel, keeping position state.*/\n unsubscribe() {\n this._unsubPromise = this._setUnsubscribed(unsubscribedCodes.unsubscribeCalled, 'unsubscribe called', true);\n }\n /** publish data to a channel.*/\n publish(data) {\n return __awaiter(this, void 0, void 0, function* () {\n yield this._methodCall();\n return this._centrifuge.publish(this.channel, data);\n });\n }\n /** get online presence for a channel.*/\n presence() {\n return __awaiter(this, void 0, void 0, function* () {\n yield this._methodCall();\n return this._centrifuge.presence(this.channel);\n });\n }\n /** presence stats for a channel (num clients and unique users).*/\n presenceStats() {\n return __awaiter(this, void 0, void 0, function* () {\n yield this._methodCall();\n return this._centrifuge.presenceStats(this.channel);\n });\n }\n /** history for a channel. By default it does not return publications (only current\n * StreamPosition data) – provide an explicit limit > 0 to load publications.*/\n history(opts) {\n return __awaiter(this, void 0, void 0, function* () {\n yield this._methodCall();\n return this._centrifuge.history(this.channel, opts);\n });\n }\n /**\n * Sets server-side tags filter for the subscription.\n * This only applies on the next subscription attempt, not the current one.\n * Cannot be used together with delta option.\n *\n * @param tagsFilter - Filter configuration object or null to remove filter\n * @throws {Error} If both delta and tagsFilter are configured\n *\n * @example\n * ```typescript\n * // Simple equality filter\n * sub.setTagsFilter({\n * key: 'ticker',\n * cmp: 'eq',\n * val: 'BTC'\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Complex filter with logical operators\n * sub.setTagsFilter({\n * op: 'and',\n * nodes: [\n * { key: 'ticker', cmp: 'eq', val: 'BTC' },\n * { key: 'price', cmp: 'gt', val: '50000' }\n * ]\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Filter with IN operator\n * sub.setTagsFilter({\n * key: 'ticker',\n * cmp: 'in',\n * vals: ['BTC', 'ETH', 'SOL']\n * });\n * ```\n */\n setTagsFilter(tagsFilter) {\n if (tagsFilter && this._delta) {\n throw new Error('cannot use delta and tagsFilter together');\n }\n this._tagsFilter = tagsFilter;\n }\n /** setData allows setting subscription data. This only applied on the next subscription attempt,\n * Note that if getData callback is configured, it will override this value during resubscriptions. */\n setData(data) {\n this._data = data;\n }\n _methodCall() {\n if (this._isSubscribed()) {\n return Promise.resolve();\n }\n if (this._isUnsubscribed()) {\n return Promise.reject({\n code: errorCodes.subscriptionUnsubscribed,\n message: this.state\n });\n }\n return new Promise((resolve, reject) => {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n const timeoutDuration = this._centrifuge._config.timeout;\n const timeout = setTimeout(() => {\n reject({ code: errorCodes.timeout, message: 'timeout' });\n }, timeoutDuration);\n this._promises[this._nextPromiseId()] = {\n timeout,\n resolve,\n reject\n };\n });\n }\n _nextPromiseId() {\n return ++this._promiseId;\n }\n _needRecover() {\n return this._recover === true;\n }\n _isUnsubscribed() {\n return this.state === SubscriptionState.Unsubscribed;\n }\n _isSubscribing() {\n return this.state === SubscriptionState.Subscribing;\n }\n _isSubscribed() {\n return this.state === SubscriptionState.Subscribed;\n }\n _setState(newState) {\n if (this.state !== newState) {\n const oldState = this.state;\n this.state = newState;\n this.emit('state', { newState, oldState, channel: this.channel });\n return true;\n }\n return false;\n }\n _usesToken() {\n return this._token !== '' || this._getToken !== null;\n }\n _clearSubscribingState() {\n this._resubscribeAttempts = 0;\n this._clearResubscribeTimeout();\n }\n _clearSubscribedState() {\n this._clearRefreshTimeout();\n }\n _setSubscribed(result) {\n if (!this._isSubscribing()) {\n return;\n }\n this._clearSubscribingState();\n if (result.id) {\n this._id = result.id;\n }\n if (result.recoverable) {\n this._recover = true;\n this._offset = result.offset || 0;\n this._epoch = result.epoch || '';\n }\n if (result.delta) {\n this._delta_negotiated = true;\n }\n else {\n this._delta_negotiated = false;\n }\n this._setState(SubscriptionState.Subscribed);\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n const ctx = this._centrifuge._getSubscribeContext(this.channel, result);\n this.emit('subscribed', ctx);\n this._resolvePromises();\n const pubs = result.publications;\n if (pubs && pubs.length > 0) {\n for (const i in pubs) {\n if (!pubs.hasOwnProperty(i)) {\n continue;\n }\n this._handlePublication(pubs[i]);\n }\n }\n if (result.expires === true) {\n this._refreshTimeout = setTimeout(() => this._refresh(), ttlMilliseconds(result.ttl));\n }\n }\n _setSubscribing(code, reason) {\n return __awaiter(this, void 0, void 0, function* () {\n if (this._isSubscribing()) {\n return;\n }\n if (this._isSubscribed()) {\n this._clearSubscribedState();\n }\n if (this._setState(SubscriptionState.Subscribing)) {\n this.emit('subscribing', { channel: this.channel, code: code, reason: reason });\n }\n // @ts-ignore – for performance reasons only await _unsubPromise for emulution case where it's required.\n if (this._centrifuge._transport && this._centrifuge._transport.emulation()) {\n yield this._unsubPromise;\n }\n if (!this._isSubscribing()) {\n return;\n }\n this._subscribe();\n });\n }\n _subscribe() {\n this._debug('subscribing on', this.channel);\n if (!this._isTransportOpen()) {\n this._debug('delay subscribe on', this.channel, 'till connected');\n return null;\n }\n if (this._inflight) {\n return null;\n }\n this._inflight = true;\n if (this._canSubscribeWithoutGettingToken()) {\n return this._subscribeWithoutToken();\n }\n this._getSubscriptionToken()\n .then(token => this._handleTokenResponse(token))\n .catch(e => this._handleTokenError(e));\n return null;\n }\n _isTransportOpen() {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n return this._centrifuge._transportIsOpen;\n }\n _canSubscribeWithoutGettingToken() {\n return !this._usesToken() || !!this._token;\n }\n _subscribeWithoutToken() {\n if (this._getData) {\n this._getDataAndSubscribe(this._token);\n return null;\n }\n else {\n return this._sendSubscribe(this._token);\n }\n }\n _getDataAndSubscribe(token) {\n if (!this._getData) {\n this._inflight = false;\n return;\n }\n this._getData({ channel: this.channel })\n .then(data => {\n if (!this._isSubscribing()) {\n this._inflight = false;\n return;\n }\n this._data = data;\n this._sendSubscribe(token);\n })\n .catch(e => this._handleGetDataError(e));\n }\n _handleGetDataError(error) {\n if (!this._isSubscribing()) {\n this._inflight = false;\n return;\n }\n if (error instanceof UnauthorizedError) {\n this._inflight = false;\n this._failUnauthorized();\n return;\n }\n this.emit('error', {\n type: 'subscribeData',\n channel: this.channel,\n error: {\n code: errorCodes.badConfiguration,\n message: (error === null || error === void 0 ? void 0 : error.toString()) || ''\n }\n });\n this._inflight = false;\n this._scheduleResubscribe();\n }\n _handleTokenResponse(token) {\n if (!this._isSubscribing()) {\n this._inflight = false;\n return;\n }\n if (!token) {\n this._inflight = false;\n this._failUnauthorized();\n return;\n }\n this._token = token;\n if (this._getData) {\n this._getDataAndSubscribe(token);\n }\n else {\n this._sendSubscribe(token);\n }\n }\n _handleTokenError(error) {\n if (!this._isSubscribing()) {\n this._inflight = false;\n return;\n }\n if (error instanceof UnauthorizedError) {\n this._inflight = false;\n this._failUnauthorized();\n return;\n }\n this.emit('error', {\n type: 'subscribeToken',\n channel: this.channel,\n error: {\n code: errorCodes.subscriptionSubscribeToken,\n message: (error === null || error === void 0 ? void 0 : error.toString()) || ''\n }\n });\n this._inflight = false;\n this._scheduleResubscribe();\n }\n _sendSubscribe(token) {\n if (!this._isTransportOpen()) {\n this._inflight = false;\n return null;\n }\n const cmd = this._buildSubscribeCommand(token);\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n this._centrifuge._call(cmd).then(resolveCtx => {\n this._inflight = false;\n const result = resolveCtx.reply.subscribe;\n this._handleSubscribeResponse(result);\n if (resolveCtx.next) {\n resolveCtx.next();\n }\n }, rejectCtx => {\n this._inflight = false;\n this._handleSubscribeError(rejectCtx.error);\n if (rejectCtx.next) {\n rejectCtx.next();\n }\n });\n return cmd;\n }\n _buildSubscribeCommand(token) {\n const req = { channel: this.channel };\n if (token)\n req.token = token;\n if (this._data)\n req.data = this._data;\n if (this._positioned)\n req.positioned = true;\n if (this._recoverable)\n req.recoverable = true;\n if (this._joinLeave)\n req.join_leave = true;\n req.flag = subscriptionFlags.channelCompaction;\n if (this._needRecover()) {\n req.recover = true;\n const offset = this._getOffset();\n if (offset)\n req.offset = offset;\n const epoch = this._getEpoch();\n if (epoch)\n req.epoch = epoch;\n }\n if (this._delta)\n req.delta = this._delta;\n if (this._tagsFilter)\n req.tf = this._tagsFilter;\n return { subscribe: req };\n }\n _debug(...args) {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n this._centrifuge._debug(...args);\n }\n _handleSubscribeError(error) {\n if (!this._isSubscribing()) {\n return;\n }\n if (error.code === errorCodes.timeout) {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n this._centrifuge._disconnect(connectingCodes.subscribeTimeout, 'subscribe timeout', true);\n return;\n }\n this._subscribeError(error);\n }\n _handleSubscribeResponse(result) {\n if (!this._isSubscribing()) {\n return;\n }\n this._setSubscribed(result);\n }\n _setUnsubscribed(code, reason, sendUnsubscribe) {\n if (this._isUnsubscribed()) {\n return Promise.resolve();\n }\n let promise = Promise.resolve();\n if (this._isSubscribed()) {\n if (sendUnsubscribe) {\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n promise = this._centrifuge._unsubscribe(this);\n }\n this._clearSubscribedState();\n }\n else if (this._isSubscribing()) {\n if (this._inflight && sendUnsubscribe) {\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n promise = this._centrifuge._unsubscribe(this);\n }\n this._clearSubscribingState();\n }\n this._inflight = false;\n if (this._setState(SubscriptionState.Unsubscribed)) {\n this.emit('unsubscribed', { channel: this.channel, code: code, reason: reason });\n }\n this._rejectPromises({ code: errorCodes.subscriptionUnsubscribed, message: this.state });\n return promise;\n }\n _handlePublication(pub) {\n if (this._delta && this._delta_negotiated) {\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n const { newData, newPrevValue } = this._centrifuge._codec.applyDeltaIfNeeded(pub, this._prevValue);\n pub.data = newData;\n this._prevValue = newPrevValue;\n }\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n const ctx = this._centrifuge._getPublicationContext(this.channel, pub);\n this.emit('publication', ctx);\n if (pub.offset) {\n this._offset = pub.offset;\n }\n }\n _handleJoin(join) {\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n const info = this._centrifuge._getJoinLeaveContext(join.info);\n this.emit('join', { channel: this.channel, info: info });\n }\n _handleLeave(leave) {\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n const info = this._centrifuge._getJoinLeaveContext(leave.info);\n this.emit('leave', { channel: this.channel, info: info });\n }\n _resolvePromises() {\n for (const id in this._promises) {\n if (!this._promises.hasOwnProperty(id)) {\n continue;\n }\n if (this._promises[id].timeout) {\n clearTimeout(this._promises[id].timeout);\n }\n this._promises[id].resolve();\n delete this._promises[id];\n }\n }\n _rejectPromises(err) {\n for (const id in this._promises) {\n if (!this._promises.hasOwnProperty(id)) {\n continue;\n }\n if (this._promises[id].timeout) {\n clearTimeout(this._promises[id].timeout);\n }\n this._promises[id].reject(err);\n delete this._promises[id];\n }\n }\n _scheduleResubscribe() {\n if (!this._isSubscribing()) {\n this._debug('not in subscribing state, skip resubscribe scheduling', this.channel);\n return;\n }\n const self = this;\n const delay = this._getResubscribeDelay();\n this._resubscribeTimeout = setTimeout(function () {\n if (self._isSubscribing()) {\n self._subscribe();\n }\n }, delay);\n this._debug('resubscribe scheduled after ' + delay, this.channel);\n }\n _subscribeError(err) {\n if (!this._isSubscribing()) {\n return;\n }\n if (err.code < 100 || err.code === 109 || err.temporary === true) {\n if (err.code === 109) { // Token expired error.\n this._token = '';\n }\n const errContext = {\n channel: this.channel,\n type: 'subscribe',\n error: err\n };\n if (this._centrifuge.state === State.Connected) {\n this.emit('error', errContext);\n }\n this._scheduleResubscribe();\n }\n else {\n this._setUnsubscribed(err.code, err.message, false);\n }\n }\n _getResubscribeDelay() {\n const delay = backoff(this._resubscribeAttempts, this._minResubscribeDelay, this._maxResubscribeDelay);\n this._resubscribeAttempts++;\n return delay;\n }\n _setOptions(options) {\n if (!options) {\n return;\n }\n if (options.since) {\n this._offset = options.since.offset || 0;\n this._epoch = options.since.epoch || '';\n this._recover = true;\n }\n if (options.data) {\n this._data = options.data;\n }\n if (options.getData) {\n this._getData = options.getData;\n }\n if (options.minResubscribeDelay !== undefined) {\n this._minResubscribeDelay = options.minResubscribeDelay;\n }\n if (options.maxResubscribeDelay !== undefined) {\n this._maxResubscribeDelay = options.maxResubscribeDelay;\n }\n if (options.token) {\n this._token = options.token;\n }\n if (options.getToken) {\n this._getToken = options.getToken;\n }\n if (options.positioned === true) {\n this._positioned = true;\n }\n if (options.recoverable === true) {\n this._recoverable = true;\n }\n if (options.joinLeave === true) {\n this._joinLeave = true;\n }\n if (options.delta) {\n if (options.delta !== 'fossil') {\n throw new Error('unsupported delta format');\n }\n this._delta = options.delta;\n }\n if (options.tagsFilter) {\n this._tagsFilter = options.tagsFilter;\n }\n if (this._tagsFilter && this._delta) {\n throw new Error('cannot use delta and tagsFilter together');\n }\n }\n _getOffset() {\n const offset = this._offset;\n if (offset !== null) {\n return offset;\n }\n return 0;\n }\n _getEpoch() {\n const epoch = this._epoch;\n if (epoch !== null) {\n return epoch;\n }\n return '';\n }\n _clearRefreshTimeout() {\n if (this._refreshTimeout !== null) {\n clearTimeout(this._refreshTimeout);\n this._refreshTimeout = null;\n }\n }\n _clearResubscribeTimeout() {\n if (this._resubscribeTimeout !== null) {\n clearTimeout(this._resubscribeTimeout);\n this._resubscribeTimeout = null;\n }\n }\n _getSubscriptionToken() {\n this._debug('get subscription token for channel', this.channel);\n const ctx = {\n channel: this.channel\n };\n const getToken = this._getToken;\n if (getToken === null) {\n this.emit('error', {\n type: 'configuration',\n channel: this.channel,\n error: {\n code: errorCodes.badConfiguration,\n message: 'provide a function to get channel subscription token'\n }\n });\n return Promise.reject(new UnauthorizedError(''));\n }\n return getToken(ctx);\n }\n _refresh() {\n this._clearRefreshTimeout();\n const self = this;\n this._getSubscriptionToken().then(function (token) {\n if (!self._isSubscribed()) {\n return;\n }\n if (!token) {\n self._failUnauthorized();\n return;\n }\n self._token = token;\n const req = {\n channel: self.channel,\n token: token\n };\n const msg = {\n 'sub_refresh': req\n };\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n self._centrifuge._call(msg).then(resolveCtx => {\n const result = resolveCtx.reply.sub_refresh;\n self._refreshResponse(result);\n if (resolveCtx.next) {\n resolveCtx.next();\n }\n }, rejectCtx => {\n self._refreshError(rejectCtx.error);\n if (rejectCtx.next) {\n rejectCtx.next();\n }\n });\n }).catch(function (e) {\n if (e instanceof UnauthorizedError) {\n self._failUnauthorized();\n return;\n }\n self.emit('error', {\n type: 'refreshToken',\n channel: self.channel,\n error: {\n code: errorCodes.subscriptionRefreshToken,\n message: e !== undefined ? e.toString() : ''\n }\n });\n self._refreshTimeout = setTimeout(() => self._refresh(), self._getRefreshRetryDelay());\n });\n }\n _refreshResponse(result) {\n if (!this._isSubscribed()) {\n return;\n }\n this._debug('subscription token refreshed, channel', this.channel);\n this._clearRefreshTimeout();\n if (result.expires === true) {\n this._refreshTimeout = setTimeout(() => this._refresh(), ttlMilliseconds(result.ttl));\n }\n }\n _refreshError(err) {\n if (!this._isSubscribed()) {\n return;\n }\n if (err.code < 100 || err.temporary === true) {\n this.emit('error', {\n type: 'refresh',\n channel: this.channel,\n error: err\n });\n this._refreshTimeout = setTimeout(() => this._refresh(), this._getRefreshRetryDelay());\n }\n else {\n this._setUnsubscribed(err.code, err.message, true);\n }\n }\n _getRefreshRetryDelay() {\n return backoff(0, 10000, 20000);\n }\n _failUnauthorized() {\n this._setUnsubscribed(unsubscribedCodes.unauthorized, 'unauthorized', true);\n }\n}\n\n/** @internal */\nclass SockjsTransport {\n constructor(endpoint, options) {\n this.endpoint = endpoint;\n this.options = options;\n this._transport = null;\n }\n name() {\n return 'sockjs';\n }\n subName() {\n return 'sockjs-' + this._transport.transport;\n }\n emulation() {\n return false;\n }\n supported() {\n return this.options.sockjs !== null;\n }\n initialize(_protocol, callbacks) {\n this._transport = new this.options.sockjs(this.endpoint, null, this.options.sockjsOptions);\n this._transport.onopen = () => {\n callbacks.onOpen();\n };\n this._transport.onerror = e => {\n callbacks.onError(e);\n };\n this._transport.onclose = closeEvent => {\n callbacks.onClose(closeEvent);\n };\n this._transport.onmessage = event => {\n callbacks.onMessage(event.data);\n };\n }\n close() {\n this._transport.close();\n }\n send(data) {\n this._transport.send(data);\n }\n}\n\n/** @internal */\nclass WebsocketTransport {\n constructor(endpoint, options) {\n this.endpoint = endpoint;\n this.options = options;\n this._transport = null;\n }\n name() {\n return 'websocket';\n }\n subName() {\n return 'websocket';\n }\n emulation() {\n return false;\n }\n supported() {\n return this.options.websocket !== undefined && this.options.websocket !== null;\n }\n initialize(protocol, callbacks) {\n let subProtocol = '';\n if (protocol === 'protobuf') {\n subProtocol = 'centrifuge-protobuf';\n }\n if (subProtocol !== '') {\n this._transport = new this.options.websocket(this.endpoint, subProtocol);\n }\n else {\n this._transport = new this.options.websocket(this.endpoint);\n }\n if (protocol === 'protobuf') {\n this._transport.binaryType = 'arraybuffer';\n }\n this._transport.onopen = () => {\n callbacks.onOpen();\n };\n this._transport.onerror = e => {\n callbacks.onError(e);\n };\n this._transport.onclose = closeEvent => {\n callbacks.onClose(closeEvent);\n };\n this._transport.onmessage = event => {\n callbacks.onMessage(event.data);\n };\n }\n close() {\n this._transport.close();\n }\n send(data) {\n this._transport.send(data);\n }\n}\n\n/** @internal */\nclass HttpStreamTransport {\n constructor(endpoint, options) {\n this.endpoint = endpoint;\n this.options = options;\n this._abortController = null;\n this._utf8decoder = new TextDecoder();\n this._protocol = 'json';\n }\n name() {\n return 'http_stream';\n }\n subName() {\n return 'http_stream';\n }\n emulation() {\n return true;\n }\n _handleErrors(response) {\n if (!response.ok)\n throw new Error(response.status);\n return response;\n }\n _fetchEventTarget(self, endpoint, options) {\n const eventTarget = new EventTarget();\n // fetch with connection timeout maybe? https://github.com/github/fetch/issues/175\n const fetchFunc = self.options.fetch;\n fetchFunc(endpoint, options)\n .then(self._handleErrors)\n .then(response => {\n eventTarget.dispatchEvent(new Event('open'));\n let jsonStreamBuf = '';\n let jsonStreamPos = 0;\n let protoStreamBuf = new Uint8Array();\n const reader = response.body.getReader();\n return new self.options.readableStream({\n start(controller) {\n function pump() {\n return reader.read().then(({ done, value }) => {\n // When no more data needs to be consumed, close the stream\n if (done) {\n eventTarget.dispatchEvent(new Event('close'));\n controller.close();\n return;\n }\n try {\n if (self._protocol === 'json') {\n jsonStreamBuf += self._utf8decoder.decode(value);\n while (jsonStreamPos < jsonStreamBuf.length) {\n if (jsonStreamBuf[jsonStreamPos] === '\\n') {\n const line = jsonStreamBuf.substring(0, jsonStreamPos);\n eventTarget.dispatchEvent(new MessageEvent('message', { data: line }));\n jsonStreamBuf = jsonStreamBuf.substring(jsonStreamPos + 1);\n jsonStreamPos = 0;\n }\n else {\n ++jsonStreamPos;\n }\n }\n }\n else {\n const mergedArray = new Uint8Array(protoStreamBuf.length + value.length);\n mergedArray.set(protoStreamBuf);\n mergedArray.set(value, protoStreamBuf.length);\n protoStreamBuf = mergedArray;\n while (true) {\n const result = self.options.decoder.decodeReply(protoStreamBuf);\n if (result.ok) {\n const data = protoStreamBuf.slice(0, result.pos);\n eventTarget.dispatchEvent(new MessageEvent('message', { data: data }));\n protoStreamBuf = protoStreamBuf.slice(result.pos);\n continue;\n }\n break;\n }\n }\n }\n catch (error) {\n // @ts-ignore - improve later.\n eventTarget.dispatchEvent(new Event('error', { detail: error }));\n eventTarget.dispatchEvent(new Event('close'));\n controller.close();\n return;\n }\n pump();\n }).catch(function (e) {\n // @ts-ignore - improve later.\n eventTarget.dispatchEvent(new Event('error', { detail: e }));\n eventTarget.dispatchEvent(new Event('close'));\n controller.close();\n return;\n });\n }\n return pump();\n }\n });\n })\n .catch(error => {\n // @ts-ignore - improve later.\n eventTarget.dispatchEvent(new Event('error', { detail: error }));\n eventTarget.dispatchEvent(new Event('close'));\n });\n return eventTarget;\n }\n supported() {\n return this.options.fetch !== null &&\n this.options.readableStream !== null &&\n typeof TextDecoder !== 'undefined' &&\n typeof AbortController !== 'undefined' &&\n typeof EventTarget !== 'undefined' &&\n typeof Event !== 'undefined' &&\n typeof MessageEvent !== 'undefined' &&\n typeof Error !== 'undefined';\n }\n initialize(protocol, callbacks, initialData) {\n this._protocol = protocol;\n this._abortController = new AbortController();\n let headers;\n let body;\n if (protocol === 'json') {\n headers = {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n };\n body = initialData;\n }\n else {\n headers = {\n 'Accept': 'application/octet-stream',\n 'Content-Type': 'application/octet-stream'\n };\n body = initialData;\n }\n const fetchOptions = {\n method: 'POST',\n headers: headers,\n body: body,\n mode: 'cors',\n credentials: 'same-origin',\n signal: this._abortController.signal\n };\n const eventTarget = this._fetchEventTarget(this, this.endpoint, fetchOptions);\n eventTarget.addEventListener('open', () => {\n callbacks.onOpen();\n });\n eventTarget.addEventListener('error', (e) => {\n this._abortController.abort();\n callbacks.onError(e);\n });\n eventTarget.addEventListener('close', () => {\n this._abortController.abort();\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n });\n eventTarget.addEventListener('message', (e) => {\n callbacks.onMessage(e.data);\n });\n }\n close() {\n this._abortController.abort();\n }\n send(data, session, node) {\n let headers;\n let body;\n const req = {\n session: session,\n node: node,\n data: data\n };\n if (this._protocol === 'json') {\n headers = {\n 'Content-Type': 'application/json'\n };\n body = JSON.stringify(req);\n }\n else {\n headers = {\n 'Content-Type': 'application/octet-stream'\n };\n body = this.options.encoder.encodeEmulationRequest(req);\n }\n const fetchFunc = this.options.fetch;\n const fetchOptions = {\n method: 'POST',\n headers: headers,\n body: body,\n mode: 'cors',\n credentials: 'same-origin',\n };\n fetchFunc(this.options.emulationEndpoint, fetchOptions);\n }\n}\n\n/** @internal */\nclass SseTransport {\n constructor(endpoint, options) {\n this.endpoint = endpoint;\n this.options = options;\n this._protocol = 'json';\n this._transport = null;\n this._onClose = null;\n }\n name() {\n return 'sse';\n }\n subName() {\n return 'sse';\n }\n emulation() {\n return true;\n }\n supported() {\n return this.options.eventsource !== null && this.options.fetch !== null;\n }\n initialize(_protocol, callbacks, initialData) {\n let url;\n if (globalThis && globalThis.document && globalThis.document.baseURI) {\n // Handle case when endpoint is relative, like //example.com/connection/sse\n url = new URL(this.endpoint, globalThis.document.baseURI);\n }\n else {\n url = new URL(this.endpoint);\n }\n url.searchParams.append('cf_connect', initialData);\n const eventsourceOptions = {};\n const eventSource = new this.options.eventsource(url.toString(), eventsourceOptions);\n this._transport = eventSource;\n const self = this;\n eventSource.onopen = function () {\n callbacks.onOpen();\n };\n eventSource.onerror = function (e) {\n eventSource.close();\n callbacks.onError(e);\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n };\n eventSource.onmessage = function (e) {\n callbacks.onMessage(e.data);\n };\n self._onClose = function () {\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n };\n }\n close() {\n this._transport.close();\n if (this._onClose !== null) {\n this._onClose();\n }\n }\n send(data, session, node) {\n const req = {\n session: session,\n node: node,\n data: data\n };\n const headers = {\n 'Content-Type': 'application/json'\n };\n const body = JSON.stringify(req);\n const fetchFunc = this.options.fetch;\n const fetchOptions = {\n method: 'POST',\n headers: headers,\n body: body,\n mode: 'cors',\n credentials: 'same-origin',\n };\n fetchFunc(this.options.emulationEndpoint, fetchOptions);\n }\n}\n\n/** @internal */\nclass WebtransportTransport {\n constructor(endpoint, options) {\n this.endpoint = endpoint;\n this.options = options;\n this._transport = null;\n this._stream = null;\n this._writer = null;\n this._utf8decoder = new TextDecoder();\n this._protocol = 'json';\n }\n name() {\n return 'webtransport';\n }\n subName() {\n return 'webtransport';\n }\n emulation() {\n return false;\n }\n supported() {\n return this.options.webtransport !== undefined && this.options.webtransport !== null;\n }\n initialize(protocol, callbacks) {\n return __awaiter(this, void 0, void 0, function* () {\n let url;\n if (globalThis && globalThis.document && globalThis.document.baseURI) {\n // Handle case when endpoint is relative, like //example.com/connection/webtransport\n url = new URL(this.endpoint, globalThis.document.baseURI);\n }\n else {\n url = new URL(this.endpoint);\n }\n if (protocol === 'protobuf') {\n url.searchParams.append('cf_protocol', 'protobuf');\n }\n this._protocol = protocol;\n const eventTarget = new EventTarget();\n this._transport = new this.options.webtransport(url.toString());\n this._transport.closed.then(() => {\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n }).catch(() => {\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n });\n try {\n yield this._transport.ready;\n }\n catch (_a) {\n this.close();\n return;\n }\n let stream;\n try {\n stream = yield this._transport.createBidirectionalStream();\n }\n catch (_b) {\n this.close();\n return;\n }\n this._stream = stream;\n this._writer = this._stream.writable.getWriter();\n eventTarget.addEventListener('close', () => {\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n });\n eventTarget.addEventListener('message', (e) => {\n callbacks.onMessage(e.data);\n });\n this._startReading(eventTarget);\n callbacks.onOpen();\n });\n }\n _startReading(eventTarget) {\n return __awaiter(this, void 0, void 0, function* () {\n const reader = this._stream.readable.getReader();\n let jsonStreamBuf = '';\n let jsonStreamPos = 0;\n let protoStreamBuf = new Uint8Array();\n try {\n while (true) {\n const { done, value } = yield reader.read();\n if (value.length > 0) {\n if (this._protocol === 'json') {\n jsonStreamBuf += this._utf8decoder.decode(value);\n while (jsonStreamPos < jsonStreamBuf.length) {\n if (jsonStreamBuf[jsonStreamPos] === '\\n') {\n const line = jsonStreamBuf.substring(0, jsonStreamPos);\n eventTarget.dispatchEvent(new MessageEvent('message', { data: line }));\n jsonStreamBuf = jsonStreamBuf.substring(jsonStreamPos + 1);\n jsonStreamPos = 0;\n }\n else {\n ++jsonStreamPos;\n }\n }\n }\n else {\n const mergedArray = new Uint8Array(protoStreamBuf.length + value.length);\n mergedArray.set(protoStreamBuf);\n mergedArray.set(value, protoStreamBuf.length);\n protoStreamBuf = mergedArray;\n while (true) {\n const result = this.options.decoder.decodeReply(protoStreamBuf);\n if (result.ok) {\n const data = protoStreamBuf.slice(0, result.pos);\n eventTarget.dispatchEvent(new MessageEvent('message', { data: data }));\n protoStreamBuf = protoStreamBuf.slice(result.pos);\n continue;\n }\n break;\n }\n }\n }\n if (done) {\n break;\n }\n }\n }\n catch (_a) {\n eventTarget.dispatchEvent(new Event('close'));\n }\n });\n }\n close() {\n return __awaiter(this, void 0, void 0, function* () {\n try {\n if (this._writer) {\n yield this._writer.close();\n }\n this._transport.close();\n }\n catch (e) {\n // already closed.\n }\n });\n }\n send(data) {\n return __awaiter(this, void 0, void 0, function* () {\n let binary;\n if (this._protocol === 'json') {\n // Need extra \\n since WT is non-frame protocol. \n binary = new TextEncoder().encode(data + '\\n');\n }\n else {\n binary = data;\n }\n try {\n yield this._writer.write(binary);\n }\n catch (e) {\n this.close();\n }\n });\n }\n}\n\n/*\nCopyright 2014-2024 Dmitry Chestnykh (JavaScript port)\nCopyright 2007 D. Richard Hipp (original C version)\n\nFossil SCM delta compression algorithm, this is only the applyDelta part extracted\nfrom https://github.com/dchest/fossil-delta-js. The code was slightly modified\nto strip unnecessary parts. The copyright on top of this file is from the original\nrepo on Github licensed under Simplified BSD License.\n*/\nconst zValue = [\n -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1,\n -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\n 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36, -1, 37,\n 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,\n 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,\n];\n// Reader reads bytes, chars, ints from array.\nclass Reader {\n constructor(array) {\n this.a = array; // source array\n this.pos = 0; // current position in array\n }\n haveBytes() {\n return this.pos < this.a.length;\n }\n getByte() {\n const b = this.a[this.pos];\n this.pos++;\n if (this.pos > this.a.length)\n throw new RangeError(\"out of bounds\");\n return b;\n }\n getChar() {\n return String.fromCharCode(this.getByte());\n }\n // Read base64-encoded unsigned integer.\n getInt() {\n let v = 0;\n let c;\n while (this.haveBytes() && (c = zValue[0x7f & this.getByte()]) >= 0) {\n v = (v << 6) + c;\n }\n this.pos--;\n return v >>> 0;\n }\n}\n// Write writes an array.\nclass Writer {\n constructor() {\n this.a = [];\n }\n toByteArray(sourceType) {\n if (Array.isArray(sourceType)) {\n return this.a;\n }\n return new Uint8Array(this.a);\n }\n // Copy from array at start to end.\n putArray(a, start, end) {\n // TODO: optimize.\n for (let i = start; i < end; i++)\n this.a.push(a[i]);\n }\n}\n// Return a 32-bit checksum of the array.\nfunction checksum(arr) {\n let sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, z = 0, N = arr.length;\n //TODO measure if this unrolling is helpful.\n while (N >= 16) {\n sum0 = (sum0 + arr[z + 0]) | 0;\n sum1 = (sum1 + arr[z + 1]) | 0;\n sum2 = (sum2 + arr[z + 2]) | 0;\n sum3 = (sum3 + arr[z + 3]) | 0;\n sum0 = (sum0 + arr[z + 4]) | 0;\n sum1 = (sum1 + arr[z + 5]) | 0;\n sum2 = (sum2 + arr[z + 6]) | 0;\n sum3 = (sum3 + arr[z + 7]) | 0;\n sum0 = (sum0 + arr[z + 8]) | 0;\n sum1 = (sum1 + arr[z + 9]) | 0;\n sum2 = (sum2 + arr[z + 10]) | 0;\n sum3 = (sum3 + arr[z + 11]) | 0;\n sum0 = (sum0 + arr[z + 12]) | 0;\n sum1 = (sum1 + arr[z + 13]) | 0;\n sum2 = (sum2 + arr[z + 14]) | 0;\n sum3 = (sum3 + arr[z + 15]) | 0;\n z += 16;\n N -= 16;\n }\n while (N >= 4) {\n sum0 = (sum0 + arr[z + 0]) | 0;\n sum1 = (sum1 + arr[z + 1]) | 0;\n sum2 = (sum2 + arr[z + 2]) | 0;\n sum3 = (sum3 + arr[z + 3]) | 0;\n z += 4;\n N -= 4;\n }\n sum3 = (((((sum3 + (sum2 << 8)) | 0) + (sum1 << 16)) | 0) + (sum0 << 24)) | 0;\n switch (N) {\n //@ts-ignore fallthrough is needed.\n case 3:\n sum3 = (sum3 + (arr[z + 2] << 8)) | 0; /* falls through */\n //@ts-ignore fallthrough is needed.\n case 2:\n sum3 = (sum3 + (arr[z + 1] << 16)) | 0; /* falls through */\n case 1:\n sum3 = (sum3 + (arr[z + 0] << 24)) | 0; /* falls through */\n }\n return sum3 >>> 0;\n}\n/**\n * Apply a delta byte array to a source byte array, returning the target byte array.\n */\nfunction applyDelta(source, delta) {\n let total = 0;\n const zDelta = new Reader(delta);\n const lenSrc = source.length;\n const lenDelta = delta.length;\n const limit = zDelta.getInt();\n if (zDelta.getChar() !== \"\\n\")\n throw new Error(\"size integer not terminated by '\\\\n'\");\n const zOut = new Writer();\n while (zDelta.haveBytes()) {\n const cnt = zDelta.getInt();\n let ofst;\n switch (zDelta.getChar()) {\n case \"@\":\n ofst = zDelta.getInt();\n if (zDelta.haveBytes() && zDelta.getChar() !== \",\")\n throw new Error(\"copy command not terminated by ','\");\n total += cnt;\n if (total > limit)\n throw new Error(\"copy exceeds output file size\");\n if (ofst + cnt > lenSrc)\n throw new Error(\"copy extends past end of input\");\n zOut.putArray(source, ofst, ofst + cnt);\n break;\n case \":\":\n total += cnt;\n if (total > limit)\n throw new Error(\"insert command gives an output larger than predicted\");\n if (cnt > lenDelta)\n throw new Error(\"insert count exceeds size of delta\");\n zOut.putArray(zDelta.a, zDelta.pos, zDelta.pos + cnt);\n zDelta.pos += cnt;\n break;\n case \";\":\n {\n const out = zOut.toByteArray(source);\n if (cnt !== checksum(out))\n throw new Error(\"bad checksum\");\n if (total !== limit)\n throw new Error(\"generated size does not match predicted size\");\n return out;\n }\n default:\n throw new Error(\"unknown delta operator\");\n }\n }\n throw new Error(\"unterminated delta\");\n}\n\n/** @internal */\nclass JsonCodec {\n name() {\n return 'json';\n }\n encodeCommands(commands) {\n return commands.map(c => JSON.stringify(c)).join('\\n');\n }\n decodeReplies(data) {\n return data.trim().split('\\n').map(r => JSON.parse(r));\n }\n applyDeltaIfNeeded(pub, prevValue) {\n let newData, newPrevValue;\n if (pub.delta) {\n // JSON string delta.\n const valueArray = applyDelta(prevValue, new TextEncoder().encode(pub.data));\n newData = JSON.parse(new TextDecoder().decode(valueArray));\n newPrevValue = valueArray;\n }\n else {\n // Full data as JSON string.\n newData = JSON.parse(pub.data);\n newPrevValue = new TextEncoder().encode(pub.data);\n }\n return { newData, newPrevValue };\n }\n}\n\nconst defaults = {\n headers: {},\n token: '',\n getToken: null,\n data: null,\n getData: null,\n debug: false,\n name: 'js',\n version: '',\n fetch: null,\n readableStream: null,\n websocket: null,\n eventsource: null,\n sockjs: null,\n sockjsOptions: {},\n emulationEndpoint: '/emulation',\n minReconnectDelay: 500,\n maxReconnectDelay: 20000,\n timeout: 5000,\n maxServerPingDelay: 10000,\n networkEventTarget: null,\n};\nclass UnauthorizedError extends Error {\n constructor(message) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n/** Centrifuge is a Centrifuge/Centrifugo bidirectional client. */\nclass Centrifuge extends EventEmitter$1 {\n /** Constructs Centrifuge client. Call connect() method to start connecting. */\n constructor(endpoint, options) {\n super();\n this._reconnectTimeout = null;\n this._refreshTimeout = null;\n this._serverPingTimeout = null;\n this.state = State.Disconnected;\n this._transportIsOpen = false;\n this._endpoint = endpoint;\n this._emulation = false;\n this._transports = [];\n this._currentTransportIndex = 0;\n this._triedAllTransports = false;\n this._transportWasOpen = false;\n this._transport = null;\n this._transportId = 0;\n this._deviceWentOffline = false;\n this._transportClosed = true;\n this._codec = new JsonCodec();\n this._reconnecting = false;\n this._reconnectTimeout = null;\n this._reconnectAttempts = 0;\n this._client = null;\n this._session = '';\n this._node = '';\n this._subs = {};\n this._serverSubs = {};\n this._commandId = 0;\n this._commands = [];\n this._batching = false;\n this._refreshRequired = false;\n this._refreshTimeout = null;\n this._callbacks = {};\n this._token = '';\n this._data = null;\n this._dispatchPromise = Promise.resolve();\n this._serverPing = 0;\n this._serverPingTimeout = null;\n this._sendPong = false;\n this._promises = {};\n this._promiseId = 0;\n this._debugEnabled = false;\n this._networkEventsSet = false;\n this._config = Object.assign(Object.assign({}, defaults), options);\n this._configure();\n if (this._debugEnabled) {\n this.on('state', (ctx) => {\n this._debug('client state', ctx.oldState, '->', ctx.newState);\n });\n this.on('error', (ctx) => {\n this._debug('client error', ctx);\n });\n }\n else {\n // Avoid unhandled exception in EventEmitter for non-set error handler.\n this.on('error', function () { Function.prototype(); });\n }\n }\n /** newSubscription allocates new Subscription to a channel. Since server only allows\n * one subscription per channel per client this method throws if client already has\n * channel subscription in internal registry.\n * */\n newSubscription(channel, options) {\n if (this.getSubscription(channel) !== null) {\n throw new Error('Subscription to the channel ' + channel + ' already exists');\n }\n const sub = new Subscription(this, channel, options);\n this._subs[channel] = sub;\n return sub;\n }\n /** getSubscription returns Subscription if it's registered in the internal\n * registry or null. */\n getSubscription(channel) {\n return this._getSub(channel);\n }\n /** removeSubscription allows removing Subcription from the internal registry. */\n removeSubscription(sub) {\n if (!sub) {\n return;\n }\n if (sub.state !== SubscriptionState.Unsubscribed) {\n sub.unsubscribe();\n }\n this._removeSubscription(sub);\n }\n /** Get a map with all current client-side subscriptions. */\n subscriptions() {\n return this._subs;\n }\n /** ready returns a Promise which resolves upon client goes to Connected\n * state and rejects in case of client goes to Disconnected or Failed state.\n * Users can provide optional timeout in milliseconds. */\n ready(timeout) {\n return __awaiter(this, void 0, void 0, function* () {\n switch (this.state) {\n case State.Disconnected:\n throw { code: errorCodes.clientDisconnected, message: 'client disconnected' };\n case State.Connected:\n return;\n default:\n return new Promise((resolve, reject) => {\n const ctx = { resolve, reject };\n if (timeout) {\n ctx.timeout = setTimeout(() => {\n reject({ code: errorCodes.timeout, message: 'timeout' });\n }, timeout);\n }\n this._promises[this._nextPromiseId()] = ctx;\n });\n }\n });\n }\n /** connect to a server. */\n connect() {\n if (this._isConnected()) {\n this._debug('connect called when already connected');\n return;\n }\n if (this._isConnecting()) {\n this._debug('connect called when already connecting');\n return;\n }\n this._debug('connect called');\n this._reconnectAttempts = 0;\n this._startConnecting();\n }\n /** disconnect from a server. */\n disconnect() {\n this._disconnect(disconnectedCodes.disconnectCalled, 'disconnect called', false);\n }\n /** setToken allows setting connection token. Or resetting used token to be empty. */\n setToken(token) {\n this._token = token;\n }\n /** setData allows setting connection data. This only affects the next connection attempt,\n * not the current one. Note that if getData callback is configured, it will override\n * this value during reconnects. */\n setData(data) {\n this._data = data;\n }\n /** setHeaders allows setting connection emulated headers. */\n setHeaders(headers) {\n this._config.headers = headers;\n }\n /** send asynchronous data to a server (without any response from a server\n * expected, see rpc method if you need response). */\n send(data) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n send: {\n data\n }\n };\n yield this._methodCall();\n const sent = this._transportSendCommands([cmd]); // can send message to server without id set\n if (!sent) {\n throw this._createErrorObject(errorCodes.transportWriteError, 'transport write error');\n }\n });\n }\n /** rpc to a server - i.e. a call which waits for a response with data. */\n rpc(method, data) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n rpc: {\n method,\n data\n }\n };\n yield this._methodCall();\n const result = yield this._callPromise(cmd, (reply) => reply.rpc);\n return {\n data: result.data\n };\n });\n }\n /** publish data to a channel. */\n publish(channel, data) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n publish: {\n channel,\n data\n }\n };\n yield this._methodCall();\n yield this._callPromise(cmd, () => ({}));\n return {};\n });\n }\n /** history for a channel. By default it does not return publications (only current\n * StreamPosition data) – provide an explicit limit > 0 to load publications.*/\n history(channel, options) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n history: this._getHistoryRequest(channel, options)\n };\n yield this._methodCall();\n const result = yield this._callPromise(cmd, (reply) => reply.history);\n const publications = [];\n if (result.publications) {\n for (let i = 0; i < result.publications.length; i++) {\n publications.push(this._getPublicationContext(channel, result.publications[i]));\n }\n }\n return {\n publications,\n epoch: result.epoch || '',\n offset: result.offset || 0\n };\n });\n }\n /** presence for a channel. */\n presence(channel) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n presence: {\n channel\n }\n };\n yield this._methodCall();\n const result = yield this._callPromise(cmd, (reply) => reply.presence);\n const clients = result.presence;\n for (const clientId in clients) {\n if (Object.prototype.hasOwnProperty.call(clients, clientId)) {\n const rawClient = clients[clientId];\n const connInfo = rawClient['conn_info'];\n const chanInfo = rawClient['chan_info'];\n if (connInfo) {\n rawClient.connInfo = connInfo;\n }\n if (chanInfo) {\n rawClient.chanInfo = chanInfo;\n }\n }\n }\n return { clients };\n });\n }\n presenceStats(channel) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n 'presence_stats': {\n channel\n }\n };\n yield this._methodCall();\n const result = yield this._callPromise(cmd, (reply) => {\n return reply.presence_stats;\n });\n return {\n numUsers: result.num_users,\n numClients: result.num_clients\n };\n });\n }\n /** start command batching (collect into temporary buffer without sending to a server)\n * until stopBatching called.*/\n startBatching() {\n // start collecting messages without sending them to Centrifuge until flush\n // method called\n this._batching = true;\n }\n /** stop batching commands and flush collected commands to the\n * network (all in one request/frame).*/\n stopBatching() {\n const self = this;\n // Why so nested? Two levels here requred to deal with promise resolving queue.\n // In Subscription case we wait 2 futures before sending data to connection.\n // Otherwise _batching becomes false before batching decision has a chance to be executed.\n Promise.resolve().then(function () {\n Promise.resolve().then(function () {\n self._batching = false;\n self._flush();\n });\n });\n }\n _debug(...args) {\n if (!this._debugEnabled) {\n return;\n }\n log('debug', args);\n }\n _codecName() {\n return this._codec.name();\n }\n /** @internal */\n _formatOverride() {\n return;\n }\n _configure() {\n if (!('Promise' in globalThis)) {\n throw new Error('Promise polyfill required');\n }\n if (!this._endpoint) {\n throw new Error('endpoint configuration required');\n }\n if (this._config.token !== null) {\n this._token = this._config.token;\n }\n if (this._config.data !== null) {\n this._data = this._config.data;\n }\n this._codec = new JsonCodec();\n this._formatOverride();\n if (this._config.debug === true ||\n (typeof localStorage !== 'undefined' && typeof localStorage.getItem === 'function' && localStorage.getItem('centrifuge.debug'))) {\n this._debugEnabled = true;\n }\n this._debug('config', this._config);\n if (typeof this._endpoint === 'string') ;\n else if (Array.isArray(this._endpoint)) {\n this._transports = this._endpoint;\n this._emulation = true;\n for (const i in this._transports) {\n if (this._transports.hasOwnProperty(i)) {\n const transportConfig = this._transports[i];\n if (!transportConfig.endpoint || !transportConfig.transport) {\n throw new Error('malformed transport configuration');\n }\n const transportName = transportConfig.transport;\n if (['websocket', 'http_stream', 'sse', 'sockjs', 'webtransport'].indexOf(transportName) < 0) {\n throw new Error('unsupported transport name: ' + transportName);\n }\n }\n }\n }\n else {\n throw new Error('unsupported url configuration type: only string or array of objects are supported');\n }\n }\n _setState(newState) {\n if (this.state !== newState) {\n this._reconnecting = false;\n const oldState = this.state;\n this.state = newState;\n this.emit('state', { newState, oldState });\n return true;\n }\n return false;\n }\n _isDisconnected() {\n return this.state === State.Disconnected;\n }\n _isConnecting() {\n return this.state === State.Connecting;\n }\n _isConnected() {\n return this.state === State.Connected;\n }\n _nextCommandId() {\n return ++this._commandId;\n }\n _setNetworkEvents() {\n if (this._networkEventsSet) {\n return;\n }\n let eventTarget = null;\n if (this._config.networkEventTarget !== null) {\n eventTarget = this._config.networkEventTarget;\n }\n else if (typeof globalThis.addEventListener !== 'undefined') {\n eventTarget = globalThis;\n }\n if (eventTarget) {\n eventTarget.addEventListener('offline', () => {\n this._debug('offline event triggered');\n if (this.state === State.Connected || this.state === State.Connecting) {\n this._disconnect(connectingCodes.transportClosed, 'transport closed', true);\n this._deviceWentOffline = true;\n }\n });\n eventTarget.addEventListener('online', () => {\n this._debug('online event triggered');\n if (this.state !== State.Connecting) {\n return;\n }\n if (this._deviceWentOffline && !this._transportClosed) {\n // This is a workaround for mobile Safari where close callback may be\n // not issued upon device going to the flight mode. We know for sure\n // that transport close was called, so we start reconnecting. In this\n // case if the close callback will be issued for some reason after some\n // time – it will be ignored due to transport ID mismatch.\n this._deviceWentOffline = false;\n this._transportClosed = true;\n }\n this._clearReconnectTimeout();\n this._startReconnecting();\n });\n this._networkEventsSet = true;\n }\n }\n _getReconnectDelay() {\n const delay = backoff(this._reconnectAttempts, this._config.minReconnectDelay, this._config.maxReconnectDelay);\n this._reconnectAttempts += 1;\n return delay;\n }\n _clearOutgoingRequests() {\n // fire errbacks of registered outgoing calls.\n for (const id in this._callbacks) {\n if (this._callbacks.hasOwnProperty(id)) {\n const callbacks = this._callbacks[id];\n clearTimeout(callbacks.timeout);\n const errback = callbacks.errback;\n if (!errback) {\n continue;\n }\n errback({ error: this._createErrorObject(errorCodes.connectionClosed, 'connection closed') });\n }\n }\n this._callbacks = {};\n }\n _clearConnectedState() {\n this._client = null;\n this._clearServerPingTimeout();\n this._clearRefreshTimeout();\n // fire events for client-side subscriptions.\n for (const channel in this._subs) {\n if (!this._subs.hasOwnProperty(channel)) {\n continue;\n }\n const sub = this._subs[channel];\n if (sub.state === SubscriptionState.Subscribed) {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._setSubscribing(subscribingCodes.transportClosed, 'transport closed');\n }\n }\n // fire events for server-side subscriptions.\n for (const channel in this._serverSubs) {\n if (this._serverSubs.hasOwnProperty(channel)) {\n this.emit('subscribing', { channel: channel });\n }\n }\n }\n _handleWriteError(commands) {\n for (const command of commands) {\n const id = command.id;\n if (!(id in this._callbacks)) {\n continue;\n }\n const callbacks = this._callbacks[id];\n clearTimeout(this._callbacks[id].timeout);\n delete this._callbacks[id];\n const errback = callbacks.errback;\n errback({ error: this._createErrorObject(errorCodes.transportWriteError, 'transport write error') });\n }\n }\n _transportSendCommands(commands) {\n if (!commands.length) {\n return true;\n }\n if (!this._transport) {\n return false;\n }\n try {\n this._transport.send(this._codec.encodeCommands(commands), this._session, this._node);\n }\n catch (e) {\n this._debug('error writing commands', e);\n this._handleWriteError(commands);\n return false;\n }\n return true;\n }\n _initializeTransport() {\n let websocket;\n if (this._config.websocket !== null) {\n websocket = this._config.websocket;\n }\n else {\n if (!(typeof globalThis.WebSocket !== 'function' && typeof globalThis.WebSocket !== 'object')) {\n websocket = globalThis.WebSocket;\n }\n }\n let sockjs = null;\n if (this._config.sockjs !== null) {\n sockjs = this._config.sockjs;\n }\n else {\n if (typeof globalThis.SockJS !== 'undefined') {\n sockjs = globalThis.SockJS;\n }\n }\n let eventsource = null;\n if (this._config.eventsource !== null) {\n eventsource = this._config.eventsource;\n }\n else {\n if (typeof globalThis.EventSource !== 'undefined') {\n eventsource = globalThis.EventSource;\n }\n }\n let fetchFunc = null;\n if (this._config.fetch !== null) {\n fetchFunc = this._config.fetch;\n }\n else {\n if (typeof globalThis.fetch !== 'undefined') {\n fetchFunc = globalThis.fetch;\n }\n }\n let readableStream = null;\n if (this._config.readableStream !== null) {\n readableStream = this._config.readableStream;\n }\n else {\n if (typeof globalThis.ReadableStream !== 'undefined') {\n readableStream = globalThis.ReadableStream;\n }\n }\n if (!this._emulation) {\n if (startsWith(this._endpoint, 'http')) {\n throw new Error('Provide explicit transport endpoints configuration in case of using HTTP (i.e. using array of TransportEndpoint instead of a single string), or use ws(s):// scheme in an endpoint if you aimed using WebSocket transport');\n }\n else {\n this._debug('client will use websocket');\n this._transport = new WebsocketTransport(this._endpoint, {\n websocket: websocket\n });\n if (!this._transport.supported()) {\n throw new Error('WebSocket constructor not found, make sure it is available globally or passed as a dependency in Centrifuge options');\n }\n }\n }\n else {\n if (this._currentTransportIndex >= this._transports.length) {\n this._triedAllTransports = true;\n this._currentTransportIndex = 0;\n }\n let count = 0;\n while (true) {\n if (count >= this._transports.length) {\n throw new Error('no supported transport found');\n }\n const transportConfig = this._transports[this._currentTransportIndex];\n const transportName = transportConfig.transport;\n const transportEndpoint = transportConfig.endpoint;\n if (transportName === 'websocket') {\n this._debug('trying websocket transport');\n this._transport = new WebsocketTransport(transportEndpoint, {\n websocket: websocket\n });\n if (!this._transport.supported()) {\n this._debug('websocket transport not available');\n this._currentTransportIndex++;\n count++;\n continue;\n }\n }\n else if (transportName === 'webtransport') {\n this._debug('trying webtransport transport');\n this._transport = new WebtransportTransport(transportEndpoint, {\n webtransport: globalThis.WebTransport,\n decoder: this._codec,\n encoder: this._codec\n });\n if (!this._transport.supported()) {\n this._debug('webtransport transport not available');\n this._currentTransportIndex++;\n count++;\n continue;\n }\n }\n else if (transportName === 'http_stream') {\n this._debug('trying http_stream transport');\n this._transport = new HttpStreamTransport(transportEndpoint, {\n fetch: fetchFunc,\n readableStream: readableStream,\n emulationEndpoint: this._config.emulationEndpoint,\n decoder: this._codec,\n encoder: this._codec\n });\n if (!this._transport.supported()) {\n this._debug('http_stream transport not available');\n this._currentTransportIndex++;\n count++;\n continue;\n }\n }\n else if (transportName === 'sse') {\n this._debug('trying sse transport');\n this._transport = new SseTransport(transportEndpoint, {\n eventsource: eventsource,\n fetch: fetchFunc,\n emulationEndpoint: this._config.emulationEndpoint,\n });\n if (!this._transport.supported()) {\n this._debug('sse transport not available');\n this._currentTransportIndex++;\n count++;\n continue;\n }\n }\n else if (transportName === 'sockjs') {\n this._debug('trying sockjs');\n this._transport = new SockjsTransport(transportEndpoint, {\n sockjs: sockjs,\n sockjsOptions: this._config.sockjsOptions\n });\n if (!this._transport.supported()) {\n this._debug('sockjs transport not available');\n this._currentTransportIndex++;\n count++;\n continue;\n }\n }\n else {\n throw new Error('unknown transport ' + transportName);\n }\n break;\n }\n }\n const self = this;\n const transport = this._transport;\n const transportId = this._nextTransportId();\n self._debug(\"id of transport\", transportId);\n let wasOpen = false;\n const initialCommands = [];\n if (this._transport.emulation()) {\n const connectCommand = self._sendConnect(true);\n initialCommands.push(connectCommand);\n }\n this._setNetworkEvents();\n const initialData = this._codec.encodeCommands(initialCommands);\n this._transportClosed = false;\n let connectTimeout;\n connectTimeout = setTimeout(function () {\n transport.close();\n }, this._config.timeout);\n this._transport.initialize(this._codecName(), {\n onOpen: function () {\n if (connectTimeout) {\n clearTimeout(connectTimeout);\n connectTimeout = null;\n }\n if (self._transportId != transportId) {\n self._debug('open callback from non-actual transport');\n transport.close();\n return;\n }\n wasOpen = true;\n self._debug(transport.subName(), 'transport open');\n if (transport.emulation()) {\n return;\n }\n self._transportIsOpen = true;\n self._transportWasOpen = true;\n self.startBatching();\n self._sendConnect(false);\n self._sendSubscribeCommands();\n self.stopBatching();\n //@ts-ignore must be used only for debug and test purposes. Exposed only for non-emulation transport.\n self.emit('__centrifuge_debug:connect_frame_sent', {});\n },\n onError: function (e) {\n if (self._transportId != transportId) {\n self._debug('error callback from non-actual transport');\n return;\n }\n self._debug('transport level error', e);\n },\n onClose: function (closeEvent) {\n if (connectTimeout) {\n clearTimeout(connectTimeout);\n connectTimeout = null;\n }\n if (self._transportId != transportId) {\n self._debug('close callback from non-actual transport');\n return;\n }\n self._debug(transport.subName(), 'transport closed');\n self._transportClosed = true;\n self._transportIsOpen = false;\n let reason = 'connection closed';\n let needReconnect = true;\n let code = 0;\n if (closeEvent && 'code' in closeEvent && closeEvent.code) {\n code = closeEvent.code;\n }\n if (closeEvent && closeEvent.reason) {\n try {\n const advice = JSON.parse(closeEvent.reason);\n reason = advice.reason;\n needReconnect = advice.reconnect;\n }\n catch (e) {\n reason = closeEvent.reason;\n if ((code >= 3500 && code < 4000) || (code >= 4500 && code < 5000)) {\n needReconnect = false;\n }\n }\n }\n if (code < 3000) {\n if (code === 1009) {\n code = disconnectedCodes.messageSizeLimit;\n reason = 'message size limit exceeded';\n needReconnect = false;\n }\n else {\n code = connectingCodes.transportClosed;\n reason = 'transport closed';\n }\n if (self._emulation && !self._transportWasOpen) {\n self._currentTransportIndex++;\n if (self._currentTransportIndex >= self._transports.length) {\n self._triedAllTransports = true;\n self._currentTransportIndex = 0;\n }\n }\n }\n else {\n // Codes >= 3000 are sent from a server application level.\n self._transportWasOpen = true;\n }\n if (self._isConnecting() && !wasOpen) {\n self.emit('error', {\n type: 'transport',\n error: {\n code: errorCodes.transportClosed,\n message: 'transport closed'\n },\n transport: transport.name()\n });\n }\n self._reconnecting = false;\n self._disconnect(code, reason, needReconnect);\n },\n onMessage: function (data) {\n self._dataReceived(data);\n }\n }, initialData);\n //@ts-ignore must be used only for debug and test purposes.\n self.emit('__centrifuge_debug:transport_initialized', {});\n }\n _sendConnect(skipSending) {\n const connectCommand = this._constructConnectCommand();\n const self = this;\n this._call(connectCommand, skipSending).then(resolveCtx => {\n const result = resolveCtx.reply.connect;\n self._connectResponse(result);\n if (resolveCtx.next) {\n resolveCtx.next();\n }\n }, rejectCtx => {\n self._connectError(rejectCtx.error);\n if (rejectCtx.next) {\n rejectCtx.next();\n }\n });\n return connectCommand;\n }\n _startReconnecting() {\n this._debug('start reconnecting');\n if (!this._isConnecting()) {\n this._debug('stop reconnecting: client not in connecting state');\n return;\n }\n if (this._reconnecting) {\n this._debug('reconnect already in progress, return from reconnect routine');\n return;\n }\n if (this._transportClosed === false) {\n this._debug('waiting for transport close');\n return;\n }\n this._reconnecting = true;\n const emptyToken = this._token === '';\n const needTokenRefresh = this._refreshRequired || (emptyToken && this._config.getToken !== null);\n if (!needTokenRefresh) {\n if (this._config.getData) {\n this._config.getData().then(data => {\n if (!this._isConnecting()) {\n return;\n }\n this._data = data;\n this._initializeTransport();\n })\n .catch(e => this._handleGetDataError(e));\n }\n else {\n this._initializeTransport();\n }\n return;\n }\n const self = this;\n this._getToken().then(function (token) {\n if (!self._isConnecting()) {\n return;\n }\n if (token == null || token == undefined) {\n self._failUnauthorized();\n return;\n }\n self._token = token;\n self._debug('connection token refreshed');\n if (self._config.getData) {\n self._config.getData().then(function (data) {\n if (!self._isConnecting()) {\n return;\n }\n self._data = data;\n self._initializeTransport();\n })\n .catch(e => self._handleGetDataError(e));\n }\n else {\n self._initializeTransport();\n }\n }).catch(function (e) {\n if (!self._isConnecting()) {\n return;\n }\n if (e instanceof UnauthorizedError) {\n self._failUnauthorized();\n return;\n }\n self.emit('error', {\n 'type': 'connectToken',\n 'error': {\n code: errorCodes.clientConnectToken,\n message: e !== undefined ? e.toString() : ''\n }\n });\n const delay = self._getReconnectDelay();\n self._debug('error on getting connection token, reconnect after ' + delay + ' milliseconds', e);\n self._reconnecting = false;\n self._reconnectTimeout = setTimeout(() => {\n self._startReconnecting();\n }, delay);\n });\n }\n _handleGetDataError(e) {\n if (e instanceof UnauthorizedError) {\n this._failUnauthorized();\n return;\n }\n this.emit('error', {\n type: 'connectData',\n error: {\n code: errorCodes.badConfiguration,\n message: (e === null || e === void 0 ? void 0 : e.toString()) || ''\n }\n });\n const delay = this._getReconnectDelay();\n this._debug('error on getting connect data, reconnect after ' + delay + ' milliseconds', e);\n this._reconnecting = false;\n this._reconnectTimeout = setTimeout(() => {\n this._startReconnecting();\n }, delay);\n }\n _connectError(err) {\n if (this.state !== State.Connecting) {\n return;\n }\n if (err.code === 109) { // token expired.\n // next connect attempt will try to refresh token.\n this._refreshRequired = true;\n }\n if (err.code < 100 || err.temporary === true || err.code === 109) {\n this.emit('error', {\n 'type': 'connect',\n 'error': err\n });\n this._debug('closing transport due to connect error');\n this._disconnect(err.code, err.message, true);\n }\n else {\n this._disconnect(err.code, err.message, false);\n }\n }\n _scheduleReconnect() {\n if (!this._isConnecting()) {\n return;\n }\n let isInitialHandshake = false;\n if (this._emulation && !this._transportWasOpen && !this._triedAllTransports) {\n isInitialHandshake = true;\n }\n let delay = this._getReconnectDelay();\n if (isInitialHandshake) {\n delay = 0;\n }\n this._debug('reconnect after ' + delay + ' milliseconds');\n this._clearReconnectTimeout();\n this._reconnectTimeout = setTimeout(() => {\n this._startReconnecting();\n }, delay);\n }\n _constructConnectCommand() {\n const req = {};\n if (this._token) {\n req.token = this._token;\n }\n if (this._data) {\n req.data = this._data;\n }\n if (this._config.name) {\n req.name = this._config.name;\n }\n if (this._config.version) {\n req.version = this._config.version;\n }\n if (Object.keys(this._config.headers).length > 0) {\n req.headers = this._config.headers;\n }\n const subs = {};\n let hasSubs = false;\n for (const channel in this._serverSubs) {\n if (this._serverSubs.hasOwnProperty(channel) && this._serverSubs[channel].recoverable) {\n hasSubs = true;\n const sub = {\n 'recover': true\n };\n if (this._serverSubs[channel].offset) {\n sub['offset'] = this._serverSubs[channel].offset;\n }\n if (this._serverSubs[channel].epoch) {\n sub['epoch'] = this._serverSubs[channel].epoch;\n }\n subs[channel] = sub;\n }\n }\n if (hasSubs) {\n req.subs = subs;\n }\n return {\n connect: req\n };\n }\n _getHistoryRequest(channel, options) {\n const req = {\n channel: channel\n };\n if (options !== undefined) {\n if (options.since) {\n req.since = {\n offset: options.since.offset\n };\n if (options.since.epoch) {\n req.since.epoch = options.since.epoch;\n }\n }\n if (options.limit !== undefined) {\n req.limit = options.limit;\n }\n if (options.reverse === true) {\n req.reverse = true;\n }\n }\n return req;\n }\n _methodCall() {\n if (this._isConnected()) {\n return Promise.resolve();\n }\n return new Promise((res, rej) => {\n const timeout = setTimeout(function () {\n rej({ code: errorCodes.timeout, message: 'timeout' });\n }, this._config.timeout);\n this._promises[this._nextPromiseId()] = {\n timeout: timeout,\n resolve: res,\n reject: rej\n };\n });\n }\n _callPromise(cmd, resultCB) {\n return new Promise((resolve, reject) => {\n this._call(cmd, false).then((resolveCtx) => {\n var _a;\n const result = resultCB(resolveCtx.reply);\n resolve(result);\n (_a = resolveCtx.next) === null || _a === void 0 ? void 0 : _a.call(resolveCtx);\n }, (rejectCtx) => {\n var _a;\n reject(rejectCtx.error);\n (_a = rejectCtx.next) === null || _a === void 0 ? void 0 : _a.call(rejectCtx);\n });\n });\n }\n _dataReceived(data) {\n if (this._serverPing > 0) {\n this._waitServerPing();\n }\n const replies = this._codec.decodeReplies(data);\n // We have to guarantee order of events in replies processing - i.e. start processing\n // next reply only when we finished processing of current one. Without syncing things in\n // this way we could get wrong publication events order as reply promises resolve\n // on next loop tick so for loop continues before we finished emitting all reply events.\n this._dispatchPromise = this._dispatchPromise.then(() => {\n let finishDispatch;\n this._dispatchPromise = new Promise(resolve => {\n finishDispatch = resolve;\n });\n this._dispatchSynchronized(replies, finishDispatch);\n });\n }\n _dispatchSynchronized(replies, finishDispatch) {\n let p = Promise.resolve();\n for (const i in replies) {\n if (replies.hasOwnProperty(i)) {\n p = p.then(() => {\n return this._dispatchReply(replies[i]);\n });\n }\n }\n p = p.then(() => {\n finishDispatch();\n });\n }\n _dispatchReply(reply) {\n let next;\n const p = new Promise(resolve => {\n next = resolve;\n });\n if (reply === undefined || reply === null) {\n this._debug('dispatch: got undefined or null reply');\n next();\n return p;\n }\n const id = reply.id;\n if (id && id > 0) {\n this._handleReply(reply, next);\n }\n else {\n if (!reply.push) {\n this._handleServerPing(next);\n }\n else {\n this._handlePush(reply.push, next);\n }\n }\n return p;\n }\n _call(cmd, skipSending) {\n return new Promise((resolve, reject) => {\n cmd.id = this._nextCommandId();\n this._registerCall(cmd.id, resolve, reject);\n if (!skipSending) {\n this._addCommand(cmd);\n }\n });\n }\n _startConnecting() {\n this._debug('start connecting');\n if (this._setState(State.Connecting)) {\n this.emit('connecting', { code: connectingCodes.connectCalled, reason: 'connect called' });\n }\n this._client = null;\n this._startReconnecting();\n }\n _disconnect(code, reason, reconnect) {\n if (this._isDisconnected()) {\n return;\n }\n // we mark transport is closed right away, because _clearConnectedState will move subscriptions to subscribing state\n // if transport will still be open at this time, subscribe frames will be sent to closing transport\n this._transportIsOpen = false;\n const previousState = this.state;\n this._reconnecting = false;\n const ctx = {\n code: code,\n reason: reason\n };\n let needEvent = false;\n if (reconnect) {\n needEvent = this._setState(State.Connecting);\n }\n else {\n needEvent = this._setState(State.Disconnected);\n this._rejectPromises({ code: errorCodes.clientDisconnected, message: 'disconnected' });\n }\n this._clearOutgoingRequests();\n if (previousState === State.Connecting) {\n this._clearReconnectTimeout();\n }\n if (previousState === State.Connected) {\n this._clearConnectedState();\n }\n if (needEvent) {\n if (this._isConnecting()) {\n this.emit('connecting', ctx);\n }\n else {\n this.emit('disconnected', ctx);\n }\n }\n if (this._transport) {\n this._debug(\"closing existing transport\");\n const transport = this._transport;\n this._transport = null;\n transport.close(); // Close only after setting this._transport to null to avoid recursion when calling transport close().\n // Need to mark as closed here, because connect call may be sync called after disconnect,\n // transport onClose callback will not be called yet\n this._transportClosed = true;\n this._nextTransportId();\n }\n else {\n this._debug(\"no transport to close\");\n }\n this._scheduleReconnect();\n }\n _failUnauthorized() {\n this._disconnect(disconnectedCodes.unauthorized, 'unauthorized', false);\n }\n _getToken() {\n this._debug('get connection token');\n if (!this._config.getToken) {\n this.emit('error', {\n type: 'configuration',\n error: {\n code: errorCodes.badConfiguration,\n message: 'token expired but no getToken function set in the configuration'\n }\n });\n return Promise.reject(new UnauthorizedError(''));\n }\n return this._config.getToken({});\n }\n _refresh() {\n const clientId = this._client;\n const self = this;\n this._getToken().then(function (token) {\n if (clientId !== self._client) {\n return;\n }\n if (!token) {\n self._failUnauthorized();\n return;\n }\n self._token = token;\n self._debug('connection token refreshed');\n if (!self._isConnected()) {\n return;\n }\n const cmd = {\n refresh: { token: self._token }\n };\n self._call(cmd, false).then(resolveCtx => {\n const result = resolveCtx.reply.refresh;\n self._refreshResponse(result);\n if (resolveCtx.next) {\n resolveCtx.next();\n }\n }, rejectCtx => {\n self._refreshError(rejectCtx.error);\n if (rejectCtx.next) {\n rejectCtx.next();\n }\n });\n }).catch(function (e) {\n if (!self._isConnected()) {\n return;\n }\n if (e instanceof UnauthorizedError) {\n self._failUnauthorized();\n return;\n }\n self.emit('error', {\n type: 'refreshToken',\n error: {\n code: errorCodes.clientRefreshToken,\n message: e !== undefined ? e.toString() : ''\n }\n });\n self._refreshTimeout = setTimeout(() => self._refresh(), self._getRefreshRetryDelay());\n });\n }\n _refreshError(err) {\n if (err.code < 100 || err.temporary === true) {\n this.emit('error', {\n type: 'refresh',\n error: err\n });\n this._refreshTimeout = setTimeout(() => this._refresh(), this._getRefreshRetryDelay());\n }\n else {\n this._disconnect(err.code, err.message, false);\n }\n }\n _getRefreshRetryDelay() {\n return backoff(0, 5000, 10000);\n }\n _refreshResponse(result) {\n if (this._refreshTimeout) {\n clearTimeout(this._refreshTimeout);\n this._refreshTimeout = null;\n }\n if (result.expires) {\n this._client = result.client;\n this._refreshTimeout = setTimeout(() => this._refresh(), ttlMilliseconds(result.ttl));\n }\n }\n _removeSubscription(sub) {\n if (sub === null) {\n return;\n }\n delete this._subs[sub.channel];\n }\n _unsubscribe(sub) {\n if (!this._transportIsOpen) {\n return Promise.resolve();\n }\n const req = {\n channel: sub.channel\n };\n const cmd = { unsubscribe: req };\n const self = this;\n const unsubscribePromise = new Promise((resolve, _) => {\n this._call(cmd, false).then(resolveCtx => {\n resolve();\n if (resolveCtx.next) {\n resolveCtx.next();\n }\n }, rejectCtx => {\n resolve();\n if (rejectCtx.next) {\n rejectCtx.next();\n }\n self._disconnect(connectingCodes.unsubscribeError, 'unsubscribe error', true);\n });\n });\n return unsubscribePromise;\n }\n _getSub(channel, id) {\n if (id && id > 0) {\n for (const ch in this._subs) {\n if (this._subs.hasOwnProperty(ch)) {\n const sub = this._subs[ch];\n // @ts-ignore – we are accessing private property for internal use\n if (sub._id === id) {\n return sub;\n }\n }\n }\n return null;\n }\n const sub = this._subs[channel];\n if (!sub) {\n return null;\n }\n return sub;\n }\n _isServerSub(channel) {\n return this._serverSubs[channel] !== undefined;\n }\n _sendSubscribeCommands() {\n const commands = [];\n for (const channel in this._subs) {\n if (!this._subs.hasOwnProperty(channel)) {\n continue;\n }\n const sub = this._subs[channel];\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n if (sub._inflight === true) {\n continue;\n }\n if (sub.state === SubscriptionState.Subscribing) {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n const cmd = sub._subscribe();\n if (cmd) {\n commands.push(cmd);\n }\n }\n }\n return commands;\n }\n _connectResponse(result) {\n this._transportIsOpen = true;\n this._transportWasOpen = true;\n this._reconnectAttempts = 0;\n this._refreshRequired = false;\n if (this._isConnected()) {\n return;\n }\n this._client = result.client;\n this._setState(State.Connected);\n if (this._refreshTimeout) {\n clearTimeout(this._refreshTimeout);\n }\n if (result.expires) {\n this._refreshTimeout = setTimeout(() => this._refresh(), ttlMilliseconds(result.ttl));\n }\n this._session = result.session;\n this._node = result.node;\n this.startBatching();\n this._sendSubscribeCommands();\n this.stopBatching();\n const ctx = {\n client: result.client,\n transport: this._transport.subName()\n };\n if (result.data) {\n ctx.data = result.data;\n }\n this.emit('connected', ctx);\n this._resolvePromises();\n this._processServerSubs(result.subs || {});\n if (result.ping && result.ping > 0) {\n this._serverPing = result.ping * 1000;\n this._sendPong = result.pong === true;\n this._waitServerPing();\n }\n else {\n this._serverPing = 0;\n }\n }\n _processServerSubs(subs) {\n for (const channel in subs) {\n if (!subs.hasOwnProperty(channel)) {\n continue;\n }\n const sub = subs[channel];\n this._serverSubs[channel] = {\n 'offset': sub.offset,\n 'epoch': sub.epoch,\n 'recoverable': sub.recoverable || false\n };\n const subCtx = this._getSubscribeContext(channel, sub);\n this.emit('subscribed', subCtx);\n }\n for (const channel in subs) {\n if (!subs.hasOwnProperty(channel)) {\n continue;\n }\n const sub = subs[channel];\n if (sub.recovered) {\n const pubs = sub.publications;\n if (pubs && pubs.length > 0) {\n for (const i in pubs) {\n if (pubs.hasOwnProperty(i)) {\n this._handlePublication(channel, pubs[i]);\n }\n }\n }\n }\n }\n for (const channel in this._serverSubs) {\n if (!this._serverSubs.hasOwnProperty(channel)) {\n continue;\n }\n if (!subs[channel]) {\n this.emit('unsubscribed', { channel: channel });\n delete this._serverSubs[channel];\n }\n }\n }\n _clearRefreshTimeout() {\n if (this._refreshTimeout !== null) {\n clearTimeout(this._refreshTimeout);\n this._refreshTimeout = null;\n }\n }\n _clearReconnectTimeout() {\n if (this._reconnectTimeout !== null) {\n clearTimeout(this._reconnectTimeout);\n this._reconnectTimeout = null;\n }\n }\n _clearServerPingTimeout() {\n if (this._serverPingTimeout !== null) {\n clearTimeout(this._serverPingTimeout);\n this._serverPingTimeout = null;\n }\n }\n _waitServerPing() {\n if (this._config.maxServerPingDelay === 0) {\n return;\n }\n if (!this._isConnected()) {\n return;\n }\n this._clearServerPingTimeout();\n this._serverPingTimeout = setTimeout(() => {\n if (!this._isConnected()) {\n return;\n }\n this._disconnect(connectingCodes.noPing, 'no ping', true);\n }, this._serverPing + this._config.maxServerPingDelay);\n }\n _getSubscribeContext(channel, result) {\n const ctx = {\n channel: channel,\n positioned: false,\n recoverable: false,\n wasRecovering: false,\n recovered: false,\n hasRecoveredPublications: false,\n };\n if (result.recovered) {\n ctx.recovered = true;\n }\n if (result.positioned) {\n ctx.positioned = true;\n }\n if (result.recoverable) {\n ctx.recoverable = true;\n }\n if (result.was_recovering) {\n ctx.wasRecovering = true;\n }\n let epoch = '';\n if ('epoch' in result) {\n epoch = result.epoch;\n }\n let offset = 0;\n if ('offset' in result) {\n offset = result.offset;\n }\n if (ctx.positioned || ctx.recoverable) {\n ctx.streamPosition = {\n 'offset': offset,\n 'epoch': epoch\n };\n }\n if (Array.isArray(result.publications) && result.publications.length > 0) {\n ctx.hasRecoveredPublications = true;\n }\n if (result.data) {\n ctx.data = result.data;\n }\n return ctx;\n }\n _handleReply(reply, next) {\n const id = reply.id;\n if (!(id in this._callbacks)) {\n next();\n return;\n }\n const callbacks = this._callbacks[id];\n clearTimeout(this._callbacks[id].timeout);\n delete this._callbacks[id];\n if (!errorExists(reply)) {\n const callback = callbacks.callback;\n if (!callback) {\n return;\n }\n callback({ reply, next });\n }\n else {\n const errback = callbacks.errback;\n if (!errback) {\n next();\n return;\n }\n const error = { code: reply.error.code, message: reply.error.message || '', temporary: reply.error.temporary || false };\n errback({ error, next });\n }\n }\n _handleJoin(channel, join, id) {\n const sub = this._getSub(channel, id);\n if (!sub && channel) {\n if (this._isServerSub(channel)) {\n const ctx = { channel: channel, info: this._getJoinLeaveContext(join.info) };\n this.emit('join', ctx);\n }\n return;\n }\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._handleJoin(join);\n }\n _handleLeave(channel, leave, id) {\n const sub = this._getSub(channel, id);\n if (!sub && channel) {\n if (this._isServerSub(channel)) {\n const ctx = { channel: channel, info: this._getJoinLeaveContext(leave.info) };\n this.emit('leave', ctx);\n }\n return;\n }\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._handleLeave(leave);\n }\n _handleUnsubscribe(channel, unsubscribe) {\n const sub = this._getSub(channel, 0);\n if (!sub && channel) {\n if (this._isServerSub(channel)) {\n delete this._serverSubs[channel];\n this.emit('unsubscribed', { channel: channel });\n }\n return;\n }\n if (unsubscribe.code < 2500) {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._setUnsubscribed(unsubscribe.code, unsubscribe.reason, false);\n }\n else {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._setSubscribing(unsubscribe.code, unsubscribe.reason);\n }\n }\n _handleSubscribe(channel, sub) {\n this._serverSubs[channel] = {\n 'offset': sub.offset,\n 'epoch': sub.epoch,\n 'recoverable': sub.recoverable || false\n };\n this.emit('subscribed', this._getSubscribeContext(channel, sub));\n }\n _handleDisconnect(disconnect) {\n const code = disconnect.code;\n let reconnect = true;\n if ((code >= 3500 && code < 4000) || (code >= 4500 && code < 5000)) {\n reconnect = false;\n }\n this._disconnect(code, disconnect.reason, reconnect);\n }\n _getPublicationContext(channel, pub) {\n const ctx = {\n channel: channel,\n data: pub.data\n };\n if (pub.offset) {\n ctx.offset = pub.offset;\n }\n if (pub.info) {\n ctx.info = this._getJoinLeaveContext(pub.info);\n }\n if (pub.tags) {\n ctx.tags = pub.tags;\n }\n return ctx;\n }\n _getJoinLeaveContext(clientInfo) {\n const info = {\n client: clientInfo.client,\n user: clientInfo.user\n };\n const connInfo = clientInfo['conn_info'];\n if (connInfo) {\n info.connInfo = connInfo;\n }\n const chanInfo = clientInfo['chan_info'];\n if (chanInfo) {\n info.chanInfo = chanInfo;\n }\n return info;\n }\n _handlePublication(channel, pub, id) {\n const sub = this._getSub(channel, id);\n if (!sub && channel) {\n if (this._isServerSub(channel)) {\n const ctx = this._getPublicationContext(channel, pub);\n this.emit('publication', ctx);\n if (pub.offset !== undefined) {\n this._serverSubs[channel].offset = pub.offset;\n }\n }\n return;\n }\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._handlePublication(pub);\n }\n _handleMessage(message) {\n this.emit('message', { data: message.data });\n }\n _handleServerPing(next) {\n if (this._sendPong) {\n const cmd = {};\n this._transportSendCommands([cmd]);\n }\n next();\n }\n _handlePush(data, next) {\n const channel = data.channel;\n const id = data.id;\n if (data.pub) {\n this._handlePublication(channel, data.pub, id);\n }\n else if (data.message) {\n this._handleMessage(data.message);\n }\n else if (data.join) {\n this._handleJoin(channel, data.join, id);\n }\n else if (data.leave) {\n this._handleLeave(channel, data.leave, id);\n }\n else if (data.unsubscribe) {\n this._handleUnsubscribe(channel, data.unsubscribe);\n }\n else if (data.subscribe) {\n this._handleSubscribe(channel, data.subscribe);\n }\n else if (data.disconnect) {\n this._handleDisconnect(data.disconnect);\n }\n next();\n }\n _flush() {\n const commands = this._commands.slice(0);\n this._commands = [];\n this._transportSendCommands(commands);\n }\n _createErrorObject(code, message, temporary) {\n const errObject = {\n code: code,\n message: message\n };\n if (temporary) {\n errObject.temporary = true;\n }\n return errObject;\n }\n _registerCall(id, callback, errback) {\n this._callbacks[id] = {\n callback: callback,\n errback: errback,\n timeout: null\n };\n this._callbacks[id].timeout = setTimeout(() => {\n delete this._callbacks[id];\n if (isFunction(errback)) {\n errback({ error: this._createErrorObject(errorCodes.timeout, 'timeout') });\n }\n }, this._config.timeout);\n }\n _addCommand(command) {\n if (this._batching) {\n this._commands.push(command);\n }\n else {\n this._transportSendCommands([command]);\n }\n }\n _nextPromiseId() {\n return ++this._promiseId;\n }\n _nextTransportId() {\n return ++this._transportId;\n }\n _resolvePromises() {\n for (const id in this._promises) {\n if (!this._promises.hasOwnProperty(id)) {\n continue;\n }\n if (this._promises[id].timeout) {\n clearTimeout(this._promises[id].timeout);\n }\n this._promises[id].resolve();\n delete this._promises[id];\n }\n }\n _rejectPromises(err) {\n for (const id in this._promises) {\n if (!this._promises.hasOwnProperty(id)) {\n continue;\n }\n if (this._promises[id].timeout) {\n clearTimeout(this._promises[id].timeout);\n }\n this._promises[id].reject(err);\n delete this._promises[id];\n }\n }\n}\nCentrifuge.SubscriptionState = SubscriptionState;\nCentrifuge.State = State;\nCentrifuge.UnauthorizedError = UnauthorizedError;\n\nexport { Centrifuge, State, Subscription, SubscriptionState, UnauthorizedError, connectingCodes, disconnectedCodes, errorCodes, subscribingCodes, subscriptionFlags, unsubscribedCodes };\n","import { Centrifuge, Subscription, PublicationContext } from 'centrifuge';\nimport type { CevroMessengerConfig, WSEventPayload } from '../types';\nimport { EventEmitter } from './EventEmitter';\n\n/**\n * Token refresh callback type\n */\nexport type TokenRefreshCallback = () => Promise<string>;\n\n/**\n * WebSocket client for real-time messaging via Centrifugo\n */\nexport class WebSocketClient {\n private config: CevroMessengerConfig;\n private events: EventEmitter;\n private client: Centrifuge | null = null;\n private personalSub: Subscription | null = null;\n private userId: string | null = null;\n private getTokenCallback: TokenRefreshCallback | null = null;\n\n constructor(config: CevroMessengerConfig, events: EventEmitter) {\n this.config = config;\n this.events = events;\n }\n\n /**\n * Update config reference (used when config object is replaced)\n */\n updateConfig(config: CevroMessengerConfig): void {\n this.config = config;\n }\n\n /**\n * Set token refresh callback\n * Called when Centrifugo needs a new token (expiration, reconnect)\n */\n setTokenRefreshCallback(callback: TokenRefreshCallback): void {\n this.getTokenCallback = callback;\n }\n\n /**\n * Connect to Centrifugo server\n */\n connect(userId: string, connectionToken: string): void {\n if (this.client?.state === 'connected') {\n return;\n }\n\n this.userId = userId;\n\n // Determine WebSocket URL from API base\n const wsUrl = this.getWebSocketUrl();\n\n // Build Centrifuge options\n const options: any = {\n token: connectionToken,\n };\n\n // Add token refresh callback if available\n // This is called when token expires or on reconnect\n if (this.getTokenCallback) {\n options.getToken = async () => {\n return await this.getTokenCallback!();\n };\n }\n\n this.client = new Centrifuge(wsUrl, options);\n\n this.setupClientEventListeners();\n\n // Connect\n this.client.connect();\n }\n\n /**\n * Get WebSocket URL from config\n */\n private getWebSocketUrl(): string {\n // If centrifugoUrl is explicitly set, use it\n if (this.config.centrifugoUrl) {\n return this.config.centrifugoUrl;\n }\n\n // Otherwise derive from apiBase\n // e.g., https://api.example.com -> wss://ws.example.com/connection/websocket\n const apiUrl = new URL(this.config.apiBase);\n const wsProtocol = apiUrl.protocol === 'https:' ? 'wss:' : 'ws:';\n\n // Default to same host with /connection/websocket path\n return `${wsProtocol}//${apiUrl.host}/connection/websocket`;\n }\n\n /**\n * Setup Centrifuge client event listeners\n */\n private setupClientEventListeners(): void {\n if (!this.client) return;\n\n this.client.on('connected', (ctx) => {\n this.events.emit('connection:open', { clientId: ctx.client });\n this.subscribeToPersonalChannel();\n });\n\n this.client.on('disconnected', (ctx) => {\n this.events.emit('connection:close', { reason: ctx.reason, code: ctx.code });\n });\n\n this.client.on('error', (ctx) => {\n this.events.emit('connection:error', { error: ctx.error?.message || 'Unknown error' });\n });\n }\n\n /**\n * Subscribe to visitor channel for receiving messages\n * Uses visitorId which is always present (even for authenticated players)\n */\n private subscribeToPersonalChannel(): void {\n if (!this.client || !this.userId) return;\n\n // Always use visitor channel - visitorId is always present\n const channelName = `visitor:${this.userId}`;\n\n // Check if already subscribed (handles reconnection case)\n const existingSub = this.client.getSubscription(channelName);\n if (existingSub) {\n this.personalSub = existingSub;\n if (existingSub.state !== 'subscribed') {\n existingSub.subscribe();\n }\n return;\n }\n\n this.personalSub = this.client.newSubscription(channelName);\n\n this.personalSub.on('publication', (ctx: PublicationContext) => {\n this.handleMessage(ctx.data as WSEventPayload);\n });\n\n this.personalSub.on('error', (ctx) => {\n this.events.emit('error', { type: 'subscription', error: ctx.error?.message });\n });\n\n this.personalSub.subscribe();\n }\n\n /**\n * Handle incoming message from Centrifugo\n * Payload structure: { type, data: {...}, timestamp }\n */\n private handleMessage(payload: any): void {\n const data = payload.data || payload;\n\n switch (payload.type) {\n case 'new_message':\n // Convert backend format to Message format\n const message = {\n id: data.id,\n body: data.body,\n inbound: data.inbound || false,\n outbound: data.outbound || false,\n createdAt: data.createdAt,\n type: data.type || 'text',\n mediaUrl: data.mediaUrl,\n senderType: data.senderType,\n agentName: data.agentName,\n };\n this.events.emit('message:received', {\n ticketId: data.ticketId,\n message,\n });\n break;\n\n case 'typing':\n if (data.isTyping) {\n this.events.emit('typing:start', {\n ticketId: data.ticketId,\n actor: data.senderType || 'agent',\n });\n } else {\n this.events.emit('typing:stop', {\n ticketId: data.ticketId,\n actor: data.senderType || 'agent',\n });\n }\n break;\n\n case 'ticket_created':\n this.events.emit('conversation:started', {\n ticketId: data.ticketId,\n contactId: data.contactId,\n createdAt: data.createdAt,\n });\n break;\n\n case 'ticket_status':\n this.events.emit('conversation:updated', {\n ticketId: data.ticketId,\n status: data.status,\n message: data.message,\n closedAt: data.closedAt,\n agentName: data.agentName,\n });\n break;\n }\n }\n\n /**\n * Update connection token (for token refresh)\n */\n updateToken(newToken: string): void {\n if (this.client) {\n this.client.setToken(newToken);\n }\n }\n\n /**\n * Disconnect from Centrifugo\n */\n disconnect(): void {\n if (this.personalSub) {\n this.personalSub.unsubscribe();\n this.personalSub = null;\n }\n\n if (this.client) {\n this.client.disconnect();\n this.client = null;\n }\n\n this.userId = null;\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.client?.state === 'connected';\n }\n\n /**\n * Get current user ID\n */\n getUserId(): string | null {\n return this.userId;\n }\n}\n","/**\n * Create DOM element with attributes\n */\nexport function createElement<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n attributes?: Record<string, string>,\n children?: (Node | string)[]\n): HTMLElementTagNameMap[K] {\n const element = document.createElement(tag);\n\n if (attributes) {\n Object.entries(attributes).forEach(([key, value]) => {\n if (key === 'className') {\n element.className = value;\n } else if (key.startsWith('data-') || key.startsWith('aria-')) {\n element.setAttribute(key, value);\n } else {\n (element as any)[key] = value;\n }\n });\n }\n\n if (children) {\n children.forEach((child) => {\n if (typeof child === 'string') {\n element.appendChild(document.createTextNode(child));\n } else {\n element.appendChild(child);\n }\n });\n }\n\n return element;\n}\n\n/**\n * Escape HTML to prevent XSS\n */\nexport function escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n}\n\n/**\n * Validate URL to prevent XSS via javascript: or data: protocols\n * Only allows http:, https:, and blob: protocols\n * blob: URLs are safe - they're generated by the browser for local files\n */\nexport function isValidUrl(url: string): boolean {\n if (!url || typeof url !== 'string') {\n return false;\n }\n\n try {\n const parsed = new URL(url, window.location.origin);\n return ['http:', 'https:', 'blob:'].includes(parsed.protocol);\n } catch {\n return false;\n }\n}\n\n/**\n * Sanitize URL - returns safe URL or empty string\n */\nexport function sanitizeUrl(url: string): string {\n return isValidUrl(url) ? url : '';\n}\n\n/**\n * Parse simple markdown (bold, italic, links, code)\n * URLs are validated to prevent XSS via javascript: protocol\n */\nexport function parseMarkdown(text: string): string {\n return escapeHtml(text)\n // Bold\n .replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>')\n // Italic\n .replace(/\\*(.+?)\\*/g, '<em>$1</em>')\n // Code\n .replace(/`(.+?)`/g, '<code>$1</code>')\n // Links - validate URL to prevent XSS\n .replace(/\\[(.+?)\\]\\((.+?)\\)/g, (_match, linkText, url) => {\n const safeUrl = sanitizeUrl(url);\n if (safeUrl) {\n return `<a href=\"${safeUrl}\" target=\"_blank\" rel=\"noopener\">${linkText}</a>`;\n }\n // If URL is invalid, just show the text without link\n return linkText;\n })\n // Line breaks\n .replace(/\\n/g, '<br>');\n}\n\n/**\n * Format timestamp\n */\nexport function formatTime(date: string | Date): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n}\n\n/**\n * Scroll element to bottom\n */\nexport function scrollToBottom(element: HTMLElement, smooth = true): void {\n element.scrollTo({\n top: element.scrollHeight,\n behavior: smooth ? 'smooth' : 'auto',\n });\n}\n\n/**\n * Check if element is scrolled to bottom\n */\nexport function isScrolledToBottom(element: HTMLElement, threshold = 50): boolean {\n return element.scrollHeight - element.scrollTop - element.clientHeight < threshold;\n}\n\n/**\n * Generate unique ID\n */\nexport function generateId(): string {\n return 'cevro_' + Math.random().toString(36).substring(2, 9);\n}\n","import type { CevroMessengerConfig } from '../types';\nimport { createElement } from '../utils/dom';\n\n/**\n * Launcher component - the chat bubble that opens/closes the chat window\n */\nexport class Launcher {\n private config: CevroMessengerConfig;\n private element: HTMLElement | null = null;\n private unreadBadge: HTMLElement | null = null;\n private onClick: () => void;\n private bubbleIconUrl?: string;\n\n constructor(config: CevroMessengerConfig, onClick: () => void, bubbleIconUrl?: string) {\n this.config = config;\n this.onClick = onClick;\n this.bubbleIconUrl = bubbleIconUrl;\n }\n\n /**\n * Render the launcher\n */\n render(): HTMLElement {\n this.element = createElement('div', {\n className: 'cevro-launcher',\n 'data-testid': 'launcher',\n });\n\n // Apply positioning from config\n this.applyPositioning();\n\n const button = createElement('button', {\n className: 'cevro-launcher__button',\n 'aria-label': 'Open chat',\n type: 'button',\n 'data-testid': 'launcher-button',\n });\n\n if (this.bubbleIconUrl) {\n const chatImg = createElement('img', {\n className: 'cevro-launcher__icon cevro-launcher__icon--chat cevro-launcher__icon--custom',\n src: this.bubbleIconUrl,\n alt: 'Chat',\n }) as HTMLImageElement;\n chatImg.style.width = '28px';\n chatImg.style.height = '28px';\n chatImg.style.objectFit = 'contain';\n button.appendChild(chatImg);\n } else {\n const chatIcon = this.createChatIcon();\n chatIcon.classList.add('cevro-launcher__icon', 'cevro-launcher__icon--chat');\n button.appendChild(chatIcon);\n }\n\n // Close icon (closed state)\n const closeIcon = this.createCloseIcon();\n closeIcon.classList.add('cevro-launcher__icon', 'cevro-launcher__icon--close');\n button.appendChild(closeIcon);\n\n // Unread badge\n this.unreadBadge = createElement('span', {\n className: 'cevro-launcher__badge',\n 'data-testid': 'unread-badge',\n });\n this.unreadBadge.style.display = 'none';\n button.appendChild(this.unreadBadge);\n\n button.addEventListener('click', this.onClick);\n this.element.appendChild(button);\n\n return this.element;\n }\n\n /**\n * Apply positioning styles from config\n */\n private applyPositioning(): void {\n if (!this.element) return;\n\n const alignment = this.config.alignment || 'right';\n const vPadding = this.config.verticalPadding ?? 20;\n const hPadding = this.config.horizontalPadding ?? 20;\n\n this.element.style.bottom = `${vPadding}px`;\n\n if (alignment === 'left') {\n this.element.style.left = `${hPadding}px`;\n this.element.style.right = 'auto';\n } else {\n this.element.style.right = `${hPadding}px`;\n this.element.style.left = 'auto';\n }\n\n if (this.config.zIndex) {\n this.element.style.zIndex = String(this.config.zIndex);\n }\n }\n\n /**\n * Create chat icon SVG\n */\n private createChatIcon(): SVGSVGElement {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.setAttribute('fill', 'none');\n svg.setAttribute('stroke', 'currentColor');\n svg.setAttribute('stroke-width', '2');\n svg.setAttribute('stroke-linecap', 'round');\n svg.setAttribute('stroke-linejoin', 'round');\n\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n path.setAttribute(\n 'd',\n 'M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z'\n );\n\n svg.appendChild(path);\n return svg;\n }\n\n /**\n * Create close icon SVG\n */\n private createCloseIcon(): SVGSVGElement {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.setAttribute('fill', 'none');\n svg.setAttribute('stroke', 'currentColor');\n svg.setAttribute('stroke-width', '2');\n svg.setAttribute('stroke-linecap', 'round');\n svg.setAttribute('stroke-linejoin', 'round');\n\n const line1 = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n line1.setAttribute('x1', '18');\n line1.setAttribute('y1', '6');\n line1.setAttribute('x2', '6');\n line1.setAttribute('y2', '18');\n\n const line2 = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n line2.setAttribute('x1', '6');\n line2.setAttribute('y1', '6');\n line2.setAttribute('x2', '18');\n line2.setAttribute('y2', '18');\n\n svg.appendChild(line1);\n svg.appendChild(line2);\n return svg;\n }\n\n /**\n * Set launcher state (open/closed)\n */\n setState(isOpen: boolean): void {\n if (this.element) {\n if (isOpen) {\n this.element.classList.add('cevro-launcher--open');\n } else {\n this.element.classList.remove('cevro-launcher--open');\n }\n }\n }\n\n /**\n * Update unread count\n */\n setUnreadCount(count: number): void {\n if (this.unreadBadge) {\n if (count > 0) {\n this.unreadBadge.textContent = count > 99 ? '99+' : String(count);\n this.unreadBadge.style.display = 'flex';\n } else {\n this.unreadBadge.style.display = 'none';\n }\n }\n }\n\n /**\n * Show/hide the launcher\n */\n setVisible(visible: boolean): void {\n if (this.element) {\n this.element.style.display = visible ? 'block' : 'none';\n }\n }\n\n /**\n * Add pulse animation to attract attention\n */\n pulse(): void {\n if (this.element) {\n this.element.classList.add('cevro-launcher--pulse');\n setTimeout(() => {\n this.element?.classList.remove('cevro-launcher--pulse');\n }, 1000);\n }\n }\n\n /**\n * Update bubble icon dynamically (for preview)\n */\n updateBubbleIcon(iconUrl?: string): void {\n this.bubbleIconUrl = iconUrl;\n\n if (!this.element) {\n return;\n }\n\n const button = this.element.querySelector('.cevro-launcher__button');\n if (!button) {\n return;\n }\n\n const existingIcon = button.querySelector('.cevro-launcher__icon--chat');\n if (existingIcon) {\n existingIcon.remove();\n }\n\n if (iconUrl) {\n const chatImg = document.createElement('img');\n chatImg.className = 'cevro-launcher__icon cevro-launcher__icon--chat cevro-launcher__icon--custom';\n chatImg.src = iconUrl;\n chatImg.alt = 'Chat';\n chatImg.style.cssText = 'width: 28px !important; height: 28px !important; object-fit: contain; border-radius: 4px;';\n button.insertBefore(chatImg, button.firstChild);\n } else {\n const chatIcon = this.createChatIcon();\n chatIcon.classList.add('cevro-launcher__icon', 'cevro-launcher__icon--chat');\n button.insertBefore(chatIcon, button.firstChild);\n }\n }\n\n /**\n * Destroy the launcher\n */\n destroy(): void {\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n this.unreadBadge = null;\n }\n}\n","/**\n * Localization strings for the Cevro Messenger widget\n */\n\nexport interface LocaleStrings {\n // Header\n headerTitle: string;\n headerSubtitle: string;\n\n // Input\n inputPlaceholder: string;\n\n // Pre-chat form (for visitors)\n preChatTitle: string;\n preChatSubtitle: string;\n preChatFirstNameLabel: string;\n preChatFirstNamePlaceholder: string;\n preChatEmailLabel: string;\n preChatEmailPlaceholder: string;\n preChatSubmit: string;\n preChatFirstNameRequired: string;\n preChatEmailRequired: string;\n preChatEmailInvalid: string;\n\n // Closed chat\n closedMessage: string;\n newConversation: string;\n\n // Conversation history\n conversationsTitle: string;\n newConversationButton: string;\n activeConversation: string;\n noConversations: string;\n noConversationsSubtitle: string;\n loadingConversations: string;\n loadMoreConversations: string;\n messagesCount: string;\n yesterday: string;\n closedStatus: string;\n defaultConversationTitle: string;\n\n // CSAT\n csatTitle: string;\n csatSubtitle: string;\n csatPlaceholder: string;\n csatPlaceholderNegative?: string;\n csatPlaceholderNeutral?: string;\n csatSubmit: string;\n csatThankYou: string;\n\n // Footer\n poweredBy: string;\n}\n\n/**\n * Default English strings\n */\nexport const defaultStrings: LocaleStrings = {\n // Header\n headerTitle: 'Cevro',\n headerSubtitle: 'We typically reply within a few minutes',\n\n // Input\n inputPlaceholder: 'How can we help?',\n\n // Pre-chat form (for visitors)\n preChatTitle: 'Start a conversation',\n preChatSubtitle: 'Please provide your contact information to get started.',\n preChatFirstNameLabel: 'First name',\n preChatFirstNamePlaceholder: 'Your first name',\n preChatEmailLabel: 'Email',\n preChatEmailPlaceholder: 'your@email.com',\n preChatSubmit: 'Start Chat',\n preChatFirstNameRequired: 'First name is required',\n preChatEmailRequired: 'Email is required',\n preChatEmailInvalid: 'Please enter a valid email',\n\n // Closed chat\n closedMessage: 'The agent closed the chat.',\n newConversation: 'Start New Conversation',\n\n // Conversation history\n conversationsTitle: 'Conversations',\n newConversationButton: 'New Conversation',\n activeConversation: 'Active',\n noConversations: 'No conversations yet',\n noConversationsSubtitle: 'Start a new conversation to get help.',\n loadingConversations: 'Loading...',\n loadMoreConversations: 'Load more',\n messagesCount: 'messages',\n yesterday: 'Yesterday',\n closedStatus: 'Closed',\n defaultConversationTitle: 'Conversation',\n\n // CSAT\n csatTitle: 'How was your conversation?',\n csatSubtitle: 'Your feedback helps us get better.',\n csatPlaceholder: 'Thank you! What stood out?',\n csatPlaceholderNegative: 'Sorry to hear that. What could we improve?',\n csatPlaceholderNeutral: 'Thanks for your feedback. Anything we could do better?',\n csatSubmit: 'Submit Feedback',\n csatThankYou: 'Thank you for your feedback!',\n\n // Footer\n poweredBy: 'Powered by Cevro AI',\n};\n\n/**\n * Merge strings with priority: defaults < client config < backend (DB)\n */\nexport function getStrings(\n clientOverrides?: Partial<LocaleStrings>,\n backendOverrides?: Partial<LocaleStrings>\n): LocaleStrings {\n return {\n ...defaultStrings,\n ...clientOverrides,\n ...backendOverrides,\n };\n}\n","import type { Message, QuickAction, Agent } from '../types';\nimport { createElement, parseMarkdown, formatTime, scrollToBottom, isScrolledToBottom, generateId, isValidUrl } from '../utils/dom';\n\n/**\n * Message list component\n */\nexport class MessageList {\n private element: HTMLElement | null = null;\n private messagesContainer: HTMLElement | null = null;\n private messages: Map<string, HTMLElement> = new Map();\n private onQuickAction: ((action: QuickAction) => void) | null = null;\n private autoScroll = true;\n private closedMessageElement: HTMLElement | null = null;\n private currentAgent: Agent | null = null;\n private lastMessageBody: string | undefined;\n private lastMessageAt: string | undefined;\n private onScrollTopCallback: (() => boolean | void | Promise<boolean | void>) | null = null;\n private isLoadingTop = false;\n private suppressScrollEvents = false;\n\n /**\n * Set quick action handler\n */\n setQuickActionHandler(handler: (action: QuickAction) => void): void {\n this.onQuickAction = handler;\n }\n\n /**\n * Set callback for when user scrolls to the top (for loading older messages)\n */\n setScrollTopHandler(handler: (() => boolean | void | Promise<boolean | void>) | null): void {\n this.onScrollTopCallback = handler;\n }\n\n /**\n * Signal that top-loading is complete, re-enabling scroll-top detection.\n * Delays re-enabling by one frame so the scroll restoration from\n * prependMessages() settles before we accept new scroll-to-top triggers.\n */\n finishLoadingTop(): void {\n // Keep isLoadingTop=true for one more frame to let scroll position settle\n requestAnimationFrame(() => {\n this.isLoadingTop = false;\n });\n }\n\n /**\n * Reset top-pagination state (keeps the scroll-top handler attached)\n */\n resetTopLoading(): void {\n this.isLoadingTop = false;\n this.suppressScrollEvents = false;\n }\n\n /**\n * Set agent info for message avatars\n */\n setAgent(agent: Agent): void {\n this.currentAgent = agent;\n }\n\n /**\n * Render the message list\n */\n render(): HTMLElement {\n if (this.element) {\n return this.element;\n }\n\n this.element = createElement('div', {\n className: 'cevro-messages',\n id: generateId(),\n });\n\n this.messagesContainer = createElement('div', {\n className: 'cevro-messages__container',\n 'data-testid': 'messages-container',\n });\n\n // Track scroll position for auto-scroll and scroll-to-top detection\n this.messagesContainer.addEventListener('scroll', () => {\n if (this.suppressScrollEvents) return;\n this.autoScroll = isScrolledToBottom(this.messagesContainer!);\n if (\n this.messagesContainer!.scrollTop < 80 &&\n this.onScrollTopCallback &&\n !this.isLoadingTop\n ) {\n const result = this.onScrollTopCallback();\n if (result instanceof Promise) {\n this.isLoadingTop = true;\n result\n .then((started) => {\n if (started === false) {\n this.isLoadingTop = false;\n }\n })\n .catch(() => {\n this.isLoadingTop = false;\n });\n } else if (result !== false) {\n this.isLoadingTop = true;\n }\n }\n });\n\n this.element.appendChild(this.messagesContainer);\n\n return this.element;\n }\n\n /**\n * Get the body of the last message added\n */\n getLastMessageBody(): string | undefined {\n return this.lastMessageBody;\n }\n\n getLastMessageAt(): string | undefined {\n return this.lastMessageAt;\n }\n\n /**\n * Count consecutive agent messages at the tail, back to the last user message.\n * If the user has replied since, returns 0.\n */\n getAgentMessagesSinceLastUserMessage(): number {\n if (!this.messagesContainer) return 0;\n const nodes = this.messagesContainer.querySelectorAll('.cevro-message');\n let count = 0;\n for (let i = nodes.length - 1; i >= 0; i--) {\n const el = nodes[i];\n if (el.classList.contains('cevro-message--outbound')) {\n // outbound in SDK = user's own message → stop\n break;\n }\n if (el.classList.contains('cevro-message--inbound')) {\n // inbound in SDK = agent's message → count\n count++;\n }\n }\n return count;\n }\n\n /**\n * Add a message to the list\n */\n addMessage(message: Message, animate = true, skipScroll = false): void {\n if (!this.messagesContainer) return;\n\n // Track last message for conversation list preview\n if (message.body) {\n this.lastMessageBody = message.body;\n this.lastMessageAt = message.createdAt;\n }\n\n // Check if message already exists\n if (this.messages.has(message.id)) {\n this.updateMessage(message);\n return;\n }\n\n const messageEl = this.createMessageElement(message);\n if (animate) {\n messageEl.classList.add('cevro-message--animate');\n }\n\n // Insert before typing indicator if it exists, otherwise append\n const typingIndicator = this.messagesContainer.querySelector('#cevro-typing-indicator');\n if (typingIndicator) {\n this.messagesContainer.insertBefore(messageEl, typingIndicator);\n } else {\n this.messagesContainer.appendChild(messageEl);\n }\n this.messages.set(message.id, messageEl);\n\n // Auto-scroll if at bottom (skip during bulk load)\n if (this.autoScroll && !skipScroll) {\n scrollToBottom(this.messagesContainer);\n }\n }\n\n /**\n * Prepend multiple messages at the top (for loading older messages).\n * Performs a single scroll restoration after all inserts to avoid jitter.\n */\n prependMessages(messages: Message[]): void {\n if (!this.messagesContainer || messages.length === 0) return;\n\n // Anchor: remember the current first child's visual position\n const anchor = this.messagesContainer.firstElementChild as HTMLElement | null;\n const anchorOffset = anchor\n ? anchor.offsetTop - this.messagesContainer.scrollTop\n : 0;\n\n // Insert all messages before the anchor in order (oldest → newest)\n for (const message of messages) {\n if (this.messages.has(message.id)) continue;\n const messageEl = this.createMessageElement(message);\n this.messagesContainer.insertBefore(messageEl, anchor);\n this.messages.set(message.id, messageEl);\n }\n\n // Single scroll restoration: keep the anchor element at the same visual position\n // Suppress scroll events to avoid re-triggering the scroll-to-top handler\n if (anchor) {\n this.suppressScrollEvents = true;\n this.messagesContainer.scrollTop = anchor.offsetTop - anchorOffset;\n // Re-enable after the browser processes the scroll\n requestAnimationFrame(() => { this.suppressScrollEvents = false; });\n }\n }\n\n /**\n * Prepend a single message at the top while preserving scroll position.\n */\n prependMessage(message: Message): void {\n this.prependMessages([message]);\n }\n\n /**\n * Update an existing message\n * @param message - Updated message data\n * @param oldId - Original message id (for optimistic updates where id changes)\n */\n updateMessage(message: Message, oldId?: string): void {\n const lookupId = oldId || message.id;\n const existingEl = this.messages.get(lookupId);\n if (!existingEl || !this.messagesContainer) return;\n\n const newEl = this.createMessageElement(message);\n this.messagesContainer.replaceChild(newEl, existingEl);\n\n // Remove old id entry and add new one\n if (oldId && oldId !== message.id) {\n this.messages.delete(oldId);\n }\n this.messages.set(message.id, newEl);\n }\n\n /**\n * Update upload progress for a message\n */\n updateMessageProgress(messageId: string, progress: number): void {\n const messageEl = this.messages.get(messageId);\n if (!messageEl) return;\n\n const progressFill = messageEl.querySelector('.cevro-file-progress__fill') as HTMLElement;\n const progressText = messageEl.querySelector('.cevro-file-progress__text');\n\n if (progressFill) {\n progressFill.style.width = `${progress}%`;\n }\n if (progressText) {\n progressText.textContent = `${progress}%`;\n }\n }\n\n /**\n * Remove a message from the list\n */\n removeMessage(messageId: string): void {\n const messageEl = this.messages.get(messageId);\n if (!messageEl) return;\n\n messageEl.remove();\n this.messages.delete(messageId);\n }\n\n /**\n * Create message element\n */\n private createMessageElement(message: Message): HTMLElement {\n // From SDK perspective:\n // - inbound: true = user's message (to backend) = show on RIGHT\n // - outbound: true = admin's message (from backend) = show on LEFT\n const isMyMessage = message.inbound === true;\n const wrapper = createElement('div', {\n className: `cevro-message ${isMyMessage ? 'cevro-message--outbound' : 'cevro-message--inbound'}`,\n 'data-message-id': message.id,\n 'data-testid': `message-${message.id}`,\n });\n\n // Avatar for admin messages\n if (!isMyMessage) {\n const isHuman = message.senderType === 'human';\n const avatar = createElement('div', {\n className: `cevro-message__avatar${isHuman ? ' cevro-message__avatar--human' : ''}`,\n });\n\n if (isHuman) {\n // Human agent: show initials avatar\n const name = message.agentName || 'Support';\n const initials = name\n .split(' ')\n .map(w => w[0])\n .join('')\n .toUpperCase()\n .slice(0, 2);\n const initialsEl = createElement('div', {\n className: 'cevro-message__avatar-initials',\n });\n initialsEl.textContent = initials;\n avatar.appendChild(initialsEl);\n } else if (this.currentAgent?.avatarUrl && isValidUrl(this.currentAgent.avatarUrl)) {\n // AI agent with custom avatar\n const img = createElement('img', {\n className: 'cevro-message__avatar-img',\n }) as HTMLImageElement;\n img.src = this.currentAgent.avatarUrl;\n img.alt = this.currentAgent.name || 'Agent';\n avatar.appendChild(img);\n } else {\n avatar.innerHTML = this.createBotAvatarSvg();\n }\n\n wrapper.appendChild(avatar);\n }\n\n // Message content wrapper\n const contentWrapper = createElement('div', {\n className: 'cevro-message__content-wrapper',\n });\n\n // Show sender name for human agent messages\n if (!isMyMessage && message.senderType === 'human' && message.agentName) {\n const senderLabel = createElement('div', {\n className: 'cevro-message__sender-name',\n });\n senderLabel.textContent = message.agentName;\n contentWrapper.appendChild(senderLabel);\n }\n\n // Message bubble\n const bubble = createElement('div', {\n className: 'cevro-message__bubble',\n });\n\n // Handle different message types\n const isImage = message.type === 'image' || message.attachment?.category === 'image';\n\n if (isImage && message.mediaUrl && isValidUrl(message.mediaUrl)) {\n // Image message - show actual image\n const imageContainer = createElement('div', {\n className: 'cevro-message__image-container',\n });\n\n const img = createElement('img', {\n className: 'cevro-message__image',\n }) as HTMLImageElement;\n img.src = message.mediaUrl;\n img.alt = message.attachment?.filename || 'Image';\n img.loading = 'lazy';\n imageContainer.appendChild(img);\n\n // Show progress overlay if uploading\n if (message.status === 'sending') {\n const progressOverlay = this.createProgressOverlay();\n imageContainer.appendChild(progressOverlay);\n }\n\n bubble.appendChild(imageContainer);\n } else if (message.type === 'file' || (message.attachment && !isImage)) {\n // File attachment (non-image) - show file card\n const fileCard = this.createFileCard(message);\n bubble.appendChild(fileCard);\n } else if (message.type === 'media' && message.mediaUrl && isValidUrl(message.mediaUrl)) {\n // Legacy media type\n const link = createElement('a', {\n className: 'cevro-message__attachment',\n }) as HTMLAnchorElement;\n link.href = message.mediaUrl;\n link.target = '_blank';\n link.rel = 'noopener';\n link.innerHTML = `\n ${this.getFileIcon('file')}\n <span>Attachment</span>\n `;\n bubble.appendChild(link);\n }\n\n // Text content\n if (message.body) {\n const textContent = createElement('div', {\n className: 'cevro-message__text',\n });\n textContent.innerHTML = parseMarkdown(message.body);\n bubble.appendChild(textContent);\n }\n\n contentWrapper.appendChild(bubble);\n\n // Quick actions\n if (message.richContent?.quickActions?.length) {\n const actionsContainer = createElement('div', {\n className: 'cevro-message__quick-actions',\n });\n\n message.richContent.quickActions.forEach((action) => {\n const button = createElement('button', {\n className: 'cevro-message__quick-action',\n });\n button.textContent = action.label;\n button.addEventListener('click', () => {\n if (this.onQuickAction) {\n this.onQuickAction(action);\n }\n });\n actionsContainer.appendChild(button);\n });\n\n contentWrapper.appendChild(actionsContainer);\n }\n\n // Timestamp and status\n const meta = createElement('div', {\n className: 'cevro-message__meta',\n });\n meta.textContent = formatTime(message.createdAt);\n\n // Status indicator for user's own messages\n if (isMyMessage && message.status) {\n const status = createElement('span', {\n className: `cevro-message__status cevro-message__status--${message.status}`,\n });\n status.innerHTML = this.getStatusIcon(message.status);\n meta.appendChild(status);\n }\n\n contentWrapper.appendChild(meta);\n wrapper.appendChild(contentWrapper);\n\n return wrapper;\n }\n\n /**\n * Create progress overlay for images\n */\n private createProgressOverlay(): HTMLElement {\n const overlay = createElement('div', {\n className: 'cevro-file-progress-overlay',\n });\n overlay.innerHTML = `\n <div class=\"cevro-file-progress\">\n <div class=\"cevro-file-progress__bar\">\n <div class=\"cevro-file-progress__fill\" style=\"width: 0%\"></div>\n </div>\n <span class=\"cevro-file-progress__text\">0%</span>\n </div>\n `;\n return overlay;\n }\n\n /**\n * Create file card for non-image attachments\n */\n private createFileCard(message: Message): HTMLElement {\n const attachment = message.attachment;\n const category = attachment?.category || 'file';\n const filename = attachment?.filename || 'File';\n const size = attachment?.size || 0;\n const isUploading = message.status === 'sending';\n\n const card = createElement('div', {\n className: `cevro-file-card cevro-file-card--${category}`,\n });\n\n // File icon\n const iconWrapper = createElement('div', {\n className: 'cevro-file-card__icon',\n });\n iconWrapper.innerHTML = this.getFileIcon(category);\n card.appendChild(iconWrapper);\n\n // File info\n const info = createElement('div', {\n className: 'cevro-file-card__info',\n });\n\n const name = createElement('div', {\n className: 'cevro-file-card__name',\n });\n name.textContent = this.truncateFilename(filename, 25);\n name.title = filename;\n info.appendChild(name);\n\n const details = createElement('div', {\n className: 'cevro-file-card__details',\n });\n details.textContent = this.formatFileSize(size);\n info.appendChild(details);\n\n card.appendChild(info);\n\n // Progress or download\n if (isUploading) {\n const progress = createElement('div', {\n className: 'cevro-file-card__progress',\n });\n progress.innerHTML = `\n <div class=\"cevro-file-progress\">\n <div class=\"cevro-file-progress__bar\">\n <div class=\"cevro-file-progress__fill\" style=\"width: 0%\"></div>\n </div>\n <span class=\"cevro-file-progress__text\">0%</span>\n </div>\n `;\n card.appendChild(progress);\n } else if (message.mediaUrl && isValidUrl(message.mediaUrl)) {\n // Make card clickable to download\n card.style.cursor = 'pointer';\n card.addEventListener('click', () => {\n window.open(message.mediaUrl, '_blank');\n });\n }\n\n return card;\n }\n\n /**\n * Get file icon SVG based on category\n */\n private getFileIcon(category: string): string {\n const icons: Record<string, string> = {\n pdf: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#E53935\"/>\n <path d=\"M14 2V8H20\" fill=\"#FFCDD2\"/>\n <path d=\"M9 13H10.5V14.5H9V16H7.5V11H10.5V12.5H9V13Z\" fill=\"white\"/>\n <path d=\"M11.5 11H13.5C14.05 11 14.5 11.45 14.5 12V14C14.5 14.55 14.05 15 13.5 15H12.5V16H11.5V11ZM13 14V12H12.5V14H13Z\" fill=\"white\"/>\n <path d=\"M15.5 11H17V12H16V13H17V14H16V16H15.5V11Z\" fill=\"white\"/>\n </svg>`,\n document: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#1976D2\"/>\n <path d=\"M14 2V8H20\" fill=\"#BBDEFB\"/>\n <path d=\"M8 12H16V13H8V12ZM8 15H14V16H8V15Z\" fill=\"white\"/>\n </svg>`,\n spreadsheet: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#388E3C\"/>\n <path d=\"M14 2V8H20\" fill=\"#C8E6C9\"/>\n <path d=\"M8 12H10V14H8V12ZM11 12H13V14H11V12ZM14 12H16V14H14V12ZM8 15H10V17H8V15ZM11 15H13V17H11V15Z\" fill=\"white\"/>\n </svg>`,\n presentation: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#F57C00\"/>\n <path d=\"M14 2V8H20\" fill=\"#FFE0B2\"/>\n <rect x=\"8\" y=\"12\" width=\"8\" height=\"5\" rx=\"1\" fill=\"white\"/>\n </svg>`,\n video: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#7B1FA2\"/>\n <path d=\"M14 2V8H20\" fill=\"#E1BEE7\"/>\n <path d=\"M10 11V17L15 14L10 11Z\" fill=\"white\"/>\n </svg>`,\n audio: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#00897B\"/>\n <path d=\"M14 2V8H20\" fill=\"#B2DFDB\"/>\n <path d=\"M12 11C10.9 11 10 11.9 10 13V15C10 16.1 10.9 17 12 17C13.1 17 14 16.1 14 15V13C14 11.9 13.1 11 12 11Z\" fill=\"white\"/>\n <path d=\"M15 14V15C15 16.66 13.66 18 12 18C10.34 18 9 16.66 9 15V14H8V15C8 17.03 9.53 18.71 11.5 18.96V20H10V21H14V20H12.5V18.96C14.47 18.71 16 17.03 16 15V14H15Z\" fill=\"white\"/>\n </svg>`,\n archive: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#795548\"/>\n <path d=\"M14 2V8H20\" fill=\"#D7CCC8\"/>\n <rect x=\"10\" y=\"11\" width=\"4\" height=\"2\" fill=\"white\"/>\n <rect x=\"10\" y=\"14\" width=\"4\" height=\"2\" fill=\"white\"/>\n <rect x=\"10\" y=\"17\" width=\"4\" height=\"2\" fill=\"white\"/>\n </svg>`,\n text: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#607D8B\"/>\n <path d=\"M14 2V8H20\" fill=\"#CFD8DC\"/>\n <path d=\"M8 12H16V13H8V12ZM8 15H14V16H8V15ZM8 18H16V19H8V18Z\" fill=\"white\"/>\n </svg>`,\n image: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#43A047\"/>\n <path d=\"M14 2V8H20\" fill=\"#C8E6C9\"/>\n <circle cx=\"10\" cy=\"13\" r=\"2\" fill=\"white\"/>\n <path d=\"M8 18L10 15L12 17L15 13L17 18H8Z\" fill=\"white\"/>\n </svg>`,\n file: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#90A4AE\"/>\n <path d=\"M14 2V8H20\" fill=\"#CFD8DC\"/>\n </svg>`,\n };\n\n return icons[category] || icons.file;\n }\n\n /**\n * Format file size to human readable\n */\n private formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];\n }\n\n /**\n * Truncate filename if too long\n */\n private truncateFilename(filename: string, maxLength: number): string {\n if (filename.length <= maxLength) return filename;\n\n const ext = filename.split('.').pop() || '';\n const name = filename.slice(0, filename.length - ext.length - 1);\n const truncatedName = name.slice(0, maxLength - ext.length - 4) + '...';\n return truncatedName + '.' + ext;\n }\n\n /**\n * Create bot avatar SVG\n */\n private createBotAvatarSvg(): string {\n return `\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 28 28\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"14\" cy=\"10\" r=\"4\" fill=\"white\"/>\n <path d=\"M7 22c0-3.866 3.134-7 7-7s7 3.134 7 7\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n `;\n }\n\n /**\n * Get status icon\n * - sending: single checkmark (message is being sent)\n * - sent: double checkmark (message delivered to server)\n * - delivered: double checkmark (same as sent)\n * - read: double checkmark filled (message was read)\n * - failed: X icon in red\n */\n private getStatusIcon(status: string): string {\n // Single checkmark\n const singleCheck = '<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>';\n // Double checkmark\n const doubleCheck = '<svg width=\"16\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"18 7 9.5 17 5 12\"/><polyline points=\"23 7 14.5 17 12 14\"/></svg>';\n // Double checkmark filled (for read)\n const doubleCheckRead = '<svg width=\"16\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#8B5CF6\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"18 7 9.5 17 5 12\"/><polyline points=\"23 7 14.5 17 12 14\"/></svg>';\n\n switch (status) {\n case 'sending':\n return singleCheck;\n case 'sent':\n case 'delivered':\n return doubleCheck;\n case 'read':\n return doubleCheckRead;\n case 'failed':\n return '<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ef4444\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/></svg>';\n default:\n return '';\n }\n }\n\n /**\n * Show typing indicator\n */\n showTypingIndicator(): void {\n if (!this.messagesContainer) return;\n\n // Remove existing typing indicator\n this.hideTypingIndicator();\n\n const indicator = createElement('div', {\n className: 'cevro-typing-indicator',\n id: 'cevro-typing-indicator',\n 'data-testid': 'typing-indicator',\n });\n\n indicator.innerHTML = `\n <div class=\"cevro-typing-indicator__avatar\">\n ${this.createBotAvatarSvg()}\n </div>\n <div class=\"cevro-typing-indicator__dots\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n `;\n\n this.messagesContainer.appendChild(indicator);\n\n if (this.autoScroll) {\n scrollToBottom(this.messagesContainer);\n }\n }\n\n /**\n * Hide typing indicator\n */\n hideTypingIndicator(): void {\n // Use querySelector on container (works with Shadow DOM)\n const indicator = this.messagesContainer?.querySelector('#cevro-typing-indicator');\n if (indicator) {\n indicator.remove();\n }\n }\n\n /**\n * Clear all messages\n */\n clear(): void {\n if (this.messagesContainer) {\n this.messagesContainer.innerHTML = '';\n }\n this.messages.clear();\n this.lastMessageBody = undefined;\n this.lastMessageAt = undefined;\n this.autoScroll = true;\n this.resetTopLoading();\n // Also remove closed message if present\n if (this.closedMessageElement) {\n this.closedMessageElement.remove();\n this.closedMessageElement = null;\n }\n }\n\n /**\n * Show closed chat message at the bottom of messages area\n * This displays when a ticket is closed (e.g., escalated and resolved)\n * @param message - Custom message text (optional)\n */\n showClosedMessage(message?: string): void {\n if (!this.messagesContainer) return;\n\n // Remove existing closed message\n this.hideClosedMessage();\n\n this.closedMessageElement = createElement('div', {\n className: 'cevro-messages__closed-notice',\n 'data-testid': 'closed-chat-message',\n });\n\n const displayMessage = message || 'The agent closed the chat. If you need assistance please start a new chat.';\n this.closedMessageElement.innerHTML = `\n <p class=\"cevro-messages__closed-text\">\n ${displayMessage}\n </p>\n `;\n\n this.messagesContainer.appendChild(this.closedMessageElement);\n\n // Scroll to show the closed message\n if (this.autoScroll) {\n scrollToBottom(this.messagesContainer);\n }\n }\n\n /**\n * Hide closed chat message\n */\n hideClosedMessage(): void {\n if (this.closedMessageElement) {\n this.closedMessageElement.remove();\n this.closedMessageElement = null;\n }\n }\n\n /**\n * Scroll to bottom\n */\n scrollToBottom(): void {\n if (this.messagesContainer) {\n scrollToBottom(this.messagesContainer, false);\n }\n }\n\n /**\n * Destroy the component\n */\n destroy(): void {\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n this.messagesContainer = null;\n this.messages.clear();\n }\n}\n","import type { CevroMessengerConfig, Message, QuickAction, Agent, LocaleStrings } from '../types';\nimport { createElement, generateId } from '../utils/dom';\nimport { generateAcceptAttribute } from '../utils/file-validation';\nimport { defaultStrings, getStrings } from '../i18n/strings';\nimport { MessageList } from './MessageList';\n\nexport interface ChatWindowCallbacks {\n onClose: () => void;\n onSendMessage: (message: string) => void;\n onQuickAction: (action: QuickAction) => void;\n onFileUpload?: (file: File) => void;\n onCSATSubmit?: (rating: number, feedback?: string) => Promise<void>;\n onStartNewChat?: () => void;\n onPreChatSubmit?: (data: { firstName: string; email: string }) => void;\n onShowHistory?: () => void;\n}\n\n/**\n * Chat window component\n */\nexport class ChatWindow {\n private config: CevroMessengerConfig;\n private callbacks: ChatWindowCallbacks;\n private element: HTMLElement | null = null;\n private messageList: MessageList;\n private inputElement: HTMLTextAreaElement | null = null;\n private sendButton: HTMLButtonElement | null = null;\n private fileInput: HTMLInputElement | null = null;\n private fileButton: HTMLButtonElement | null = null;\n private isVisible = false;\n private logoElement: HTMLElement | null = null;\n private brandNameElement: HTMLElement | null = null;\n private headerSubtitleElement: HTMLElement | null = null;\n private inputWrapper: HTMLElement | null = null;\n private closedFooter: HTMLElement | null = null;\n private csatContainer: HTMLElement | null = null;\n\n // Localization\n private strings: LocaleStrings = defaultStrings;\n\n // CSAT state\n private csatRating: number = 0;\n private csatFeedback: string = '';\n private csatSubmitting: boolean = false;\n\n // Pre-chat form state\n private preChatContainer: HTMLElement | null = null;\n private preChatCompleted: boolean = false;\n\n private customLogoUrl?: string;\n\n constructor(\n config: CevroMessengerConfig,\n callbacks: ChatWindowCallbacks,\n strings?: LocaleStrings,\n customLogoUrl?: string\n ) {\n this.config = config;\n this.callbacks = callbacks;\n this.strings = strings || getStrings(config.locale);\n this.customLogoUrl = customLogoUrl;\n this.messageList = new MessageList();\n this.messageList.setQuickActionHandler((action) => {\n this.callbacks.onQuickAction(action);\n });\n }\n\n /**\n * Update locale strings (e.g., after receiving from backend)\n */\n setStrings(backendStrings?: Partial<LocaleStrings>): void {\n this.strings = getStrings(this.config.locale, backendStrings);\n this.updateUIStrings();\n }\n\n /**\n * Update UI elements with current strings\n */\n private updateUIStrings(): void {\n if (this.headerSubtitleElement) {\n this.headerSubtitleElement.textContent = this.strings.headerSubtitle;\n }\n if (this.inputElement) {\n this.inputElement.placeholder = this.strings.inputPlaceholder;\n }\n }\n\n /**\n * Render the chat window\n */\n render(): HTMLElement {\n if (this.element) {\n return this.element;\n }\n\n // Main container\n this.element = createElement('div', {\n className: 'cevro-chat-window',\n id: generateId(),\n });\n\n // Apply positioning\n this.applyPositioning();\n\n // Header\n const header = this.createHeader();\n this.element.appendChild(header);\n\n // Messages area\n const messagesArea = this.messageList.render();\n this.element.appendChild(messagesArea);\n\n // Input area\n this.inputWrapper = this.createInputArea();\n this.element.appendChild(this.inputWrapper);\n\n return this.element;\n }\n\n /**\n * Apply positioning styles\n */\n private applyPositioning(): void {\n if (!this.element) return;\n\n const alignment = this.config.alignment || 'right';\n const vPadding = this.config.verticalPadding ?? 20;\n const hPadding = this.config.horizontalPadding ?? 20;\n\n // Position above launcher\n this.element.style.bottom = `${vPadding + 70}px`;\n\n if (alignment === 'left') {\n this.element.style.left = `${hPadding}px`;\n this.element.style.right = 'auto';\n } else {\n this.element.style.right = `${hPadding}px`;\n this.element.style.left = 'auto';\n }\n\n if (this.config.zIndex) {\n this.element.style.zIndex = String(this.config.zIndex - 1);\n }\n }\n\n /**\n * Create header element\n */\n private createHeader(): HTMLElement {\n const header = createElement('div', {\n className: 'cevro-chat-window__header',\n });\n\n this.logoElement = createElement('div', {\n className: 'cevro-chat-window__logo',\n 'data-testid': 'company-logo',\n });\n if (this.customLogoUrl) {\n const logoImg = createElement('img', {\n src: this.customLogoUrl,\n alt: 'Logo',\n className: 'cevro-chat-window__logo-img',\n }) as HTMLImageElement;\n logoImg.style.width = '40px';\n logoImg.style.height = '40px';\n logoImg.style.objectFit = 'contain';\n logoImg.style.borderRadius = '8px';\n this.logoElement.appendChild(logoImg);\n } else {\n this.logoElement.innerHTML = this.createCompanyLogoSvg();\n }\n\n // History button (back chevron on the left)\n const historyButton = createElement('button', {\n className: 'cevro-chat-window__history-button',\n 'aria-label': 'Conversation history',\n 'data-testid': 'history-button',\n });\n historyButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\"/>\n </svg>\n `;\n historyButton.addEventListener('click', () => {\n if (this.callbacks.onShowHistory) {\n this.callbacks.onShowHistory();\n }\n });\n header.appendChild(historyButton);\n\n header.appendChild(this.logoElement);\n\n // Title section\n const titleSection = createElement('div', {\n className: 'cevro-chat-window__title-section',\n });\n\n this.brandNameElement = createElement('h2', {\n className: 'cevro-chat-window__title',\n 'data-testid': 'brand-name',\n }, [this.strings.headerTitle]);\n\n this.headerSubtitleElement = createElement('p', {\n className: 'cevro-chat-window__subtitle',\n }, [this.strings.headerSubtitle]);\n\n titleSection.appendChild(this.brandNameElement);\n titleSection.appendChild(this.headerSubtitleElement);\n header.appendChild(titleSection);\n\n // Close button\n const closeButton = createElement('button', {\n className: 'cevro-chat-window__close',\n 'aria-label': 'Close chat',\n 'data-testid': 'close-button',\n });\n closeButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n `;\n closeButton.addEventListener('click', () => {\n this.callbacks.onClose();\n });\n header.appendChild(closeButton);\n\n return header;\n }\n\n /**\n * Create company logo SVG\n */\n private createCompanyLogoSvg(): string {\n return `\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 40 40\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"40\" height=\"40\" rx=\"8\" fill=\"url(#cevro-logo-gradient)\"/>\n <svg x=\"6\" y=\"6\" width=\"28\" height=\"28\" viewBox=\"0 0 512 498\">\n <g>\n <path fill=\"#FFFFFF\" d=\"M298.97,91.19l-32.23-32.23c-6.12-6.12-6.12-16.03,0-22.15l32.23-32.23c6.12-6.12,16.03-6.12,22.15,0\n l30.06,30.06c2.94,2.94,6.92,4.59,11.07,4.59h48.31v17.32h-48.31c-4.15,0-8.14,1.65-11.07,4.59l-30.05,30.06\n C315,97.3,305.09,97.31,298.97,91.19z\"/>\n <path fill=\"#FFFFFF\" d=\"M260.84,157h96.5c4.15,0,8.14,1.65,11.07,4.59l30.05,30.05c6.12,6.12,16.03,6.12,22.15,0l30.06-30.06\n c2.94-2.94,6.92-4.59,11.07-4.59h50.21v-17.32h-50.21c-4.15,0-8.14-1.65-11.07-4.59l-30.06-30.06\n c-6.12-6.12-16.03-6.12-22.15,0l-30.06,30.05c-2.94,2.94-6.92,4.59-11.07,4.59h-96.5c-4.15,0-8.14-1.65-11.07-4.59\n l-30.06-30.05c-6.12-6.12-16.03-6.12-22.15,0l-32.23,32.23c-6.12,6.12-6.12,16.03,0,22.15l32.23,32.23\n c6.12,6.12,16.03,6.12,22.15,0l30.06-30.05C252.7,158.65,256.69,157,260.84,157z\"/>\n <path fill=\"#FFFFFF\" d=\"M260.84,340.58h96.5c4.15,0,8.14-1.65,11.07-4.59l30.06-30.06c6.12-6.12,16.03-6.12,22.15,0L450.67,336\n c2.94,2.94,6.92,4.59,11.07,4.59h50.21v17.32h-50.21c-4.15,0-8.14,1.65-11.07,4.59l-30.05,30.06\n c-6.12,6.12-16.03,6.12-22.15,0l-30.06-30.06c-2.94-2.94-6.92-4.59-11.07-4.59h-96.5c-4.15,0-8.14,1.65-11.07,4.59\n l-30.05,30.06c-6.12,6.12-16.03,6.12-22.15,0l-32.23-32.23c-6.12-6.12-6.12-16.03,0-22.15l32.23-32.23\n c6.12,6.12,16.03-6.12,22.15,0L249.77,336C252.7,338.93,256.69,340.58,260.84,340.58z\"/>\n <path fill=\"#FFFFFF\" d=\"M343.17,259.89l-1.13,1.13l-31.09,31.09c-1.9,1.9-4.16,3.21-6.6,3.92c-3.92,1.19-8.2,0.83-11.83-1.13\n c-0.89-0.54-1.72-1.07-2.56-1.72c-0.42-0.3-0.83-0.65-1.25-1.07l-30.02-30.08h-0.06c-2.91-2.91-6.9-4.58-11.06-4.58h-86.71\n c-2.62,0-5.11,0.65-7.37,1.84c-0.89,0.53-1.72,1.07-2.5,1.72c-0.06-0.06-0.06-0.06-0.06,0c-0.36,0.36-0.71,0.65-1.07,1.01\n l-30.08,30.08h-0.06c-0.36,0.36-0.77,0.71-1.19,1.07c-0.77,0.71-1.66,1.25-2.56,1.72c-3.63,1.9-7.91,2.32-11.83,1.13\n c-0.95-0.3-1.84-0.71-2.73-1.13c-0.06,0-0.06,0-0.06,0c-1.31-0.77-2.56-1.66-3.69-2.79l-30.08-30.08h-0.06\n c-0.71-0.77-1.49-1.37-2.32-1.96c-0.06,0.06-0.06,0.06-0.06,0c-1.31-0.89-2.68-1.55-4.16-1.96\n c-1.49-0.42-3.03-0.65-4.58-0.65H6.3v-17.3h50.12c1.55,0,3.09-0.24,4.58-0.65c1.49-0.42,2.85-1.07,4.16-1.96\n c0-0.06,0-0.06,0.06,0c0.83-0.59,1.61-1.19,2.32-1.96h0.06l30.08-30.08c1.13-1.13,2.38-2.08,3.69-2.79c0,0,0-0.06,0.06,0\n c0.47-0.24,0.95-0.48,1.43-0.65c0.48-0.18,0.95-0.36,1.43-0.48c3.86-1.19,8.08-0.77,11.71,1.13\n c0.89,0.48,1.79,1.01,2.56,1.72c0.42,0.36,0.83,0.71,1.19,1.07h0.06l30.08,30.08c0.36,0.36,0.71,0.65,1.07,1.01\n c0,0.06,0,0.06,0.06,0c0.77,0.65,1.61,1.19,2.5,1.72c2.26,1.19,4.76,1.84,7.37,1.84h86.71c4.16,0,8.14-1.66,11.06-4.58h0.06\n l30.08-30.08c0.36-0.42,0.77-0.77,1.19-1.07c0.83-0.65,1.66-1.25,2.56-1.72c3.63-1.9,7.85-2.32,11.71-1.13\n c0.48,0.12,0.95,0.3,1.43,0.48c1.96,0.71,3.74,1.84,5.29,3.45l32.22,32.22C349.23,243.83,349.23,253.76,343.17,259.89z\"/>\n <path fill=\"#FFFFFF\" d=\"M298.02,406.39l-32.23,32.23c-6.12,6.12-6.12,16.03,0,22.15L298.02,493c6.12,6.12,16.03,6.12,22.15,0\n l30.06-30.06c2.94-2.94,6.92-4.59,11.07-4.59h50.21v-17.32h-50.21c-4.15,0-8.14-1.65-11.07-4.59l-30.06-30.06\n C314.05,400.28,304.13,400.28,298.02,406.39z\"/>\n </g>\n </svg>\n <defs>\n <linearGradient id=\"cevro-logo-gradient\" x1=\"0\" y1=\"0\" x2=\"40\" y2=\"40\" gradientUnits=\"userSpaceOnUse\">\n <stop offset=\"0%\" stop-color=\"#8B5CF6\"/>\n <stop offset=\"100%\" stop-color=\"#7C3AED\"/>\n </linearGradient>\n </defs>\n </svg>\n `;\n }\n\n /**\n * Set agent info (used for message avatars)\n */\n setAgent(agent: Agent): void {\n // Pass agent info to MessageList for message avatars\n this.messageList.setAgent(agent);\n }\n\n /**\n * Create input area element\n */\n private createInputArea(): HTMLElement {\n const wrapper = createElement('div', {\n className: 'cevro-chat-window__input-wrapper',\n });\n\n const inputArea = createElement('div', {\n className: 'cevro-chat-window__input-area',\n });\n\n // File upload button (paperclip icon)\n this.fileButton = createElement('button', {\n className: 'cevro-chat-window__file-button',\n 'aria-label': 'Attach file',\n 'data-testid': 'file-button',\n }) as HTMLButtonElement;\n this.fileButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M16.5 6V17.5C16.5 19.71 14.71 21.5 12.5 21.5C10.29 21.5 8.5 19.71 8.5 17.5V5C8.5 3.62 9.62 2.5 11 2.5C12.38 2.5 13.5 3.62 13.5 5V16.5C13.5 17.05 13.05 17.5 12.5 17.5C11.95 17.5 11.5 17.05 11.5 16.5V6H10V16.5C10 17.88 11.12 19 12.5 19C13.88 19 15 17.88 15 16.5V5C15 2.79 13.21 1 11 1C8.79 1 7 2.79 7 5V17.5C7 20.54 9.46 23 12.5 23C15.54 23 18 20.54 18 17.5V6H16.5Z\" fill=\"currentColor\"/>\n </svg>\n `;\n\n // Hidden file input\n this.fileInput = createElement('input', {\n className: 'cevro-chat-window__file-input',\n }) as HTMLInputElement;\n this.fileInput.type = 'file';\n this.fileInput.accept = generateAcceptAttribute();\n this.fileInput.addEventListener('change', () => {\n if (this.fileInput?.files?.length && this.callbacks.onFileUpload) {\n this.callbacks.onFileUpload(this.fileInput.files[0]);\n this.fileInput.value = '';\n }\n });\n\n this.fileButton.addEventListener('click', () => {\n this.fileInput?.click();\n });\n\n inputArea.appendChild(this.fileButton);\n inputArea.appendChild(this.fileInput);\n\n // Text input (max 2000 characters)\n this.inputElement = createElement('textarea', {\n className: 'cevro-chat-window__input',\n 'data-testid': 'chat-input',\n }) as HTMLTextAreaElement;\n this.inputElement.placeholder = this.strings.inputPlaceholder;\n this.inputElement.rows = 1;\n this.inputElement.setAttribute('maxlength', '2000');\n\n // Auto-resize textarea\n this.inputElement.addEventListener('input', () => {\n this.resizeInput();\n this.updateSendButtonState();\n });\n\n // Handle enter key\n this.inputElement.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n this.handleSend();\n }\n });\n\n inputArea.appendChild(this.inputElement);\n\n // Send button - arrow icon\n this.sendButton = createElement('button', {\n className: 'cevro-chat-window__send-button',\n 'aria-label': 'Send message',\n 'data-testid': 'send-button',\n }) as HTMLButtonElement;\n this.sendButton.disabled = true;\n this.sendButton.innerHTML = `\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 19V5M5 12L12 5L19 12\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n `;\n\n this.sendButton.addEventListener('click', () => {\n this.handleSend();\n });\n\n inputArea.appendChild(this.sendButton);\n wrapper.appendChild(inputArea);\n\n // Powered by footer\n const footer = createElement('div', {\n className: 'cevro-chat-window__footer',\n });\n footer.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n wrapper.appendChild(footer);\n\n return wrapper;\n }\n\n /**\n * Handle send message\n */\n private handleSend(): void {\n if (!this.inputElement) return;\n\n const message = this.inputElement.value.trim();\n if (!message) return;\n\n this.callbacks.onSendMessage(message);\n this.inputElement.value = '';\n this.resizeInput();\n this.updateSendButtonState();\n this.inputElement.focus({ preventScroll: true });\n }\n\n /**\n * Update send button state\n */\n private updateSendButtonState(): void {\n if (this.sendButton && this.inputElement) {\n this.sendButton.disabled = !this.inputElement.value.trim();\n }\n }\n\n /**\n * Resize textarea to fit its content, capped at 100px\n */\n private resizeInput(): void {\n if (!this.inputElement) return;\n this.inputElement.style.height = 'auto';\n this.inputElement.style.height = Math.min(this.inputElement.scrollHeight, 100) + 'px';\n }\n\n /**\n * Set draft message in the textarea without sending\n */\n setDraft(message: string): void {\n if (!this.inputElement) return;\n const maxLength = Number(this.inputElement.getAttribute('maxlength')) || 2000;\n this.inputElement.value = message.slice(0, maxLength);\n this.resizeInput();\n this.updateSendButtonState();\n this.inputElement.focus({ preventScroll: true });\n }\n\n /**\n * Set callback for when user scrolls to the top (for loading older messages)\n */\n setScrollTopHandler(handler: (() => boolean | void | Promise<boolean | void>) | null): void {\n this.messageList.setScrollTopHandler(handler);\n }\n\n /**\n * Prepend a message at the top (for loading older messages)\n */\n prependMessage(message: Message): void {\n this.messageList.prependMessage(message);\n }\n\n /**\n * Prepend multiple messages at the top (for loading older messages)\n */\n prependMessages(messages: Message[]): void {\n this.messageList.prependMessages(messages);\n }\n\n /**\n * Signal that top-loading is complete\n */\n finishLoadingTop(): void {\n this.messageList.finishLoadingTop();\n }\n\n /**\n * Add message to the chat\n */\n addMessage(message: Message, animate = true): void {\n this.messageList.addMessage(message, animate);\n }\n\n /**\n * Update message\n */\n updateMessage(message: Message, oldId?: string): void {\n this.messageList.updateMessage(message, oldId);\n }\n\n /**\n * Update upload progress for a message\n */\n updateMessageProgress(messageId: string, progress: number): void {\n this.messageList.updateMessageProgress(messageId, progress);\n }\n\n /**\n * Remove a message from the chat\n */\n removeMessage(messageId: string): void {\n this.messageList.removeMessage(messageId);\n }\n\n /**\n * Show typing indicator\n */\n showTypingIndicator(): void {\n this.messageList.showTypingIndicator();\n }\n\n /**\n * Hide typing indicator\n */\n hideTypingIndicator(): void {\n this.messageList.hideTypingIndicator();\n }\n\n /**\n * Clear messages\n */\n clearMessages(): void {\n this.messageList.clear();\n }\n\n /**\n * Show the chat window\n */\n show(): void {\n if (this.element) {\n this.element.classList.add('cevro-chat-window--visible');\n this.isVisible = true;\n this.inputElement?.focus({ preventScroll: true });\n this.messageList.scrollToBottom();\n }\n }\n\n /**\n * Hide the chat window\n */\n hide(): void {\n if (this.element) {\n this.element.classList.remove('cevro-chat-window--visible');\n this.isVisible = false;\n }\n }\n\n /**\n * Check if visible\n */\n isWindowVisible(): boolean {\n return this.isVisible;\n }\n\n /**\n * Focus input\n */\n focusInput(): void {\n this.inputElement?.focus({ preventScroll: true });\n }\n\n /**\n * Set ticket closed state\n * Shows CSAT form inline (replacing input area), preserving message history\n *\n * @param closed - Whether the ticket is closed\n * @param onStartNewChat - Callback when user clicks \"New Conversation\"\n * @param options - Additional options\n * @param options.showHistory - Show message history (always true now for better UX)\n * @param options.skipCSAT - Skip CSAT and show new chat directly\n * @param options.ticketId - Ticket ID for CSAT localStorage tracking\n */\n setTicketClosed(\n closed: boolean,\n onStartNewChat?: () => void,\n options?: { showHistory?: boolean; skipCSAT?: boolean; ticketId?: string }\n ): void {\n const skipCSAT = options?.skipCSAT ?? false;\n const ticketId = options?.ticketId;\n\n if (closed) {\n // Clean up any existing closed UI first\n this.removeClosedUI();\n\n // IMPORTANT: Keep message history visible so users can see what they missed\n // Show \"Chat closed\" message in the message list\n this.messageList.showClosedMessage(this.strings.closedMessage);\n\n // Hide input area (will be replaced by CSAT or new chat button)\n if (this.inputWrapper) {\n this.inputWrapper.style.display = 'none';\n }\n\n // Check if CSAT already submitted for this ticket\n const csatSubmitted = ticketId && localStorage.getItem(`cevro_csat_${ticketId}`);\n\n if (skipCSAT || csatSubmitted) {\n this.showClosedFooter(onStartNewChat);\n } else {\n this.showInlineCSATForm(onStartNewChat, ticketId);\n }\n } else {\n this.removeClosedUI();\n\n // Show input area — unless pre-chat form is currently displayed\n // (during startNewChat from history, input must stay hidden behind pre-chat)\n if (this.inputWrapper && !this.preChatContainer) {\n this.inputWrapper.style.display = '';\n }\n\n // Hide closed message\n this.messageList.hideClosedMessage();\n }\n }\n\n private showInlineCSATForm(onStartNewChat?: () => void, ticketId?: string): void {\n this.removeClosedUI();\n this.csatRating = 0;\n this.csatFeedback = '';\n\n if (!this.element) return;\n\n this.csatContainer = createElement('div', {\n className: 'cevro-csat-inline',\n });\n\n const headerRow = createElement('div', {\n className: 'cevro-csat-inline__header',\n });\n\n const title = createElement('span', {\n className: 'cevro-csat-inline__title',\n }, [this.strings.csatTitle]);\n\n const skipButton = createElement('button', {\n className: 'cevro-csat-inline__skip',\n 'aria-label': 'Skip feedback',\n }, ['Skip']);\n skipButton.addEventListener('click', () => {\n // Save skip to localStorage so it persists across page reloads\n if (ticketId) {\n localStorage.setItem(`cevro_csat_${ticketId}`, 'skipped');\n }\n this.showClosedFooter(onStartNewChat);\n });\n\n headerRow.appendChild(title);\n headerRow.appendChild(skipButton);\n\n const starsRow = createElement('div', {\n className: 'cevro-csat-inline__stars',\n });\n\n for (let i = 1; i <= 5; i++) {\n const star = createElement('button', {\n className: 'cevro-csat-inline__star',\n 'data-rating': String(i),\n 'aria-label': `Rate ${i} stars`,\n });\n star.innerHTML = this.createStarSvg(false);\n star.addEventListener('click', () => this.selectInlineRating(i, starsRow));\n star.addEventListener('mouseenter', () => this.previewRating(i, starsRow));\n star.addEventListener('mouseleave', () => this.previewRating(this.csatRating, starsRow));\n starsRow.appendChild(star);\n }\n\n // Feedback textarea - shown immediately\n const feedbackInput = createElement('textarea', {\n className: 'cevro-csat-inline__feedback',\n placeholder: this.strings.csatPlaceholder,\n }) as HTMLTextAreaElement;\n feedbackInput.rows = 2;\n feedbackInput.addEventListener('input', () => {\n this.csatFeedback = feedbackInput.value;\n });\n\n // Submit button\n const submitButton = createElement('button', {\n className: 'cevro-csat-inline__submit',\n }, [this.strings.csatSubmit || 'Submit']);\n submitButton.addEventListener('click', () => this.submitInlineCSAT(onStartNewChat, ticketId));\n\n const poweredBy = createElement('div', {\n className: 'cevro-csat-inline__powered-by',\n });\n poweredBy.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n this.csatContainer.appendChild(headerRow);\n this.csatContainer.appendChild(starsRow);\n this.csatContainer.appendChild(feedbackInput);\n this.csatContainer.appendChild(submitButton);\n this.csatContainer.appendChild(poweredBy);\n\n this.element.appendChild(this.csatContainer);\n }\n\n private selectInlineRating(rating: number, container: HTMLElement): void {\n if (this.csatSubmitting) return;\n this.csatRating = rating;\n this.updateStars(rating, container);\n\n const feedbackInput = container.parentElement?.querySelector('.cevro-csat-inline__feedback') as HTMLTextAreaElement;\n if (feedbackInput) {\n if (rating <= 2) {\n feedbackInput.placeholder = this.strings.csatPlaceholderNegative || this.strings.csatPlaceholder;\n } else if (rating === 3) {\n feedbackInput.placeholder = this.strings.csatPlaceholderNeutral || this.strings.csatPlaceholder;\n } else {\n feedbackInput.placeholder = this.strings.csatPlaceholder;\n }\n }\n }\n\n private async submitInlineCSAT(onStartNewChat?: () => void, ticketId?: string): Promise<void> {\n if (this.csatSubmitting || this.csatRating === 0) return;\n\n this.csatSubmitting = true;\n\n const submitButton = this.csatContainer?.querySelector('.cevro-csat-inline__submit') as HTMLButtonElement;\n if (submitButton) {\n submitButton.disabled = true;\n submitButton.textContent = 'Submitting...';\n }\n\n try {\n if (this.callbacks.onCSATSubmit) {\n await this.callbacks.onCSATSubmit(this.csatRating, this.csatFeedback || undefined);\n }\n\n if (ticketId) {\n localStorage.setItem(`cevro_csat_${ticketId}`, '1');\n }\n\n this.showInlineThankYou(onStartNewChat);\n } catch {\n if (submitButton) {\n submitButton.disabled = false;\n submitButton.textContent = this.strings.csatSubmit || 'Submit';\n }\n } finally {\n this.csatSubmitting = false;\n }\n }\n\n /**\n * Show inline thank you message\n */\n private showInlineThankYou(onStartNewChat?: () => void): void {\n this.removeClosedUI();\n\n if (!this.element) return;\n\n this.csatContainer = createElement('div', {\n className: 'cevro-csat-inline cevro-csat-inline--thank-you',\n });\n\n // Thank you row\n const thankYouRow = createElement('div', {\n className: 'cevro-csat-inline__thank-you-row',\n });\n\n const checkIcon = createElement('span', {\n className: 'cevro-csat-inline__check',\n });\n checkIcon.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#10B981\"/>\n <path d=\"M7 12L10 15L17 8\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n `;\n\n const message = createElement('span', {\n className: 'cevro-csat-inline__message',\n }, [this.strings.csatThankYou]);\n\n thankYouRow.appendChild(checkIcon);\n thankYouRow.appendChild(message);\n\n // New conversation button\n const newChatButton = createElement('button', {\n className: 'cevro-csat-inline__new-chat',\n }, [this.strings.newConversation]);\n\n newChatButton.addEventListener('click', () => {\n if (onStartNewChat) {\n onStartNewChat();\n }\n });\n\n // Powered by footer\n const poweredBy = createElement('div', {\n className: 'cevro-csat-inline__powered-by',\n });\n poweredBy.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n this.csatContainer.appendChild(thankYouRow);\n this.csatContainer.appendChild(newChatButton);\n this.csatContainer.appendChild(poweredBy);\n\n this.element.appendChild(this.csatContainer);\n }\n\n /**\n * Show closed footer with new conversation button (after CSAT skip or when CSAT already submitted)\n */\n private showClosedFooter(onStartNewChat?: () => void): void {\n this.removeClosedUI();\n\n if (this.element) {\n this.closedFooter = createElement('div', {\n className: 'cevro-chat-window__closed-footer',\n });\n\n const newChatButton = createElement('button', {\n className: 'cevro-chat-window__new-chat-button',\n }, [this.strings.newConversation]);\n\n newChatButton.addEventListener('click', () => {\n if (onStartNewChat) {\n onStartNewChat();\n }\n });\n\n const poweredBy = createElement('div', {\n className: 'cevro-chat-window__powered-by',\n });\n poweredBy.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n this.closedFooter.appendChild(newChatButton);\n this.closedFooter.appendChild(poweredBy);\n this.element.appendChild(this.closedFooter);\n }\n }\n\n /**\n * Remove all closed-state UI (CSAT form, thank-you, closed footer)\n */\n private removeClosedUI(): void {\n if (this.csatContainer && this.csatContainer.parentNode) {\n this.csatContainer.parentNode.removeChild(this.csatContainer);\n this.csatContainer = null;\n }\n if (this.closedFooter && this.closedFooter.parentNode) {\n this.closedFooter.parentNode.removeChild(this.closedFooter);\n this.closedFooter = null;\n }\n }\n\n /**\n * Preview star rating on hover\n */\n private previewRating(rating: number, container: HTMLElement): void {\n this.updateStars(rating, container);\n }\n\n /**\n * Update stars display (works for both old and inline CSAT)\n */\n private updateStars(rating: number, container: HTMLElement): void {\n // Support both old and new star classes\n const stars = container.querySelectorAll('.cevro-csat__star, .cevro-csat-inline__star');\n stars.forEach((star, index) => {\n const filled = index < rating;\n star.innerHTML = this.createStarSvg(filled);\n star.classList.toggle('cevro-csat__star--filled', filled);\n star.classList.toggle('cevro-csat-inline__star--filled', filled);\n });\n }\n\n /**\n * Create star SVG\n */\n private createStarSvg(filled: boolean): string {\n if (filled) {\n return `\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"#FBBF24\" stroke=\"#FBBF24\" stroke-width=\"1\">\n <polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\"/>\n </svg>\n `;\n }\n return `\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#D1D5DB\" stroke-width=\"1.5\">\n <polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\"/>\n </svg>\n `;\n }\n\n /**\n * Show pre-chat form for visitors\n */\n showPreChatForm(): void {\n if (this.preChatCompleted || this.preChatContainer) return;\n if (!this.element) return;\n\n // Add compact mode class for smaller modal\n this.element.classList.add('cevro-chat-window--prechat');\n\n // Hide messages and input\n const messagesArea = this.element.querySelector('.cevro-messages');\n if (messagesArea) {\n (messagesArea as HTMLElement).style.display = 'none';\n }\n if (this.inputWrapper) {\n this.inputWrapper.style.display = 'none';\n }\n\n // Create pre-chat form\n this.preChatContainer = createElement('div', {\n className: 'cevro-prechat',\n });\n\n // Title\n const title = createElement('h3', {\n className: 'cevro-prechat__title',\n }, [this.strings.preChatTitle]);\n\n // Subtitle\n const subtitle = createElement('p', {\n className: 'cevro-prechat__subtitle',\n }, [this.strings.preChatSubtitle]);\n\n // Form\n const form = createElement('form', {\n className: 'cevro-prechat__form',\n });\n\n // First name field\n const firstNameGroup = createElement('div', {\n className: 'cevro-prechat__field',\n });\n const firstNameLabel = createElement('label', {\n className: 'cevro-prechat__label',\n for: 'cevro-prechat-firstname',\n }, [this.strings.preChatFirstNameLabel]);\n const firstNameInput = createElement('input', {\n className: 'cevro-prechat__input',\n id: 'cevro-prechat-firstname',\n type: 'text',\n 'data-testid': 'prechat-firstname',\n }) as HTMLInputElement;\n firstNameInput.placeholder = this.strings.preChatFirstNamePlaceholder;\n const firstNameError = createElement('span', {\n className: 'cevro-prechat__error',\n 'data-field': 'firstName',\n });\n\n // Highlight invalid fields on blur (no text — avoids extra localization)\n firstNameInput.addEventListener('blur', () => {\n firstNameInput.classList.toggle('cevro-prechat__input--error', !firstNameInput.value.trim());\n });\n\n firstNameGroup.appendChild(firstNameLabel);\n firstNameGroup.appendChild(firstNameInput);\n firstNameGroup.appendChild(firstNameError);\n\n // Email field\n const emailGroup = createElement('div', {\n className: 'cevro-prechat__field',\n });\n const emailLabel = createElement('label', {\n className: 'cevro-prechat__label',\n for: 'cevro-prechat-email',\n }, [this.strings.preChatEmailLabel]);\n const emailInput = createElement('input', {\n className: 'cevro-prechat__input',\n id: 'cevro-prechat-email',\n type: 'text',\n autocomplete: 'email',\n 'data-testid': 'prechat-email',\n }) as HTMLInputElement;\n emailInput.placeholder = this.strings.preChatEmailPlaceholder;\n const emailError = createElement('span', {\n className: 'cevro-prechat__error',\n 'data-field': 'email',\n });\n\n // Highlight invalid fields on blur (no text — avoids extra localization)\n emailInput.addEventListener('blur', () => {\n const email = emailInput.value.trim();\n emailInput.classList.toggle('cevro-prechat__input--error', !email || !this.isValidEmail(email));\n });\n\n emailGroup.appendChild(emailLabel);\n emailGroup.appendChild(emailInput);\n emailGroup.appendChild(emailError);\n\n // Submit button\n const submitButton = createElement('button', {\n className: 'cevro-prechat__submit',\n type: 'submit',\n 'data-testid': 'prechat-submit',\n }, [this.strings.preChatSubmit]) as HTMLButtonElement;\n\n // Form validation and submit\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n\n // Clear previous errors\n firstNameError.textContent = '';\n emailError.textContent = '';\n firstNameInput.classList.remove('cevro-prechat__input--error');\n emailInput.classList.remove('cevro-prechat__input--error');\n\n const firstName = firstNameInput.value.trim();\n const email = emailInput.value.trim();\n\n let hasError = false;\n\n if (!firstName) {\n firstNameError.textContent = this.strings.preChatFirstNameRequired;\n firstNameInput.classList.add('cevro-prechat__input--error');\n hasError = true;\n }\n\n if (!email) {\n emailError.textContent = this.strings.preChatEmailRequired;\n emailInput.classList.add('cevro-prechat__input--error');\n hasError = true;\n } else if (!this.isValidEmail(email)) {\n emailError.textContent = this.strings.preChatEmailInvalid;\n emailInput.classList.add('cevro-prechat__input--error');\n hasError = true;\n }\n\n if (hasError) return;\n\n // Submit successful\n this.preChatCompleted = true;\n\n if (this.callbacks.onPreChatSubmit) {\n this.callbacks.onPreChatSubmit({ firstName, email });\n }\n });\n\n form.appendChild(firstNameGroup);\n form.appendChild(emailGroup);\n form.appendChild(submitButton);\n\n // Powered by footer\n const poweredBy = createElement('div', {\n className: 'cevro-prechat__powered-by',\n });\n poweredBy.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n this.preChatContainer.appendChild(title);\n this.preChatContainer.appendChild(subtitle);\n this.preChatContainer.appendChild(form);\n this.preChatContainer.appendChild(poweredBy);\n\n this.element.appendChild(this.preChatContainer);\n\n // Focus on name input\n firstNameInput.focus({ preventScroll: true });\n }\n\n /**\n * Hide pre-chat form and show chat\n */\n hidePreChatForm(): void {\n if (this.preChatContainer && this.preChatContainer.parentNode) {\n this.preChatContainer.parentNode.removeChild(this.preChatContainer);\n this.preChatContainer = null;\n }\n\n // Remove compact mode class\n this.element?.classList.remove('cevro-chat-window--prechat');\n\n // Show messages and input with fade-in\n if (this.element) {\n const messagesArea = this.element.querySelector('.cevro-messages');\n if (messagesArea) {\n (messagesArea as HTMLElement).style.display = '';\n messagesArea.classList.add('cevro-messages--fade-in');\n }\n }\n if (this.inputWrapper) {\n this.inputWrapper.style.display = '';\n }\n\n // Focus input\n this.inputElement?.focus({ preventScroll: true });\n }\n\n /**\n * Validate email format\n */\n private isValidEmail(email: string): boolean {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n }\n\n updateCustomLogo(logoUrl?: string): void {\n this.customLogoUrl = logoUrl;\n\n if (!this.logoElement) return;\n\n // Clear existing logo content\n this.logoElement.innerHTML = '';\n\n if (logoUrl) {\n const logoImg = document.createElement('img');\n logoImg.src = logoUrl;\n logoImg.alt = 'Logo';\n logoImg.className = 'cevro-chat-window__logo-img';\n logoImg.style.width = '40px';\n logoImg.style.height = '40px';\n logoImg.style.objectFit = 'contain';\n logoImg.style.borderRadius = '8px';\n this.logoElement.appendChild(logoImg);\n } else {\n this.logoElement.innerHTML = this.createCompanyLogoSvg();\n }\n }\n\n /**\n * Get the body of the last message (for conversation list preview)\n */\n getLastMessageBody(): string | undefined {\n return this.messageList.getLastMessageBody();\n }\n\n getLastMessageAt(): string | undefined {\n return this.messageList.getLastMessageAt();\n }\n\n getAgentMessagesSinceLastUserMessage(): number {\n return this.messageList.getAgentMessagesSinceLastUserMessage();\n }\n\n /**\n * Destroy the component\n */\n destroy(): void {\n this.messageList.destroy();\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n this.inputElement = null;\n this.sendButton = null;\n this.fileInput = null;\n this.fileButton = null;\n this.closedFooter = null;\n this.csatContainer = null;\n this.preChatContainer = null;\n this.preChatCompleted = false;\n }\n}\n","import type { ConversationHistoryItem, LocaleStrings } from '../types';\nimport { createElement } from '../utils/dom';\n\nexport interface ActiveConversationInfo {\n ticketId: string;\n lastMessageBody?: string;\n lastMessageAt?: string;\n agentName?: string;\n unreadCount?: number;\n}\n\nexport interface ConversationListCallbacks {\n onClose: () => void;\n onNewConversation: () => void;\n onSelectActive: () => void;\n onSelectPast: (ticketId: string, title: string) => void;\n onLoadConversations: (cursor?: string) => Promise<{\n conversations: ConversationHistoryItem[];\n hasMore: boolean;\n cursor?: string;\n }>;\n}\n\n/**\n * Conversation history list screen\n */\nexport class ConversationList {\n private element: HTMLElement | null = null;\n private listContainer: HTMLElement | null = null;\n private titleElement: HTMLElement | null = null;\n private callbacks: ConversationListCallbacks;\n private strings: LocaleStrings;\n private activeInfo: ActiveConversationInfo | null = null;\n private cursor: string | undefined = undefined;\n private hasMore = false;\n private loadMoreButton: HTMLElement | null = null;\n private isLoadingMore = false;\n\n constructor(callbacks: ConversationListCallbacks, strings: LocaleStrings) {\n this.callbacks = callbacks;\n this.strings = strings;\n }\n\n setStrings(strings: LocaleStrings): void {\n this.strings = strings;\n if (this.titleElement) {\n this.titleElement.textContent = strings.conversationsTitle;\n }\n }\n\n setActiveConversation(info: ActiveConversationInfo | null): void {\n this.activeInfo = info;\n }\n\n render(): HTMLElement {\n if (this.element) return this.element;\n\n this.element = createElement('div', {\n className: 'cevro-conversation-list',\n });\n\n // Header\n const header = createElement('div', {\n className: 'cevro-conversation-list__header',\n });\n\n this.titleElement = createElement('h2', {\n className: 'cevro-conversation-list__title',\n }, [this.strings.conversationsTitle]);\n\n const closeButton = createElement('button', {\n className: 'cevro-conversation-list__close',\n 'aria-label': 'Close',\n });\n closeButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n `;\n closeButton.addEventListener('click', () => this.callbacks.onClose());\n\n header.appendChild(this.titleElement);\n header.appendChild(closeButton);\n this.element.appendChild(header);\n\n // Scrollable list container\n this.listContainer = createElement('div', {\n className: 'cevro-conversation-list__items',\n });\n this.element.appendChild(this.listContainer);\n\n // New Conversation button\n const newConvButton = createElement('button', {\n className: 'cevro-conversation-list__new-conversation',\n }, [this.strings.newConversationButton]);\n newConvButton.addEventListener('click', () => this.callbacks.onNewConversation());\n\n // Footer\n const footer = createElement('div', {\n className: 'cevro-conversation-list__footer',\n });\n footer.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n // Action panel wrapping button + powered-by (per design)\n const actionPanel = createElement('div', { className: 'cevro-action-panel' });\n actionPanel.appendChild(newConvButton);\n actionPanel.appendChild(footer);\n this.element.appendChild(actionPanel);\n\n return this.element;\n }\n\n /**\n * Load and display conversations\n */\n async load(): Promise<void> {\n if (!this.listContainer) return;\n\n // Reset pagination state\n this.cursor = undefined;\n this.hasMore = false;\n this.loadMoreButton = null;\n\n // Show loading\n this.listContainer.innerHTML = '';\n const loading = createElement('div', {\n className: 'cevro-conversation-list__loading',\n }, [this.strings.loadingConversations]);\n this.listContainer.appendChild(loading);\n\n try {\n const result = await this.callbacks.onLoadConversations();\n\n this.listContainer.innerHTML = '';\n this.cursor = result.cursor;\n this.hasMore = result.hasMore;\n\n // Active conversation card (if exists) — shows last message preview\n if (this.activeInfo) {\n const activeCard = this.createActiveCard();\n this.listContainer.appendChild(activeCard);\n }\n\n // Past conversations\n if (result.conversations.length === 0 && !this.activeInfo) {\n this.showEmptyState();\n return;\n }\n\n for (const conv of result.conversations) {\n // Skip if this is the active ticket\n if (conv.ticketId === this.activeInfo?.ticketId) continue;\n const card = this.createConversationCard(conv);\n this.listContainer.appendChild(card);\n }\n\n this.renderLoadMoreButton();\n } catch {\n this.listContainer.innerHTML = '';\n if (this.activeInfo) {\n const activeCard = this.createActiveCard();\n this.listContainer.appendChild(activeCard);\n }\n this.showEmptyState();\n }\n }\n\n private async loadMore(): Promise<void> {\n if (!this.listContainer || !this.hasMore || this.isLoadingMore) return;\n\n this.isLoadingMore = true;\n if (this.loadMoreButton) {\n this.loadMoreButton.textContent = this.strings.loadingConversations;\n (this.loadMoreButton as HTMLButtonElement).disabled = true;\n }\n\n try {\n const result = await this.callbacks.onLoadConversations(this.cursor);\n this.cursor = result.cursor;\n this.hasMore = result.hasMore;\n\n // Remove old load-more button before appending new cards\n this.loadMoreButton?.remove();\n this.loadMoreButton = null;\n\n for (const conv of result.conversations) {\n if (conv.ticketId === this.activeInfo?.ticketId) continue;\n const card = this.createConversationCard(conv);\n this.listContainer!.appendChild(card);\n }\n\n this.renderLoadMoreButton();\n } catch {\n // Restore button on error\n if (this.loadMoreButton) {\n this.loadMoreButton.textContent = this.strings.loadMoreConversations;\n (this.loadMoreButton as HTMLButtonElement).disabled = false;\n }\n } finally {\n this.isLoadingMore = false;\n }\n }\n\n private renderLoadMoreButton(): void {\n if (!this.hasMore || !this.listContainer) return;\n\n this.loadMoreButton = createElement('button', {\n className: 'cevro-conversation-list__load-more',\n }, [this.strings.loadMoreConversations]);\n this.loadMoreButton.addEventListener('click', () => this.loadMore());\n this.listContainer.appendChild(this.loadMoreButton);\n }\n\n private createActiveCard(): HTMLElement {\n const unread = this.activeInfo?.unreadCount ?? 0;\n const card = createElement('div', {\n className: `cevro-conversation-card cevro-conversation-card--active${unread > 0 ? ' cevro-conversation-card--unread' : ''}`,\n });\n\n const content = createElement('div', {\n className: 'cevro-conversation-card__content',\n });\n\n const titleRow = createElement('div', {\n className: 'cevro-conversation-card__title-row',\n });\n\n const agentName = createElement('span', {\n className: 'cevro-conversation-card__title',\n }, [this.activeInfo?.agentName || 'Support']);\n\n const date = createElement('span', {\n className: 'cevro-conversation-card__date',\n }, [this.activeInfo?.lastMessageAt ? this.formatDate(this.activeInfo.lastMessageAt) : '']);\n\n titleRow.appendChild(agentName);\n titleRow.appendChild(date);\n\n const previewRow = createElement('div', {\n className: 'cevro-conversation-card__preview-row',\n });\n\n const preview = createElement('div', {\n className: 'cevro-conversation-card__preview',\n }, [this.activeInfo?.lastMessageBody || this.strings.inputPlaceholder]);\n previewRow.appendChild(preview);\n\n if (unread > 0) {\n const unreadBadge = createElement('span', {\n className: 'cevro-conversation-card__unread',\n }, [unread > 99 ? '99+' : String(unread)]);\n previewRow.appendChild(unreadBadge);\n }\n\n content.appendChild(titleRow);\n content.appendChild(previewRow);\n card.appendChild(content);\n\n card.addEventListener('click', () => this.callbacks.onSelectActive());\n return card;\n }\n\n private createConversationCard(conv: ConversationHistoryItem): HTMLElement {\n const card = createElement('div', {\n className: 'cevro-conversation-card',\n });\n\n const content = createElement('div', {\n className: 'cevro-conversation-card__content',\n });\n\n const titleRow = createElement('div', {\n className: 'cevro-conversation-card__title-row',\n });\n\n const titleText = createElement('span', {\n className: 'cevro-conversation-card__title',\n }, [conv.title || this.strings.defaultConversationTitle]);\n\n const date = createElement('span', {\n className: 'cevro-conversation-card__date',\n }, [this.formatDate(conv.lastMessageAt || conv.createdAt)]);\n\n titleRow.appendChild(titleText);\n titleRow.appendChild(date);\n\n const preview = createElement('div', {\n className: 'cevro-conversation-card__preview',\n }, [conv.lastMessageBody || `${conv.messageCount} ${this.strings.messagesCount}`]);\n\n content.appendChild(titleRow);\n content.appendChild(preview);\n card.appendChild(content);\n\n card.addEventListener('click', () => {\n this.callbacks.onSelectPast(conv.ticketId, conv.title);\n });\n\n return card;\n }\n\n private showEmptyState(): void {\n if (!this.listContainer) return;\n\n const empty = createElement('div', {\n className: 'cevro-conversation-list__empty',\n });\n\n const emptyTitle = createElement('p', {\n className: 'cevro-conversation-list__empty-title',\n }, [this.strings.noConversations]);\n\n const emptySubtitle = createElement('p', {\n className: 'cevro-conversation-list__empty-subtitle',\n }, [this.strings.noConversationsSubtitle]);\n\n empty.appendChild(emptyTitle);\n empty.appendChild(emptySubtitle);\n this.listContainer.appendChild(empty);\n }\n\n private formatDate(dateStr: string): string {\n try {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) {\n return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n } else if (diffDays === 1) {\n return this.strings.yesterday;\n } else if (diffDays < 7) {\n return date.toLocaleDateString([], { weekday: 'short' });\n } else {\n return date.toLocaleDateString([], { month: 'short', day: 'numeric' });\n }\n } catch {\n return '';\n }\n }\n\n show(): void {\n if (this.element) {\n this.element.style.display = 'flex';\n }\n }\n\n hide(): void {\n if (this.element) {\n this.element.style.display = 'none';\n }\n }\n\n destroy(): void {\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n this.listContainer = null;\n }\n}\n","import type { Message, LocaleStrings } from '../types';\nimport { createElement } from '../utils/dom';\nimport { MessageList } from './MessageList';\n\nexport interface PastConversationCallbacks {\n onBack: () => void;\n onClose: () => void;\n onNewConversation: () => void;\n onLoadMessages: (ticketId: string, cursor?: string) => Promise<{\n messages: Message[];\n hasMore: boolean;\n cursor?: string;\n }>;\n}\n\n/**\n * Read-only view of a past conversation\n */\nexport class PastConversation {\n private element: HTMLElement | null = null;\n private avatarElement: HTMLElement | null = null;\n private titleElement: HTMLElement | null = null;\n private avatarUrl: string | undefined;\n private messageList: MessageList;\n private callbacks: PastConversationCallbacks;\n private strings: LocaleStrings;\n private currentTicketId: string | null = null;\n private cursor: string | undefined;\n private hasMore = false;\n private isLoadingMore = false;\n\n constructor(callbacks: PastConversationCallbacks, strings: LocaleStrings) {\n this.callbacks = callbacks;\n this.strings = strings;\n this.messageList = new MessageList();\n }\n\n setStrings(strings: LocaleStrings): void {\n this.strings = strings;\n }\n\n setAvatarUrl(url: string | undefined): void {\n this.avatarUrl = url;\n this.renderAvatar();\n }\n\n private renderAvatar(): void {\n if (!this.avatarElement) return;\n if (this.avatarUrl) {\n this.avatarElement.innerHTML = `<img src=\"${this.avatarUrl}\" alt=\"Agent\" class=\"cevro-past-conversation__avatar-img\" />`;\n this.avatarElement.style.display = '';\n } else {\n this.avatarElement.innerHTML = '';\n this.avatarElement.style.display = 'none';\n }\n }\n\n render(): HTMLElement {\n if (this.element) return this.element;\n\n this.element = createElement('div', {\n className: 'cevro-past-conversation',\n });\n\n // Header (will be populated on load)\n const header = createElement('div', {\n className: 'cevro-past-conversation__header',\n });\n\n const backButton = createElement('button', {\n className: 'cevro-past-conversation__back',\n 'aria-label': 'Back',\n });\n backButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"15 18 9 12 15 6\"/>\n </svg>\n `;\n backButton.addEventListener('click', () => this.callbacks.onBack());\n\n // Agent avatar\n this.avatarElement = createElement('div', {\n className: 'cevro-past-conversation__avatar',\n });\n this.renderAvatar();\n\n // Title\n this.titleElement = createElement('h2', {\n className: 'cevro-past-conversation__title',\n });\n\n const closeButton = createElement('button', {\n className: 'cevro-past-conversation__close',\n 'aria-label': 'Close',\n });\n closeButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n `;\n closeButton.addEventListener('click', () => this.callbacks.onClose());\n\n header.appendChild(backButton);\n header.appendChild(this.avatarElement);\n header.appendChild(this.titleElement);\n header.appendChild(closeButton);\n this.element.appendChild(header);\n\n // Messages area (read-only)\n const messagesArea = this.messageList.render();\n this.messageList.setScrollTopHandler(() => this.loadMoreMessages());\n this.element.appendChild(messagesArea);\n\n // New Conversation button\n const newConvButton = createElement('button', {\n className: 'cevro-past-conversation__new-conversation',\n }, [this.strings.newConversationButton]);\n newConvButton.addEventListener('click', () => this.callbacks.onNewConversation());\n\n // Footer (Powered by)\n const footer = createElement('div', {\n className: 'cevro-past-conversation__footer',\n });\n footer.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n // Action panel wrapping button + powered-by (per design)\n const actionPanel = createElement('div', { className: 'cevro-action-panel' });\n actionPanel.appendChild(newConvButton);\n actionPanel.appendChild(footer);\n this.element.appendChild(actionPanel);\n\n return this.element;\n }\n\n /**\n * Load a past conversation\n */\n async loadConversation(ticketId: string, title: string): Promise<void> {\n if (this.titleElement) {\n this.titleElement.textContent = title;\n }\n // Reset pagination state\n this.currentTicketId = ticketId;\n this.cursor = undefined;\n this.hasMore = false;\n this.messageList.clear();\n\n try {\n // Load latest page (no cursor = most recent messages)\n const result = await this.callbacks.onLoadMessages(ticketId);\n\n // Guard: user may have switched to another conversation while we were loading\n if (this.currentTicketId !== ticketId) return;\n\n this.cursor = result.cursor;\n this.hasMore = result.hasMore;\n\n // Bulk load: no animation, no scroll per message\n for (const msg of result.messages) {\n this.messageList.addMessage(msg, false, true);\n }\n // Scroll to bottom — show latest messages\n this.messageList.scrollToBottom();\n } catch (error) {\n console.error('[Cevro] Failed to load conversation messages:', error);\n }\n }\n\n private async loadMoreMessages(): Promise<boolean> {\n if (!this.currentTicketId || !this.hasMore || this.isLoadingMore) return false;\n\n const requestedTicketId = this.currentTicketId;\n this.isLoadingMore = true;\n try {\n const result = await this.callbacks.onLoadMessages(\n requestedTicketId,\n this.cursor,\n );\n\n // Guard: user may have switched conversations while loading\n if (this.currentTicketId !== requestedTicketId) return false;\n\n this.cursor = result.cursor;\n this.hasMore = result.hasMore;\n\n // Prepend older messages at the top\n this.messageList.prependMessages(result.messages);\n return true;\n } catch (error) {\n console.error('[Cevro] Failed to load more messages:', error);\n return false;\n } finally {\n this.isLoadingMore = false;\n this.messageList.finishLoadingTop();\n }\n }\n\n show(): void {\n if (this.element) {\n this.element.style.display = 'flex';\n }\n }\n\n hide(): void {\n if (this.element) {\n this.element.style.display = 'none';\n }\n }\n\n destroy(): void {\n this.messageList.destroy();\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n this.avatarElement = null;\n this.titleElement = null;\n }\n}\n","import type {\n CevroMessengerConfig,\n PlayerData,\n Message,\n QuickAction,\n ThemeConfig,\n WidgetAppearanceConfig,\n} from '../types';\nimport { EventEmitter } from './EventEmitter';\nimport { ApiClient } from './ApiClient';\nimport { WebSocketClient } from './WebSocketClient';\nimport { Launcher } from '../ui/Launcher';\nimport { ChatWindow } from '../ui/ChatWindow';\nimport { ConversationList } from '../ui/ConversationList';\nimport { PastConversation } from '../ui/PastConversation';\nimport {\n generateVisitorId,\n getStoredSession,\n storeSession,\n clearStoredSession,\n clearStoredVisitorToken,\n getStoredVisitorToken,\n storeVisitorToken,\n recoverVisitorToken,\n detectAndRecordPlayerSwitch,\n clearActivePlayer,\n} from '../utils/session';\nimport { isValidUrl } from '../utils/dom';\nimport { getStrings } from '../i18n/strings';\nimport styles from '../styles/index.css?inline';\n\n/**\n * Main Cevro Messenger SDK class\n */\nexport class CevroMessenger {\n private static instance: CevroMessenger | null = null;\n\n private config: CevroMessengerConfig;\n private events: EventEmitter;\n private api: ApiClient;\n private ws: WebSocketClient;\n private launcher: Launcher | null = null;\n private chatWindow: ChatWindow | null = null;\n private conversationList: ConversationList | null = null;\n private pastConversation: PastConversation | null = null;\n private currentScreen: 'chat' | 'history' | 'past-conversation' = 'chat';\n private container: HTMLElement | null = null;\n private shadowRoot: ShadowRoot | null = null;\n private isBooted = false;\n private isVisible = false;\n private unreadCount = 0;\n private visitorId: string | null;\n\n private isSessionInitialized = false;\n private isInitializingSession: Promise<void> | null = null;\n private connectingPromise: Promise<void> | null = null;\n private typingCycleTimeout: ReturnType<typeof setTimeout> | null = null;\n private isTypingVisible = false;\n private typingConfig = { onDurationMs: 7000, offDurationMs: 4000 };\n private escapeHandler: ((e: KeyboardEvent) => void) | null = null;\n private visitorContactInfo: { firstName: string; email: string } | null = null;\n private widgetAppearance: WidgetAppearanceConfig = {};\n private customLauncherHandler: (() => void) | null = null;\n private customLauncherElement: Element | null = null;\n private isDestroyed = false;\n\n constructor(config: CevroMessengerConfig) {\n this.config = this.normalizeConfig(config);\n this.events = new EventEmitter();\n this.api = new ApiClient(this.config);\n this.ws = new WebSocketClient(this.config, this.events);\n this.visitorId = generateVisitorId();\n\n // Setup token refresh callback for WebSocket\n this.ws.setTokenRefreshCallback(async () => {\n return this.refreshConnectionToken();\n });\n\n // Setup internal event handlers\n this.setupEventHandlers();\n\n // Singleton pattern\n CevroMessenger.instance = this;\n }\n\n /**\n * Get singleton instance\n */\n static getInstance(): CevroMessenger | null {\n return CevroMessenger.instance;\n }\n\n /**\n * Normalize and validate config\n */\n private normalizeConfig(config: CevroMessengerConfig): CevroMessengerConfig {\n return {\n ...config,\n apiBase: config.apiBase.replace(/\\/$/, ''), // Remove trailing slash\n alignment: config.alignment || 'right',\n verticalPadding: config.verticalPadding ?? 20,\n horizontalPadding: config.horizontalPadding ?? 20,\n zIndex: config.zIndex ?? 2147483647,\n };\n }\n\n /**\n * Setup internal event handlers\n */\n private setupEventHandlers(): void {\n // Handle incoming messages\n this.events.on('message:received', (data: { ticketId: string; message: Message }) => {\n // Stop typing cycle and hide indicator when message arrives\n this.stopTypingCycle();\n\n if (this.chatWindow) {\n this.chatWindow.addMessage(data.message);\n }\n\n // Update unread count if window is not visible\n if (!this.isVisible) {\n this.setUnreadCount(this.unreadCount + 1);\n }\n });\n\n // Handle typing indicators from backend\n this.events.on('typing:start', (data: { ticketId: string; actor: string }) => {\n if (data.ticketId === this.api.getCurrentTicketId()) {\n this.startTypingCycle();\n }\n });\n\n this.events.on('typing:stop', () => {\n this.stopTypingCycle();\n });\n\n // Handle conversation/ticket status updates (real-time close from admin)\n this.events.on('conversation:updated', (data: { ticketId: string; status: string; message?: string; agentName?: string }) => {\n // Ignore events for tickets that aren't the current one\n if (data.ticketId !== this.api.getCurrentTicketId()) return;\n\n if (data.status === 'escalated') {\n // Show system message that a human agent joined\n const agentName = data.agentName || 'Support';\n const escalationMsg = data.message || `${agentName} has joined the conversation.`;\n this.chatWindow?.addMessage({\n id: `escalation-${Date.now()}`,\n body: escalationMsg,\n inbound: false,\n outbound: true,\n createdAt: new Date().toISOString(),\n type: 'text',\n senderType: 'human',\n agentName,\n });\n }\n\n if (data.status === 'closed') {\n const skipCSAT = this.widgetAppearance.csatEnabled !== true;\n this.chatWindow?.setTicketClosed(true, () => this.startNewChat(), {\n ticketId: data.ticketId,\n skipCSAT,\n });\n }\n });\n }\n\n /**\n * Boot the messenger\n */\n async boot(): Promise<void> {\n if (this.isBooted) {\n return;\n }\n\n this.isDestroyed = false;\n\n // Recover visitor identity from cookie/IndexedDB if localStorage was cleared\n if (!this.config.preview) {\n const recovered = await recoverVisitorToken();\n if (recovered) {\n this.api.setVisitorToken(recovered);\n }\n }\n\n // Fetch widget config from backend (non-blocking for UI)\n if (!this.config.preview) {\n try {\n this.widgetAppearance = await this.api.getWidgetConfig();\n } catch {\n this.widgetAppearance = {};\n }\n }\n\n // Guard again after async — another boot() or shutdown() may have run\n if (this.isBooted || this.isDestroyed) {\n return;\n }\n\n // Create container with Shadow DOM for style isolation\n const host = document.createElement('div');\n host.id = 'cevro-messenger-host';\n document.body.appendChild(host);\n\n // Create Shadow DOM\n this.shadowRoot = host.attachShadow({ mode: 'open' });\n\n // Inject styles into Shadow DOM\n const styleEl = document.createElement('style');\n styleEl.textContent = styles;\n this.shadowRoot.appendChild(styleEl);\n\n // Create inner container for CSS variables\n this.container = document.createElement('div');\n this.container.id = 'cevro-messenger-container';\n this.shadowRoot.appendChild(this.container);\n\n this.applyPrimaryColor();\n\n // Create launcher (skip if hideDefaultLauncher is set)\n if (!this.config.hideDefaultLauncher) {\n this.createAndMountLauncher();\n }\n\n // Create chat window with merged locale strings\n const strings = getStrings(this.config.locale);\n this.chatWindow = new ChatWindow(\n this.config,\n {\n onClose: () => this.hide(),\n onSendMessage: (message) => this.sendMessage(message),\n onQuickAction: (action) => this.handleQuickAction(action),\n onFileUpload: (file) => this.handleFileUpload(file),\n onCSATSubmit: async (rating, feedback) => this.submitCSAT(rating, feedback),\n onStartNewChat: () => this.startNewChat(),\n onPreChatSubmit: (data) => this.handlePreChatSubmit(data),\n onShowHistory: () => this.navigateTo('history'),\n },\n strings,\n this.widgetAppearance.customLogoUrl\n );\n this.container.appendChild(this.chatWindow.render());\n\n // Create conversation history screens\n this.createConversationList(strings);\n this.createPastConversation(strings);\n\n // Check for existing session (will be properly restored on show())\n const storedSession = getStoredSession();\n if (storedSession?.ticketId) {\n this.api.setCurrentTicketId(storedSession.ticketId);\n }\n\n // Bind custom launcher element if selector provided\n if (this.config.customLauncherSelector) {\n this.bindCustomLauncher(this.config.customLauncherSelector);\n }\n\n this.isBooted = true;\n this.events.emit('boot');\n\n if (this.widgetAppearance.autoOpen) {\n setTimeout(() => this.show(), 100);\n }\n }\n\n private applyPrimaryColor(): void {\n const color = this.widgetAppearance.primaryColor || this.config.primaryColor;\n if (color && this.container) {\n // Set CSS custom property on container\n this.container.style.setProperty('--cevro-primary', color);\n\n // Generate hover (darker) and light variants\n const hoverColor = this.adjustColorBrightness(color, -20);\n const lightColor = this.adjustColorBrightness(color, 40);\n\n this.container.style.setProperty('--cevro-primary-hover', hoverColor);\n this.container.style.setProperty('--cevro-primary-light', lightColor);\n }\n\n // Apply theme (from config or backend)\n this.applyTheme();\n }\n\n /**\n * Apply theme configuration\n * Backend theme is applied first, then local config overrides\n */\n private applyTheme(): void {\n if (!this.container) return;\n\n const backendTheme = this.widgetAppearance.theme;\n const localTheme = this.config.theme;\n\n if (!backendTheme && !localTheme) return;\n\n const mergedTheme: ThemeConfig = {\n ...backendTheme,\n ...localTheme,\n };\n\n this.applyCustomTheme(mergedTheme);\n }\n\n /**\n * Apply custom theme configuration\n */\n private applyCustomTheme(theme: ThemeConfig): void {\n if (!this.container) return;\n\n // Remove all theme CSS vars first so unset properties fall back to CSS defaults\n const themeVars = [\n '--cevro-bg', '--cevro-bg-secondary', '--cevro-text', '--cevro-text-secondary',\n '--cevro-border', '--cevro-user-msg-bg', '--cevro-user-msg-text',\n '--cevro-header-bg', '--cevro-header-text', '--cevro-bg-input',\n '--cevro-radius', '--cevro-radius-sm', '--cevro-shadow', '--cevro-shadow-sm',\n '--cevro-launcher-bg', '--cevro-launcher-icon', '--cevro-launcher-hover-shadow',\n '--cevro-send-btn-bg', '--cevro-send-btn-icon',\n '--cevro-file-btn-bg', '--cevro-file-btn-icon',\n '--cevro-agent-msg-bg', '--cevro-agent-msg-text',\n ];\n for (const v of themeVars) {\n this.container.style.removeProperty(v);\n }\n\n if (theme.backgroundColor) {\n this.container.style.setProperty('--cevro-bg', theme.backgroundColor);\n }\n if (theme.backgroundSecondaryColor) {\n this.container.style.setProperty('--cevro-bg-secondary', theme.backgroundSecondaryColor);\n }\n if (theme.textColor) {\n this.container.style.setProperty('--cevro-text', theme.textColor);\n }\n if (theme.textSecondaryColor) {\n this.container.style.setProperty('--cevro-text-secondary', theme.textSecondaryColor);\n }\n if (theme.borderColor) {\n this.container.style.setProperty('--cevro-border', theme.borderColor);\n }\n if (theme.userMessageBackgroundColor) {\n this.container.style.setProperty('--cevro-user-msg-bg', theme.userMessageBackgroundColor);\n }\n if (theme.userMessageTextColor) {\n this.container.style.setProperty('--cevro-user-msg-text', theme.userMessageTextColor);\n }\n if (theme.headerBackgroundColor) {\n this.container.style.setProperty('--cevro-header-bg', theme.headerBackgroundColor);\n }\n if (theme.headerTextColor) {\n this.container.style.setProperty('--cevro-header-text', theme.headerTextColor);\n }\n if (theme.inputBackgroundColor) {\n this.container.style.setProperty('--cevro-bg-input', theme.inputBackgroundColor);\n }\n if (theme.borderRadius !== undefined) {\n this.container.style.setProperty('--cevro-radius', `${theme.borderRadius}px`);\n this.container.style.setProperty('--cevro-radius-sm', `${Math.max(4, theme.borderRadius - 4)}px`);\n }\n if (theme.shadowColor) {\n this.container.style.setProperty('--cevro-shadow', `0 10px 40px ${theme.shadowColor}`);\n this.container.style.setProperty('--cevro-shadow-sm', `0 2px 8px ${theme.shadowColor}`);\n }\n // Launcher styling\n if (theme.launcherBackgroundColor) {\n this.container.style.setProperty('--cevro-launcher-bg', theme.launcherBackgroundColor);\n }\n if (theme.launcherIconColor) {\n this.container.style.setProperty('--cevro-launcher-icon', theme.launcherIconColor);\n }\n if (theme.launcherHoverShadowColor) {\n this.container.style.setProperty('--cevro-launcher-hover-shadow', theme.launcherHoverShadowColor);\n }\n // Send button styling\n if (theme.sendButtonBackgroundColor) {\n this.container.style.setProperty('--cevro-send-btn-bg', theme.sendButtonBackgroundColor);\n }\n if (theme.sendButtonIconColor) {\n this.container.style.setProperty('--cevro-send-btn-icon', theme.sendButtonIconColor);\n }\n // File button styling\n if (theme.fileButtonBackgroundColor) {\n this.container.style.setProperty('--cevro-file-btn-bg', theme.fileButtonBackgroundColor);\n }\n if (theme.fileButtonIconColor) {\n this.container.style.setProperty('--cevro-file-btn-icon', theme.fileButtonIconColor);\n }\n // Agent message styling\n if (theme.agentMessageBackgroundColor) {\n this.container.style.setProperty('--cevro-agent-msg-bg', theme.agentMessageBackgroundColor);\n }\n if (theme.agentMessageTextColor) {\n this.container.style.setProperty('--cevro-agent-msg-text', theme.agentMessageTextColor);\n }\n }\n\n /**\n * Adjust color brightness\n * @param hex - Hex color string\n * @param percent - Positive to lighten, negative to darken\n */\n private adjustColorBrightness(hex: string, percent: number): string {\n // Remove # if present\n hex = hex.replace(/^#/, '');\n\n // Parse RGB\n const num = parseInt(hex, 16);\n let r = (num >> 16) + percent;\n let g = ((num >> 8) & 0x00ff) + percent;\n let b = (num & 0x0000ff) + percent;\n\n // Clamp values\n r = Math.max(0, Math.min(255, r));\n g = Math.max(0, Math.min(255, g));\n b = Math.max(0, Math.min(255, b));\n\n return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;\n }\n\n /**\n * Create and mount the launcher into the container\n */\n private createAndMountLauncher(): void {\n if (!this.container) return;\n this.launcher = new Launcher(\n this.config,\n () => this.toggle(),\n this.widgetAppearance.bubbleIconUrl\n );\n this.container.appendChild(this.launcher.render());\n }\n\n /**\n * Create and mount conversation list screen\n */\n private createConversationList(strings: ReturnType<typeof getStrings>): void {\n if (!this.container) return;\n\n this.conversationList = new ConversationList(\n {\n onClose: () => this.hide(),\n onNewConversation: async () => {\n this.navigateTo('chat');\n await this.startNewChat();\n },\n onSelectActive: () => {\n this.navigateTo('chat');\n },\n onSelectPast: (ticketId, title) => {\n this.navigateTo('past-conversation');\n this.pastConversation?.loadConversation(ticketId, title);\n },\n onLoadConversations: (cursor) => this.api.getConversations(cursor),\n },\n strings\n );\n\n const el = this.conversationList.render();\n el.style.display = 'none';\n this.container.appendChild(el);\n }\n\n /**\n * Create and mount past conversation view\n */\n private createPastConversation(strings: ReturnType<typeof getStrings>): void {\n if (!this.container) return;\n\n this.pastConversation = new PastConversation(\n {\n onBack: () => this.navigateTo('history'),\n onClose: () => this.hide(),\n onNewConversation: async () => {\n this.navigateTo('chat');\n await this.startNewChat();\n },\n onLoadMessages: (ticketId, cursor) => this.api.getConversationMessages(ticketId, cursor),\n },\n strings\n );\n\n const el = this.pastConversation.render();\n this.pastConversation.setAvatarUrl(this.widgetAppearance.customLogoUrl);\n el.style.display = 'none';\n this.container.appendChild(el);\n }\n\n /**\n * Navigate between screens\n */\n private navigateTo(screen: 'chat' | 'history' | 'past-conversation'): void {\n this.currentScreen = screen;\n\n // Hide all screens\n this.chatWindow?.hide();\n this.conversationList?.hide();\n this.pastConversation?.hide();\n\n // Show target screen\n switch (screen) {\n case 'chat':\n this.chatWindow?.show();\n break;\n case 'history':\n if (this.isSessionInitialized && this.api.getCurrentTicketId()) {\n this.conversationList?.setActiveConversation({\n ticketId: this.api.getCurrentTicketId()!,\n lastMessageBody: this.chatWindow?.getLastMessageBody(),\n lastMessageAt: this.chatWindow?.getLastMessageAt(),\n agentName: this.api.getCurrentAgent()?.name,\n unreadCount: this.chatWindow?.getAgentMessagesSinceLastUserMessage() ?? 0,\n });\n } else {\n this.conversationList?.setActiveConversation(null);\n }\n this.conversationList?.show();\n this.conversationList?.load();\n break;\n case 'past-conversation':\n this.pastConversation?.show();\n break;\n }\n }\n\n /**\n * Bind a custom launcher element by CSS selector\n */\n private bindCustomLauncher(selector: string): void {\n const el = document.querySelector(selector);\n if (!el) {\n console.warn(`[CevroMessenger] customLauncherSelector \"${selector}\" did not match any element`);\n return;\n }\n\n this.customLauncherHandler = () => this.toggle();\n this.customLauncherElement = el;\n el.addEventListener('click', this.customLauncherHandler);\n }\n\n /**\n * Connect to Centrifugo WebSocket server\n * Fetches connection token from API first\n *\n * Security: Uses signed visitorToken to prevent visitor spoofing\n */\n private async connectWebSocket(): Promise<void> {\n // If already connecting, wait for existing promise\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n this.connectingPromise = this.doConnectWebSocket();\n return this.connectingPromise;\n }\n\n private async doConnectWebSocket(): Promise<void> {\n try {\n const storedVisitorToken = getStoredVisitorToken();\n const result = await this.api.getConnectionToken(storedVisitorToken);\n\n this.visitorId = result.visitorId;\n\n if (result.visitorToken) {\n storeVisitorToken(result.visitorToken);\n this.api.setVisitorToken(result.visitorToken);\n }\n\n this.ws.connect(result.visitorId, result.token);\n this.events.emit('ready');\n } catch (error) {\n // Still emit ready - SDK works without real-time, just with polling\n this.events.emit('ready');\n this.events.emit('error', { type: 'websocket_connect', error });\n } finally {\n this.connectingPromise = null;\n }\n }\n\n /**\n * Refresh connection token for Centrifugo\n * Called automatically when token expires or on reconnect\n */\n private async refreshConnectionToken(): Promise<string> {\n const storedVisitorToken = getStoredVisitorToken();\n const result = await this.api.getConnectionToken(storedVisitorToken);\n\n if (result.visitorToken) {\n storeVisitorToken(result.visitorToken);\n this.api.setVisitorToken(result.visitorToken);\n }\n\n return result.token;\n }\n\n /**\n * Shutdown the messenger\n * @param options.clearVisitorData - If true, clears visitor token (visitor will get new identity on next init)\n */\n shutdown(options?: { clearVisitorData?: boolean }): void {\n this.isDestroyed = true;\n\n if (!this.isBooted) {\n // Even pre-boot, clear stored data if requested — the caller\n // explicitly wants a clean slate (e.g. logout flow).\n if (options?.clearVisitorData) {\n clearStoredSession();\n clearStoredVisitorToken();\n clearActivePlayer();\n this.visitorId = null;\n }\n return;\n }\n\n // Stop typing cycle\n this.stopTypingCycle();\n\n // Disconnect WebSocket\n this.ws.disconnect();\n\n // Unbind custom launcher\n if (this.customLauncherElement && this.customLauncherHandler) {\n this.customLauncherElement.removeEventListener('click', this.customLauncherHandler);\n this.customLauncherElement = null;\n this.customLauncherHandler = null;\n }\n\n // Destroy UI components\n this.launcher?.destroy();\n this.chatWindow?.destroy();\n this.conversationList?.destroy();\n this.pastConversation?.destroy();\n\n // Remove Shadow DOM host element\n const host = this.shadowRoot?.host;\n if (host && host.parentNode) {\n host.parentNode.removeChild(host);\n }\n this.shadowRoot = null;\n\n // Clear stored data\n clearStoredSession();\n if (options?.clearVisitorData) {\n clearStoredVisitorToken();\n clearActivePlayer();\n this.visitorId = null;\n }\n this.api.clear();\n\n // Reset state\n this.launcher = null;\n this.chatWindow = null;\n this.conversationList = null;\n this.pastConversation = null;\n this.currentScreen = 'chat';\n this.container = null;\n this.isBooted = false;\n this.isVisible = false;\n this.unreadCount = 0;\n this.isSessionInitialized = false;\n this.isInitializingSession = null;\n this.connectingPromise = null;\n\n this.events.emit('shutdown');\n }\n\n /**\n * Show the messenger\n */\n async show(): Promise<void> {\n if (!this.isBooted) {\n await this.boot();\n }\n\n if (this.chatWindow) {\n // Show the current screen (default: chat)\n this.navigateTo(this.currentScreen);\n this.isVisible = true;\n this.launcher?.setState(true);\n this.setUnreadCount(0);\n this.events.emit('show');\n\n // Close on Escape key (desktop only)\n if (!this.escapeHandler) {\n this.escapeHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') this.hide();\n };\n document.addEventListener('keydown', this.escapeHandler);\n }\n\n // In preview mode, skip WebSocket and session initialization\n if (!this.config.preview) {\n await this.connectWebSocket();\n\n // Set visitor ID on API client for history requests\n if (this.visitorId) {\n this.api.setVisitorId(this.visitorId);\n }\n\n await this.initializeSession();\n }\n }\n }\n\n /**\n * Initialize session with backend\n * Creates/retrieves Contact and Ticket, loads existing messages\n * Uses promise pattern to ensure proper waiting when called concurrently\n */\n private async initializeSession(forceNew = false): Promise<void> {\n // If forcing new session, reset state\n if (forceNew) {\n this.isSessionInitialized = false;\n this.isInitializingSession = null;\n }\n\n // Already initialized - nothing to do\n if (this.isSessionInitialized) {\n return;\n }\n\n // If initialization is in progress, wait for it to complete\n if (this.isInitializingSession) {\n return this.isInitializingSession;\n }\n\n // Start new initialization - wrap with finally to ensure cleanup\n const initPromise = this.doInitializeSession().finally(() => {\n // Only clear if this is still the current initialization promise\n if (this.isInitializingSession === initPromise) {\n this.isInitializingSession = null;\n }\n });\n\n this.isInitializingSession = initPromise;\n return initPromise;\n }\n\n /**\n * Actual session initialization logic\n */\n private async doInitializeSession(options?: { forceNewTicket?: boolean }): Promise<void> {\n try {\n const result = await this.api.initSession(this.visitorId, this.visitorContactInfo, options);\n\n // Check if contact info is required but missing\n if (result.requireContactInfo && result.missingFields && result.missingFields.length > 0) {\n this.chatWindow?.showPreChatForm();\n return;\n }\n\n // Store session data\n storeSession(result.sessionId, result.contactId, result.ticketId);\n this.isSessionInitialized = true;\n\n // Set agent info in header\n if (result.agent && this.chatWindow) {\n this.chatWindow.setAgent(result.agent);\n }\n\n // Store typing config from server\n if (result.typingConfig) {\n this.typingConfig = result.typingConfig;\n }\n\n // Apply backend locale strings (highest priority: backend > client config > defaults)\n if (result.locale && this.chatWindow) {\n const mergedStrings = getStrings(this.config.locale, result.locale);\n this.chatWindow.setStrings(mergedStrings);\n this.conversationList?.setStrings(mergedStrings);\n this.pastConversation?.setStrings(mergedStrings);\n }\n\n this.chatWindow?.setScrollTopHandler(null);\n\n // Load existing messages into chat window\n if (result.messages && result.messages.length > 0) {\n for (const message of result.messages) {\n this.chatWindow?.addMessage(message);\n }\n\n // Enable scroll-up loading for older messages.\n // Do not depend solely on /session hasMoreMessages, because some backends\n // return only the latest slice here and expose pagination only via\n // /conversations/:ticketId/messages.\n if (result.ticketId) {\n let olderMessagesCursor: string | undefined =\n result.cursor || result.messages[0]?.createdAt;\n let isLoadingOlder = false;\n\n this.chatWindow?.setScrollTopHandler(async () => {\n if (isLoadingOlder || !olderMessagesCursor) return;\n isLoadingOlder = true;\n try {\n const older = await this.api.getConversationMessages(\n result.ticketId,\n olderMessagesCursor,\n );\n this.chatWindow?.prependMessages(older.messages);\n olderMessagesCursor = older.hasMore\n ? (older.cursor || older.messages[0]?.createdAt)\n : undefined;\n } catch (error) {\n console.error('[Cevro] Failed to load older messages:', error);\n } finally {\n isLoadingOlder = false;\n this.chatWindow?.finishLoadingTop();\n }\n });\n }\n }\n\n // Handle closed ticket state\n if (result.ticketClosed) {\n const skipCSAT = this.widgetAppearance.csatEnabled !== true;\n this.chatWindow?.setTicketClosed(true, () => this.startNewChat(), {\n ticketId: result.ticketId,\n skipCSAT,\n });\n }\n\n this.events.emit('session:initialized', {\n sessionId: result.sessionId,\n contactId: result.contactId,\n ticketId: result.ticketId,\n isNewSession: result.isNewSession,\n isNewTicket: result.isNewTicket,\n ticketClosed: result.ticketClosed,\n messageCount: result.messages?.length || 0,\n });\n\n } catch (error) {\n this.events.emit('error', { type: 'session_init', error });\n throw error;\n }\n }\n\n /**\n * Submit CSAT rating for the current conversation\n */\n private async submitCSAT(rating: number, feedback?: string): Promise<void> {\n const ticketId = this.api.getCurrentTicketId();\n const contactId = this.api.getContactId();\n\n if (!ticketId || !contactId) {\n throw new Error('No active session');\n }\n\n await this.api.submitCSAT(ticketId, contactId, rating, feedback);\n }\n\n /**\n * Start a new chat (creates a new ticket)\n * Used when the previous chat was closed\n */\n async startNewChat(): Promise<void> {\n // Navigate to chat screen first\n this.navigateTo('chat');\n\n // Clear current chat window messages\n this.chatWindow?.clearMessages();\n this.chatWindow?.setTicketClosed(false);\n\n // Re-initialize session with forceNewTicket\n this.isSessionInitialized = false;\n await this.doInitializeSession({ forceNewTicket: true });\n\n this.events.emit('chat:new_started');\n }\n\n /**\n * Hide the messenger\n */\n hide(): void {\n if (this.chatWindow) {\n this.chatWindow.hide();\n this.conversationList?.hide();\n this.pastConversation?.hide();\n this.isVisible = false;\n this.launcher?.setState(false);\n this.events.emit('hide');\n\n if (this.escapeHandler) {\n document.removeEventListener('keydown', this.escapeHandler);\n this.escapeHandler = null;\n }\n }\n }\n\n /**\n * Show the default launcher bubble\n */\n showLauncher(): void {\n if (!this.isBooted) return;\n if (!this.launcher) {\n this.createAndMountLauncher();\n }\n this.launcher?.setVisible(true);\n }\n\n /**\n * Hide the default launcher bubble (widget remains functional via show())\n */\n hideLauncher(): void {\n if (!this.isBooted) return;\n this.launcher?.setVisible(false);\n }\n\n /**\n * Toggle messenger visibility\n */\n toggle(): void {\n if (this.isVisible) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n /**\n * Maximum message length (2000 characters)\n */\n private static readonly MAX_MESSAGE_LENGTH = 2000;\n\n /**\n * Set draft message in the textarea without sending\n */\n setDraft(message: string): void {\n this.chatWindow?.setDraft(message);\n }\n\n /**\n * Send a message\n */\n async sendMessage(message: string): Promise<void> {\n if (!message.trim()) return;\n\n // Validate message length\n if (message.length > CevroMessenger.MAX_MESSAGE_LENGTH) {\n this.events.emit('error', {\n type: 'validation',\n error: new Error(`Message is too long. Maximum ${CevroMessenger.MAX_MESSAGE_LENGTH} characters allowed.`),\n message: `Message is too long. Maximum ${CevroMessenger.MAX_MESSAGE_LENGTH} characters allowed.`,\n });\n return;\n }\n\n // Create optimistic message\n // inbound: true = user's message going TO backend (consistent with backend storage)\n const optimisticMessage: Message = {\n id: 'temp_' + Date.now(),\n body: message,\n inbound: true,\n outbound: false,\n createdAt: new Date().toISOString(),\n type: 'text',\n status: 'sending',\n };\n\n // Add to UI immediately\n this.chatWindow?.addMessage(optimisticMessage);\n\n // In preview mode, just show the message without API call\n if (this.config.preview) {\n optimisticMessage.status = 'sent';\n this.chatWindow?.updateMessage(optimisticMessage);\n return;\n }\n\n try {\n // Ensure session is initialized before sending\n if (!this.isSessionInitialized) {\n await this.initializeSession();\n }\n\n // Store original temp id for lookup\n const tempId = optimisticMessage.id;\n\n // Send message to existing conversation\n const result = await this.api.sendMessage(message);\n\n // Update optimistic message with real data\n optimisticMessage.id = result.id;\n optimisticMessage.status = 'sent';\n this.chatWindow?.updateMessage(optimisticMessage, tempId);\n\n this.events.emit('message:sent', { message: result });\n\n // Typing indicator will be shown by backend via WebSocket event\n\n } catch (error: any) {\n // Check if conversation is closed\n const isConversationClosed =\n error?.message?.includes('closed') ||\n error?.message?.includes('resolved') ||\n error?.message?.includes('escalated') ||\n error?.response?.data?.message?.includes('closed');\n\n if (isConversationClosed) {\n // Remove the failed optimistic message\n this.chatWindow?.removeMessage(optimisticMessage.id);\n\n // Show closed UI with \"New Conversation\" button\n const ticketId = this.api.getCurrentTicketId() || undefined;\n this.chatWindow?.setTicketClosed(true, () => this.startNewChat(), {\n ticketId,\n skipCSAT: this.widgetAppearance.csatEnabled !== true,\n });\n return;\n }\n\n // Update optimistic message with error status\n optimisticMessage.status = 'failed';\n this.chatWindow?.updateMessage(optimisticMessage);\n\n this.events.emit('error', { error, type: 'send_message' });\n }\n }\n\n /**\n * Handle quick action click\n */\n private async handleQuickAction(action: QuickAction): Promise<void> {\n if (action.type === 'link' && action.url) {\n // Validate URL to prevent XSS via javascript: protocol\n if (isValidUrl(action.url)) {\n window.open(action.url, '_blank');\n }\n } else {\n // Send the action value as a message\n await this.sendMessage(action.value || action.label);\n }\n }\n\n /**\n * Handle pre-chat form submission (for visitors)\n */\n private async handlePreChatSubmit(data: { firstName: string; email: string }): Promise<void> {\n this.visitorContactInfo = data;\n\n // Hide the form and re-initialize session with contact info\n this.chatWindow?.hidePreChatForm();\n await this.initializeSession();\n }\n\n /**\n * Handle file upload with progress tracking\n * Shows preview immediately, then uploads to S3, then sends to backend\n *\n * Security: File is validated before upload (size, type, extension)\n */\n private async handleFileUpload(file: File): Promise<void> {\n // Variables for cleanup on error\n let localPreviewUrl: string | undefined;\n let tempId: string | undefined;\n\n try {\n // Ensure session is initialized before uploading\n if (!this.isSessionInitialized) {\n await this.initializeSession();\n }\n\n // Determine file type for display\n const isImage = file.type.startsWith('image/');\n const fileCategory = this.getFileCategory(file.type);\n\n // Create local preview URL for images\n localPreviewUrl = isImage ? URL.createObjectURL(file) : undefined;\n\n // Create optimistic message IMMEDIATELY (before upload starts)\n tempId = 'temp_' + Date.now();\n const optimisticMessage: Message = {\n id: tempId,\n body: '',\n inbound: true,\n outbound: false,\n createdAt: new Date().toISOString(),\n type: isImage ? 'image' : 'file',\n mediaUrl: localPreviewUrl,\n mediaType: file.type,\n status: 'sending',\n attachment: {\n filename: file.name,\n contentType: file.type || 'application/octet-stream',\n size: file.size,\n category: fileCategory,\n },\n };\n\n // Show preview in chat immediately\n this.chatWindow?.addMessage(optimisticMessage);\n\n // Now start the upload with progress (validation happens inside uploadFile)\n const assetId = await this.api.uploadFile(file, (progress) => {\n // Update progress in the message itself\n this.chatWindow?.updateMessageProgress(tempId!, progress);\n });\n\n // Send message to backend\n const result = await this.api.sendMessage('', assetId);\n\n // Update with real data from server, keeping blob URL if server didn't return mediaUrl\n const serverHasMediaUrl = result.mediaUrl && isValidUrl(result.mediaUrl);\n\n const updatedMessage: Message = {\n ...result,\n status: 'sent',\n type: isImage ? 'image' : 'file',\n mediaUrl: serverHasMediaUrl ? result.mediaUrl : localPreviewUrl,\n attachment: optimisticMessage.attachment,\n };\n this.chatWindow?.updateMessage(updatedMessage, tempId);\n\n // Only revoke blob URL if server returned a real URL\n if (localPreviewUrl && serverHasMediaUrl) {\n URL.revokeObjectURL(localPreviewUrl);\n }\n\n this.events.emit('message:sent', { type: fileCategory, fileName: file.name });\n\n } catch (error: any) {\n // Clean up blob URL on error\n if (localPreviewUrl) {\n URL.revokeObjectURL(localPreviewUrl);\n }\n\n // Remove failed optimistic message from UI\n if (tempId) {\n this.chatWindow?.removeMessage(tempId);\n }\n\n // Determine error type for better UX\n const errorMessage = error?.message || 'File upload failed';\n const isValidationError =\n errorMessage.includes('too large') ||\n errorMessage.includes('too small') ||\n errorMessage.includes('not allowed') ||\n errorMessage.includes('Too many uploads');\n\n // Emit specific error event with details\n this.events.emit('error', {\n error,\n type: isValidationError ? 'file_validation' : 'file_upload',\n message: errorMessage,\n fileName: file.name,\n });\n }\n }\n\n /**\n * Get file category for display purposes\n */\n private getFileCategory(mimeType: string): 'image' | 'pdf' | 'document' | 'spreadsheet' | 'presentation' | 'video' | 'audio' | 'archive' | 'text' | 'file' {\n if (mimeType.startsWith('image/')) return 'image';\n if (mimeType === 'application/pdf') return 'pdf';\n if (mimeType.includes('word') || mimeType.includes('document')) return 'document';\n if (mimeType.includes('sheet') || mimeType.includes('excel')) return 'spreadsheet';\n if (mimeType.includes('presentation') || mimeType.includes('powerpoint')) return 'presentation';\n if (mimeType.startsWith('video/')) return 'video';\n if (mimeType.startsWith('audio/')) return 'audio';\n if (mimeType.includes('zip') || mimeType.includes('archive') || mimeType.includes('compressed')) return 'archive';\n if (mimeType.startsWith('text/')) return 'text';\n return 'file';\n }\n\n /**\n * Set unread count\n */\n private setUnreadCount(count: number): void {\n this.unreadCount = count;\n this.launcher?.setUnreadCount(count);\n this.events.emit('unread_count_change', { count });\n }\n\n updateAppearance(config: Partial<WidgetAppearanceConfig>): void {\n this.widgetAppearance = {\n ...this.widgetAppearance,\n ...config,\n };\n\n if ('primaryColor' in config) {\n this.applyPrimaryColor();\n }\n\n if ('theme' in config) {\n this.applyTheme();\n }\n\n if ('bubbleIconUrl' in config && this.launcher) {\n this.launcher.updateBubbleIcon(config.bubbleIconUrl);\n }\n\n // Update chat window logo if changed (check if key exists in config)\n if ('customLogoUrl' in config && this.chatWindow) {\n this.chatWindow.updateCustomLogo(config.customLogoUrl);\n }\n\n this.events.emit('appearance:updated', this.widgetAppearance);\n }\n\n /**\n * Get current appearance config\n */\n getAppearance(): WidgetAppearanceConfig {\n return { ...this.widgetAppearance };\n }\n\n /**\n * Subscribe to an event\n * @param event - Event type to listen for\n * @param handler - Callback function\n * @returns Unsubscribe function\n */\n on<T = any>(event: string, handler: (data: T) => void): () => void {\n return this.events.on(event as any, handler);\n }\n\n /**\n * Subscribe to an event (fires only once)\n */\n once<T = any>(event: string, handler: (data: T) => void): () => void {\n return this.events.once(event as any, handler);\n }\n\n /**\n * Unsubscribe from an event\n * @param event - Event type\n * @param handler - Handler to remove\n */\n off(event: string, handler: (data: any) => void): void {\n this.events.off(event as any, handler);\n }\n\n /**\n * Get current unread message count\n */\n getUnreadCount(): number {\n return this.unreadCount;\n }\n\n /**\n * Get current visitor ID\n */\n getVisitorId(): string | null {\n return this.visitorId;\n }\n\n /**\n * Update config with new data (merges into current config)\n * Used by the loader queue replay pattern: Cevro('update', { ... })\n */\n update(data: Partial<CevroMessengerConfig>): void {\n this.config = this.normalizeConfig({ ...this.config, ...data });\n // Propagate new config reference to ApiClient and WebSocketClient\n this.api.updateConfig(this.config);\n this.ws.updateConfig(this.config);\n }\n\n /**\n * Identify a player (sets player data on config)\n * Used by the loader queue replay pattern: Cevro('identify', { playerId: '...' })\n *\n * Performs a soft re-initialization: keeps the UI intact, only re-creates\n * the session (new token + new session with updated player data).\n * No DOM destruction — no flickering.\n */\n async identify(playerData: PlayerData): Promise<void> {\n this.config.player = { ...this.config.player, ...playerData };\n\n // Detect account switches. First identify() stores the player hash and\n // returns false (anonymous session is preserved for server-side merge).\n // Subsequent identify() with a DIFFERENT playerId returns true — clear\n // stale session data so the new identity doesn't see the old conversation.\n const isSwitch = playerData.playerId\n ? detectAndRecordPlayerSwitch(playerData.playerId)\n : false;\n\n if (isSwitch) {\n clearStoredSession();\n clearStoredVisitorToken();\n }\n\n // Propagate updated config to ApiClient and WebSocketClient\n this.api.updateConfig(this.config);\n this.ws.updateConfig(this.config);\n\n // If not booted yet, just store the data — boot() will use it.\n // On first identify: existing session/visitor data preserved (anonymous→identified merge).\n // On account switch: data was cleared above, boot() starts fresh.\n if (!this.isBooted) {\n return;\n }\n\n // Soft re-init: disconnect WS, clear session state, reconnect with new identity\n const wasVisible = this.isVisible;\n this.ws.disconnect();\n this.api.clear();\n clearStoredSession();\n this.isSessionInitialized = false;\n this.isInitializingSession = null;\n this.connectingPromise = null;\n\n try {\n // Reconnect and re-initialize session with new player data\n await this.connectWebSocket();\n\n // Clear old messages before loading new session's messages\n this.chatWindow?.clearMessages();\n\n await this.initializeSession(true);\n\n // Re-apply visibility (session init may have reset UI state)\n if (wasVisible && this.chatWindow) {\n this.chatWindow.show();\n }\n\n this.events.emit('identify', { playerId: playerData.playerId });\n } catch (error) {\n this.events.emit('error', { type: 'identify', error });\n }\n }\n\n /**\n * Add a preview message (only works in preview mode)\n * @param text - Message text\n * @param fromAgent - If true, message appears as from agent; if false, from user\n */\n addPreviewMessage(text: string, fromAgent = true): void {\n if (!this.config.preview || !this.chatWindow) return;\n\n const message: Message = {\n id: 'preview_' + Date.now(),\n body: text,\n inbound: !fromAgent,\n outbound: fromAgent,\n createdAt: new Date().toISOString(),\n type: 'text',\n status: 'sent',\n };\n\n this.chatWindow.addMessage(message);\n }\n\n /**\n * Show or hide typing indicator (only works in preview mode)\n * @param show - Whether to show or hide the typing indicator\n */\n setPreviewTyping(show: boolean): void {\n if (!this.config.preview || !this.chatWindow) return;\n\n if (show) {\n this.chatWindow.showTypingIndicator();\n } else {\n this.chatWindow.hideTypingIndicator();\n }\n }\n\n /**\n * Set agent info for preview mode (name and avatar)\n * @param name - Agent name\n * @param avatarUrl - Agent avatar URL (optional)\n */\n setPreviewAgent(name: string, avatarUrl?: string): void {\n if (!this.config.preview || !this.chatWindow) return;\n\n this.chatWindow.setAgent({ name, avatarUrl });\n }\n\n /**\n * Start typing indicator cycle (5s on, 5s off, repeat)\n */\n private startTypingCycle(): void {\n // Clear any existing cycle\n this.stopTypingCycle();\n\n const { onDurationMs, offDurationMs } = this.typingConfig;\n\n const runCycle = () => {\n if (this.isTypingVisible) {\n this.chatWindow?.hideTypingIndicator();\n this.isTypingVisible = false;\n this.typingCycleTimeout = setTimeout(runCycle, offDurationMs);\n } else {\n this.chatWindow?.showTypingIndicator();\n this.isTypingVisible = true;\n this.typingCycleTimeout = setTimeout(runCycle, onDurationMs);\n }\n };\n\n this.chatWindow?.showTypingIndicator();\n this.isTypingVisible = true;\n this.typingCycleTimeout = setTimeout(runCycle, onDurationMs);\n }\n\n /**\n * Stop typing indicator cycle\n */\n private stopTypingCycle(): void {\n if (this.typingCycleTimeout) {\n clearTimeout(this.typingCycleTimeout);\n this.typingCycleTimeout = null;\n }\n\n if (this.isTypingVisible) {\n this.chatWindow?.hideTypingIndicator();\n this.isTypingVisible = false;\n }\n }\n}\n","/**\n * Cevro Messenger SDK\n *\n * A customer support chat widget for web applications.\n *\n * @example\n * // ES Module\n * import CevroMessenger from '@cevro/messenger-sdk';\n *\n * const messenger = new CevroMessenger({\n * apiBase: 'https://chat.cevro.ai',\n * workspaceId: 'your-workspace-id',\n * });\n *\n * messenger.boot();\n *\n * @example\n * // UMD (Script tag)\n * <script src=\"https://cdn.jsdelivr.net/npm/@cevro/messenger-sdk\"></script>\n * <script>\n * const messenger = new CevroMessenger({\n * apiBase: 'https://api.yoursite.com',\n * workspaceId: 'your-workspace-id',\n * });\n * messenger.boot();\n * </script>\n */\n\n// Import styles as string for Shadow DOM injection\nimport styles from './styles/index.css?inline';\n\n// Export styles for Shadow DOM\nexport { styles as __styles };\n\n// Export main class\nexport { CevroMessenger } from './core/CevroMessenger';\n\n// Export types\nexport type {\n CevroMessengerConfig,\n PlayerData,\n SessionData,\n Message,\n Conversation,\n QuickAction,\n RichContent,\n} from './types';\n\n// Default export for convenience\nimport { CevroMessenger } from './core/CevroMessenger';\nexport default CevroMessenger;\n\n// Global instance management for UMD builds and loader pattern\ndeclare global {\n interface Window {\n CevroMessenger: typeof CevroMessenger;\n cevroMessenger?: CevroMessenger;\n /** Settings object set by partner embed snippet, read by loader.js */\n cevroSettings?: import('./types').CevroMessengerConfig;\n /** Command queue / live proxy created by embed snippet and replaced by loader */\n Cevro?: ((...args: unknown[]) => void) & { q?: unknown[][] };\n }\n}\n\n// Auto-attach to window for UMD builds\nif (typeof window !== 'undefined') {\n window.CevroMessenger = CevroMessenger;\n}\n"],"names":["EventEmitter$2","constructor","__publicField","this","Map","on","event","handler","listeners","has","set","Set","get","add","off","once","onceHandler","data","onceHandlers","delete","handlers","emit","forEach","removeAllListeners","clear","listenerCount","_a","size","VISITOR_TOKEN_KEY","SESSION_KEY","IDB_STORE_NAME","setCookie","name","value","document","cookie","encodeURIComponent","openIDB","Promise","resolve","reject","req","indexedDB","open","onupgradeneeded","db","result","objectStoreNames","contains","createObjectStore","onsuccess","onerror","error","getStoredVisitorToken","fromLS","localStorage","getItem","fromCookie","match","RegExp","decodeURIComponent","getCookie","setItem","async","recoverVisitorToken","sync","fromIDB","key","then","tx","transaction","objectStore","oncomplete","close","catch","storeVisitorToken","token","put","generateVisitorId","lastDotIndex","lastIndexOf","substring","extractVisitorIdFromToken","getStoredVisitorId","ACTIVE_PLAYER_KEY","detectAndRecordPlayerSwitch","playerId","playerHash","input","hash","i","length","charCodeAt","Math","abs","toString","hashForKey","stored","clearActivePlayer","removeItem","clearStoredSession","clearStoredVisitorToken","deleteCookie","ALLOWED_MIME_TYPES","BLOCKED_EXTENSIONS","DEFAULT_FILE_CONSTRAINTS","maxSizeBytes","minSizeBytes","maxFilenameLength","getFileExtension","filename","lastDot","toLowerCase","formatFileSize","bytes","floor","log","parseFloat","pow","toFixed","UploadRateLimiter","maxUploads","windowMs","canUpload","now","Date","uploadTimestamps","filter","timestamp","recordUpload","push","getRemainingUploads","max","getTimeUntilNextUpload","oldestTimestamp","min","reset","ApiClient","config","uploadRateLimiter","updateConfig","setVisitorToken","visitorToken","getVisitorToken","setAccessToken","accessToken","getContactId","contactId","getCurrentTicketId","currentTicketId","setCurrentTicketId","ticketId","getCurrentAgent","currentAgent","request","endpoint","options","url","apiBase","headers","workspaceId","brandId","player","_b","visitorId","response","fetch","ok","json","message","statusText","Error","status","initSession","visitorContactInfo","payload","session","window","navigator","userAgent","language","platform","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","currentPage","location","href","pageTitle","title","referrer","screenWidth","screen","width","screenHeight","height","viewportWidth","innerWidth","viewportHeight","innerHeight","devicePixelRatio","urlParams","URLSearchParams","search","utmSource","utmMedium","utmCampaign","utmContent","utmTerm","cookiesEnabled","cookieEnabled","touchSupport","maxTouchPoints","online","onLine","connection","connectionType","effectiveType","e","collectSessionData","firstName","lastName","email","_c","phone","_d","customAttributes","_e","forceNewTicket","_f","method","body","JSON","stringify","requireContactInfo","_g","missingFields","sessionId","isNewSession","isNewTicket","agent","ticketClosed","ticketClosedReason","typingConfig","messages","_h","map","msg","normalizeMessage","hasMoreMessages","cursor","locale","sendMessage","assetId","getMessages","targetTicketId","results","getMyTickets","tickets","ticket","normalizeConversation","uploadFile","file","onProgress","waitTime","ceil","validation","allowedMimeTypes","blockedExtensions","valid","errorCode","extension","mimeType","type","validateFile","sanitizedFilename","sanitized","replace","ext","nameWithoutExt","slice","maxNameLength","sanitizeFilename","uploadUrl","contentType","uploadToS3","xhr","XMLHttpRequest","upload","addEventListener","lengthComputable","progress","round","loaded","total","setRequestHeader","send","id","objectId","inbound","outbound","createdAt","toISOString","mediaUrl","mediaType","richContent","conversationId","updatedAt","resolved","escalated","unreadCount","lastMessage","latestMessage","getConnectionToken","refreshConnectionToken","submitCSAT","rating","feedback","getConversations","params","conversations","hasMore","getConversationMessages","base","setVisitorId","getWidgetConfig","__awaiter","thisArg","_arguments","P","generator","fulfilled","step","next","rejected","done","apply","getDefaultExportFromCjs","x","__esModule","Object","prototype","hasOwnProperty","call","SuppressedError","ReflectOwnKeys","events","exports","R","Reflect","ReflectApply","target","receiver","args","Function","ownKeys","getOwnPropertySymbols","getOwnPropertyNames","concat","NumberIsNaN","Number","isNaN","EventEmitter","init","emitter","errorListener","err","removeListener","resolver","arguments","eventTargetAgnosticAddListener","flags","addErrorHandlerIfEventEmitter","_events","_eventsCount","_maxListeners","defaultMaxListeners","checkListener","listener","TypeError","_getMaxListeners","that","_addListener","prepend","m","existing","warning","create","newListener","unshift","warned","w","String","count","console","warn","onceWrapper","fired","wrapFn","_onceWrap","state","wrapped","bind","_listeners","unwrap","evlistener","arr","ret","Array","unwrapListeners","arrayClone","n","copy","wrapListener","arg","removeEventListener","defineProperty","enumerable","RangeError","getPrototypeOf","setMaxListeners","getMaxListeners","doError","er","context","len","addListener","prependListener","prependOnceListener","list","position","originalListener","shift","index","pop","spliceOne","keys","rawListeners","eventNames","errorCodes","connectingCodes","disconnectedCodes","subscribingCodes","unsubscribedCodes","subscriptionFlags","State","SubscriptionState","EventEmitter$1","isFunction","backoff","interval","random","randomInt","ttlMilliseconds","ttl","Subscription","centrifuge","channel","super","_resubscribeTimeout","_refreshTimeout","Unsubscribed","_centrifuge","_token","_getToken","_data","_getData","_recover","_offset","_epoch","_id","_recoverable","_positioned","_joinLeave","_minResubscribeDelay","_maxResubscribeDelay","_resubscribeAttempts","_promises","_promiseId","_inflight","_delta","_delta_negotiated","_tagsFilter","_prevValue","_unsubPromise","_setOptions","_debugEnabled","ctx","_debug","oldState","newState","ready","timeout","code","subscriptionUnsubscribed","Subscribed","res","rej","setTimeout","_nextPromiseId","subscribe","_isSubscribed","_setSubscribing","subscribeCalled","unsubscribe","_setUnsubscribed","unsubscribeCalled","publish","_methodCall","presence","presenceStats","history","opts","setTagsFilter","tagsFilter","setData","_isUnsubscribed","timeoutDuration","_config","_needRecover","_isSubscribing","Subscribing","_setState","_usesToken","_clearSubscribingState","_clearResubscribeTimeout","_clearSubscribedState","_clearRefreshTimeout","_setSubscribed","recoverable","offset","epoch","delta","_getSubscribeContext","_resolvePromises","pubs","publications","_handlePublication","expires","_refresh","reason","_transport","emulation","_subscribe","_isTransportOpen","_canSubscribeWithoutGettingToken","_subscribeWithoutToken","_getSubscriptionToken","_handleTokenResponse","_handleTokenError","_transportIsOpen","_getDataAndSubscribe","_sendSubscribe","_handleGetDataError","UnauthorizedError","_failUnauthorized","badConfiguration","_scheduleResubscribe","subscriptionSubscribeToken","cmd","_buildSubscribeCommand","_call","resolveCtx","reply","_handleSubscribeResponse","rejectCtx","_handleSubscribeError","positioned","join_leave","flag","channelCompaction","recover","_getOffset","_getEpoch","tf","_subscribeError","_disconnect","subscribeTimeout","sendUnsubscribe","promise","_unsubscribe","_rejectPromises","pub","newData","newPrevValue","_codec","applyDeltaIfNeeded","_getPublicationContext","_handleJoin","join","info","_getJoinLeaveContext","_handleLeave","leave","clearTimeout","self","delay","_getResubscribeDelay","temporary","errContext","Connected","since","getData","minResubscribeDelay","maxResubscribeDelay","getToken","joinLeave","sub_refresh","_refreshResponse","_refreshError","subscriptionRefreshToken","_getRefreshRetryDelay","unauthorized","SockjsTransport","subName","transport","supported","sockjs","initialize","_protocol","callbacks","sockjsOptions","onopen","onOpen","onError","onclose","closeEvent","onClose","onmessage","onMessage","WebsocketTransport","websocket","protocol","subProtocol","binaryType","HttpStreamTransport","_abortController","_utf8decoder","TextDecoder","_handleErrors","_fetchEventTarget","eventTarget","EventTarget","fetchFunc","dispatchEvent","Event","jsonStreamBuf","jsonStreamPos","protoStreamBuf","Uint8Array","reader","getReader","readableStream","start","controller","pump","read","decode","line","MessageEvent","mergedArray","decoder","decodeReply","pos","detail","AbortController","initialData","Accept","fetchOptions","mode","credentials","signal","abort","node","encoder","encodeEmulationRequest","emulationEndpoint","SseTransport","_onClose","eventsource","globalThis","baseURI","URL","searchParams","append","eventSource","WebtransportTransport","_stream","_writer","webtransport","closed","stream","createBidirectionalStream","writable","getWriter","_startReading","readable","binary","TextEncoder","encode","write","zValue","Reader","array","a","haveBytes","getByte","b","getChar","fromCharCode","getInt","c","v","Writer","toByteArray","sourceType","isArray","putArray","end","checksum","sum0","sum1","sum2","sum3","z","N","JsonCodec","encodeCommands","commands","decodeReplies","trim","split","r","parse","prevValue","valueArray","source","zDelta","lenSrc","lenDelta","limit","zOut","cnt","ofst","out","applyDelta","defaults","debug","version","minReconnectDelay","maxReconnectDelay","maxServerPingDelay","networkEventTarget","Centrifuge","_reconnectTimeout","_serverPingTimeout","Disconnected","_endpoint","_emulation","_transports","_currentTransportIndex","_triedAllTransports","_transportWasOpen","_transportId","_deviceWentOffline","_transportClosed","_reconnecting","_reconnectAttempts","_client","_session","_node","_subs","_serverSubs","_commandId","_commands","_batching","_refreshRequired","_callbacks","_dispatchPromise","_serverPing","_sendPong","_networkEventsSet","assign","_configure","newSubscription","getSubscription","sub","_getSub","removeSubscription","_removeSubscription","subscriptions","clientDisconnected","connect","_isConnected","_isConnecting","_startConnecting","disconnect","disconnectCalled","setToken","setHeaders","_transportSendCommands","_createErrorObject","transportWriteError","rpc","_callPromise","_getHistoryRequest","clients","clientId","rawClient","connInfo","chanInfo","presence_stats","numUsers","num_users","numClients","num_clients","startBatching","stopBatching","_flush","level","logger","_codecName","_formatOverride","transportConfig","transportName","indexOf","_isDisconnected","Connecting","_nextCommandId","_setNetworkEvents","transportClosed","_clearReconnectTimeout","_startReconnecting","_getReconnectDelay","_clearOutgoingRequests","errback","connectionClosed","_clearConnectedState","_clearServerPingTimeout","_handleWriteError","command","_initializeTransport","WebSocket","SockJS","EventSource","ReadableStream","transportEndpoint","WebTransport","prefix","transportId","_nextTransportId","wasOpen","initialCommands","connectCommand","_sendConnect","connectTimeout","_sendSubscribeCommands","needReconnect","advice","reconnect","messageSizeLimit","_dataReceived","skipSending","_constructConnectCommand","_connectResponse","_connectError","emptyToken","clientConnectToken","_scheduleReconnect","isInitialHandshake","subs","hasSubs","reverse","resultCB","_waitServerPing","replies","finishDispatch","_dispatchSynchronized","p","_dispatchReply","_handleReply","_handlePush","_handleServerPing","_registerCall","_addCommand","connectCalled","previousState","needEvent","refresh","clientRefreshToken","client","_","unsubscribeError","ch","_isServerSub","_processServerSubs","ping","pong","subCtx","recovered","noPing","wasRecovering","hasRecoveredPublications","was_recovering","streamPosition","callback","_handleUnsubscribe","_handleSubscribe","_handleDisconnect","tags","clientInfo","user","_handleMessage","errObject","WebSocketClient","setTokenRefreshCallback","getTokenCallback","userId","connectionToken","wsUrl","getWebSocketUrl","setupClientEventListeners","centrifugoUrl","apiUrl","host","subscribeToPersonalChannel","channelName","existingSub","personalSub","handleMessage","senderType","agentName","isTyping","actor","closedAt","updateToken","newToken","isConnected","getUserId","createElement","tag","attributes","children","element","entries","className","startsWith","setAttribute","child","appendChild","createTextNode","isValidUrl","parsed","origin","includes","parseMarkdown","text","div","textContent","innerHTML","escapeHtml","_match","linkText","safeUrl","sanitizeUrl","scrollToBottom","smooth","scrollTo","top","scrollHeight","behavior","generateId","Launcher","onClick","bubbleIconUrl","render","applyPositioning","button","chatImg","src","alt","style","objectFit","chatIcon","createChatIcon","classList","closeIcon","createCloseIcon","unreadBadge","display","alignment","vPadding","verticalPadding","hPadding","horizontalPadding","bottom","left","right","zIndex","svg","createElementNS","path","line1","line2","setState","isOpen","remove","setUnreadCount","setVisible","visible","pulse","updateBubbleIcon","iconUrl","querySelector","existingIcon","cssText","insertBefore","firstChild","destroy","parentNode","removeChild","defaultStrings","headerTitle","headerSubtitle","inputPlaceholder","preChatTitle","preChatSubtitle","preChatFirstNameLabel","preChatFirstNamePlaceholder","preChatEmailLabel","preChatEmailPlaceholder","preChatSubmit","preChatFirstNameRequired","preChatEmailRequired","preChatEmailInvalid","closedMessage","newConversation","conversationsTitle","newConversationButton","activeConversation","noConversations","noConversationsSubtitle","loadingConversations","loadMoreConversations","messagesCount","yesterday","closedStatus","defaultConversationTitle","csatTitle","csatSubtitle","csatPlaceholder","csatPlaceholderNegative","csatPlaceholderNeutral","csatSubmit","csatThankYou","poweredBy","getStrings","clientOverrides","backendOverrides","MessageList","setQuickActionHandler","onQuickAction","setScrollTopHandler","onScrollTopCallback","finishLoadingTop","requestAnimationFrame","isLoadingTop","resetTopLoading","suppressScrollEvents","setAgent","messagesContainer","autoScroll","threshold","scrollTop","clientHeight","isScrolledToBottom","started","getLastMessageBody","lastMessageBody","getLastMessageAt","lastMessageAt","getAgentMessagesSinceLastUserMessage","nodes","querySelectorAll","el","addMessage","animate","skipScroll","updateMessage","messageEl","createMessageElement","typingIndicator","prependMessages","anchor","firstElementChild","anchorOffset","offsetTop","prependMessage","oldId","lookupId","existingEl","newEl","replaceChild","updateMessageProgress","messageId","progressFill","progressText","removeMessage","isMyMessage","wrapper","isHuman","avatar","initials","toUpperCase","initialsEl","avatarUrl","img","createBotAvatarSvg","contentWrapper","senderLabel","bubble","isImage","attachment","category","imageContainer","loading","progressOverlay","createProgressOverlay","fileCard","createFileCard","link","rel","getFileIcon","quickActions","actionsContainer","action","label","meta","date","toLocaleTimeString","hour","minute","getStatusIcon","overlay","isUploading","card","iconWrapper","truncateFilename","details","icons","pdf","spreadsheet","presentation","video","audio","archive","image","maxLength","showTypingIndicator","hideTypingIndicator","indicator","closedMessageElement","showClosedMessage","hideClosedMessage","displayMessage","ChatWindow","strings","customLogoUrl","messageList","setStrings","backendStrings","updateUIStrings","headerSubtitleElement","inputElement","placeholder","header","createHeader","messagesArea","inputWrapper","createInputArea","logoElement","logoImg","borderRadius","createCompanyLogoSvg","historyButton","onShowHistory","titleSection","brandNameElement","closeButton","inputArea","fileButton","fileInput","accept","accepts","generateAcceptAttribute","files","onFileUpload","click","rows","resizeInput","updateSendButtonState","shiftKey","preventDefault","handleSend","sendButton","disabled","footer","onSendMessage","focus","preventScroll","setDraft","getAttribute","clearMessages","show","isVisible","hide","isWindowVisible","focusInput","setTicketClosed","onStartNewChat","skipCSAT","removeClosedUI","csatSubmitted","showClosedFooter","showInlineCSATForm","preChatContainer","csatRating","csatFeedback","csatContainer","headerRow","skipButton","starsRow","star","createStarSvg","selectInlineRating","previewRating","feedbackInput","submitButton","submitInlineCSAT","container","csatSubmitting","updateStars","parentElement","onCSATSubmit","showInlineThankYou","thankYouRow","checkIcon","newChatButton","closedFooter","filled","toggle","showPreChatForm","preChatCompleted","subtitle","form","firstNameGroup","firstNameLabel","for","firstNameInput","firstNameError","emailGroup","emailLabel","emailInput","autocomplete","emailError","isValidEmail","hasError","onPreChatSubmit","hidePreChatForm","test","updateCustomLogo","logoUrl","ConversationList","titleElement","setActiveConversation","activeInfo","listContainer","newConvButton","onNewConversation","actionPanel","load","loadMoreButton","onLoadConversations","activeCard","createActiveCard","showEmptyState","conv","createConversationCard","renderLoadMoreButton","loadMore","isLoadingMore","unread","content","titleRow","formatDate","previewRow","preview","onSelectActive","titleText","messageCount","onSelectPast","empty","emptyTitle","emptySubtitle","dateStr","diffMs","getTime","diffDays","toLocaleDateString","weekday","month","day","PastConversation","setAvatarUrl","renderAvatar","avatarElement","backButton","onBack","loadMoreMessages","loadConversation","onLoadMessages","requestedTicketId","_CevroMessenger","onDurationMs","offDurationMs","normalizeConfig","api","ws","setupEventHandlers","instance","getInstance","stopTypingCycle","chatWindow","startTypingCycle","escalationMsg","widgetAppearance","csatEnabled","startNewChat","boot","isBooted","isDestroyed","shadowRoot","attachShadow","styleEl","styles","applyPrimaryColor","hideDefaultLauncher","createAndMountLauncher","handleQuickAction","handleFileUpload","handlePreChatSubmit","navigateTo","createConversationList","createPastConversation","storedSession","getStoredSession","customLauncherSelector","bindCustomLauncher","autoOpen","color","primaryColor","setProperty","hoverColor","adjustColorBrightness","lightColor","applyTheme","backendTheme","theme","localTheme","mergedTheme","applyCustomTheme","themeVars","removeProperty","backgroundColor","backgroundSecondaryColor","textColor","textSecondaryColor","borderColor","userMessageBackgroundColor","userMessageTextColor","headerBackgroundColor","headerTextColor","inputBackgroundColor","shadowColor","launcherBackgroundColor","launcherIconColor","launcherHoverShadowColor","sendButtonBackgroundColor","sendButtonIconColor","fileButtonBackgroundColor","fileButtonIconColor","agentMessageBackgroundColor","agentMessageTextColor","hex","percent","num","parseInt","g","padStart","launcher","conversationList","pastConversation","currentScreen","isSessionInitialized","_i","_j","_k","_l","_m","selector","customLauncherHandler","customLauncherElement","connectWebSocket","connectingPromise","doConnectWebSocket","storedVisitorToken","shutdown","clearVisitorData","isInitializingSession","escapeHandler","initializeSession","forceNew","initPromise","doInitializeSession","finally","storeSession","mergedStrings","olderMessagesCursor","isLoadingOlder","older","showLauncher","hideLauncher","MAX_MESSAGE_LENGTH","optimisticMessage","tempId","localPreviewUrl","fileCategory","getFileCategory","createObjectURL","serverHasMediaUrl","updatedMessage","revokeObjectURL","fileName","errorMessage","isValidationError","updateAppearance","getAppearance","getUnreadCount","getVisitorId","update","identify","playerData","wasVisible","addPreviewMessage","fromAgent","setPreviewTyping","setPreviewAgent","runCycle","isTypingVisible","typingCycleTimeout","CevroMessenger"],"mappings":"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","x_google_ignoreList":[4]}
|
|
1
|
+
{"version":3,"file":"cevro-messenger.min.js","sources":["../../src/core/EventEmitter.ts","../../src/utils/session.ts","../../src/utils/file-validation.ts","../../src/core/ApiClient.ts","../../node_modules/centrifuge/build/index.mjs","../../src/core/WebSocketClient.ts","../../src/utils/dom.ts","../../src/ui/Launcher.ts","../../src/i18n/strings.ts","../../src/ui/MessageList.ts","../../src/ui/ChatWindow.ts","../../src/ui/ConversationList.ts","../../src/ui/PastConversation.ts","../../src/core/CevroMessenger.ts","../../src/index.ts"],"sourcesContent":["import type { EventType, EventHandler } from '../types';\n\n/**\n * Simple event emitter for SDK events\n */\nexport class EventEmitter {\n private listeners: Map<EventType, Set<EventHandler>> = new Map();\n private onceHandlers: Map<EventHandler, EventHandler> = new Map(); // Maps wrapper -> original\n\n /**\n * Subscribe to an event\n */\n on<T = any>(event: EventType, handler: EventHandler<T>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler);\n\n // Return unsubscribe function\n return () => this.off(event, handler);\n }\n\n /**\n * Subscribe to an event (fires only once)\n */\n once<T = any>(event: EventType, handler: EventHandler<T>): () => void {\n const onceHandler: EventHandler<T> = (data) => {\n this.onceHandlers.delete(onceHandler);\n this.off(event, onceHandler);\n handler(data);\n };\n this.onceHandlers.set(onceHandler, handler);\n return this.on(event, onceHandler);\n }\n\n /**\n * Unsubscribe from an event\n */\n off(event: EventType, handler: EventHandler): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.delete(handler);\n // Also clean up from onceHandlers if it was a once handler\n this.onceHandlers.delete(handler);\n }\n }\n\n /**\n * Emit an event\n */\n emit<T = any>(event: EventType, data?: T): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(data);\n } catch {\n // Silently ignore handler errors\n }\n });\n }\n }\n\n /**\n * Remove all listeners for an event (or all events if no event specified)\n */\n removeAllListeners(event?: EventType): void {\n if (event) {\n // Clean up once handlers for this event\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.forEach((handler) => {\n this.onceHandlers.delete(handler);\n });\n }\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n this.onceHandlers.clear();\n }\n }\n\n /**\n * Get listener count for an event\n */\n listenerCount(event: EventType): number {\n return this.listeners.get(event)?.size || 0;\n }\n}\n","import type { SessionData } from '../types';\n\n// ============================================\n// Multi-layer identity persistence\n// Stores visitor token in localStorage + cookie + indexedDB\n// so clearing one doesn't lose the visitor identity.\n// ============================================\n\nconst VISITOR_TOKEN_KEY = 'cevro_visitor_token';\nconst SESSION_KEY = 'cevro_session';\nconst COOKIE_MAX_AGE_SECONDS = 270 * 24 * 60 * 60; // 9 months (same as Intercom)\nconst IDB_DB_NAME = 'cevro_sdk';\nconst IDB_STORE_NAME = 'identity';\n\n// --- Cookie helpers ---\n\nfunction setCookie(name: string, value: string): void {\n try {\n document.cookie = `${name}=${encodeURIComponent(value)};max-age=${COOKIE_MAX_AGE_SECONDS};path=/;SameSite=Lax`;\n } catch {\n // Cookies may be blocked\n }\n}\n\nfunction getCookie(name: string): string | null {\n try {\n const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));\n return match ? decodeURIComponent(match[1]) : null;\n } catch {\n return null;\n }\n}\n\nfunction deleteCookie(name: string): void {\n try {\n document.cookie = `${name}=;max-age=0;path=/;SameSite=Lax`;\n } catch {\n // Ignore\n }\n}\n\n// --- IndexedDB helpers (async, fire-and-forget for writes) ---\n\nfunction openIDB(): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const req = indexedDB.open(IDB_DB_NAME, 1);\n req.onupgradeneeded = () => {\n const db = req.result;\n if (!db.objectStoreNames.contains(IDB_STORE_NAME)) {\n db.createObjectStore(IDB_STORE_NAME);\n }\n };\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n}\n\nfunction idbSet(key: string, value: string): void {\n // Fire-and-forget — don't block on write\n openIDB()\n .then(db => {\n const tx = db.transaction(IDB_STORE_NAME, 'readwrite');\n tx.objectStore(IDB_STORE_NAME).put(value, key);\n tx.oncomplete = () => db.close();\n tx.onerror = () => db.close();\n })\n .catch(() => {});\n}\n\nfunction idbGet(key: string): Promise<string | null> {\n return openIDB()\n .then(db => {\n return new Promise<string | null>((resolve) => {\n const tx = db.transaction(IDB_STORE_NAME, 'readonly');\n const req = tx.objectStore(IDB_STORE_NAME).get(key);\n req.onsuccess = () => resolve(req.result ?? null);\n req.onerror = () => resolve(null);\n tx.oncomplete = () => db.close();\n tx.onerror = () => db.close();\n });\n })\n .catch(() => null);\n}\n\nfunction idbDelete(key: string): void {\n openIDB()\n .then(db => {\n const tx = db.transaction(IDB_STORE_NAME, 'readwrite');\n tx.objectStore(IDB_STORE_NAME).delete(key);\n tx.oncomplete = () => db.close();\n tx.onerror = () => db.close();\n })\n .catch(() => {});\n}\n\n/**\n * Collect browser session data\n */\nexport function collectSessionData(): SessionData {\n const session: SessionData = {};\n\n if (typeof window === 'undefined' || typeof navigator === 'undefined') {\n return session;\n }\n\n try {\n // Browser info\n session.userAgent = navigator.userAgent;\n session.language = navigator.language;\n session.platform = navigator.platform;\n session.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n // Page context\n session.currentPage = window.location.href;\n session.pageTitle = document.title;\n session.referrer = document.referrer;\n\n // Screen dimensions\n session.screenWidth = window.screen.width;\n session.screenHeight = window.screen.height;\n session.viewportWidth = window.innerWidth;\n session.viewportHeight = window.innerHeight;\n session.devicePixelRatio = window.devicePixelRatio;\n\n // UTM parameters from URL\n const urlParams = new URLSearchParams(window.location.search);\n session.utmSource = urlParams.get('utm_source') || undefined;\n session.utmMedium = urlParams.get('utm_medium') || undefined;\n session.utmCampaign = urlParams.get('utm_campaign') || undefined;\n session.utmContent = urlParams.get('utm_content') || undefined;\n session.utmTerm = urlParams.get('utm_term') || undefined;\n\n // Capabilities\n session.cookiesEnabled = navigator.cookieEnabled;\n session.touchSupport = 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n session.online = navigator.onLine;\n\n // Connection info (if available)\n const connection = (navigator as any).connection;\n if (connection) {\n session.connectionType = connection.effectiveType;\n }\n } catch (e) {\n // Silently ignore errors in session collection\n }\n\n return session;\n}\n\n/**\n * Get stored visitor token (signed by server)\n * Checks localStorage first, then cookie fallback.\n * IndexedDB is checked asynchronously via recoverVisitorToken().\n */\nexport function getStoredVisitorToken(): string | null {\n // Layer 1: localStorage (fastest, synchronous)\n try {\n const fromLS = localStorage.getItem(VISITOR_TOKEN_KEY);\n if (fromLS) return fromLS;\n } catch {\n // localStorage unavailable\n }\n\n // Layer 2: cookie fallback\n const fromCookie = getCookie(VISITOR_TOKEN_KEY);\n if (fromCookie) {\n // Restore to localStorage\n try { localStorage.setItem(VISITOR_TOKEN_KEY, fromCookie); } catch {}\n return fromCookie;\n }\n\n return null;\n}\n\n/**\n * Async recovery: check IndexedDB if synchronous stores are empty.\n * Call once at boot — if a token is recovered, it's written back to all layers.\n */\nexport async function recoverVisitorToken(): Promise<string | null> {\n // If synchronous stores already have it, nothing to recover\n const sync = getStoredVisitorToken();\n if (sync) return sync;\n\n // Layer 3: IndexedDB\n try {\n const fromIDB = await idbGet(VISITOR_TOKEN_KEY);\n if (fromIDB) {\n // Restore to all synchronous layers\n try { localStorage.setItem(VISITOR_TOKEN_KEY, fromIDB); } catch {}\n setCookie(VISITOR_TOKEN_KEY, fromIDB);\n return fromIDB;\n }\n } catch {\n // IndexedDB unavailable\n }\n\n return null;\n}\n\n/**\n * Store visitor token received from server.\n * Writes to all three layers for maximum persistence.\n */\nexport function storeVisitorToken(token: string): void {\n // Layer 1: localStorage\n try { localStorage.setItem(VISITOR_TOKEN_KEY, token); } catch {}\n\n // Layer 2: cookie (9 months)\n setCookie(VISITOR_TOKEN_KEY, token);\n\n // Layer 3: indexedDB (async, fire-and-forget)\n idbSet(VISITOR_TOKEN_KEY, token);\n}\n\n/**\n * Extract visitorId from visitorToken\n * Token format: visitorId.signature\n */\nexport function extractVisitorIdFromToken(token: string): string | null {\n if (!token) return null;\n const lastDotIndex = token.lastIndexOf('.');\n if (lastDotIndex <= 0) return null;\n return token.substring(0, lastDotIndex);\n}\n\n/**\n * Get visitorId from stored token (or null if not available)\n */\nexport function getStoredVisitorId(): string | null {\n const token = getStoredVisitorToken();\n return token ? extractVisitorIdFromToken(token) : null;\n}\n\n/**\n * Get visitor ID from stored token, or null if not yet available.\n * The visitor ID is assigned by the server and stored in the visitor token.\n */\nexport function generateVisitorId(): string | null {\n return getStoredVisitorId();\n}\n\n/**\n * Stored session data\n */\nexport interface StoredSessionData {\n sessionId?: string;\n contactId?: string;\n ticketId?: string;\n}\n\n// --- Account-switch detection ---\n//\n// Storage keys are always plain (`cevro_session`, `cevro_visitor_token`).\n// We track the last identified playerId in `cevro_active_player`.\n//\n// On first identify(): store the player hash, keep existing session/visitor\n// data intact. The anonymous→identified merge happens server-side (backend\n// links the visitorId to the playerId in initSession).\n//\n// On subsequent identify() with a DIFFERENT playerId: account switch detected.\n// Clear session + visitor data so the new identity starts fresh, then store\n// the new player hash.\n//\n// This optimizes for the 99% case (single account) with zero disruption,\n// and only pays the reset cost on actual account switches.\n\nconst ACTIVE_PLAYER_KEY = 'cevro_active_player';\n\n/**\n * Simple hash to avoid storing raw playerIds in localStorage.\n */\nfunction hashForKey(input: string): string {\n let hash = 0;\n for (let i = 0; i < input.length; i++) {\n hash = ((hash << 5) - hash + input.charCodeAt(i)) | 0;\n }\n return Math.abs(hash).toString(36);\n}\n\n/**\n * Check if identify() is being called for a different player than the\n * one currently stored. Returns true if this is an account switch that\n * requires clearing session data.\n *\n * Also stores the new player hash so subsequent calls detect correctly.\n * First-time identify (no previous player) returns false — the anonymous\n * session should be preserved for server-side merge.\n */\nexport function detectAndRecordPlayerSwitch(playerId: string): boolean {\n const playerHash = hashForKey(playerId);\n try {\n const stored = localStorage.getItem(ACTIVE_PLAYER_KEY);\n localStorage.setItem(ACTIVE_PLAYER_KEY, playerHash);\n\n // First identify — no previous player, not a switch\n if (!stored) return false;\n\n // Same player — not a switch\n if (stored === playerHash) return false;\n\n // Different player — account switch\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Clear the active player record (e.g. on shutdown with clearVisitorData).\n */\nexport function clearActivePlayer(): void {\n try {\n localStorage.removeItem(ACTIVE_PLAYER_KEY);\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Get stored session data\n */\nexport function getStoredSession(): StoredSessionData | null {\n try {\n const stored = localStorage.getItem(SESSION_KEY);\n return stored ? JSON.parse(stored) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Store session data\n */\nexport function storeSession(sessionId: string, contactId: string, ticketId: string): void {\n try {\n localStorage.setItem(SESSION_KEY, JSON.stringify({ sessionId, contactId, ticketId }));\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Clear stored session data\n */\nexport function clearStoredSession(): void {\n try {\n localStorage.removeItem(SESSION_KEY);\n } catch {\n // Ignore storage errors\n }\n}\n\n/**\n * Clear stored visitor token from all layers.\n */\nexport function clearStoredVisitorToken(): void {\n try { localStorage.removeItem(VISITOR_TOKEN_KEY); } catch {}\n deleteCookie(VISITOR_TOKEN_KEY);\n idbDelete(VISITOR_TOKEN_KEY);\n}\n\n/**\n * Clear all stored data (session + visitor token + active player)\n */\nexport function clearAllStoredData(): void {\n clearStoredSession();\n clearStoredVisitorToken();\n clearActivePlayer();\n}\n","/**\n * File validation utilities for secure file uploads\n * Provides client-side validation as first line of defense\n */\n\n/**\n * Allowed MIME types for file uploads\n * This whitelist prevents potentially dangerous file types\n */\nexport const ALLOWED_MIME_TYPES: ReadonlySet<string> = new Set([\n // Images\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'image/svg+xml',\n // Documents\n 'application/pdf',\n 'text/plain',\n 'text/csv',\n // Microsoft Office\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'application/vnd.ms-excel',\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'application/vnd.ms-powerpoint',\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n // Audio/Video\n 'audio/mpeg',\n 'audio/wav',\n 'audio/ogg',\n 'video/mp4',\n 'video/webm',\n // Archives (optional - can be disabled)\n 'application/zip',\n 'application/x-rar-compressed',\n]);\n\n/**\n * Dangerous file extensions that should always be blocked\n * Even if MIME type looks safe, these extensions are risky\n */\nexport const BLOCKED_EXTENSIONS: ReadonlySet<string> = new Set([\n '.exe', '.dll', '.bat', '.cmd', '.sh', '.bash',\n '.ps1', '.psm1', '.psd1', // PowerShell\n '.vbs', '.vbe', '.js', '.jse', '.ws', '.wsf', '.wsc', '.wsh', // Scripts\n '.msi', '.msp', '.mst', // Windows installers\n '.scr', '.pif', '.com', // Executables\n '.hta', '.cpl', '.msc', // Control panel/settings\n '.jar', '.class', // Java\n '.php', '.php3', '.php4', '.php5', '.phtml', // PHP\n '.asp', '.aspx', '.ashx', '.asmx', // ASP.NET\n '.jsp', '.jspx', // JSP\n '.py', '.pyc', '.pyw', // Python\n '.rb', '.rbw', // Ruby\n '.pl', '.pm', '.cgi', // Perl/CGI\n '.htaccess', '.htpasswd', // Apache config\n]);\n\n/**\n * Default file upload constraints\n */\nexport const DEFAULT_FILE_CONSTRAINTS = {\n maxSizeBytes: 25 * 1024 * 1024, // 25MB\n minSizeBytes: 1, // At least 1 byte\n maxFilenameLength: 255,\n} as const;\n\n/**\n * File validation configuration\n */\nexport interface FileValidationConfig {\n maxSizeBytes?: number;\n minSizeBytes?: number;\n allowedMimeTypes?: ReadonlySet<string> | Set<string>;\n blockedExtensions?: ReadonlySet<string> | Set<string>;\n maxFilenameLength?: number;\n}\n\n/**\n * File validation result\n */\nexport interface FileValidationResult {\n valid: boolean;\n error?: string;\n errorCode?: 'FILE_TOO_LARGE' | 'FILE_TOO_SMALL' | 'INVALID_TYPE' | 'BLOCKED_EXTENSION' | 'FILENAME_TOO_LONG' | 'EMPTY_FILE';\n}\n\n/**\n * Get file extension from filename (lowercase)\n */\nexport function getFileExtension(filename: string): string {\n const lastDot = filename.lastIndexOf('.');\n if (lastDot === -1 || lastDot === filename.length - 1) {\n return '';\n }\n return filename.substring(lastDot).toLowerCase();\n}\n\n/**\n * Sanitize filename for safe storage\n * Removes path traversal attempts and dangerous characters\n */\nexport function sanitizeFilename(filename: string): string {\n // Remove path components\n let sanitized = filename.replace(/^.*[\\\\/]/, '');\n\n // Remove null bytes and other control characters\n sanitized = sanitized.replace(/[\\x00-\\x1f\\x7f]/g, '');\n\n // Replace problematic characters\n sanitized = sanitized.replace(/[<>:\"/\\\\|?*]/g, '_');\n\n // Trim whitespace and dots from start/end\n sanitized = sanitized.replace(/^[\\s.]+|[\\s.]+$/g, '');\n\n // If empty after sanitization, use default name\n if (!sanitized) {\n sanitized = 'unnamed_file';\n }\n\n // Limit length\n if (sanitized.length > DEFAULT_FILE_CONSTRAINTS.maxFilenameLength) {\n const ext = getFileExtension(sanitized);\n const nameWithoutExt = sanitized.slice(0, -ext.length || undefined);\n const maxNameLength = DEFAULT_FILE_CONSTRAINTS.maxFilenameLength - ext.length;\n sanitized = nameWithoutExt.slice(0, maxNameLength) + ext;\n }\n\n return sanitized;\n}\n\n/**\n * Validate a file before upload\n * Returns validation result with error details if invalid\n */\nexport function validateFile(\n file: File,\n config: FileValidationConfig = {}\n): FileValidationResult {\n const {\n maxSizeBytes = DEFAULT_FILE_CONSTRAINTS.maxSizeBytes,\n minSizeBytes = DEFAULT_FILE_CONSTRAINTS.minSizeBytes,\n allowedMimeTypes = ALLOWED_MIME_TYPES,\n blockedExtensions = BLOCKED_EXTENSIONS,\n maxFilenameLength = DEFAULT_FILE_CONSTRAINTS.maxFilenameLength,\n } = config;\n\n // Check file size\n if (file.size === 0) {\n return {\n valid: false,\n error: 'File is empty',\n errorCode: 'EMPTY_FILE',\n };\n }\n\n if (file.size < minSizeBytes) {\n return {\n valid: false,\n error: `File is too small. Minimum size is ${formatFileSize(minSizeBytes)}`,\n errorCode: 'FILE_TOO_SMALL',\n };\n }\n\n if (file.size > maxSizeBytes) {\n return {\n valid: false,\n error: `File is too large. Maximum size is ${formatFileSize(maxSizeBytes)}`,\n errorCode: 'FILE_TOO_LARGE',\n };\n }\n\n // Check filename length\n if (file.name.length > maxFilenameLength) {\n return {\n valid: false,\n error: `Filename is too long. Maximum length is ${maxFilenameLength} characters`,\n errorCode: 'FILENAME_TOO_LONG',\n };\n }\n\n // Check for blocked extensions\n const extension = getFileExtension(file.name);\n if (extension && blockedExtensions.has(extension)) {\n return {\n valid: false,\n error: `File type \"${extension}\" is not allowed for security reasons`,\n errorCode: 'BLOCKED_EXTENSION',\n };\n }\n\n // Check MIME type\n const mimeType = file.type || 'application/octet-stream';\n if (!allowedMimeTypes.has(mimeType)) {\n // Allow files without explicit type if extension is safe\n if (mimeType === 'application/octet-stream' && extension && !blockedExtensions.has(extension)) {\n // Let it pass - backend will verify\n } else {\n return {\n valid: false,\n error: `File type \"${mimeType}\" is not allowed. Allowed types: images, documents, audio, video`,\n errorCode: 'INVALID_TYPE',\n };\n }\n }\n\n return { valid: true };\n}\n\n/**\n * Format file size to human-readable string\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];\n}\n\n/**\n * Generate accept attribute string from ALLOWED_MIME_TYPES\n * Used to sync file input accept with validation rules\n */\nexport function generateAcceptAttribute(allowedMimeTypes: ReadonlySet<string> = ALLOWED_MIME_TYPES): string {\n const accepts: string[] = [];\n\n allowedMimeTypes.forEach((mimeType) => {\n accepts.push(mimeType);\n });\n\n return accepts.join(',');\n}\n\n/**\n * Rate limiter for file uploads\n * Prevents rapid successive uploads\n */\nexport class UploadRateLimiter {\n private uploadTimestamps: number[] = [];\n private readonly maxUploads: number;\n private readonly windowMs: number;\n\n constructor(maxUploads = 5, windowMs = 60000) {\n this.maxUploads = maxUploads;\n this.windowMs = windowMs;\n }\n\n /**\n * Check if upload is allowed\n * Returns true if allowed, false if rate limited\n */\n canUpload(): boolean {\n const now = Date.now();\n // Remove timestamps outside the window\n this.uploadTimestamps = this.uploadTimestamps.filter(\n (timestamp) => now - timestamp < this.windowMs\n );\n return this.uploadTimestamps.length < this.maxUploads;\n }\n\n /**\n * Record an upload attempt\n */\n recordUpload(): void {\n this.uploadTimestamps.push(Date.now());\n }\n\n /**\n * Get remaining uploads in current window\n */\n getRemainingUploads(): number {\n const now = Date.now();\n this.uploadTimestamps = this.uploadTimestamps.filter(\n (timestamp) => now - timestamp < this.windowMs\n );\n return Math.max(0, this.maxUploads - this.uploadTimestamps.length);\n }\n\n /**\n * Get time until next upload is allowed (in ms)\n * Returns 0 if upload is allowed now\n */\n getTimeUntilNextUpload(): number {\n if (this.canUpload()) return 0;\n const oldestTimestamp = Math.min(...this.uploadTimestamps);\n return Math.max(0, this.windowMs - (Date.now() - oldestTimestamp));\n }\n\n /**\n * Reset the rate limiter\n */\n reset(): void {\n this.uploadTimestamps = [];\n }\n}\n","import type {\n CevroMessengerConfig,\n SendMessageRequest,\n Message,\n Conversation,\n ConversationHistoryItem,\n ConversationHistoryResponse,\n ConversationMessagesResponse,\n Agent,\n LocaleStrings,\n WidgetAppearanceConfig,\n} from '../types';\nimport { collectSessionData } from '../utils/session';\nimport {\n validateFile,\n sanitizeFilename,\n UploadRateLimiter,\n} from '../utils/file-validation';\n\n/**\n * API client for communicating with Cevro backend\n */\nexport class ApiClient {\n private config: CevroMessengerConfig;\n private accessToken: string | null = null;\n private contactId: string | null = null;\n private currentTicketId: string | null = null;\n private visitorToken: string | null = null;\n private currentAgent: Agent | null = null;\n private uploadRateLimiter: UploadRateLimiter;\n private visitorId: string | null = null;\n\n constructor(config: CevroMessengerConfig) {\n this.config = config;\n this.uploadRateLimiter = new UploadRateLimiter();\n }\n\n /**\n * Update config reference (used when config object is replaced)\n */\n updateConfig(config: CevroMessengerConfig): void {\n this.config = config;\n }\n\n /**\n * Set visitor token for authenticated requests\n */\n setVisitorToken(token: string): void {\n this.visitorToken = token;\n }\n\n /**\n * Get visitor token\n */\n getVisitorToken(): string | null {\n return this.visitorToken;\n }\n\n /**\n * Set access token for authenticated requests\n */\n setAccessToken(token: string): void {\n this.accessToken = token;\n }\n\n /**\n * Get current contact ID\n */\n getContactId(): string | null {\n return this.contactId;\n }\n\n /**\n * Get current ticket ID\n */\n getCurrentTicketId(): string | null {\n return this.currentTicketId;\n }\n\n /**\n * Set current ticket ID\n */\n setCurrentTicketId(ticketId: string): void {\n this.currentTicketId = ticketId;\n }\n\n /**\n * Get current agent info\n */\n getCurrentAgent(): Agent | null {\n return this.currentAgent;\n }\n\n /**\n * Make API request\n */\n private async request<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<T> {\n const url = `${this.config.apiBase}${endpoint}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(options.headers as Record<string, string> || {}),\n };\n\n // Add workspace headers for gateway auth\n if (this.config.workspaceId) {\n headers['X-Workspace-Id'] = this.config.workspaceId;\n }\n if (this.config.brandId) {\n headers['X-Brand-Id'] = this.config.brandId;\n }\n if (this.visitorToken) {\n headers['X-Visitor-Token'] = this.visitorToken;\n }\n if (this.config.player?.playerId) {\n headers['X-Player-Id'] = this.config.player.playerId;\n }\n if (this.config.player?.playerHash) {\n headers['X-Player-Hash'] = this.config.player.playerHash;\n }\n if (this.visitorId) {\n headers['X-Visitor-Id'] = this.visitorId;\n }\n\n if (this.accessToken) {\n headers['Authorization'] = `Bearer ${this.accessToken}`;\n }\n\n const response = await fetch(url, {\n ...options,\n headers,\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ message: response.statusText }));\n throw new Error(error.message || `Request failed: ${response.status}`);\n }\n\n return response.json();\n }\n\n /**\n * Initialize a chat session\n * Called when chat opens to create/restore session\n */\n async initSession(\n visitorId: string | null,\n visitorContactInfo?: { firstName: string; email: string } | null,\n options?: { forceNewTicket?: boolean }\n ): Promise<{\n sessionId: string;\n contactId: string;\n ticketId: string;\n visitorId: string;\n isNewSession: boolean;\n isNewTicket: boolean;\n ticketClosed?: boolean;\n ticketClosedReason?: string;\n agent?: Agent;\n typingConfig?: {\n onDurationMs: number;\n offDurationMs: number;\n };\n messages?: Message[];\n hasMoreMessages?: boolean;\n cursor?: string;\n locale?: Partial<LocaleStrings>;\n requireContactInfo?: boolean;\n missingFields?: ('firstName' | 'email')[];\n }> {\n const session = collectSessionData();\n\n const payload: any = {\n visitorId,\n session,\n brandId: this.config.brandId,\n // Use visitor contact info if provided, otherwise fall back to player config\n firstName: visitorContactInfo?.firstName || this.config.player?.firstName,\n lastName: this.config.player?.lastName,\n email: (visitorContactInfo?.email || this.config.player?.email) || undefined,\n phone: this.config.player?.phone,\n customAttributes: this.config.player?.customAttributes,\n forceNewTicket: options?.forceNewTicket,\n };\n\n // Add player data for authenticated users (for merge logic)\n if (this.config.player?.playerId) {\n payload.playerId = this.config.player.playerId;\n payload.playerHash = this.config.player.playerHash;\n }\n\n const result = await this.request<any>('/api/v1/sdk/session', {\n method: 'POST',\n body: JSON.stringify(payload),\n headers: visitorId ? { 'X-Visitor-Id': visitorId } : undefined,\n });\n\n // If contact info is required, return early without storing session\n if (result.requireContactInfo && result.missingFields?.length > 0) {\n return {\n sessionId: '',\n contactId: '',\n ticketId: '',\n visitorId: result.visitorId || '',\n isNewSession: false,\n isNewTicket: false,\n requireContactInfo: result.requireContactInfo,\n missingFields: result.missingFields,\n };\n }\n\n // Store contact, ticket IDs and agent info\n this.contactId = result.contactId;\n this.currentTicketId = result.ticketId;\n if (result.agent) {\n this.currentAgent = result.agent;\n }\n\n return {\n sessionId: result.sessionId,\n contactId: result.contactId,\n ticketId: result.ticketId,\n visitorId: result.visitorId,\n isNewSession: result.isNewSession,\n isNewTicket: result.isNewTicket,\n ticketClosed: result.ticketClosed,\n ticketClosedReason: result.ticketClosedReason,\n agent: result.agent,\n typingConfig: result.typingConfig,\n messages: result.messages?.map((msg: any) => this.normalizeMessage(msg)),\n hasMoreMessages: result.hasMoreMessages,\n cursor: result.cursor,\n locale: result.locale,\n requireContactInfo: result.requireContactInfo,\n };\n }\n\n /**\n * Send a message to an existing conversation\n */\n async sendMessage(message: string, assetId?: string): Promise<Message> {\n if (!this.contactId || !this.currentTicketId) {\n throw new Error('No active session. Call initSession first.');\n }\n\n const payload: SendMessageRequest = {\n contactId: this.contactId,\n ticketId: this.currentTicketId,\n message,\n assetId,\n };\n\n const result = await this.request<any>('/api/v1/sdk/send', {\n method: 'POST',\n body: JSON.stringify(payload),\n });\n\n // Server returns {success: true, message: {...}}, extract the message\n return this.normalizeMessage(result.message || result);\n }\n\n /**\n * Get messages for the current ticket (for authenticated users)\n */\n async getMessages(ticketId?: string): Promise<Message[]> {\n const targetTicketId = ticketId || this.currentTicketId;\n if (!targetTicketId) {\n throw new Error('No ticket ID available');\n }\n\n const result = await this.request<any>(\n `/api/v1/messages/my-tickets?supportTicketId=${targetTicketId}`\n );\n\n const messages = result.results || result.messages || result || [];\n return messages.map((msg: any) => this.normalizeMessage(msg));\n }\n\n /**\n * Get user's support tickets (for authenticated users)\n */\n async getMyTickets(): Promise<Conversation[]> {\n const result = await this.request<any>('/api/v1/messages/my-tickets');\n\n const tickets = result.results || result.tickets || result || [];\n return tickets.map((ticket: any) => this.normalizeConversation(ticket));\n }\n\n /**\n * Upload a file using presigned S3 URL for better performance.\n * The file is uploaded directly to S3, bypassing the backend.\n *\n * Security features:\n * - File size validation (client-side)\n * - MIME type whitelist validation\n * - Blocked extension check\n * - Rate limiting (uploads per minute)\n * - Filename sanitization\n *\n * @param file - The file to upload\n * @param onProgress - Optional callback for upload progress (0-100)\n * @returns The asset ID to use when sending messages\n * @throws Error if validation fails or rate limited\n */\n async uploadFile(\n file: File,\n onProgress?: (progress: number) => void\n ): Promise<string> {\n // Step 0: Rate limiting check\n if (!this.uploadRateLimiter.canUpload()) {\n const waitTime = Math.ceil(this.uploadRateLimiter.getTimeUntilNextUpload() / 1000);\n throw new Error(`Too many uploads. Please wait ${waitTime} seconds before uploading again.`);\n }\n\n // Step 1: Validate file (size, type, extension)\n const validation = validateFile(file);\n if (!validation.valid) {\n throw new Error(validation.error || 'File validation failed');\n }\n\n // Step 2: Sanitize filename\n const sanitizedFilename = sanitizeFilename(file.name);\n\n // Step 3: Record upload attempt for rate limiting\n this.uploadRateLimiter.recordUpload();\n\n // Step 4: Get presigned URL from backend\n const { uploadUrl, assetId } = await this.request<{\n uploadUrl: string;\n assetId: string;\n expiresIn: number;\n }>('/api/v1/sdk/upload-url', {\n method: 'POST',\n body: JSON.stringify({\n filename: sanitizedFilename,\n contentType: file.type || 'application/octet-stream',\n size: file.size,\n }),\n });\n\n // Step 5: Upload file directly to S3\n await this.uploadToS3(uploadUrl, file, onProgress);\n\n return assetId;\n }\n\n /**\n * Upload file directly to S3 using presigned URL\n */\n private async uploadToS3(\n uploadUrl: string,\n file: File,\n onProgress?: (progress: number) => void\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable && onProgress) {\n const progress = Math.round((event.loaded / event.total) * 100);\n onProgress(progress);\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve();\n } else {\n reject(new Error(`Upload failed with status ${xhr.status}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Upload failed'));\n });\n\n xhr.open('PUT', uploadUrl);\n xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');\n xhr.send(file);\n });\n }\n\n /**\n * Normalize message object from API response\n */\n private normalizeMessage(data: any): Message {\n return {\n id: data.objectId || data.id,\n body: data.body || '',\n inbound: data.inbound || false,\n outbound: data.outbound || !data.inbound,\n createdAt: data.createdAt || new Date().toISOString(),\n type: data.type || 'text',\n mediaUrl: data.mediaUrl,\n mediaType: data.mediaType,\n status: data.status || 'sent',\n richContent: data.richContent,\n };\n }\n\n /**\n * Normalize conversation object from API response\n */\n private normalizeConversation(data: any): Conversation {\n return {\n id: data.objectId || data.id,\n conversationId: data.conversationId || data.objectId || data.id,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n status: data.resolved ? 'resolved' : data.escalated ? 'escalated' : 'open',\n unreadCount: data.unreadCount || 0,\n lastMessage: data.latestMessage ? this.normalizeMessage(data.latestMessage) : undefined,\n };\n }\n\n /**\n * Get Centrifugo connection token for real-time messaging\n *\n * For authenticated players: uses playerHash for identity verification\n * For visitors: uses server-signed visitorToken for security\n *\n * @param visitorToken - Server-signed visitor token (optional, server generates if not provided)\n */\n async getConnectionToken(visitorToken?: string | null): Promise<{\n token: string;\n visitorId: string;\n visitorToken: string;\n expiresAt: number;\n }> {\n const payload: any = {\n workspaceId: this.config.workspaceId,\n brandId: this.config.brandId,\n };\n\n if (visitorToken) {\n payload.visitorToken = visitorToken;\n }\n\n // Add player data for authenticated users\n if (this.config.player?.playerId) {\n payload.playerId = this.config.player.playerId;\n payload.playerHash = this.config.player.playerHash;\n payload.email = this.config.player.email || undefined;\n payload.firstName = this.config.player.firstName;\n }\n\n const result = await this.request<{\n token: string;\n visitorId: string;\n visitorToken: string;\n expiresAt: number;\n }>('/api/v1/sdk/token', {\n method: 'POST',\n body: JSON.stringify(payload),\n });\n\n return result;\n }\n\n /**\n * Refresh Centrifugo token before expiration\n */\n async refreshConnectionToken(visitorToken?: string | null): Promise<{\n token: string;\n visitorToken: string;\n expiresAt: number;\n }> {\n return this.getConnectionToken(visitorToken);\n }\n\n /**\n * Submit CSAT rating for a closed conversation\n */\n async submitCSAT(\n ticketId: string,\n contactId: string,\n rating: number,\n feedback?: string\n ): Promise<void> {\n await this.request('/api/v1/sdk/csat', {\n method: 'POST',\n body: JSON.stringify({\n ticketId,\n contactId,\n rating,\n feedback,\n }),\n });\n }\n\n /**\n * Get past conversations for the current contact\n */\n async getConversations(cursor?: string): Promise<{\n conversations: ConversationHistoryItem[];\n hasMore: boolean;\n cursor?: string;\n }> {\n const params = new URLSearchParams();\n if (cursor) params.set('cursor', cursor);\n\n const url = params.toString()\n ? `/api/v1/sdk/conversations?${params.toString()}`\n : '/api/v1/sdk/conversations';\n\n const result = await this.request<ConversationHistoryResponse>(url);\n\n return {\n conversations: result.conversations || [],\n hasMore: result.hasMore || false,\n cursor: result.cursor,\n };\n }\n\n /**\n * Get messages for a past conversation (paginated)\n */\n async getConversationMessages(ticketId: string, cursor?: string): Promise<{\n messages: Message[];\n hasMore: boolean;\n cursor?: string;\n }> {\n const params = new URLSearchParams();\n if (cursor) params.set('cursor', cursor);\n\n const base = `/api/v1/sdk/conversations/${ticketId}/messages`;\n const url = params.toString() ? `${base}?${params.toString()}` : base;\n\n const result = await this.request<ConversationMessagesResponse>(url);\n\n return {\n messages: (result.messages || []).map((msg: any) => this.normalizeMessage(msg)),\n hasMore: result.hasMore || false,\n cursor: result.cursor,\n };\n }\n\n /**\n * Set visitor ID (sent as X-Visitor-Id header on all requests)\n */\n setVisitorId(id: string): void {\n this.visitorId = id;\n }\n\n async getWidgetConfig(): Promise<WidgetAppearanceConfig> {\n try {\n const result = await this.request<WidgetAppearanceConfig>('/api/v1/sdk/widget-config', {\n method: 'GET',\n });\n return result;\n } catch (error) {\n // Return empty config on error - widget will use defaults\n return {};\n }\n }\n\n /**\n * Clear stored data (on shutdown)\n */\n clear(): void {\n this.accessToken = null;\n this.contactId = null;\n this.currentTicketId = null;\n this.visitorToken = null;\n this.visitorId = null;\n this.currentAgent = null;\n }\n}\n","/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise, SuppressedError, Symbol */\r\n\r\n\r\nfunction __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\ntypeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\n\nfunction getDefaultExportFromCjs (x) {\n\treturn x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;\n}\n\nvar events = {exports: {}};\n\nvar R = typeof Reflect === 'object' ? Reflect : null;\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n };\n\nvar ReflectOwnKeys;\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys;\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n};\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nevents.exports = EventEmitter;\nevents.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction _getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the `throw` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n checkListener(listener);\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = _getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n if (arguments.length === 0)\n return this.listener.call(this.target);\n return this.listener.apply(this.target, arguments);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n checkListener(listener);\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n checkListener(listener);\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n checkListener(listener);\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n\nfunction once(emitter, name) {\n return new Promise(function (resolve, reject) {\n function errorListener(err) {\n emitter.removeListener(name, resolver);\n reject(err);\n }\n\n function resolver() {\n if (typeof emitter.removeListener === 'function') {\n emitter.removeListener('error', errorListener);\n }\n resolve([].slice.call(arguments));\n }\n eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n if (name !== 'error') {\n addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n }\n });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n if (typeof emitter.on === 'function') {\n eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n if (typeof emitter.on === 'function') {\n if (flags.once) {\n emitter.once(name, listener);\n } else {\n emitter.on(name, listener);\n }\n } else if (typeof emitter.addEventListener === 'function') {\n // EventTarget does not have `error` event semantics like Node\n // EventEmitters, we do not listen for `error` events here.\n emitter.addEventListener(name, function wrapListener(arg) {\n // IE does not have builtin `{ once: true }` support so we\n // have to do it manually.\n if (flags.once) {\n emitter.removeEventListener(name, wrapListener);\n }\n listener(arg);\n });\n } else {\n throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n }\n}\n\nvar eventsExports = events.exports;\nvar EventEmitter$1 = /*@__PURE__*/getDefaultExportFromCjs(eventsExports);\n\nvar errorCodes;\n(function (errorCodes) {\n errorCodes[errorCodes[\"timeout\"] = 1] = \"timeout\";\n errorCodes[errorCodes[\"transportClosed\"] = 2] = \"transportClosed\";\n errorCodes[errorCodes[\"clientDisconnected\"] = 3] = \"clientDisconnected\";\n errorCodes[errorCodes[\"clientClosed\"] = 4] = \"clientClosed\";\n errorCodes[errorCodes[\"clientConnectToken\"] = 5] = \"clientConnectToken\";\n errorCodes[errorCodes[\"clientRefreshToken\"] = 6] = \"clientRefreshToken\";\n errorCodes[errorCodes[\"subscriptionUnsubscribed\"] = 7] = \"subscriptionUnsubscribed\";\n errorCodes[errorCodes[\"subscriptionSubscribeToken\"] = 8] = \"subscriptionSubscribeToken\";\n errorCodes[errorCodes[\"subscriptionRefreshToken\"] = 9] = \"subscriptionRefreshToken\";\n errorCodes[errorCodes[\"transportWriteError\"] = 10] = \"transportWriteError\";\n errorCodes[errorCodes[\"connectionClosed\"] = 11] = \"connectionClosed\";\n errorCodes[errorCodes[\"badConfiguration\"] = 12] = \"badConfiguration\";\n})(errorCodes || (errorCodes = {}));\nvar connectingCodes;\n(function (connectingCodes) {\n connectingCodes[connectingCodes[\"connectCalled\"] = 0] = \"connectCalled\";\n connectingCodes[connectingCodes[\"transportClosed\"] = 1] = \"transportClosed\";\n connectingCodes[connectingCodes[\"noPing\"] = 2] = \"noPing\";\n connectingCodes[connectingCodes[\"subscribeTimeout\"] = 3] = \"subscribeTimeout\";\n connectingCodes[connectingCodes[\"unsubscribeError\"] = 4] = \"unsubscribeError\";\n})(connectingCodes || (connectingCodes = {}));\nvar disconnectedCodes;\n(function (disconnectedCodes) {\n disconnectedCodes[disconnectedCodes[\"disconnectCalled\"] = 0] = \"disconnectCalled\";\n disconnectedCodes[disconnectedCodes[\"unauthorized\"] = 1] = \"unauthorized\";\n disconnectedCodes[disconnectedCodes[\"badProtocol\"] = 2] = \"badProtocol\";\n disconnectedCodes[disconnectedCodes[\"messageSizeLimit\"] = 3] = \"messageSizeLimit\";\n})(disconnectedCodes || (disconnectedCodes = {}));\nvar subscribingCodes;\n(function (subscribingCodes) {\n subscribingCodes[subscribingCodes[\"subscribeCalled\"] = 0] = \"subscribeCalled\";\n subscribingCodes[subscribingCodes[\"transportClosed\"] = 1] = \"transportClosed\";\n})(subscribingCodes || (subscribingCodes = {}));\nvar unsubscribedCodes;\n(function (unsubscribedCodes) {\n unsubscribedCodes[unsubscribedCodes[\"unsubscribeCalled\"] = 0] = \"unsubscribeCalled\";\n unsubscribedCodes[unsubscribedCodes[\"unauthorized\"] = 1] = \"unauthorized\";\n unsubscribedCodes[unsubscribedCodes[\"clientClosed\"] = 2] = \"clientClosed\";\n})(unsubscribedCodes || (unsubscribedCodes = {}));\nvar subscriptionFlags;\n(function (subscriptionFlags) {\n subscriptionFlags[subscriptionFlags[\"channelCompaction\"] = 1] = \"channelCompaction\";\n})(subscriptionFlags || (subscriptionFlags = {}));\n\n/** State of client. */\nvar State;\n(function (State) {\n State[\"Disconnected\"] = \"disconnected\";\n State[\"Connecting\"] = \"connecting\";\n State[\"Connected\"] = \"connected\";\n})(State || (State = {}));\n/** State of Subscription */\nvar SubscriptionState;\n(function (SubscriptionState) {\n SubscriptionState[\"Unsubscribed\"] = \"unsubscribed\";\n SubscriptionState[\"Subscribing\"] = \"subscribing\";\n SubscriptionState[\"Subscribed\"] = \"subscribed\";\n})(SubscriptionState || (SubscriptionState = {}));\n\n/** @internal */\nfunction startsWith(value, prefix) {\n return value.lastIndexOf(prefix, 0) === 0;\n}\n/** @internal */\nfunction isFunction(value) {\n if (value === undefined || value === null) {\n return false;\n }\n return typeof value === 'function';\n}\n/** @internal */\nfunction log(level, args) {\n if (globalThis.console) {\n const logger = globalThis.console[level];\n if (isFunction(logger)) {\n logger.apply(globalThis.console, args);\n }\n }\n}\nfunction randomInt(min, max) {\n return Math.floor(Math.random() * (max - min + 1) + min);\n}\n/** @internal */\nfunction backoff(step, min, max) {\n // Full jitter technique, see:\n // https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/\n if (step > 31) {\n step = 31;\n }\n const interval = randomInt(0, Math.min(max, min * Math.pow(2, step)));\n return Math.min(max, min + interval);\n}\n/** @internal */\nfunction errorExists(data) {\n return 'error' in data && data.error !== null;\n}\n/** @internal */\nfunction ttlMilliseconds(ttl) {\n // https://stackoverflow.com/questions/12633405/what-is-the-maximum-delay-for-setinterval\n return Math.min(ttl * 1000, 2147483647);\n}\n\n/** Subscription to a channel */\nclass Subscription extends EventEmitter$1 {\n /** Subscription constructor should not be used directly, create subscriptions using Client method. */\n constructor(centrifuge, channel, options) {\n super();\n this._resubscribeTimeout = null;\n this._refreshTimeout = null;\n this.channel = channel;\n this.state = SubscriptionState.Unsubscribed;\n this._centrifuge = centrifuge;\n this._token = '';\n this._getToken = null;\n this._data = null;\n this._getData = null;\n this._recover = false;\n this._offset = null;\n this._epoch = null;\n this._id = 0;\n this._recoverable = false;\n this._positioned = false;\n this._joinLeave = false;\n this._minResubscribeDelay = 500;\n this._maxResubscribeDelay = 20000;\n this._resubscribeTimeout = null;\n this._resubscribeAttempts = 0;\n this._promises = {};\n this._promiseId = 0;\n this._inflight = false;\n this._refreshTimeout = null;\n this._delta = '';\n this._delta_negotiated = false;\n this._tagsFilter = null;\n this._prevValue = null;\n this._unsubPromise = Promise.resolve();\n this._setOptions(options);\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n if (this._centrifuge._debugEnabled) {\n this.on('state', (ctx) => {\n this._debug('subscription state', channel, ctx.oldState, '->', ctx.newState);\n });\n this.on('error', (ctx) => {\n this._debug('subscription error', channel, ctx);\n });\n }\n else {\n // Avoid unhandled exception in EventEmitter for non-set error handler.\n this.on('error', function () { Function.prototype(); });\n }\n }\n /** ready returns a Promise which resolves upon subscription goes to Subscribed\n * state and rejects in case of subscription goes to Unsubscribed state.\n * Optional timeout can be passed.*/\n ready(timeout) {\n if (this.state === SubscriptionState.Unsubscribed) {\n return Promise.reject({ code: errorCodes.subscriptionUnsubscribed, message: this.state });\n }\n if (this.state === SubscriptionState.Subscribed) {\n return Promise.resolve();\n }\n return new Promise((res, rej) => {\n const ctx = {\n resolve: res,\n reject: rej\n };\n if (timeout) {\n ctx.timeout = setTimeout(function () {\n rej({ code: errorCodes.timeout, message: 'timeout' });\n }, timeout);\n }\n this._promises[this._nextPromiseId()] = ctx;\n });\n }\n /** subscribe to a channel.*/\n subscribe() {\n if (this._isSubscribed()) {\n return;\n }\n this._resubscribeAttempts = 0;\n this._setSubscribing(subscribingCodes.subscribeCalled, 'subscribe called');\n }\n /** unsubscribe from a channel, keeping position state.*/\n unsubscribe() {\n this._unsubPromise = this._setUnsubscribed(unsubscribedCodes.unsubscribeCalled, 'unsubscribe called', true);\n }\n /** publish data to a channel.*/\n publish(data) {\n return __awaiter(this, void 0, void 0, function* () {\n yield this._methodCall();\n return this._centrifuge.publish(this.channel, data);\n });\n }\n /** get online presence for a channel.*/\n presence() {\n return __awaiter(this, void 0, void 0, function* () {\n yield this._methodCall();\n return this._centrifuge.presence(this.channel);\n });\n }\n /** presence stats for a channel (num clients and unique users).*/\n presenceStats() {\n return __awaiter(this, void 0, void 0, function* () {\n yield this._methodCall();\n return this._centrifuge.presenceStats(this.channel);\n });\n }\n /** history for a channel. By default it does not return publications (only current\n * StreamPosition data) – provide an explicit limit > 0 to load publications.*/\n history(opts) {\n return __awaiter(this, void 0, void 0, function* () {\n yield this._methodCall();\n return this._centrifuge.history(this.channel, opts);\n });\n }\n /**\n * Sets server-side tags filter for the subscription.\n * This only applies on the next subscription attempt, not the current one.\n * Cannot be used together with delta option.\n *\n * @param tagsFilter - Filter configuration object or null to remove filter\n * @throws {Error} If both delta and tagsFilter are configured\n *\n * @example\n * ```typescript\n * // Simple equality filter\n * sub.setTagsFilter({\n * key: 'ticker',\n * cmp: 'eq',\n * val: 'BTC'\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Complex filter with logical operators\n * sub.setTagsFilter({\n * op: 'and',\n * nodes: [\n * { key: 'ticker', cmp: 'eq', val: 'BTC' },\n * { key: 'price', cmp: 'gt', val: '50000' }\n * ]\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Filter with IN operator\n * sub.setTagsFilter({\n * key: 'ticker',\n * cmp: 'in',\n * vals: ['BTC', 'ETH', 'SOL']\n * });\n * ```\n */\n setTagsFilter(tagsFilter) {\n if (tagsFilter && this._delta) {\n throw new Error('cannot use delta and tagsFilter together');\n }\n this._tagsFilter = tagsFilter;\n }\n /** setData allows setting subscription data. This only applied on the next subscription attempt,\n * Note that if getData callback is configured, it will override this value during resubscriptions. */\n setData(data) {\n this._data = data;\n }\n _methodCall() {\n if (this._isSubscribed()) {\n return Promise.resolve();\n }\n if (this._isUnsubscribed()) {\n return Promise.reject({\n code: errorCodes.subscriptionUnsubscribed,\n message: this.state\n });\n }\n return new Promise((resolve, reject) => {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n const timeoutDuration = this._centrifuge._config.timeout;\n const timeout = setTimeout(() => {\n reject({ code: errorCodes.timeout, message: 'timeout' });\n }, timeoutDuration);\n this._promises[this._nextPromiseId()] = {\n timeout,\n resolve,\n reject\n };\n });\n }\n _nextPromiseId() {\n return ++this._promiseId;\n }\n _needRecover() {\n return this._recover === true;\n }\n _isUnsubscribed() {\n return this.state === SubscriptionState.Unsubscribed;\n }\n _isSubscribing() {\n return this.state === SubscriptionState.Subscribing;\n }\n _isSubscribed() {\n return this.state === SubscriptionState.Subscribed;\n }\n _setState(newState) {\n if (this.state !== newState) {\n const oldState = this.state;\n this.state = newState;\n this.emit('state', { newState, oldState, channel: this.channel });\n return true;\n }\n return false;\n }\n _usesToken() {\n return this._token !== '' || this._getToken !== null;\n }\n _clearSubscribingState() {\n this._resubscribeAttempts = 0;\n this._clearResubscribeTimeout();\n }\n _clearSubscribedState() {\n this._clearRefreshTimeout();\n }\n _setSubscribed(result) {\n if (!this._isSubscribing()) {\n return;\n }\n this._clearSubscribingState();\n if (result.id) {\n this._id = result.id;\n }\n if (result.recoverable) {\n this._recover = true;\n this._offset = result.offset || 0;\n this._epoch = result.epoch || '';\n }\n if (result.delta) {\n this._delta_negotiated = true;\n }\n else {\n this._delta_negotiated = false;\n }\n this._setState(SubscriptionState.Subscribed);\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n const ctx = this._centrifuge._getSubscribeContext(this.channel, result);\n this.emit('subscribed', ctx);\n this._resolvePromises();\n const pubs = result.publications;\n if (pubs && pubs.length > 0) {\n for (const i in pubs) {\n if (!pubs.hasOwnProperty(i)) {\n continue;\n }\n this._handlePublication(pubs[i]);\n }\n }\n if (result.expires === true) {\n this._refreshTimeout = setTimeout(() => this._refresh(), ttlMilliseconds(result.ttl));\n }\n }\n _setSubscribing(code, reason) {\n return __awaiter(this, void 0, void 0, function* () {\n if (this._isSubscribing()) {\n return;\n }\n if (this._isSubscribed()) {\n this._clearSubscribedState();\n }\n if (this._setState(SubscriptionState.Subscribing)) {\n this.emit('subscribing', { channel: this.channel, code: code, reason: reason });\n }\n // @ts-ignore – for performance reasons only await _unsubPromise for emulution case where it's required.\n if (this._centrifuge._transport && this._centrifuge._transport.emulation()) {\n yield this._unsubPromise;\n }\n if (!this._isSubscribing()) {\n return;\n }\n this._subscribe();\n });\n }\n _subscribe() {\n this._debug('subscribing on', this.channel);\n if (!this._isTransportOpen()) {\n this._debug('delay subscribe on', this.channel, 'till connected');\n return null;\n }\n if (this._inflight) {\n return null;\n }\n this._inflight = true;\n if (this._canSubscribeWithoutGettingToken()) {\n return this._subscribeWithoutToken();\n }\n this._getSubscriptionToken()\n .then(token => this._handleTokenResponse(token))\n .catch(e => this._handleTokenError(e));\n return null;\n }\n _isTransportOpen() {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n return this._centrifuge._transportIsOpen;\n }\n _canSubscribeWithoutGettingToken() {\n return !this._usesToken() || !!this._token;\n }\n _subscribeWithoutToken() {\n if (this._getData) {\n this._getDataAndSubscribe(this._token);\n return null;\n }\n else {\n return this._sendSubscribe(this._token);\n }\n }\n _getDataAndSubscribe(token) {\n if (!this._getData) {\n this._inflight = false;\n return;\n }\n this._getData({ channel: this.channel })\n .then(data => {\n if (!this._isSubscribing()) {\n this._inflight = false;\n return;\n }\n this._data = data;\n this._sendSubscribe(token);\n })\n .catch(e => this._handleGetDataError(e));\n }\n _handleGetDataError(error) {\n if (!this._isSubscribing()) {\n this._inflight = false;\n return;\n }\n if (error instanceof UnauthorizedError) {\n this._inflight = false;\n this._failUnauthorized();\n return;\n }\n this.emit('error', {\n type: 'subscribeData',\n channel: this.channel,\n error: {\n code: errorCodes.badConfiguration,\n message: (error === null || error === void 0 ? void 0 : error.toString()) || ''\n }\n });\n this._inflight = false;\n this._scheduleResubscribe();\n }\n _handleTokenResponse(token) {\n if (!this._isSubscribing()) {\n this._inflight = false;\n return;\n }\n if (!token) {\n this._inflight = false;\n this._failUnauthorized();\n return;\n }\n this._token = token;\n if (this._getData) {\n this._getDataAndSubscribe(token);\n }\n else {\n this._sendSubscribe(token);\n }\n }\n _handleTokenError(error) {\n if (!this._isSubscribing()) {\n this._inflight = false;\n return;\n }\n if (error instanceof UnauthorizedError) {\n this._inflight = false;\n this._failUnauthorized();\n return;\n }\n this.emit('error', {\n type: 'subscribeToken',\n channel: this.channel,\n error: {\n code: errorCodes.subscriptionSubscribeToken,\n message: (error === null || error === void 0 ? void 0 : error.toString()) || ''\n }\n });\n this._inflight = false;\n this._scheduleResubscribe();\n }\n _sendSubscribe(token) {\n if (!this._isTransportOpen()) {\n this._inflight = false;\n return null;\n }\n const cmd = this._buildSubscribeCommand(token);\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n this._centrifuge._call(cmd).then(resolveCtx => {\n this._inflight = false;\n const result = resolveCtx.reply.subscribe;\n this._handleSubscribeResponse(result);\n if (resolveCtx.next) {\n resolveCtx.next();\n }\n }, rejectCtx => {\n this._inflight = false;\n this._handleSubscribeError(rejectCtx.error);\n if (rejectCtx.next) {\n rejectCtx.next();\n }\n });\n return cmd;\n }\n _buildSubscribeCommand(token) {\n const req = { channel: this.channel };\n if (token)\n req.token = token;\n if (this._data)\n req.data = this._data;\n if (this._positioned)\n req.positioned = true;\n if (this._recoverable)\n req.recoverable = true;\n if (this._joinLeave)\n req.join_leave = true;\n req.flag = subscriptionFlags.channelCompaction;\n if (this._needRecover()) {\n req.recover = true;\n const offset = this._getOffset();\n if (offset)\n req.offset = offset;\n const epoch = this._getEpoch();\n if (epoch)\n req.epoch = epoch;\n }\n if (this._delta)\n req.delta = this._delta;\n if (this._tagsFilter)\n req.tf = this._tagsFilter;\n return { subscribe: req };\n }\n _debug(...args) {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n this._centrifuge._debug(...args);\n }\n _handleSubscribeError(error) {\n if (!this._isSubscribing()) {\n return;\n }\n if (error.code === errorCodes.timeout) {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n this._centrifuge._disconnect(connectingCodes.subscribeTimeout, 'subscribe timeout', true);\n return;\n }\n this._subscribeError(error);\n }\n _handleSubscribeResponse(result) {\n if (!this._isSubscribing()) {\n return;\n }\n this._setSubscribed(result);\n }\n _setUnsubscribed(code, reason, sendUnsubscribe) {\n if (this._isUnsubscribed()) {\n return Promise.resolve();\n }\n let promise = Promise.resolve();\n if (this._isSubscribed()) {\n if (sendUnsubscribe) {\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n promise = this._centrifuge._unsubscribe(this);\n }\n this._clearSubscribedState();\n }\n else if (this._isSubscribing()) {\n if (this._inflight && sendUnsubscribe) {\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n promise = this._centrifuge._unsubscribe(this);\n }\n this._clearSubscribingState();\n }\n this._inflight = false;\n if (this._setState(SubscriptionState.Unsubscribed)) {\n this.emit('unsubscribed', { channel: this.channel, code: code, reason: reason });\n }\n this._rejectPromises({ code: errorCodes.subscriptionUnsubscribed, message: this.state });\n return promise;\n }\n _handlePublication(pub) {\n if (this._delta && this._delta_negotiated) {\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n const { newData, newPrevValue } = this._centrifuge._codec.applyDeltaIfNeeded(pub, this._prevValue);\n pub.data = newData;\n this._prevValue = newPrevValue;\n }\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n const ctx = this._centrifuge._getPublicationContext(this.channel, pub);\n this.emit('publication', ctx);\n if (pub.offset) {\n this._offset = pub.offset;\n }\n }\n _handleJoin(join) {\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n const info = this._centrifuge._getJoinLeaveContext(join.info);\n this.emit('join', { channel: this.channel, info: info });\n }\n _handleLeave(leave) {\n // @ts-ignore – we are hiding some methods from public API autocompletion.\n const info = this._centrifuge._getJoinLeaveContext(leave.info);\n this.emit('leave', { channel: this.channel, info: info });\n }\n _resolvePromises() {\n for (const id in this._promises) {\n if (!this._promises.hasOwnProperty(id)) {\n continue;\n }\n if (this._promises[id].timeout) {\n clearTimeout(this._promises[id].timeout);\n }\n this._promises[id].resolve();\n delete this._promises[id];\n }\n }\n _rejectPromises(err) {\n for (const id in this._promises) {\n if (!this._promises.hasOwnProperty(id)) {\n continue;\n }\n if (this._promises[id].timeout) {\n clearTimeout(this._promises[id].timeout);\n }\n this._promises[id].reject(err);\n delete this._promises[id];\n }\n }\n _scheduleResubscribe() {\n if (!this._isSubscribing()) {\n this._debug('not in subscribing state, skip resubscribe scheduling', this.channel);\n return;\n }\n const self = this;\n const delay = this._getResubscribeDelay();\n this._resubscribeTimeout = setTimeout(function () {\n if (self._isSubscribing()) {\n self._subscribe();\n }\n }, delay);\n this._debug('resubscribe scheduled after ' + delay, this.channel);\n }\n _subscribeError(err) {\n if (!this._isSubscribing()) {\n return;\n }\n if (err.code < 100 || err.code === 109 || err.temporary === true) {\n if (err.code === 109) { // Token expired error.\n this._token = '';\n }\n const errContext = {\n channel: this.channel,\n type: 'subscribe',\n error: err\n };\n if (this._centrifuge.state === State.Connected) {\n this.emit('error', errContext);\n }\n this._scheduleResubscribe();\n }\n else {\n this._setUnsubscribed(err.code, err.message, false);\n }\n }\n _getResubscribeDelay() {\n const delay = backoff(this._resubscribeAttempts, this._minResubscribeDelay, this._maxResubscribeDelay);\n this._resubscribeAttempts++;\n return delay;\n }\n _setOptions(options) {\n if (!options) {\n return;\n }\n if (options.since) {\n this._offset = options.since.offset || 0;\n this._epoch = options.since.epoch || '';\n this._recover = true;\n }\n if (options.data) {\n this._data = options.data;\n }\n if (options.getData) {\n this._getData = options.getData;\n }\n if (options.minResubscribeDelay !== undefined) {\n this._minResubscribeDelay = options.minResubscribeDelay;\n }\n if (options.maxResubscribeDelay !== undefined) {\n this._maxResubscribeDelay = options.maxResubscribeDelay;\n }\n if (options.token) {\n this._token = options.token;\n }\n if (options.getToken) {\n this._getToken = options.getToken;\n }\n if (options.positioned === true) {\n this._positioned = true;\n }\n if (options.recoverable === true) {\n this._recoverable = true;\n }\n if (options.joinLeave === true) {\n this._joinLeave = true;\n }\n if (options.delta) {\n if (options.delta !== 'fossil') {\n throw new Error('unsupported delta format');\n }\n this._delta = options.delta;\n }\n if (options.tagsFilter) {\n this._tagsFilter = options.tagsFilter;\n }\n if (this._tagsFilter && this._delta) {\n throw new Error('cannot use delta and tagsFilter together');\n }\n }\n _getOffset() {\n const offset = this._offset;\n if (offset !== null) {\n return offset;\n }\n return 0;\n }\n _getEpoch() {\n const epoch = this._epoch;\n if (epoch !== null) {\n return epoch;\n }\n return '';\n }\n _clearRefreshTimeout() {\n if (this._refreshTimeout !== null) {\n clearTimeout(this._refreshTimeout);\n this._refreshTimeout = null;\n }\n }\n _clearResubscribeTimeout() {\n if (this._resubscribeTimeout !== null) {\n clearTimeout(this._resubscribeTimeout);\n this._resubscribeTimeout = null;\n }\n }\n _getSubscriptionToken() {\n this._debug('get subscription token for channel', this.channel);\n const ctx = {\n channel: this.channel\n };\n const getToken = this._getToken;\n if (getToken === null) {\n this.emit('error', {\n type: 'configuration',\n channel: this.channel,\n error: {\n code: errorCodes.badConfiguration,\n message: 'provide a function to get channel subscription token'\n }\n });\n return Promise.reject(new UnauthorizedError(''));\n }\n return getToken(ctx);\n }\n _refresh() {\n this._clearRefreshTimeout();\n const self = this;\n this._getSubscriptionToken().then(function (token) {\n if (!self._isSubscribed()) {\n return;\n }\n if (!token) {\n self._failUnauthorized();\n return;\n }\n self._token = token;\n const req = {\n channel: self.channel,\n token: token\n };\n const msg = {\n 'sub_refresh': req\n };\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n self._centrifuge._call(msg).then(resolveCtx => {\n const result = resolveCtx.reply.sub_refresh;\n self._refreshResponse(result);\n if (resolveCtx.next) {\n resolveCtx.next();\n }\n }, rejectCtx => {\n self._refreshError(rejectCtx.error);\n if (rejectCtx.next) {\n rejectCtx.next();\n }\n });\n }).catch(function (e) {\n if (e instanceof UnauthorizedError) {\n self._failUnauthorized();\n return;\n }\n self.emit('error', {\n type: 'refreshToken',\n channel: self.channel,\n error: {\n code: errorCodes.subscriptionRefreshToken,\n message: e !== undefined ? e.toString() : ''\n }\n });\n self._refreshTimeout = setTimeout(() => self._refresh(), self._getRefreshRetryDelay());\n });\n }\n _refreshResponse(result) {\n if (!this._isSubscribed()) {\n return;\n }\n this._debug('subscription token refreshed, channel', this.channel);\n this._clearRefreshTimeout();\n if (result.expires === true) {\n this._refreshTimeout = setTimeout(() => this._refresh(), ttlMilliseconds(result.ttl));\n }\n }\n _refreshError(err) {\n if (!this._isSubscribed()) {\n return;\n }\n if (err.code < 100 || err.temporary === true) {\n this.emit('error', {\n type: 'refresh',\n channel: this.channel,\n error: err\n });\n this._refreshTimeout = setTimeout(() => this._refresh(), this._getRefreshRetryDelay());\n }\n else {\n this._setUnsubscribed(err.code, err.message, true);\n }\n }\n _getRefreshRetryDelay() {\n return backoff(0, 10000, 20000);\n }\n _failUnauthorized() {\n this._setUnsubscribed(unsubscribedCodes.unauthorized, 'unauthorized', true);\n }\n}\n\n/** @internal */\nclass SockjsTransport {\n constructor(endpoint, options) {\n this.endpoint = endpoint;\n this.options = options;\n this._transport = null;\n }\n name() {\n return 'sockjs';\n }\n subName() {\n return 'sockjs-' + this._transport.transport;\n }\n emulation() {\n return false;\n }\n supported() {\n return this.options.sockjs !== null;\n }\n initialize(_protocol, callbacks) {\n this._transport = new this.options.sockjs(this.endpoint, null, this.options.sockjsOptions);\n this._transport.onopen = () => {\n callbacks.onOpen();\n };\n this._transport.onerror = e => {\n callbacks.onError(e);\n };\n this._transport.onclose = closeEvent => {\n callbacks.onClose(closeEvent);\n };\n this._transport.onmessage = event => {\n callbacks.onMessage(event.data);\n };\n }\n close() {\n this._transport.close();\n }\n send(data) {\n this._transport.send(data);\n }\n}\n\n/** @internal */\nclass WebsocketTransport {\n constructor(endpoint, options) {\n this.endpoint = endpoint;\n this.options = options;\n this._transport = null;\n }\n name() {\n return 'websocket';\n }\n subName() {\n return 'websocket';\n }\n emulation() {\n return false;\n }\n supported() {\n return this.options.websocket !== undefined && this.options.websocket !== null;\n }\n initialize(protocol, callbacks) {\n let subProtocol = '';\n if (protocol === 'protobuf') {\n subProtocol = 'centrifuge-protobuf';\n }\n if (subProtocol !== '') {\n this._transport = new this.options.websocket(this.endpoint, subProtocol);\n }\n else {\n this._transport = new this.options.websocket(this.endpoint);\n }\n if (protocol === 'protobuf') {\n this._transport.binaryType = 'arraybuffer';\n }\n this._transport.onopen = () => {\n callbacks.onOpen();\n };\n this._transport.onerror = e => {\n callbacks.onError(e);\n };\n this._transport.onclose = closeEvent => {\n callbacks.onClose(closeEvent);\n };\n this._transport.onmessage = event => {\n callbacks.onMessage(event.data);\n };\n }\n close() {\n this._transport.close();\n }\n send(data) {\n this._transport.send(data);\n }\n}\n\n/** @internal */\nclass HttpStreamTransport {\n constructor(endpoint, options) {\n this.endpoint = endpoint;\n this.options = options;\n this._abortController = null;\n this._utf8decoder = new TextDecoder();\n this._protocol = 'json';\n }\n name() {\n return 'http_stream';\n }\n subName() {\n return 'http_stream';\n }\n emulation() {\n return true;\n }\n _handleErrors(response) {\n if (!response.ok)\n throw new Error(response.status);\n return response;\n }\n _fetchEventTarget(self, endpoint, options) {\n const eventTarget = new EventTarget();\n // fetch with connection timeout maybe? https://github.com/github/fetch/issues/175\n const fetchFunc = self.options.fetch;\n fetchFunc(endpoint, options)\n .then(self._handleErrors)\n .then(response => {\n eventTarget.dispatchEvent(new Event('open'));\n let jsonStreamBuf = '';\n let jsonStreamPos = 0;\n let protoStreamBuf = new Uint8Array();\n const reader = response.body.getReader();\n return new self.options.readableStream({\n start(controller) {\n function pump() {\n return reader.read().then(({ done, value }) => {\n // When no more data needs to be consumed, close the stream\n if (done) {\n eventTarget.dispatchEvent(new Event('close'));\n controller.close();\n return;\n }\n try {\n if (self._protocol === 'json') {\n jsonStreamBuf += self._utf8decoder.decode(value);\n while (jsonStreamPos < jsonStreamBuf.length) {\n if (jsonStreamBuf[jsonStreamPos] === '\\n') {\n const line = jsonStreamBuf.substring(0, jsonStreamPos);\n eventTarget.dispatchEvent(new MessageEvent('message', { data: line }));\n jsonStreamBuf = jsonStreamBuf.substring(jsonStreamPos + 1);\n jsonStreamPos = 0;\n }\n else {\n ++jsonStreamPos;\n }\n }\n }\n else {\n const mergedArray = new Uint8Array(protoStreamBuf.length + value.length);\n mergedArray.set(protoStreamBuf);\n mergedArray.set(value, protoStreamBuf.length);\n protoStreamBuf = mergedArray;\n while (true) {\n const result = self.options.decoder.decodeReply(protoStreamBuf);\n if (result.ok) {\n const data = protoStreamBuf.slice(0, result.pos);\n eventTarget.dispatchEvent(new MessageEvent('message', { data: data }));\n protoStreamBuf = protoStreamBuf.slice(result.pos);\n continue;\n }\n break;\n }\n }\n }\n catch (error) {\n // @ts-ignore - improve later.\n eventTarget.dispatchEvent(new Event('error', { detail: error }));\n eventTarget.dispatchEvent(new Event('close'));\n controller.close();\n return;\n }\n pump();\n }).catch(function (e) {\n // @ts-ignore - improve later.\n eventTarget.dispatchEvent(new Event('error', { detail: e }));\n eventTarget.dispatchEvent(new Event('close'));\n controller.close();\n return;\n });\n }\n return pump();\n }\n });\n })\n .catch(error => {\n // @ts-ignore - improve later.\n eventTarget.dispatchEvent(new Event('error', { detail: error }));\n eventTarget.dispatchEvent(new Event('close'));\n });\n return eventTarget;\n }\n supported() {\n return this.options.fetch !== null &&\n this.options.readableStream !== null &&\n typeof TextDecoder !== 'undefined' &&\n typeof AbortController !== 'undefined' &&\n typeof EventTarget !== 'undefined' &&\n typeof Event !== 'undefined' &&\n typeof MessageEvent !== 'undefined' &&\n typeof Error !== 'undefined';\n }\n initialize(protocol, callbacks, initialData) {\n this._protocol = protocol;\n this._abortController = new AbortController();\n let headers;\n let body;\n if (protocol === 'json') {\n headers = {\n 'Accept': 'application/json',\n 'Content-Type': 'application/json'\n };\n body = initialData;\n }\n else {\n headers = {\n 'Accept': 'application/octet-stream',\n 'Content-Type': 'application/octet-stream'\n };\n body = initialData;\n }\n const fetchOptions = {\n method: 'POST',\n headers: headers,\n body: body,\n mode: 'cors',\n credentials: 'same-origin',\n signal: this._abortController.signal\n };\n const eventTarget = this._fetchEventTarget(this, this.endpoint, fetchOptions);\n eventTarget.addEventListener('open', () => {\n callbacks.onOpen();\n });\n eventTarget.addEventListener('error', (e) => {\n this._abortController.abort();\n callbacks.onError(e);\n });\n eventTarget.addEventListener('close', () => {\n this._abortController.abort();\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n });\n eventTarget.addEventListener('message', (e) => {\n callbacks.onMessage(e.data);\n });\n }\n close() {\n this._abortController.abort();\n }\n send(data, session, node) {\n let headers;\n let body;\n const req = {\n session: session,\n node: node,\n data: data\n };\n if (this._protocol === 'json') {\n headers = {\n 'Content-Type': 'application/json'\n };\n body = JSON.stringify(req);\n }\n else {\n headers = {\n 'Content-Type': 'application/octet-stream'\n };\n body = this.options.encoder.encodeEmulationRequest(req);\n }\n const fetchFunc = this.options.fetch;\n const fetchOptions = {\n method: 'POST',\n headers: headers,\n body: body,\n mode: 'cors',\n credentials: 'same-origin',\n };\n fetchFunc(this.options.emulationEndpoint, fetchOptions);\n }\n}\n\n/** @internal */\nclass SseTransport {\n constructor(endpoint, options) {\n this.endpoint = endpoint;\n this.options = options;\n this._protocol = 'json';\n this._transport = null;\n this._onClose = null;\n }\n name() {\n return 'sse';\n }\n subName() {\n return 'sse';\n }\n emulation() {\n return true;\n }\n supported() {\n return this.options.eventsource !== null && this.options.fetch !== null;\n }\n initialize(_protocol, callbacks, initialData) {\n let url;\n if (globalThis && globalThis.document && globalThis.document.baseURI) {\n // Handle case when endpoint is relative, like //example.com/connection/sse\n url = new URL(this.endpoint, globalThis.document.baseURI);\n }\n else {\n url = new URL(this.endpoint);\n }\n url.searchParams.append('cf_connect', initialData);\n const eventsourceOptions = {};\n const eventSource = new this.options.eventsource(url.toString(), eventsourceOptions);\n this._transport = eventSource;\n const self = this;\n eventSource.onopen = function () {\n callbacks.onOpen();\n };\n eventSource.onerror = function (e) {\n eventSource.close();\n callbacks.onError(e);\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n };\n eventSource.onmessage = function (e) {\n callbacks.onMessage(e.data);\n };\n self._onClose = function () {\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n };\n }\n close() {\n this._transport.close();\n if (this._onClose !== null) {\n this._onClose();\n }\n }\n send(data, session, node) {\n const req = {\n session: session,\n node: node,\n data: data\n };\n const headers = {\n 'Content-Type': 'application/json'\n };\n const body = JSON.stringify(req);\n const fetchFunc = this.options.fetch;\n const fetchOptions = {\n method: 'POST',\n headers: headers,\n body: body,\n mode: 'cors',\n credentials: 'same-origin',\n };\n fetchFunc(this.options.emulationEndpoint, fetchOptions);\n }\n}\n\n/** @internal */\nclass WebtransportTransport {\n constructor(endpoint, options) {\n this.endpoint = endpoint;\n this.options = options;\n this._transport = null;\n this._stream = null;\n this._writer = null;\n this._utf8decoder = new TextDecoder();\n this._protocol = 'json';\n }\n name() {\n return 'webtransport';\n }\n subName() {\n return 'webtransport';\n }\n emulation() {\n return false;\n }\n supported() {\n return this.options.webtransport !== undefined && this.options.webtransport !== null;\n }\n initialize(protocol, callbacks) {\n return __awaiter(this, void 0, void 0, function* () {\n let url;\n if (globalThis && globalThis.document && globalThis.document.baseURI) {\n // Handle case when endpoint is relative, like //example.com/connection/webtransport\n url = new URL(this.endpoint, globalThis.document.baseURI);\n }\n else {\n url = new URL(this.endpoint);\n }\n if (protocol === 'protobuf') {\n url.searchParams.append('cf_protocol', 'protobuf');\n }\n this._protocol = protocol;\n const eventTarget = new EventTarget();\n this._transport = new this.options.webtransport(url.toString());\n this._transport.closed.then(() => {\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n }).catch(() => {\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n });\n try {\n yield this._transport.ready;\n }\n catch (_a) {\n this.close();\n return;\n }\n let stream;\n try {\n stream = yield this._transport.createBidirectionalStream();\n }\n catch (_b) {\n this.close();\n return;\n }\n this._stream = stream;\n this._writer = this._stream.writable.getWriter();\n eventTarget.addEventListener('close', () => {\n callbacks.onClose({\n code: 4,\n reason: 'connection closed'\n });\n });\n eventTarget.addEventListener('message', (e) => {\n callbacks.onMessage(e.data);\n });\n this._startReading(eventTarget);\n callbacks.onOpen();\n });\n }\n _startReading(eventTarget) {\n return __awaiter(this, void 0, void 0, function* () {\n const reader = this._stream.readable.getReader();\n let jsonStreamBuf = '';\n let jsonStreamPos = 0;\n let protoStreamBuf = new Uint8Array();\n try {\n while (true) {\n const { done, value } = yield reader.read();\n if (value.length > 0) {\n if (this._protocol === 'json') {\n jsonStreamBuf += this._utf8decoder.decode(value);\n while (jsonStreamPos < jsonStreamBuf.length) {\n if (jsonStreamBuf[jsonStreamPos] === '\\n') {\n const line = jsonStreamBuf.substring(0, jsonStreamPos);\n eventTarget.dispatchEvent(new MessageEvent('message', { data: line }));\n jsonStreamBuf = jsonStreamBuf.substring(jsonStreamPos + 1);\n jsonStreamPos = 0;\n }\n else {\n ++jsonStreamPos;\n }\n }\n }\n else {\n const mergedArray = new Uint8Array(protoStreamBuf.length + value.length);\n mergedArray.set(protoStreamBuf);\n mergedArray.set(value, protoStreamBuf.length);\n protoStreamBuf = mergedArray;\n while (true) {\n const result = this.options.decoder.decodeReply(protoStreamBuf);\n if (result.ok) {\n const data = protoStreamBuf.slice(0, result.pos);\n eventTarget.dispatchEvent(new MessageEvent('message', { data: data }));\n protoStreamBuf = protoStreamBuf.slice(result.pos);\n continue;\n }\n break;\n }\n }\n }\n if (done) {\n break;\n }\n }\n }\n catch (_a) {\n eventTarget.dispatchEvent(new Event('close'));\n }\n });\n }\n close() {\n return __awaiter(this, void 0, void 0, function* () {\n try {\n if (this._writer) {\n yield this._writer.close();\n }\n this._transport.close();\n }\n catch (e) {\n // already closed.\n }\n });\n }\n send(data) {\n return __awaiter(this, void 0, void 0, function* () {\n let binary;\n if (this._protocol === 'json') {\n // Need extra \\n since WT is non-frame protocol. \n binary = new TextEncoder().encode(data + '\\n');\n }\n else {\n binary = data;\n }\n try {\n yield this._writer.write(binary);\n }\n catch (e) {\n this.close();\n }\n });\n }\n}\n\n/*\nCopyright 2014-2024 Dmitry Chestnykh (JavaScript port)\nCopyright 2007 D. Richard Hipp (original C version)\n\nFossil SCM delta compression algorithm, this is only the applyDelta part extracted\nfrom https://github.com/dchest/fossil-delta-js. The code was slightly modified\nto strip unnecessary parts. The copyright on top of this file is from the original\nrepo on Github licensed under Simplified BSD License.\n*/\nconst zValue = [\n -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1,\n -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,\n 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36, -1, 37,\n 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,\n 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1,\n];\n// Reader reads bytes, chars, ints from array.\nclass Reader {\n constructor(array) {\n this.a = array; // source array\n this.pos = 0; // current position in array\n }\n haveBytes() {\n return this.pos < this.a.length;\n }\n getByte() {\n const b = this.a[this.pos];\n this.pos++;\n if (this.pos > this.a.length)\n throw new RangeError(\"out of bounds\");\n return b;\n }\n getChar() {\n return String.fromCharCode(this.getByte());\n }\n // Read base64-encoded unsigned integer.\n getInt() {\n let v = 0;\n let c;\n while (this.haveBytes() && (c = zValue[0x7f & this.getByte()]) >= 0) {\n v = (v << 6) + c;\n }\n this.pos--;\n return v >>> 0;\n }\n}\n// Write writes an array.\nclass Writer {\n constructor() {\n this.a = [];\n }\n toByteArray(sourceType) {\n if (Array.isArray(sourceType)) {\n return this.a;\n }\n return new Uint8Array(this.a);\n }\n // Copy from array at start to end.\n putArray(a, start, end) {\n // TODO: optimize.\n for (let i = start; i < end; i++)\n this.a.push(a[i]);\n }\n}\n// Return a 32-bit checksum of the array.\nfunction checksum(arr) {\n let sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, z = 0, N = arr.length;\n //TODO measure if this unrolling is helpful.\n while (N >= 16) {\n sum0 = (sum0 + arr[z + 0]) | 0;\n sum1 = (sum1 + arr[z + 1]) | 0;\n sum2 = (sum2 + arr[z + 2]) | 0;\n sum3 = (sum3 + arr[z + 3]) | 0;\n sum0 = (sum0 + arr[z + 4]) | 0;\n sum1 = (sum1 + arr[z + 5]) | 0;\n sum2 = (sum2 + arr[z + 6]) | 0;\n sum3 = (sum3 + arr[z + 7]) | 0;\n sum0 = (sum0 + arr[z + 8]) | 0;\n sum1 = (sum1 + arr[z + 9]) | 0;\n sum2 = (sum2 + arr[z + 10]) | 0;\n sum3 = (sum3 + arr[z + 11]) | 0;\n sum0 = (sum0 + arr[z + 12]) | 0;\n sum1 = (sum1 + arr[z + 13]) | 0;\n sum2 = (sum2 + arr[z + 14]) | 0;\n sum3 = (sum3 + arr[z + 15]) | 0;\n z += 16;\n N -= 16;\n }\n while (N >= 4) {\n sum0 = (sum0 + arr[z + 0]) | 0;\n sum1 = (sum1 + arr[z + 1]) | 0;\n sum2 = (sum2 + arr[z + 2]) | 0;\n sum3 = (sum3 + arr[z + 3]) | 0;\n z += 4;\n N -= 4;\n }\n sum3 = (((((sum3 + (sum2 << 8)) | 0) + (sum1 << 16)) | 0) + (sum0 << 24)) | 0;\n switch (N) {\n //@ts-ignore fallthrough is needed.\n case 3:\n sum3 = (sum3 + (arr[z + 2] << 8)) | 0; /* falls through */\n //@ts-ignore fallthrough is needed.\n case 2:\n sum3 = (sum3 + (arr[z + 1] << 16)) | 0; /* falls through */\n case 1:\n sum3 = (sum3 + (arr[z + 0] << 24)) | 0; /* falls through */\n }\n return sum3 >>> 0;\n}\n/**\n * Apply a delta byte array to a source byte array, returning the target byte array.\n */\nfunction applyDelta(source, delta) {\n let total = 0;\n const zDelta = new Reader(delta);\n const lenSrc = source.length;\n const lenDelta = delta.length;\n const limit = zDelta.getInt();\n if (zDelta.getChar() !== \"\\n\")\n throw new Error(\"size integer not terminated by '\\\\n'\");\n const zOut = new Writer();\n while (zDelta.haveBytes()) {\n const cnt = zDelta.getInt();\n let ofst;\n switch (zDelta.getChar()) {\n case \"@\":\n ofst = zDelta.getInt();\n if (zDelta.haveBytes() && zDelta.getChar() !== \",\")\n throw new Error(\"copy command not terminated by ','\");\n total += cnt;\n if (total > limit)\n throw new Error(\"copy exceeds output file size\");\n if (ofst + cnt > lenSrc)\n throw new Error(\"copy extends past end of input\");\n zOut.putArray(source, ofst, ofst + cnt);\n break;\n case \":\":\n total += cnt;\n if (total > limit)\n throw new Error(\"insert command gives an output larger than predicted\");\n if (cnt > lenDelta)\n throw new Error(\"insert count exceeds size of delta\");\n zOut.putArray(zDelta.a, zDelta.pos, zDelta.pos + cnt);\n zDelta.pos += cnt;\n break;\n case \";\":\n {\n const out = zOut.toByteArray(source);\n if (cnt !== checksum(out))\n throw new Error(\"bad checksum\");\n if (total !== limit)\n throw new Error(\"generated size does not match predicted size\");\n return out;\n }\n default:\n throw new Error(\"unknown delta operator\");\n }\n }\n throw new Error(\"unterminated delta\");\n}\n\n/** @internal */\nclass JsonCodec {\n name() {\n return 'json';\n }\n encodeCommands(commands) {\n return commands.map(c => JSON.stringify(c)).join('\\n');\n }\n decodeReplies(data) {\n return data.trim().split('\\n').map(r => JSON.parse(r));\n }\n applyDeltaIfNeeded(pub, prevValue) {\n let newData, newPrevValue;\n if (pub.delta) {\n // JSON string delta.\n const valueArray = applyDelta(prevValue, new TextEncoder().encode(pub.data));\n newData = JSON.parse(new TextDecoder().decode(valueArray));\n newPrevValue = valueArray;\n }\n else {\n // Full data as JSON string.\n newData = JSON.parse(pub.data);\n newPrevValue = new TextEncoder().encode(pub.data);\n }\n return { newData, newPrevValue };\n }\n}\n\nconst defaults = {\n headers: {},\n token: '',\n getToken: null,\n data: null,\n getData: null,\n debug: false,\n name: 'js',\n version: '',\n fetch: null,\n readableStream: null,\n websocket: null,\n eventsource: null,\n sockjs: null,\n sockjsOptions: {},\n emulationEndpoint: '/emulation',\n minReconnectDelay: 500,\n maxReconnectDelay: 20000,\n timeout: 5000,\n maxServerPingDelay: 10000,\n networkEventTarget: null,\n};\nclass UnauthorizedError extends Error {\n constructor(message) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n/** Centrifuge is a Centrifuge/Centrifugo bidirectional client. */\nclass Centrifuge extends EventEmitter$1 {\n /** Constructs Centrifuge client. Call connect() method to start connecting. */\n constructor(endpoint, options) {\n super();\n this._reconnectTimeout = null;\n this._refreshTimeout = null;\n this._serverPingTimeout = null;\n this.state = State.Disconnected;\n this._transportIsOpen = false;\n this._endpoint = endpoint;\n this._emulation = false;\n this._transports = [];\n this._currentTransportIndex = 0;\n this._triedAllTransports = false;\n this._transportWasOpen = false;\n this._transport = null;\n this._transportId = 0;\n this._deviceWentOffline = false;\n this._transportClosed = true;\n this._codec = new JsonCodec();\n this._reconnecting = false;\n this._reconnectTimeout = null;\n this._reconnectAttempts = 0;\n this._client = null;\n this._session = '';\n this._node = '';\n this._subs = {};\n this._serverSubs = {};\n this._commandId = 0;\n this._commands = [];\n this._batching = false;\n this._refreshRequired = false;\n this._refreshTimeout = null;\n this._callbacks = {};\n this._token = '';\n this._data = null;\n this._dispatchPromise = Promise.resolve();\n this._serverPing = 0;\n this._serverPingTimeout = null;\n this._sendPong = false;\n this._promises = {};\n this._promiseId = 0;\n this._debugEnabled = false;\n this._networkEventsSet = false;\n this._config = Object.assign(Object.assign({}, defaults), options);\n this._configure();\n if (this._debugEnabled) {\n this.on('state', (ctx) => {\n this._debug('client state', ctx.oldState, '->', ctx.newState);\n });\n this.on('error', (ctx) => {\n this._debug('client error', ctx);\n });\n }\n else {\n // Avoid unhandled exception in EventEmitter for non-set error handler.\n this.on('error', function () { Function.prototype(); });\n }\n }\n /** newSubscription allocates new Subscription to a channel. Since server only allows\n * one subscription per channel per client this method throws if client already has\n * channel subscription in internal registry.\n * */\n newSubscription(channel, options) {\n if (this.getSubscription(channel) !== null) {\n throw new Error('Subscription to the channel ' + channel + ' already exists');\n }\n const sub = new Subscription(this, channel, options);\n this._subs[channel] = sub;\n return sub;\n }\n /** getSubscription returns Subscription if it's registered in the internal\n * registry or null. */\n getSubscription(channel) {\n return this._getSub(channel);\n }\n /** removeSubscription allows removing Subcription from the internal registry. */\n removeSubscription(sub) {\n if (!sub) {\n return;\n }\n if (sub.state !== SubscriptionState.Unsubscribed) {\n sub.unsubscribe();\n }\n this._removeSubscription(sub);\n }\n /** Get a map with all current client-side subscriptions. */\n subscriptions() {\n return this._subs;\n }\n /** ready returns a Promise which resolves upon client goes to Connected\n * state and rejects in case of client goes to Disconnected or Failed state.\n * Users can provide optional timeout in milliseconds. */\n ready(timeout) {\n return __awaiter(this, void 0, void 0, function* () {\n switch (this.state) {\n case State.Disconnected:\n throw { code: errorCodes.clientDisconnected, message: 'client disconnected' };\n case State.Connected:\n return;\n default:\n return new Promise((resolve, reject) => {\n const ctx = { resolve, reject };\n if (timeout) {\n ctx.timeout = setTimeout(() => {\n reject({ code: errorCodes.timeout, message: 'timeout' });\n }, timeout);\n }\n this._promises[this._nextPromiseId()] = ctx;\n });\n }\n });\n }\n /** connect to a server. */\n connect() {\n if (this._isConnected()) {\n this._debug('connect called when already connected');\n return;\n }\n if (this._isConnecting()) {\n this._debug('connect called when already connecting');\n return;\n }\n this._debug('connect called');\n this._reconnectAttempts = 0;\n this._startConnecting();\n }\n /** disconnect from a server. */\n disconnect() {\n this._disconnect(disconnectedCodes.disconnectCalled, 'disconnect called', false);\n }\n /** setToken allows setting connection token. Or resetting used token to be empty. */\n setToken(token) {\n this._token = token;\n }\n /** setData allows setting connection data. This only affects the next connection attempt,\n * not the current one. Note that if getData callback is configured, it will override\n * this value during reconnects. */\n setData(data) {\n this._data = data;\n }\n /** setHeaders allows setting connection emulated headers. */\n setHeaders(headers) {\n this._config.headers = headers;\n }\n /** send asynchronous data to a server (without any response from a server\n * expected, see rpc method if you need response). */\n send(data) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n send: {\n data\n }\n };\n yield this._methodCall();\n const sent = this._transportSendCommands([cmd]); // can send message to server without id set\n if (!sent) {\n throw this._createErrorObject(errorCodes.transportWriteError, 'transport write error');\n }\n });\n }\n /** rpc to a server - i.e. a call which waits for a response with data. */\n rpc(method, data) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n rpc: {\n method,\n data\n }\n };\n yield this._methodCall();\n const result = yield this._callPromise(cmd, (reply) => reply.rpc);\n return {\n data: result.data\n };\n });\n }\n /** publish data to a channel. */\n publish(channel, data) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n publish: {\n channel,\n data\n }\n };\n yield this._methodCall();\n yield this._callPromise(cmd, () => ({}));\n return {};\n });\n }\n /** history for a channel. By default it does not return publications (only current\n * StreamPosition data) – provide an explicit limit > 0 to load publications.*/\n history(channel, options) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n history: this._getHistoryRequest(channel, options)\n };\n yield this._methodCall();\n const result = yield this._callPromise(cmd, (reply) => reply.history);\n const publications = [];\n if (result.publications) {\n for (let i = 0; i < result.publications.length; i++) {\n publications.push(this._getPublicationContext(channel, result.publications[i]));\n }\n }\n return {\n publications,\n epoch: result.epoch || '',\n offset: result.offset || 0\n };\n });\n }\n /** presence for a channel. */\n presence(channel) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n presence: {\n channel\n }\n };\n yield this._methodCall();\n const result = yield this._callPromise(cmd, (reply) => reply.presence);\n const clients = result.presence;\n for (const clientId in clients) {\n if (Object.prototype.hasOwnProperty.call(clients, clientId)) {\n const rawClient = clients[clientId];\n const connInfo = rawClient['conn_info'];\n const chanInfo = rawClient['chan_info'];\n if (connInfo) {\n rawClient.connInfo = connInfo;\n }\n if (chanInfo) {\n rawClient.chanInfo = chanInfo;\n }\n }\n }\n return { clients };\n });\n }\n presenceStats(channel) {\n return __awaiter(this, void 0, void 0, function* () {\n const cmd = {\n 'presence_stats': {\n channel\n }\n };\n yield this._methodCall();\n const result = yield this._callPromise(cmd, (reply) => {\n return reply.presence_stats;\n });\n return {\n numUsers: result.num_users,\n numClients: result.num_clients\n };\n });\n }\n /** start command batching (collect into temporary buffer without sending to a server)\n * until stopBatching called.*/\n startBatching() {\n // start collecting messages without sending them to Centrifuge until flush\n // method called\n this._batching = true;\n }\n /** stop batching commands and flush collected commands to the\n * network (all in one request/frame).*/\n stopBatching() {\n const self = this;\n // Why so nested? Two levels here requred to deal with promise resolving queue.\n // In Subscription case we wait 2 futures before sending data to connection.\n // Otherwise _batching becomes false before batching decision has a chance to be executed.\n Promise.resolve().then(function () {\n Promise.resolve().then(function () {\n self._batching = false;\n self._flush();\n });\n });\n }\n _debug(...args) {\n if (!this._debugEnabled) {\n return;\n }\n log('debug', args);\n }\n _codecName() {\n return this._codec.name();\n }\n /** @internal */\n _formatOverride() {\n return;\n }\n _configure() {\n if (!('Promise' in globalThis)) {\n throw new Error('Promise polyfill required');\n }\n if (!this._endpoint) {\n throw new Error('endpoint configuration required');\n }\n if (this._config.token !== null) {\n this._token = this._config.token;\n }\n if (this._config.data !== null) {\n this._data = this._config.data;\n }\n this._codec = new JsonCodec();\n this._formatOverride();\n if (this._config.debug === true ||\n (typeof localStorage !== 'undefined' && typeof localStorage.getItem === 'function' && localStorage.getItem('centrifuge.debug'))) {\n this._debugEnabled = true;\n }\n this._debug('config', this._config);\n if (typeof this._endpoint === 'string') ;\n else if (Array.isArray(this._endpoint)) {\n this._transports = this._endpoint;\n this._emulation = true;\n for (const i in this._transports) {\n if (this._transports.hasOwnProperty(i)) {\n const transportConfig = this._transports[i];\n if (!transportConfig.endpoint || !transportConfig.transport) {\n throw new Error('malformed transport configuration');\n }\n const transportName = transportConfig.transport;\n if (['websocket', 'http_stream', 'sse', 'sockjs', 'webtransport'].indexOf(transportName) < 0) {\n throw new Error('unsupported transport name: ' + transportName);\n }\n }\n }\n }\n else {\n throw new Error('unsupported url configuration type: only string or array of objects are supported');\n }\n }\n _setState(newState) {\n if (this.state !== newState) {\n this._reconnecting = false;\n const oldState = this.state;\n this.state = newState;\n this.emit('state', { newState, oldState });\n return true;\n }\n return false;\n }\n _isDisconnected() {\n return this.state === State.Disconnected;\n }\n _isConnecting() {\n return this.state === State.Connecting;\n }\n _isConnected() {\n return this.state === State.Connected;\n }\n _nextCommandId() {\n return ++this._commandId;\n }\n _setNetworkEvents() {\n if (this._networkEventsSet) {\n return;\n }\n let eventTarget = null;\n if (this._config.networkEventTarget !== null) {\n eventTarget = this._config.networkEventTarget;\n }\n else if (typeof globalThis.addEventListener !== 'undefined') {\n eventTarget = globalThis;\n }\n if (eventTarget) {\n eventTarget.addEventListener('offline', () => {\n this._debug('offline event triggered');\n if (this.state === State.Connected || this.state === State.Connecting) {\n this._disconnect(connectingCodes.transportClosed, 'transport closed', true);\n this._deviceWentOffline = true;\n }\n });\n eventTarget.addEventListener('online', () => {\n this._debug('online event triggered');\n if (this.state !== State.Connecting) {\n return;\n }\n if (this._deviceWentOffline && !this._transportClosed) {\n // This is a workaround for mobile Safari where close callback may be\n // not issued upon device going to the flight mode. We know for sure\n // that transport close was called, so we start reconnecting. In this\n // case if the close callback will be issued for some reason after some\n // time – it will be ignored due to transport ID mismatch.\n this._deviceWentOffline = false;\n this._transportClosed = true;\n }\n this._clearReconnectTimeout();\n this._startReconnecting();\n });\n this._networkEventsSet = true;\n }\n }\n _getReconnectDelay() {\n const delay = backoff(this._reconnectAttempts, this._config.minReconnectDelay, this._config.maxReconnectDelay);\n this._reconnectAttempts += 1;\n return delay;\n }\n _clearOutgoingRequests() {\n // fire errbacks of registered outgoing calls.\n for (const id in this._callbacks) {\n if (this._callbacks.hasOwnProperty(id)) {\n const callbacks = this._callbacks[id];\n clearTimeout(callbacks.timeout);\n const errback = callbacks.errback;\n if (!errback) {\n continue;\n }\n errback({ error: this._createErrorObject(errorCodes.connectionClosed, 'connection closed') });\n }\n }\n this._callbacks = {};\n }\n _clearConnectedState() {\n this._client = null;\n this._clearServerPingTimeout();\n this._clearRefreshTimeout();\n // fire events for client-side subscriptions.\n for (const channel in this._subs) {\n if (!this._subs.hasOwnProperty(channel)) {\n continue;\n }\n const sub = this._subs[channel];\n if (sub.state === SubscriptionState.Subscribed) {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._setSubscribing(subscribingCodes.transportClosed, 'transport closed');\n }\n }\n // fire events for server-side subscriptions.\n for (const channel in this._serverSubs) {\n if (this._serverSubs.hasOwnProperty(channel)) {\n this.emit('subscribing', { channel: channel });\n }\n }\n }\n _handleWriteError(commands) {\n for (const command of commands) {\n const id = command.id;\n if (!(id in this._callbacks)) {\n continue;\n }\n const callbacks = this._callbacks[id];\n clearTimeout(this._callbacks[id].timeout);\n delete this._callbacks[id];\n const errback = callbacks.errback;\n errback({ error: this._createErrorObject(errorCodes.transportWriteError, 'transport write error') });\n }\n }\n _transportSendCommands(commands) {\n if (!commands.length) {\n return true;\n }\n if (!this._transport) {\n return false;\n }\n try {\n this._transport.send(this._codec.encodeCommands(commands), this._session, this._node);\n }\n catch (e) {\n this._debug('error writing commands', e);\n this._handleWriteError(commands);\n return false;\n }\n return true;\n }\n _initializeTransport() {\n let websocket;\n if (this._config.websocket !== null) {\n websocket = this._config.websocket;\n }\n else {\n if (!(typeof globalThis.WebSocket !== 'function' && typeof globalThis.WebSocket !== 'object')) {\n websocket = globalThis.WebSocket;\n }\n }\n let sockjs = null;\n if (this._config.sockjs !== null) {\n sockjs = this._config.sockjs;\n }\n else {\n if (typeof globalThis.SockJS !== 'undefined') {\n sockjs = globalThis.SockJS;\n }\n }\n let eventsource = null;\n if (this._config.eventsource !== null) {\n eventsource = this._config.eventsource;\n }\n else {\n if (typeof globalThis.EventSource !== 'undefined') {\n eventsource = globalThis.EventSource;\n }\n }\n let fetchFunc = null;\n if (this._config.fetch !== null) {\n fetchFunc = this._config.fetch;\n }\n else {\n if (typeof globalThis.fetch !== 'undefined') {\n fetchFunc = globalThis.fetch;\n }\n }\n let readableStream = null;\n if (this._config.readableStream !== null) {\n readableStream = this._config.readableStream;\n }\n else {\n if (typeof globalThis.ReadableStream !== 'undefined') {\n readableStream = globalThis.ReadableStream;\n }\n }\n if (!this._emulation) {\n if (startsWith(this._endpoint, 'http')) {\n throw new Error('Provide explicit transport endpoints configuration in case of using HTTP (i.e. using array of TransportEndpoint instead of a single string), or use ws(s):// scheme in an endpoint if you aimed using WebSocket transport');\n }\n else {\n this._debug('client will use websocket');\n this._transport = new WebsocketTransport(this._endpoint, {\n websocket: websocket\n });\n if (!this._transport.supported()) {\n throw new Error('WebSocket constructor not found, make sure it is available globally or passed as a dependency in Centrifuge options');\n }\n }\n }\n else {\n if (this._currentTransportIndex >= this._transports.length) {\n this._triedAllTransports = true;\n this._currentTransportIndex = 0;\n }\n let count = 0;\n while (true) {\n if (count >= this._transports.length) {\n throw new Error('no supported transport found');\n }\n const transportConfig = this._transports[this._currentTransportIndex];\n const transportName = transportConfig.transport;\n const transportEndpoint = transportConfig.endpoint;\n if (transportName === 'websocket') {\n this._debug('trying websocket transport');\n this._transport = new WebsocketTransport(transportEndpoint, {\n websocket: websocket\n });\n if (!this._transport.supported()) {\n this._debug('websocket transport not available');\n this._currentTransportIndex++;\n count++;\n continue;\n }\n }\n else if (transportName === 'webtransport') {\n this._debug('trying webtransport transport');\n this._transport = new WebtransportTransport(transportEndpoint, {\n webtransport: globalThis.WebTransport,\n decoder: this._codec,\n encoder: this._codec\n });\n if (!this._transport.supported()) {\n this._debug('webtransport transport not available');\n this._currentTransportIndex++;\n count++;\n continue;\n }\n }\n else if (transportName === 'http_stream') {\n this._debug('trying http_stream transport');\n this._transport = new HttpStreamTransport(transportEndpoint, {\n fetch: fetchFunc,\n readableStream: readableStream,\n emulationEndpoint: this._config.emulationEndpoint,\n decoder: this._codec,\n encoder: this._codec\n });\n if (!this._transport.supported()) {\n this._debug('http_stream transport not available');\n this._currentTransportIndex++;\n count++;\n continue;\n }\n }\n else if (transportName === 'sse') {\n this._debug('trying sse transport');\n this._transport = new SseTransport(transportEndpoint, {\n eventsource: eventsource,\n fetch: fetchFunc,\n emulationEndpoint: this._config.emulationEndpoint,\n });\n if (!this._transport.supported()) {\n this._debug('sse transport not available');\n this._currentTransportIndex++;\n count++;\n continue;\n }\n }\n else if (transportName === 'sockjs') {\n this._debug('trying sockjs');\n this._transport = new SockjsTransport(transportEndpoint, {\n sockjs: sockjs,\n sockjsOptions: this._config.sockjsOptions\n });\n if (!this._transport.supported()) {\n this._debug('sockjs transport not available');\n this._currentTransportIndex++;\n count++;\n continue;\n }\n }\n else {\n throw new Error('unknown transport ' + transportName);\n }\n break;\n }\n }\n const self = this;\n const transport = this._transport;\n const transportId = this._nextTransportId();\n self._debug(\"id of transport\", transportId);\n let wasOpen = false;\n const initialCommands = [];\n if (this._transport.emulation()) {\n const connectCommand = self._sendConnect(true);\n initialCommands.push(connectCommand);\n }\n this._setNetworkEvents();\n const initialData = this._codec.encodeCommands(initialCommands);\n this._transportClosed = false;\n let connectTimeout;\n connectTimeout = setTimeout(function () {\n transport.close();\n }, this._config.timeout);\n this._transport.initialize(this._codecName(), {\n onOpen: function () {\n if (connectTimeout) {\n clearTimeout(connectTimeout);\n connectTimeout = null;\n }\n if (self._transportId != transportId) {\n self._debug('open callback from non-actual transport');\n transport.close();\n return;\n }\n wasOpen = true;\n self._debug(transport.subName(), 'transport open');\n if (transport.emulation()) {\n return;\n }\n self._transportIsOpen = true;\n self._transportWasOpen = true;\n self.startBatching();\n self._sendConnect(false);\n self._sendSubscribeCommands();\n self.stopBatching();\n //@ts-ignore must be used only for debug and test purposes. Exposed only for non-emulation transport.\n self.emit('__centrifuge_debug:connect_frame_sent', {});\n },\n onError: function (e) {\n if (self._transportId != transportId) {\n self._debug('error callback from non-actual transport');\n return;\n }\n self._debug('transport level error', e);\n },\n onClose: function (closeEvent) {\n if (connectTimeout) {\n clearTimeout(connectTimeout);\n connectTimeout = null;\n }\n if (self._transportId != transportId) {\n self._debug('close callback from non-actual transport');\n return;\n }\n self._debug(transport.subName(), 'transport closed');\n self._transportClosed = true;\n self._transportIsOpen = false;\n let reason = 'connection closed';\n let needReconnect = true;\n let code = 0;\n if (closeEvent && 'code' in closeEvent && closeEvent.code) {\n code = closeEvent.code;\n }\n if (closeEvent && closeEvent.reason) {\n try {\n const advice = JSON.parse(closeEvent.reason);\n reason = advice.reason;\n needReconnect = advice.reconnect;\n }\n catch (e) {\n reason = closeEvent.reason;\n if ((code >= 3500 && code < 4000) || (code >= 4500 && code < 5000)) {\n needReconnect = false;\n }\n }\n }\n if (code < 3000) {\n if (code === 1009) {\n code = disconnectedCodes.messageSizeLimit;\n reason = 'message size limit exceeded';\n needReconnect = false;\n }\n else {\n code = connectingCodes.transportClosed;\n reason = 'transport closed';\n }\n if (self._emulation && !self._transportWasOpen) {\n self._currentTransportIndex++;\n if (self._currentTransportIndex >= self._transports.length) {\n self._triedAllTransports = true;\n self._currentTransportIndex = 0;\n }\n }\n }\n else {\n // Codes >= 3000 are sent from a server application level.\n self._transportWasOpen = true;\n }\n if (self._isConnecting() && !wasOpen) {\n self.emit('error', {\n type: 'transport',\n error: {\n code: errorCodes.transportClosed,\n message: 'transport closed'\n },\n transport: transport.name()\n });\n }\n self._reconnecting = false;\n self._disconnect(code, reason, needReconnect);\n },\n onMessage: function (data) {\n self._dataReceived(data);\n }\n }, initialData);\n //@ts-ignore must be used only for debug and test purposes.\n self.emit('__centrifuge_debug:transport_initialized', {});\n }\n _sendConnect(skipSending) {\n const connectCommand = this._constructConnectCommand();\n const self = this;\n this._call(connectCommand, skipSending).then(resolveCtx => {\n const result = resolveCtx.reply.connect;\n self._connectResponse(result);\n if (resolveCtx.next) {\n resolveCtx.next();\n }\n }, rejectCtx => {\n self._connectError(rejectCtx.error);\n if (rejectCtx.next) {\n rejectCtx.next();\n }\n });\n return connectCommand;\n }\n _startReconnecting() {\n this._debug('start reconnecting');\n if (!this._isConnecting()) {\n this._debug('stop reconnecting: client not in connecting state');\n return;\n }\n if (this._reconnecting) {\n this._debug('reconnect already in progress, return from reconnect routine');\n return;\n }\n if (this._transportClosed === false) {\n this._debug('waiting for transport close');\n return;\n }\n this._reconnecting = true;\n const emptyToken = this._token === '';\n const needTokenRefresh = this._refreshRequired || (emptyToken && this._config.getToken !== null);\n if (!needTokenRefresh) {\n if (this._config.getData) {\n this._config.getData().then(data => {\n if (!this._isConnecting()) {\n return;\n }\n this._data = data;\n this._initializeTransport();\n })\n .catch(e => this._handleGetDataError(e));\n }\n else {\n this._initializeTransport();\n }\n return;\n }\n const self = this;\n this._getToken().then(function (token) {\n if (!self._isConnecting()) {\n return;\n }\n if (token == null || token == undefined) {\n self._failUnauthorized();\n return;\n }\n self._token = token;\n self._debug('connection token refreshed');\n if (self._config.getData) {\n self._config.getData().then(function (data) {\n if (!self._isConnecting()) {\n return;\n }\n self._data = data;\n self._initializeTransport();\n })\n .catch(e => self._handleGetDataError(e));\n }\n else {\n self._initializeTransport();\n }\n }).catch(function (e) {\n if (!self._isConnecting()) {\n return;\n }\n if (e instanceof UnauthorizedError) {\n self._failUnauthorized();\n return;\n }\n self.emit('error', {\n 'type': 'connectToken',\n 'error': {\n code: errorCodes.clientConnectToken,\n message: e !== undefined ? e.toString() : ''\n }\n });\n const delay = self._getReconnectDelay();\n self._debug('error on getting connection token, reconnect after ' + delay + ' milliseconds', e);\n self._reconnecting = false;\n self._reconnectTimeout = setTimeout(() => {\n self._startReconnecting();\n }, delay);\n });\n }\n _handleGetDataError(e) {\n if (e instanceof UnauthorizedError) {\n this._failUnauthorized();\n return;\n }\n this.emit('error', {\n type: 'connectData',\n error: {\n code: errorCodes.badConfiguration,\n message: (e === null || e === void 0 ? void 0 : e.toString()) || ''\n }\n });\n const delay = this._getReconnectDelay();\n this._debug('error on getting connect data, reconnect after ' + delay + ' milliseconds', e);\n this._reconnecting = false;\n this._reconnectTimeout = setTimeout(() => {\n this._startReconnecting();\n }, delay);\n }\n _connectError(err) {\n if (this.state !== State.Connecting) {\n return;\n }\n if (err.code === 109) { // token expired.\n // next connect attempt will try to refresh token.\n this._refreshRequired = true;\n }\n if (err.code < 100 || err.temporary === true || err.code === 109) {\n this.emit('error', {\n 'type': 'connect',\n 'error': err\n });\n this._debug('closing transport due to connect error');\n this._disconnect(err.code, err.message, true);\n }\n else {\n this._disconnect(err.code, err.message, false);\n }\n }\n _scheduleReconnect() {\n if (!this._isConnecting()) {\n return;\n }\n let isInitialHandshake = false;\n if (this._emulation && !this._transportWasOpen && !this._triedAllTransports) {\n isInitialHandshake = true;\n }\n let delay = this._getReconnectDelay();\n if (isInitialHandshake) {\n delay = 0;\n }\n this._debug('reconnect after ' + delay + ' milliseconds');\n this._clearReconnectTimeout();\n this._reconnectTimeout = setTimeout(() => {\n this._startReconnecting();\n }, delay);\n }\n _constructConnectCommand() {\n const req = {};\n if (this._token) {\n req.token = this._token;\n }\n if (this._data) {\n req.data = this._data;\n }\n if (this._config.name) {\n req.name = this._config.name;\n }\n if (this._config.version) {\n req.version = this._config.version;\n }\n if (Object.keys(this._config.headers).length > 0) {\n req.headers = this._config.headers;\n }\n const subs = {};\n let hasSubs = false;\n for (const channel in this._serverSubs) {\n if (this._serverSubs.hasOwnProperty(channel) && this._serverSubs[channel].recoverable) {\n hasSubs = true;\n const sub = {\n 'recover': true\n };\n if (this._serverSubs[channel].offset) {\n sub['offset'] = this._serverSubs[channel].offset;\n }\n if (this._serverSubs[channel].epoch) {\n sub['epoch'] = this._serverSubs[channel].epoch;\n }\n subs[channel] = sub;\n }\n }\n if (hasSubs) {\n req.subs = subs;\n }\n return {\n connect: req\n };\n }\n _getHistoryRequest(channel, options) {\n const req = {\n channel: channel\n };\n if (options !== undefined) {\n if (options.since) {\n req.since = {\n offset: options.since.offset\n };\n if (options.since.epoch) {\n req.since.epoch = options.since.epoch;\n }\n }\n if (options.limit !== undefined) {\n req.limit = options.limit;\n }\n if (options.reverse === true) {\n req.reverse = true;\n }\n }\n return req;\n }\n _methodCall() {\n if (this._isConnected()) {\n return Promise.resolve();\n }\n return new Promise((res, rej) => {\n const timeout = setTimeout(function () {\n rej({ code: errorCodes.timeout, message: 'timeout' });\n }, this._config.timeout);\n this._promises[this._nextPromiseId()] = {\n timeout: timeout,\n resolve: res,\n reject: rej\n };\n });\n }\n _callPromise(cmd, resultCB) {\n return new Promise((resolve, reject) => {\n this._call(cmd, false).then((resolveCtx) => {\n var _a;\n const result = resultCB(resolveCtx.reply);\n resolve(result);\n (_a = resolveCtx.next) === null || _a === void 0 ? void 0 : _a.call(resolveCtx);\n }, (rejectCtx) => {\n var _a;\n reject(rejectCtx.error);\n (_a = rejectCtx.next) === null || _a === void 0 ? void 0 : _a.call(rejectCtx);\n });\n });\n }\n _dataReceived(data) {\n if (this._serverPing > 0) {\n this._waitServerPing();\n }\n const replies = this._codec.decodeReplies(data);\n // We have to guarantee order of events in replies processing - i.e. start processing\n // next reply only when we finished processing of current one. Without syncing things in\n // this way we could get wrong publication events order as reply promises resolve\n // on next loop tick so for loop continues before we finished emitting all reply events.\n this._dispatchPromise = this._dispatchPromise.then(() => {\n let finishDispatch;\n this._dispatchPromise = new Promise(resolve => {\n finishDispatch = resolve;\n });\n this._dispatchSynchronized(replies, finishDispatch);\n });\n }\n _dispatchSynchronized(replies, finishDispatch) {\n let p = Promise.resolve();\n for (const i in replies) {\n if (replies.hasOwnProperty(i)) {\n p = p.then(() => {\n return this._dispatchReply(replies[i]);\n });\n }\n }\n p = p.then(() => {\n finishDispatch();\n });\n }\n _dispatchReply(reply) {\n let next;\n const p = new Promise(resolve => {\n next = resolve;\n });\n if (reply === undefined || reply === null) {\n this._debug('dispatch: got undefined or null reply');\n next();\n return p;\n }\n const id = reply.id;\n if (id && id > 0) {\n this._handleReply(reply, next);\n }\n else {\n if (!reply.push) {\n this._handleServerPing(next);\n }\n else {\n this._handlePush(reply.push, next);\n }\n }\n return p;\n }\n _call(cmd, skipSending) {\n return new Promise((resolve, reject) => {\n cmd.id = this._nextCommandId();\n this._registerCall(cmd.id, resolve, reject);\n if (!skipSending) {\n this._addCommand(cmd);\n }\n });\n }\n _startConnecting() {\n this._debug('start connecting');\n if (this._setState(State.Connecting)) {\n this.emit('connecting', { code: connectingCodes.connectCalled, reason: 'connect called' });\n }\n this._client = null;\n this._startReconnecting();\n }\n _disconnect(code, reason, reconnect) {\n if (this._isDisconnected()) {\n return;\n }\n // we mark transport is closed right away, because _clearConnectedState will move subscriptions to subscribing state\n // if transport will still be open at this time, subscribe frames will be sent to closing transport\n this._transportIsOpen = false;\n const previousState = this.state;\n this._reconnecting = false;\n const ctx = {\n code: code,\n reason: reason\n };\n let needEvent = false;\n if (reconnect) {\n needEvent = this._setState(State.Connecting);\n }\n else {\n needEvent = this._setState(State.Disconnected);\n this._rejectPromises({ code: errorCodes.clientDisconnected, message: 'disconnected' });\n }\n this._clearOutgoingRequests();\n if (previousState === State.Connecting) {\n this._clearReconnectTimeout();\n }\n if (previousState === State.Connected) {\n this._clearConnectedState();\n }\n if (needEvent) {\n if (this._isConnecting()) {\n this.emit('connecting', ctx);\n }\n else {\n this.emit('disconnected', ctx);\n }\n }\n if (this._transport) {\n this._debug(\"closing existing transport\");\n const transport = this._transport;\n this._transport = null;\n transport.close(); // Close only after setting this._transport to null to avoid recursion when calling transport close().\n // Need to mark as closed here, because connect call may be sync called after disconnect,\n // transport onClose callback will not be called yet\n this._transportClosed = true;\n this._nextTransportId();\n }\n else {\n this._debug(\"no transport to close\");\n }\n this._scheduleReconnect();\n }\n _failUnauthorized() {\n this._disconnect(disconnectedCodes.unauthorized, 'unauthorized', false);\n }\n _getToken() {\n this._debug('get connection token');\n if (!this._config.getToken) {\n this.emit('error', {\n type: 'configuration',\n error: {\n code: errorCodes.badConfiguration,\n message: 'token expired but no getToken function set in the configuration'\n }\n });\n return Promise.reject(new UnauthorizedError(''));\n }\n return this._config.getToken({});\n }\n _refresh() {\n const clientId = this._client;\n const self = this;\n this._getToken().then(function (token) {\n if (clientId !== self._client) {\n return;\n }\n if (!token) {\n self._failUnauthorized();\n return;\n }\n self._token = token;\n self._debug('connection token refreshed');\n if (!self._isConnected()) {\n return;\n }\n const cmd = {\n refresh: { token: self._token }\n };\n self._call(cmd, false).then(resolveCtx => {\n const result = resolveCtx.reply.refresh;\n self._refreshResponse(result);\n if (resolveCtx.next) {\n resolveCtx.next();\n }\n }, rejectCtx => {\n self._refreshError(rejectCtx.error);\n if (rejectCtx.next) {\n rejectCtx.next();\n }\n });\n }).catch(function (e) {\n if (!self._isConnected()) {\n return;\n }\n if (e instanceof UnauthorizedError) {\n self._failUnauthorized();\n return;\n }\n self.emit('error', {\n type: 'refreshToken',\n error: {\n code: errorCodes.clientRefreshToken,\n message: e !== undefined ? e.toString() : ''\n }\n });\n self._refreshTimeout = setTimeout(() => self._refresh(), self._getRefreshRetryDelay());\n });\n }\n _refreshError(err) {\n if (err.code < 100 || err.temporary === true) {\n this.emit('error', {\n type: 'refresh',\n error: err\n });\n this._refreshTimeout = setTimeout(() => this._refresh(), this._getRefreshRetryDelay());\n }\n else {\n this._disconnect(err.code, err.message, false);\n }\n }\n _getRefreshRetryDelay() {\n return backoff(0, 5000, 10000);\n }\n _refreshResponse(result) {\n if (this._refreshTimeout) {\n clearTimeout(this._refreshTimeout);\n this._refreshTimeout = null;\n }\n if (result.expires) {\n this._client = result.client;\n this._refreshTimeout = setTimeout(() => this._refresh(), ttlMilliseconds(result.ttl));\n }\n }\n _removeSubscription(sub) {\n if (sub === null) {\n return;\n }\n delete this._subs[sub.channel];\n }\n _unsubscribe(sub) {\n if (!this._transportIsOpen) {\n return Promise.resolve();\n }\n const req = {\n channel: sub.channel\n };\n const cmd = { unsubscribe: req };\n const self = this;\n const unsubscribePromise = new Promise((resolve, _) => {\n this._call(cmd, false).then(resolveCtx => {\n resolve();\n if (resolveCtx.next) {\n resolveCtx.next();\n }\n }, rejectCtx => {\n resolve();\n if (rejectCtx.next) {\n rejectCtx.next();\n }\n self._disconnect(connectingCodes.unsubscribeError, 'unsubscribe error', true);\n });\n });\n return unsubscribePromise;\n }\n _getSub(channel, id) {\n if (id && id > 0) {\n for (const ch in this._subs) {\n if (this._subs.hasOwnProperty(ch)) {\n const sub = this._subs[ch];\n // @ts-ignore – we are accessing private property for internal use\n if (sub._id === id) {\n return sub;\n }\n }\n }\n return null;\n }\n const sub = this._subs[channel];\n if (!sub) {\n return null;\n }\n return sub;\n }\n _isServerSub(channel) {\n return this._serverSubs[channel] !== undefined;\n }\n _sendSubscribeCommands() {\n const commands = [];\n for (const channel in this._subs) {\n if (!this._subs.hasOwnProperty(channel)) {\n continue;\n }\n const sub = this._subs[channel];\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n if (sub._inflight === true) {\n continue;\n }\n if (sub.state === SubscriptionState.Subscribing) {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n const cmd = sub._subscribe();\n if (cmd) {\n commands.push(cmd);\n }\n }\n }\n return commands;\n }\n _connectResponse(result) {\n this._transportIsOpen = true;\n this._transportWasOpen = true;\n this._reconnectAttempts = 0;\n this._refreshRequired = false;\n if (this._isConnected()) {\n return;\n }\n this._client = result.client;\n this._setState(State.Connected);\n if (this._refreshTimeout) {\n clearTimeout(this._refreshTimeout);\n }\n if (result.expires) {\n this._refreshTimeout = setTimeout(() => this._refresh(), ttlMilliseconds(result.ttl));\n }\n this._session = result.session;\n this._node = result.node;\n this.startBatching();\n this._sendSubscribeCommands();\n this.stopBatching();\n const ctx = {\n client: result.client,\n transport: this._transport.subName()\n };\n if (result.data) {\n ctx.data = result.data;\n }\n this.emit('connected', ctx);\n this._resolvePromises();\n this._processServerSubs(result.subs || {});\n if (result.ping && result.ping > 0) {\n this._serverPing = result.ping * 1000;\n this._sendPong = result.pong === true;\n this._waitServerPing();\n }\n else {\n this._serverPing = 0;\n }\n }\n _processServerSubs(subs) {\n for (const channel in subs) {\n if (!subs.hasOwnProperty(channel)) {\n continue;\n }\n const sub = subs[channel];\n this._serverSubs[channel] = {\n 'offset': sub.offset,\n 'epoch': sub.epoch,\n 'recoverable': sub.recoverable || false\n };\n const subCtx = this._getSubscribeContext(channel, sub);\n this.emit('subscribed', subCtx);\n }\n for (const channel in subs) {\n if (!subs.hasOwnProperty(channel)) {\n continue;\n }\n const sub = subs[channel];\n if (sub.recovered) {\n const pubs = sub.publications;\n if (pubs && pubs.length > 0) {\n for (const i in pubs) {\n if (pubs.hasOwnProperty(i)) {\n this._handlePublication(channel, pubs[i]);\n }\n }\n }\n }\n }\n for (const channel in this._serverSubs) {\n if (!this._serverSubs.hasOwnProperty(channel)) {\n continue;\n }\n if (!subs[channel]) {\n this.emit('unsubscribed', { channel: channel });\n delete this._serverSubs[channel];\n }\n }\n }\n _clearRefreshTimeout() {\n if (this._refreshTimeout !== null) {\n clearTimeout(this._refreshTimeout);\n this._refreshTimeout = null;\n }\n }\n _clearReconnectTimeout() {\n if (this._reconnectTimeout !== null) {\n clearTimeout(this._reconnectTimeout);\n this._reconnectTimeout = null;\n }\n }\n _clearServerPingTimeout() {\n if (this._serverPingTimeout !== null) {\n clearTimeout(this._serverPingTimeout);\n this._serverPingTimeout = null;\n }\n }\n _waitServerPing() {\n if (this._config.maxServerPingDelay === 0) {\n return;\n }\n if (!this._isConnected()) {\n return;\n }\n this._clearServerPingTimeout();\n this._serverPingTimeout = setTimeout(() => {\n if (!this._isConnected()) {\n return;\n }\n this._disconnect(connectingCodes.noPing, 'no ping', true);\n }, this._serverPing + this._config.maxServerPingDelay);\n }\n _getSubscribeContext(channel, result) {\n const ctx = {\n channel: channel,\n positioned: false,\n recoverable: false,\n wasRecovering: false,\n recovered: false,\n hasRecoveredPublications: false,\n };\n if (result.recovered) {\n ctx.recovered = true;\n }\n if (result.positioned) {\n ctx.positioned = true;\n }\n if (result.recoverable) {\n ctx.recoverable = true;\n }\n if (result.was_recovering) {\n ctx.wasRecovering = true;\n }\n let epoch = '';\n if ('epoch' in result) {\n epoch = result.epoch;\n }\n let offset = 0;\n if ('offset' in result) {\n offset = result.offset;\n }\n if (ctx.positioned || ctx.recoverable) {\n ctx.streamPosition = {\n 'offset': offset,\n 'epoch': epoch\n };\n }\n if (Array.isArray(result.publications) && result.publications.length > 0) {\n ctx.hasRecoveredPublications = true;\n }\n if (result.data) {\n ctx.data = result.data;\n }\n return ctx;\n }\n _handleReply(reply, next) {\n const id = reply.id;\n if (!(id in this._callbacks)) {\n next();\n return;\n }\n const callbacks = this._callbacks[id];\n clearTimeout(this._callbacks[id].timeout);\n delete this._callbacks[id];\n if (!errorExists(reply)) {\n const callback = callbacks.callback;\n if (!callback) {\n return;\n }\n callback({ reply, next });\n }\n else {\n const errback = callbacks.errback;\n if (!errback) {\n next();\n return;\n }\n const error = { code: reply.error.code, message: reply.error.message || '', temporary: reply.error.temporary || false };\n errback({ error, next });\n }\n }\n _handleJoin(channel, join, id) {\n const sub = this._getSub(channel, id);\n if (!sub && channel) {\n if (this._isServerSub(channel)) {\n const ctx = { channel: channel, info: this._getJoinLeaveContext(join.info) };\n this.emit('join', ctx);\n }\n return;\n }\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._handleJoin(join);\n }\n _handleLeave(channel, leave, id) {\n const sub = this._getSub(channel, id);\n if (!sub && channel) {\n if (this._isServerSub(channel)) {\n const ctx = { channel: channel, info: this._getJoinLeaveContext(leave.info) };\n this.emit('leave', ctx);\n }\n return;\n }\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._handleLeave(leave);\n }\n _handleUnsubscribe(channel, unsubscribe) {\n const sub = this._getSub(channel, 0);\n if (!sub && channel) {\n if (this._isServerSub(channel)) {\n delete this._serverSubs[channel];\n this.emit('unsubscribed', { channel: channel });\n }\n return;\n }\n if (unsubscribe.code < 2500) {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._setUnsubscribed(unsubscribe.code, unsubscribe.reason, false);\n }\n else {\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._setSubscribing(unsubscribe.code, unsubscribe.reason);\n }\n }\n _handleSubscribe(channel, sub) {\n this._serverSubs[channel] = {\n 'offset': sub.offset,\n 'epoch': sub.epoch,\n 'recoverable': sub.recoverable || false\n };\n this.emit('subscribed', this._getSubscribeContext(channel, sub));\n }\n _handleDisconnect(disconnect) {\n const code = disconnect.code;\n let reconnect = true;\n if ((code >= 3500 && code < 4000) || (code >= 4500 && code < 5000)) {\n reconnect = false;\n }\n this._disconnect(code, disconnect.reason, reconnect);\n }\n _getPublicationContext(channel, pub) {\n const ctx = {\n channel: channel,\n data: pub.data\n };\n if (pub.offset) {\n ctx.offset = pub.offset;\n }\n if (pub.info) {\n ctx.info = this._getJoinLeaveContext(pub.info);\n }\n if (pub.tags) {\n ctx.tags = pub.tags;\n }\n return ctx;\n }\n _getJoinLeaveContext(clientInfo) {\n const info = {\n client: clientInfo.client,\n user: clientInfo.user\n };\n const connInfo = clientInfo['conn_info'];\n if (connInfo) {\n info.connInfo = connInfo;\n }\n const chanInfo = clientInfo['chan_info'];\n if (chanInfo) {\n info.chanInfo = chanInfo;\n }\n return info;\n }\n _handlePublication(channel, pub, id) {\n const sub = this._getSub(channel, id);\n if (!sub && channel) {\n if (this._isServerSub(channel)) {\n const ctx = this._getPublicationContext(channel, pub);\n this.emit('publication', ctx);\n if (pub.offset !== undefined) {\n this._serverSubs[channel].offset = pub.offset;\n }\n }\n return;\n }\n // @ts-ignore – we are hiding some symbols from public API autocompletion.\n sub._handlePublication(pub);\n }\n _handleMessage(message) {\n this.emit('message', { data: message.data });\n }\n _handleServerPing(next) {\n if (this._sendPong) {\n const cmd = {};\n this._transportSendCommands([cmd]);\n }\n next();\n }\n _handlePush(data, next) {\n const channel = data.channel;\n const id = data.id;\n if (data.pub) {\n this._handlePublication(channel, data.pub, id);\n }\n else if (data.message) {\n this._handleMessage(data.message);\n }\n else if (data.join) {\n this._handleJoin(channel, data.join, id);\n }\n else if (data.leave) {\n this._handleLeave(channel, data.leave, id);\n }\n else if (data.unsubscribe) {\n this._handleUnsubscribe(channel, data.unsubscribe);\n }\n else if (data.subscribe) {\n this._handleSubscribe(channel, data.subscribe);\n }\n else if (data.disconnect) {\n this._handleDisconnect(data.disconnect);\n }\n next();\n }\n _flush() {\n const commands = this._commands.slice(0);\n this._commands = [];\n this._transportSendCommands(commands);\n }\n _createErrorObject(code, message, temporary) {\n const errObject = {\n code: code,\n message: message\n };\n if (temporary) {\n errObject.temporary = true;\n }\n return errObject;\n }\n _registerCall(id, callback, errback) {\n this._callbacks[id] = {\n callback: callback,\n errback: errback,\n timeout: null\n };\n this._callbacks[id].timeout = setTimeout(() => {\n delete this._callbacks[id];\n if (isFunction(errback)) {\n errback({ error: this._createErrorObject(errorCodes.timeout, 'timeout') });\n }\n }, this._config.timeout);\n }\n _addCommand(command) {\n if (this._batching) {\n this._commands.push(command);\n }\n else {\n this._transportSendCommands([command]);\n }\n }\n _nextPromiseId() {\n return ++this._promiseId;\n }\n _nextTransportId() {\n return ++this._transportId;\n }\n _resolvePromises() {\n for (const id in this._promises) {\n if (!this._promises.hasOwnProperty(id)) {\n continue;\n }\n if (this._promises[id].timeout) {\n clearTimeout(this._promises[id].timeout);\n }\n this._promises[id].resolve();\n delete this._promises[id];\n }\n }\n _rejectPromises(err) {\n for (const id in this._promises) {\n if (!this._promises.hasOwnProperty(id)) {\n continue;\n }\n if (this._promises[id].timeout) {\n clearTimeout(this._promises[id].timeout);\n }\n this._promises[id].reject(err);\n delete this._promises[id];\n }\n }\n}\nCentrifuge.SubscriptionState = SubscriptionState;\nCentrifuge.State = State;\nCentrifuge.UnauthorizedError = UnauthorizedError;\n\nexport { Centrifuge, State, Subscription, SubscriptionState, UnauthorizedError, connectingCodes, disconnectedCodes, errorCodes, subscribingCodes, subscriptionFlags, unsubscribedCodes };\n","import { Centrifuge, Subscription, PublicationContext } from 'centrifuge';\nimport type { CevroMessengerConfig, WSEventPayload } from '../types';\nimport { EventEmitter } from './EventEmitter';\n\n/**\n * Token refresh callback type\n */\nexport type TokenRefreshCallback = () => Promise<string>;\n\n/**\n * WebSocket client for real-time messaging via Centrifugo\n */\nexport class WebSocketClient {\n private config: CevroMessengerConfig;\n private events: EventEmitter;\n private client: Centrifuge | null = null;\n private personalSub: Subscription | null = null;\n private userId: string | null = null;\n private getTokenCallback: TokenRefreshCallback | null = null;\n\n constructor(config: CevroMessengerConfig, events: EventEmitter) {\n this.config = config;\n this.events = events;\n }\n\n /**\n * Update config reference (used when config object is replaced)\n */\n updateConfig(config: CevroMessengerConfig): void {\n this.config = config;\n }\n\n /**\n * Set token refresh callback\n * Called when Centrifugo needs a new token (expiration, reconnect)\n */\n setTokenRefreshCallback(callback: TokenRefreshCallback): void {\n this.getTokenCallback = callback;\n }\n\n /**\n * Connect to Centrifugo server\n */\n connect(userId: string, connectionToken: string): void {\n if (this.client?.state === 'connected') {\n return;\n }\n\n this.userId = userId;\n\n // Determine WebSocket URL from API base\n const wsUrl = this.getWebSocketUrl();\n\n // Build Centrifuge options\n const options: any = {\n token: connectionToken,\n };\n\n // Add token refresh callback if available\n // This is called when token expires or on reconnect\n if (this.getTokenCallback) {\n options.getToken = async () => {\n return await this.getTokenCallback!();\n };\n }\n\n this.client = new Centrifuge(wsUrl, options);\n\n this.setupClientEventListeners();\n\n // Connect\n this.client.connect();\n }\n\n /**\n * Get WebSocket URL from config\n */\n private getWebSocketUrl(): string {\n // If centrifugoUrl is explicitly set, use it\n if (this.config.centrifugoUrl) {\n return this.config.centrifugoUrl;\n }\n\n // Otherwise derive from apiBase\n // e.g., https://api.example.com -> wss://ws.example.com/connection/websocket\n const apiUrl = new URL(this.config.apiBase);\n const wsProtocol = apiUrl.protocol === 'https:' ? 'wss:' : 'ws:';\n\n // Default to same host with /connection/websocket path\n return `${wsProtocol}//${apiUrl.host}/connection/websocket`;\n }\n\n /**\n * Setup Centrifuge client event listeners\n */\n private setupClientEventListeners(): void {\n if (!this.client) return;\n\n this.client.on('connected', (ctx) => {\n this.events.emit('connection:open', { clientId: ctx.client });\n this.subscribeToPersonalChannel();\n });\n\n this.client.on('disconnected', (ctx) => {\n this.events.emit('connection:close', { reason: ctx.reason, code: ctx.code });\n });\n\n this.client.on('error', (ctx) => {\n this.events.emit('connection:error', { error: ctx.error?.message || 'Unknown error' });\n });\n }\n\n /**\n * Subscribe to visitor channel for receiving messages\n * Uses visitorId which is always present (even for authenticated players)\n */\n private subscribeToPersonalChannel(): void {\n if (!this.client || !this.userId) return;\n\n // Always use visitor channel - visitorId is always present\n const channelName = `visitor:${this.userId}`;\n\n // Check if already subscribed (handles reconnection case)\n const existingSub = this.client.getSubscription(channelName);\n if (existingSub) {\n this.personalSub = existingSub;\n if (existingSub.state !== 'subscribed') {\n existingSub.subscribe();\n }\n return;\n }\n\n this.personalSub = this.client.newSubscription(channelName);\n\n this.personalSub.on('publication', (ctx: PublicationContext) => {\n this.handleMessage(ctx.data as WSEventPayload);\n });\n\n this.personalSub.on('error', (ctx) => {\n this.events.emit('error', { type: 'subscription', error: ctx.error?.message });\n });\n\n this.personalSub.subscribe();\n }\n\n /**\n * Handle incoming message from Centrifugo\n * Payload structure: { type, data: {...}, timestamp }\n */\n private handleMessage(payload: any): void {\n const data = payload.data || payload;\n\n switch (payload.type) {\n case 'new_message':\n // Convert backend format to Message format\n const message = {\n id: data.id,\n body: data.body,\n inbound: data.inbound || false,\n outbound: data.outbound || false,\n createdAt: data.createdAt,\n type: data.type || 'text',\n mediaUrl: data.mediaUrl,\n senderType: data.senderType,\n agentName: data.agentName,\n };\n this.events.emit('message:received', {\n ticketId: data.ticketId,\n message,\n });\n break;\n\n case 'typing':\n if (data.isTyping) {\n this.events.emit('typing:start', {\n ticketId: data.ticketId,\n actor: data.senderType || 'agent',\n });\n } else {\n this.events.emit('typing:stop', {\n ticketId: data.ticketId,\n actor: data.senderType || 'agent',\n });\n }\n break;\n\n case 'ticket_created':\n this.events.emit('conversation:started', {\n ticketId: data.ticketId,\n contactId: data.contactId,\n createdAt: data.createdAt,\n });\n break;\n\n case 'ticket_status':\n this.events.emit('conversation:updated', {\n ticketId: data.ticketId,\n status: data.status,\n message: data.message,\n closedAt: data.closedAt,\n agentName: data.agentName,\n });\n break;\n }\n }\n\n /**\n * Update connection token (for token refresh)\n */\n updateToken(newToken: string): void {\n if (this.client) {\n this.client.setToken(newToken);\n }\n }\n\n /**\n * Disconnect from Centrifugo\n */\n disconnect(): void {\n if (this.personalSub) {\n this.personalSub.unsubscribe();\n this.personalSub = null;\n }\n\n if (this.client) {\n this.client.disconnect();\n this.client = null;\n }\n\n this.userId = null;\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.client?.state === 'connected';\n }\n\n /**\n * Get current user ID\n */\n getUserId(): string | null {\n return this.userId;\n }\n}\n","/**\n * Create DOM element with attributes\n */\nexport function createElement<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n attributes?: Record<string, string>,\n children?: (Node | string)[]\n): HTMLElementTagNameMap[K] {\n const element = document.createElement(tag);\n\n if (attributes) {\n Object.entries(attributes).forEach(([key, value]) => {\n if (key === 'className') {\n element.className = value;\n } else if (key.startsWith('data-') || key.startsWith('aria-')) {\n element.setAttribute(key, value);\n } else {\n (element as any)[key] = value;\n }\n });\n }\n\n if (children) {\n children.forEach((child) => {\n if (typeof child === 'string') {\n element.appendChild(document.createTextNode(child));\n } else {\n element.appendChild(child);\n }\n });\n }\n\n return element;\n}\n\n/**\n * Escape HTML to prevent XSS\n */\nexport function escapeHtml(text: string): string {\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n}\n\n/**\n * Validate URL to prevent XSS via javascript: or data: protocols\n * Only allows http:, https:, and blob: protocols\n * blob: URLs are safe - they're generated by the browser for local files\n */\nexport function isValidUrl(url: string): boolean {\n if (!url || typeof url !== 'string') {\n return false;\n }\n\n try {\n const parsed = new URL(url, window.location.origin);\n return ['http:', 'https:', 'blob:'].includes(parsed.protocol);\n } catch {\n return false;\n }\n}\n\n/**\n * Sanitize URL - returns safe URL or empty string\n */\nexport function sanitizeUrl(url: string): string {\n return isValidUrl(url) ? url : '';\n}\n\n/**\n * Parse simple markdown (bold, italic, links, code)\n * URLs are validated to prevent XSS via javascript: protocol\n */\nexport function parseMarkdown(text: string): string {\n return escapeHtml(text)\n // Bold\n .replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>')\n // Italic\n .replace(/\\*(.+?)\\*/g, '<em>$1</em>')\n // Code\n .replace(/`(.+?)`/g, '<code>$1</code>')\n // Links - validate URL to prevent XSS\n .replace(/\\[(.+?)\\]\\((.+?)\\)/g, (_match, linkText, url) => {\n const safeUrl = sanitizeUrl(url);\n if (safeUrl) {\n return `<a href=\"${safeUrl}\" target=\"_blank\" rel=\"noopener\">${linkText}</a>`;\n }\n // If URL is invalid, just show the text without link\n return linkText;\n })\n // Line breaks\n .replace(/\\n/g, '<br>');\n}\n\n/**\n * Format timestamp\n */\nexport function formatTime(date: string | Date): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n}\n\n/**\n * Scroll element to bottom\n */\nexport function scrollToBottom(element: HTMLElement, smooth = true): void {\n element.scrollTo({\n top: element.scrollHeight,\n behavior: smooth ? 'smooth' : 'auto',\n });\n}\n\n/**\n * Check if element is scrolled to bottom\n */\nexport function isScrolledToBottom(element: HTMLElement, threshold = 50): boolean {\n return element.scrollHeight - element.scrollTop - element.clientHeight < threshold;\n}\n\n/**\n * Generate unique ID\n */\nexport function generateId(): string {\n return 'cevro_' + Math.random().toString(36).substring(2, 9);\n}\n","import type { CevroMessengerConfig } from '../types';\nimport { createElement } from '../utils/dom';\n\n/**\n * Launcher component - the chat bubble that opens/closes the chat window\n */\nexport class Launcher {\n private config: CevroMessengerConfig;\n private element: HTMLElement | null = null;\n private unreadBadge: HTMLElement | null = null;\n private onClick: () => void;\n private bubbleIconUrl?: string;\n\n constructor(config: CevroMessengerConfig, onClick: () => void, bubbleIconUrl?: string) {\n this.config = config;\n this.onClick = onClick;\n this.bubbleIconUrl = bubbleIconUrl;\n }\n\n /**\n * Render the launcher\n */\n render(): HTMLElement {\n this.element = createElement('div', {\n className: 'cevro-launcher',\n 'data-testid': 'launcher',\n });\n\n // Apply positioning from config\n this.applyPositioning();\n\n const button = createElement('button', {\n className: 'cevro-launcher__button',\n 'aria-label': 'Open chat',\n type: 'button',\n 'data-testid': 'launcher-button',\n });\n\n if (this.bubbleIconUrl) {\n const chatImg = createElement('img', {\n className: 'cevro-launcher__icon cevro-launcher__icon--chat cevro-launcher__icon--custom',\n src: this.bubbleIconUrl,\n alt: 'Chat',\n }) as HTMLImageElement;\n chatImg.style.width = '28px';\n chatImg.style.height = '28px';\n chatImg.style.objectFit = 'contain';\n button.appendChild(chatImg);\n } else {\n const chatIcon = this.createChatIcon();\n chatIcon.classList.add('cevro-launcher__icon', 'cevro-launcher__icon--chat');\n button.appendChild(chatIcon);\n }\n\n // Close icon (closed state)\n const closeIcon = this.createCloseIcon();\n closeIcon.classList.add('cevro-launcher__icon', 'cevro-launcher__icon--close');\n button.appendChild(closeIcon);\n\n // Unread badge\n this.unreadBadge = createElement('span', {\n className: 'cevro-launcher__badge',\n 'data-testid': 'unread-badge',\n });\n this.unreadBadge.style.display = 'none';\n button.appendChild(this.unreadBadge);\n\n button.addEventListener('click', this.onClick);\n this.element.appendChild(button);\n\n return this.element;\n }\n\n /**\n * Apply positioning styles from config\n */\n private applyPositioning(): void {\n if (!this.element) return;\n\n const alignment = this.config.alignment || 'right';\n const vPadding = this.config.verticalPadding ?? 20;\n const hPadding = this.config.horizontalPadding ?? 20;\n\n this.element.style.bottom = `${vPadding}px`;\n\n if (alignment === 'left') {\n this.element.style.left = `${hPadding}px`;\n this.element.style.right = 'auto';\n } else {\n this.element.style.right = `${hPadding}px`;\n this.element.style.left = 'auto';\n }\n\n if (this.config.zIndex) {\n this.element.style.zIndex = String(this.config.zIndex);\n }\n }\n\n /**\n * Create chat icon SVG\n */\n private createChatIcon(): SVGSVGElement {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.setAttribute('fill', 'none');\n svg.setAttribute('stroke', 'currentColor');\n svg.setAttribute('stroke-width', '2');\n svg.setAttribute('stroke-linecap', 'round');\n svg.setAttribute('stroke-linejoin', 'round');\n\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n path.setAttribute(\n 'd',\n 'M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z'\n );\n\n svg.appendChild(path);\n return svg;\n }\n\n /**\n * Create close icon SVG\n */\n private createCloseIcon(): SVGSVGElement {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('viewBox', '0 0 24 24');\n svg.setAttribute('fill', 'none');\n svg.setAttribute('stroke', 'currentColor');\n svg.setAttribute('stroke-width', '2');\n svg.setAttribute('stroke-linecap', 'round');\n svg.setAttribute('stroke-linejoin', 'round');\n\n const line1 = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n line1.setAttribute('x1', '18');\n line1.setAttribute('y1', '6');\n line1.setAttribute('x2', '6');\n line1.setAttribute('y2', '18');\n\n const line2 = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n line2.setAttribute('x1', '6');\n line2.setAttribute('y1', '6');\n line2.setAttribute('x2', '18');\n line2.setAttribute('y2', '18');\n\n svg.appendChild(line1);\n svg.appendChild(line2);\n return svg;\n }\n\n /**\n * Set launcher state (open/closed)\n */\n setState(isOpen: boolean): void {\n if (this.element) {\n if (isOpen) {\n this.element.classList.add('cevro-launcher--open');\n } else {\n this.element.classList.remove('cevro-launcher--open');\n }\n }\n }\n\n /**\n * Update unread count\n */\n setUnreadCount(count: number): void {\n if (this.unreadBadge) {\n if (count > 0) {\n this.unreadBadge.textContent = count > 99 ? '99+' : String(count);\n this.unreadBadge.style.display = 'flex';\n } else {\n this.unreadBadge.style.display = 'none';\n }\n }\n }\n\n /**\n * Show/hide the launcher\n */\n setVisible(visible: boolean): void {\n if (this.element) {\n this.element.style.display = visible ? 'block' : 'none';\n }\n }\n\n /**\n * Add pulse animation to attract attention\n */\n pulse(): void {\n if (this.element) {\n this.element.classList.add('cevro-launcher--pulse');\n setTimeout(() => {\n this.element?.classList.remove('cevro-launcher--pulse');\n }, 1000);\n }\n }\n\n /**\n * Update bubble icon dynamically (for preview)\n */\n updateBubbleIcon(iconUrl?: string): void {\n this.bubbleIconUrl = iconUrl;\n\n if (!this.element) {\n return;\n }\n\n const button = this.element.querySelector('.cevro-launcher__button');\n if (!button) {\n return;\n }\n\n const existingIcon = button.querySelector('.cevro-launcher__icon--chat');\n if (existingIcon) {\n existingIcon.remove();\n }\n\n if (iconUrl) {\n const chatImg = document.createElement('img');\n chatImg.className = 'cevro-launcher__icon cevro-launcher__icon--chat cevro-launcher__icon--custom';\n chatImg.src = iconUrl;\n chatImg.alt = 'Chat';\n chatImg.style.cssText = 'width: 28px !important; height: 28px !important; object-fit: contain; border-radius: 4px;';\n button.insertBefore(chatImg, button.firstChild);\n } else {\n const chatIcon = this.createChatIcon();\n chatIcon.classList.add('cevro-launcher__icon', 'cevro-launcher__icon--chat');\n button.insertBefore(chatIcon, button.firstChild);\n }\n }\n\n /**\n * Destroy the launcher\n */\n destroy(): void {\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n this.unreadBadge = null;\n }\n}\n","/**\n * Localization strings for the Cevro Messenger widget\n */\n\nexport interface LocaleStrings {\n // Header\n headerTitle: string;\n headerSubtitle: string;\n\n // Input\n inputPlaceholder: string;\n\n // Pre-chat form (for visitors)\n preChatTitle: string;\n preChatSubtitle: string;\n preChatFirstNameLabel: string;\n preChatFirstNamePlaceholder: string;\n preChatEmailLabel: string;\n preChatEmailPlaceholder: string;\n preChatSubmit: string;\n preChatFirstNameRequired: string;\n preChatEmailRequired: string;\n preChatEmailInvalid: string;\n\n // Closed chat\n closedMessage: string;\n newConversation: string;\n\n // Conversation history\n conversationsTitle: string;\n newConversationButton: string;\n activeConversation: string;\n noConversations: string;\n noConversationsSubtitle: string;\n loadingConversations: string;\n loadMoreConversations: string;\n messagesCount: string;\n yesterday: string;\n closedStatus: string;\n defaultConversationTitle: string;\n\n // CSAT\n csatTitle: string;\n csatSubtitle: string;\n csatPlaceholder: string;\n csatPlaceholderNegative?: string;\n csatPlaceholderNeutral?: string;\n csatSubmit: string;\n csatThankYou: string;\n\n // Footer\n poweredBy: string;\n}\n\n/**\n * Default English strings\n */\nexport const defaultStrings: LocaleStrings = {\n // Header\n headerTitle: 'Cevro',\n headerSubtitle: 'We typically reply within a few minutes',\n\n // Input\n inputPlaceholder: 'How can we help?',\n\n // Pre-chat form (for visitors)\n preChatTitle: 'Start a conversation',\n preChatSubtitle: 'Please provide your contact information to get started.',\n preChatFirstNameLabel: 'First name',\n preChatFirstNamePlaceholder: 'Your first name',\n preChatEmailLabel: 'Email',\n preChatEmailPlaceholder: 'your@email.com',\n preChatSubmit: 'Start Chat',\n preChatFirstNameRequired: 'First name is required',\n preChatEmailRequired: 'Email is required',\n preChatEmailInvalid: 'Please enter a valid email',\n\n // Closed chat\n closedMessage: 'The agent closed the chat.',\n newConversation: 'Start New Conversation',\n\n // Conversation history\n conversationsTitle: 'Conversations',\n newConversationButton: 'New Conversation',\n activeConversation: 'Active',\n noConversations: 'No conversations yet',\n noConversationsSubtitle: 'Start a new conversation to get help.',\n loadingConversations: 'Loading...',\n loadMoreConversations: 'Load more',\n messagesCount: 'messages',\n yesterday: 'Yesterday',\n closedStatus: 'Closed',\n defaultConversationTitle: 'Conversation',\n\n // CSAT\n csatTitle: 'How was your conversation?',\n csatSubtitle: 'Your feedback helps us get better.',\n csatPlaceholder: 'Thank you! What stood out?',\n csatPlaceholderNegative: 'Sorry to hear that. What could we improve?',\n csatPlaceholderNeutral: 'Thanks for your feedback. Anything we could do better?',\n csatSubmit: 'Submit Feedback',\n csatThankYou: 'Thank you for your feedback!',\n\n // Footer\n poweredBy: 'Powered by Cevro AI',\n};\n\n/**\n * Merge strings with priority: defaults < client config < backend (DB)\n */\nexport function getStrings(\n clientOverrides?: Partial<LocaleStrings>,\n backendOverrides?: Partial<LocaleStrings>\n): LocaleStrings {\n return {\n ...defaultStrings,\n ...clientOverrides,\n ...backendOverrides,\n };\n}\n","import type { Message, QuickAction, Agent } from '../types';\nimport { createElement, parseMarkdown, formatTime, scrollToBottom, isScrolledToBottom, generateId, isValidUrl } from '../utils/dom';\n\n/**\n * Message list component\n */\nexport class MessageList {\n private element: HTMLElement | null = null;\n private messagesContainer: HTMLElement | null = null;\n private messages: Map<string, HTMLElement> = new Map();\n private messageData: Map<string, Message> = new Map();\n private onQuickAction: ((action: QuickAction) => void) | null = null;\n private autoScroll = true;\n private closedMessageElement: HTMLElement | null = null;\n private currentAgent: Agent | null = null;\n private brandLogoUrl: string | undefined;\n private firstAdminMessageId: string | null = null;\n private lastMessageBody: string | undefined;\n private lastMessageAt: string | undefined;\n private onScrollTopCallback: (() => boolean | void | Promise<boolean | void>) | null = null;\n private isLoadingTop = false;\n private suppressScrollEvents = false;\n\n /**\n * Set quick action handler\n */\n setQuickActionHandler(handler: (action: QuickAction) => void): void {\n this.onQuickAction = handler;\n }\n\n /**\n * Set callback for when user scrolls to the top (for loading older messages)\n */\n setScrollTopHandler(handler: (() => boolean | void | Promise<boolean | void>) | null): void {\n this.onScrollTopCallback = handler;\n }\n\n /**\n * Signal that top-loading is complete, re-enabling scroll-top detection.\n * Delays re-enabling by one frame so the scroll restoration from\n * prependMessages() settles before we accept new scroll-to-top triggers.\n */\n finishLoadingTop(): void {\n // Keep isLoadingTop=true for one more frame to let scroll position settle\n requestAnimationFrame(() => {\n this.isLoadingTop = false;\n });\n }\n\n /**\n * Reset top-pagination state (keeps the scroll-top handler attached)\n */\n resetTopLoading(): void {\n this.isLoadingTop = false;\n this.suppressScrollEvents = false;\n }\n\n /**\n * Set agent info for message avatars\n */\n setAgent(agent: Agent): void {\n this.currentAgent = agent;\n }\n\n /**\n * Set the brand logo shown as the avatar of the conversation's first message only\n */\n setBrandLogoUrl(url?: string): void {\n this.brandLogoUrl = url;\n this.refreshFirstAdminMessageAvatar();\n }\n\n /**\n * Re-render the message currently holding the first-admin-message slot, e.g.\n * after the brand logo changes mid-session. No-ops if none is tracked yet.\n */\n private refreshFirstAdminMessageAvatar(): void {\n if (!this.firstAdminMessageId) return;\n const message = this.messageData.get(this.firstAdminMessageId);\n const el = this.messages.get(this.firstAdminMessageId);\n if (!message || !el) return;\n const rebuiltEl = this.createMessageElement(message, true);\n el.replaceWith(rebuiltEl);\n this.messages.set(this.firstAdminMessageId, rebuiltEl);\n }\n\n /**\n * Render the message list\n */\n render(): HTMLElement {\n if (this.element) {\n return this.element;\n }\n\n this.element = createElement('div', {\n className: 'cevro-messages',\n id: generateId(),\n });\n\n this.messagesContainer = createElement('div', {\n className: 'cevro-messages__container',\n 'data-testid': 'messages-container',\n });\n\n // Track scroll position for auto-scroll and scroll-to-top detection\n this.messagesContainer.addEventListener('scroll', () => {\n if (this.suppressScrollEvents) return;\n this.autoScroll = isScrolledToBottom(this.messagesContainer!);\n if (\n this.messagesContainer!.scrollTop < 80 &&\n this.onScrollTopCallback &&\n !this.isLoadingTop\n ) {\n const result = this.onScrollTopCallback();\n if (result instanceof Promise) {\n this.isLoadingTop = true;\n result\n .then((started) => {\n if (started === false) {\n this.isLoadingTop = false;\n }\n })\n .catch(() => {\n this.isLoadingTop = false;\n });\n } else if (result !== false) {\n this.isLoadingTop = true;\n }\n }\n });\n\n this.element.appendChild(this.messagesContainer);\n\n return this.element;\n }\n\n /**\n * Get the body of the last message added\n */\n getLastMessageBody(): string | undefined {\n return this.lastMessageBody;\n }\n\n getLastMessageAt(): string | undefined {\n return this.lastMessageAt;\n }\n\n /**\n * Count consecutive agent messages at the tail, back to the last user message.\n * If the user has replied since, returns 0.\n */\n getAgentMessagesSinceLastUserMessage(): number {\n if (!this.messagesContainer) return 0;\n const nodes = this.messagesContainer.querySelectorAll('.cevro-message');\n let count = 0;\n for (let i = nodes.length - 1; i >= 0; i--) {\n const el = nodes[i];\n if (el.classList.contains('cevro-message--outbound')) {\n // outbound in SDK = user's own message → stop\n break;\n }\n if (el.classList.contains('cevro-message--inbound')) {\n // inbound in SDK = agent's message → count\n count++;\n }\n }\n return count;\n }\n\n /**\n * Add a message to the list\n */\n addMessage(message: Message, animate = true, skipScroll = false): void {\n if (!this.messagesContainer) return;\n\n // Track last message for conversation list preview\n if (message.body) {\n this.lastMessageBody = message.body;\n this.lastMessageAt = message.createdAt;\n }\n\n // Check if message already exists\n if (this.messages.has(message.id)) {\n this.updateMessage(message);\n return;\n }\n\n this.messageData.set(message.id, message);\n const isFirst = message.inbound !== true && this.firstAdminMessageId === null;\n if (isFirst) {\n this.firstAdminMessageId = message.id;\n }\n const messageEl = this.createMessageElement(message, isFirst);\n if (animate) {\n messageEl.classList.add('cevro-message--animate');\n }\n\n // Insert before typing indicator if it exists, otherwise append\n const typingIndicator = this.messagesContainer.querySelector('#cevro-typing-indicator');\n if (typingIndicator) {\n this.messagesContainer.insertBefore(messageEl, typingIndicator);\n } else {\n this.messagesContainer.appendChild(messageEl);\n }\n this.messages.set(message.id, messageEl);\n\n // Auto-scroll if at bottom (skip during bulk load)\n if (this.autoScroll && !skipScroll) {\n scrollToBottom(this.messagesContainer);\n }\n }\n\n /**\n * Prepend multiple messages at the top (for loading older messages).\n * Performs a single scroll restoration after all inserts to avoid jitter.\n */\n prependMessages(messages: Message[]): void {\n if (!this.messagesContainer || messages.length === 0) return;\n\n // Anchor: remember the current first child's visual position\n let anchor = this.messagesContainer.firstElementChild as HTMLElement | null;\n const anchorOffset = anchor\n ? anchor.offsetTop - this.messagesContainer.scrollTop\n : 0;\n\n // These are older than everything currently loaded — if one of them is an\n // admin message, it's the true first-of-conversation, superseding whatever\n // held that slot before (which needs re-rendering without the brand logo).\n const earliestAdminMessage = messages.find(m => m.inbound !== true);\n if (earliestAdminMessage && earliestAdminMessage.id !== this.firstAdminMessageId) {\n const previousFirstId = this.firstAdminMessageId;\n this.firstAdminMessageId = earliestAdminMessage.id;\n const previousFirstMessage = previousFirstId ? this.messageData.get(previousFirstId) : undefined;\n const previousFirstEl = previousFirstId ? this.messages.get(previousFirstId) : undefined;\n if (previousFirstId && previousFirstMessage && previousFirstEl) {\n const rebuiltEl = this.createMessageElement(previousFirstMessage, false);\n previousFirstEl.replaceWith(rebuiltEl);\n this.messages.set(previousFirstId, rebuiltEl);\n // The rebuilt node replaced the DOM element insertBefore() below anchors\n // on — keep the reference valid so the batch insert doesn't throw.\n if (anchor === previousFirstEl) {\n anchor = rebuiltEl;\n }\n }\n }\n\n // Insert all messages before the anchor in order (oldest → newest)\n for (const message of messages) {\n if (this.messages.has(message.id)) continue;\n this.messageData.set(message.id, message);\n const isFirst = message.id === this.firstAdminMessageId;\n const messageEl = this.createMessageElement(message, isFirst);\n this.messagesContainer.insertBefore(messageEl, anchor);\n this.messages.set(message.id, messageEl);\n }\n\n // Single scroll restoration: keep the anchor element at the same visual position\n // Suppress scroll events to avoid re-triggering the scroll-to-top handler\n if (anchor) {\n this.suppressScrollEvents = true;\n this.messagesContainer.scrollTop = anchor.offsetTop - anchorOffset;\n // Re-enable after the browser processes the scroll\n requestAnimationFrame(() => { this.suppressScrollEvents = false; });\n }\n }\n\n /**\n * Prepend a single message at the top while preserving scroll position.\n */\n prependMessage(message: Message): void {\n this.prependMessages([message]);\n }\n\n /**\n * Update an existing message\n * @param message - Updated message data\n * @param oldId - Original message id (for optimistic updates where id changes)\n */\n updateMessage(message: Message, oldId?: string): void {\n const lookupId = oldId || message.id;\n const existingEl = this.messages.get(lookupId);\n if (!existingEl || !this.messagesContainer) return;\n\n if (this.firstAdminMessageId === lookupId) {\n this.firstAdminMessageId = message.id;\n }\n const isFirst = this.firstAdminMessageId === message.id;\n this.messageData.set(message.id, message);\n const newEl = this.createMessageElement(message, isFirst);\n this.messagesContainer.replaceChild(newEl, existingEl);\n\n // Remove old id entry and add new one\n if (oldId && oldId !== message.id) {\n this.messages.delete(oldId);\n this.messageData.delete(oldId);\n }\n this.messages.set(message.id, newEl);\n }\n\n /**\n * Update upload progress for a message\n */\n updateMessageProgress(messageId: string, progress: number): void {\n const messageEl = this.messages.get(messageId);\n if (!messageEl) return;\n\n const progressFill = messageEl.querySelector('.cevro-file-progress__fill') as HTMLElement;\n const progressText = messageEl.querySelector('.cevro-file-progress__text');\n\n if (progressFill) {\n progressFill.style.width = `${progress}%`;\n }\n if (progressText) {\n progressText.textContent = `${progress}%`;\n }\n }\n\n /**\n * Remove a message from the list\n */\n removeMessage(messageId: string): void {\n const messageEl = this.messages.get(messageId);\n if (!messageEl) return;\n\n messageEl.remove();\n this.messages.delete(messageId);\n this.messageData.delete(messageId);\n if (this.firstAdminMessageId === messageId) {\n this.firstAdminMessageId = null;\n this.promoteNextAdminMessageToFirst();\n }\n }\n\n /**\n * Give the first-message treatment to the earliest remaining admin message\n * (by DOM position), e.g. after the previous holder is removed.\n */\n private promoteNextAdminMessageToFirst(): void {\n if (!this.messagesContainer) return;\n for (const child of Array.from(this.messagesContainer.children)) {\n const id = (child as HTMLElement).dataset.messageId;\n if (!id) continue;\n const message = this.messageData.get(id);\n if (!message || message.inbound === true) continue;\n\n this.firstAdminMessageId = id;\n const rebuiltEl = this.createMessageElement(message, true);\n child.replaceWith(rebuiltEl);\n this.messages.set(id, rebuiltEl);\n return;\n }\n }\n\n /**\n * Create message element\n */\n private createMessageElement(message: Message, isFirst = false): HTMLElement {\n // From SDK perspective:\n // - inbound: true = user's message (to backend) = show on RIGHT\n // - outbound: true = admin's message (from backend) = show on LEFT\n const isMyMessage = message.inbound === true;\n const wrapper = createElement('div', {\n className: `cevro-message ${isMyMessage ? 'cevro-message--outbound' : 'cevro-message--inbound'}`,\n 'data-message-id': message.id,\n 'data-testid': `message-${message.id}`,\n });\n\n // Shared by the avatar block below and the sender-name label further down,\n // so both agree on whether this message is rendered as a human agent.\n const showBrandLogo = !isMyMessage && isFirst && !!this.brandLogoUrl && isValidUrl(this.brandLogoUrl);\n const isHuman = !isMyMessage && !showBrandLogo && message.senderType === 'human';\n\n // Avatar for admin messages\n if (!isMyMessage) {\n const avatar = createElement('div', {\n className: `cevro-message__avatar${isHuman ? ' cevro-message__avatar--human' : ''}`,\n });\n\n if (isHuman) {\n // Human agent: show initials avatar\n const name = message.agentName || 'Support';\n const initials = name\n .split(' ')\n .map(w => w[0])\n .join('')\n .toUpperCase()\n .slice(0, 2);\n const initialsEl = createElement('div', {\n className: 'cevro-message__avatar-initials',\n });\n initialsEl.textContent = initials;\n avatar.appendChild(initialsEl);\n } else {\n const validAgentAvatarUrl =\n this.currentAgent?.avatarUrl && isValidUrl(this.currentAgent.avatarUrl)\n ? this.currentAgent.avatarUrl\n : null;\n const avatarSrc = showBrandLogo ? this.brandLogoUrl : validAgentAvatarUrl;\n if (avatarSrc) {\n const img = createElement('img', {\n className: 'cevro-message__avatar-img',\n src: avatarSrc,\n alt: showBrandLogo ? 'Logo' : this.currentAgent?.name || 'Agent',\n }) as HTMLImageElement;\n avatar.appendChild(img);\n } else {\n avatar.innerHTML = this.createBotAvatarSvg();\n }\n }\n\n wrapper.appendChild(avatar);\n }\n\n // Message content wrapper\n const contentWrapper = createElement('div', {\n className: 'cevro-message__content-wrapper',\n });\n\n // Show sender name for human agent messages\n if (isHuman && message.agentName) {\n const senderLabel = createElement('div', {\n className: 'cevro-message__sender-name',\n });\n senderLabel.textContent = message.agentName;\n contentWrapper.appendChild(senderLabel);\n }\n\n // Message bubble\n const bubble = createElement('div', {\n className: 'cevro-message__bubble',\n });\n\n // Handle different message types\n const isImage = message.type === 'image' || message.attachment?.category === 'image';\n\n if (isImage && message.mediaUrl && isValidUrl(message.mediaUrl)) {\n // Image message - show actual image\n const imageContainer = createElement('div', {\n className: 'cevro-message__image-container',\n });\n\n const img = createElement('img', {\n className: 'cevro-message__image',\n }) as HTMLImageElement;\n img.src = message.mediaUrl;\n img.alt = message.attachment?.filename || 'Image';\n img.loading = 'lazy';\n imageContainer.appendChild(img);\n\n // Show progress overlay if uploading\n if (message.status === 'sending') {\n const progressOverlay = this.createProgressOverlay();\n imageContainer.appendChild(progressOverlay);\n }\n\n bubble.appendChild(imageContainer);\n } else if (message.type === 'file' || (message.attachment && !isImage)) {\n // File attachment (non-image) - show file card\n const fileCard = this.createFileCard(message);\n bubble.appendChild(fileCard);\n } else if (message.type === 'media' && message.mediaUrl && isValidUrl(message.mediaUrl)) {\n // Legacy media type\n const link = createElement('a', {\n className: 'cevro-message__attachment',\n }) as HTMLAnchorElement;\n link.href = message.mediaUrl;\n link.target = '_blank';\n link.rel = 'noopener';\n link.innerHTML = `\n ${this.getFileIcon('file')}\n <span>Attachment</span>\n `;\n bubble.appendChild(link);\n }\n\n // Text content\n if (message.body) {\n const textContent = createElement('div', {\n className: 'cevro-message__text',\n });\n textContent.innerHTML = parseMarkdown(message.body);\n bubble.appendChild(textContent);\n }\n\n contentWrapper.appendChild(bubble);\n\n // Quick actions\n if (message.richContent?.quickActions?.length) {\n const actionsContainer = createElement('div', {\n className: 'cevro-message__quick-actions',\n });\n\n message.richContent.quickActions.forEach((action) => {\n const button = createElement('button', {\n className: 'cevro-message__quick-action',\n });\n button.textContent = action.label;\n button.addEventListener('click', () => {\n if (this.onQuickAction) {\n this.onQuickAction(action);\n }\n });\n actionsContainer.appendChild(button);\n });\n\n contentWrapper.appendChild(actionsContainer);\n }\n\n // Timestamp and status\n const meta = createElement('div', {\n className: 'cevro-message__meta',\n });\n meta.textContent = formatTime(message.createdAt);\n\n // Status indicator for user's own messages\n if (isMyMessage && message.status) {\n const status = createElement('span', {\n className: `cevro-message__status cevro-message__status--${message.status}`,\n });\n status.innerHTML = this.getStatusIcon(message.status);\n meta.appendChild(status);\n }\n\n contentWrapper.appendChild(meta);\n wrapper.appendChild(contentWrapper);\n\n return wrapper;\n }\n\n /**\n * Create progress overlay for images\n */\n private createProgressOverlay(): HTMLElement {\n const overlay = createElement('div', {\n className: 'cevro-file-progress-overlay',\n });\n overlay.innerHTML = `\n <div class=\"cevro-file-progress\">\n <div class=\"cevro-file-progress__bar\">\n <div class=\"cevro-file-progress__fill\" style=\"width: 0%\"></div>\n </div>\n <span class=\"cevro-file-progress__text\">0%</span>\n </div>\n `;\n return overlay;\n }\n\n /**\n * Create file card for non-image attachments\n */\n private createFileCard(message: Message): HTMLElement {\n const attachment = message.attachment;\n const category = attachment?.category || 'file';\n const filename = attachment?.filename || 'File';\n const size = attachment?.size || 0;\n const isUploading = message.status === 'sending';\n\n const card = createElement('div', {\n className: `cevro-file-card cevro-file-card--${category}`,\n });\n\n // File icon\n const iconWrapper = createElement('div', {\n className: 'cevro-file-card__icon',\n });\n iconWrapper.innerHTML = this.getFileIcon(category);\n card.appendChild(iconWrapper);\n\n // File info\n const info = createElement('div', {\n className: 'cevro-file-card__info',\n });\n\n const name = createElement('div', {\n className: 'cevro-file-card__name',\n });\n name.textContent = this.truncateFilename(filename, 25);\n name.title = filename;\n info.appendChild(name);\n\n const details = createElement('div', {\n className: 'cevro-file-card__details',\n });\n details.textContent = this.formatFileSize(size);\n info.appendChild(details);\n\n card.appendChild(info);\n\n // Progress or download\n if (isUploading) {\n const progress = createElement('div', {\n className: 'cevro-file-card__progress',\n });\n progress.innerHTML = `\n <div class=\"cevro-file-progress\">\n <div class=\"cevro-file-progress__bar\">\n <div class=\"cevro-file-progress__fill\" style=\"width: 0%\"></div>\n </div>\n <span class=\"cevro-file-progress__text\">0%</span>\n </div>\n `;\n card.appendChild(progress);\n } else if (message.mediaUrl && isValidUrl(message.mediaUrl)) {\n // Make card clickable to download\n card.style.cursor = 'pointer';\n card.addEventListener('click', () => {\n window.open(message.mediaUrl, '_blank');\n });\n }\n\n return card;\n }\n\n /**\n * Get file icon SVG based on category\n */\n private getFileIcon(category: string): string {\n const icons: Record<string, string> = {\n pdf: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#E53935\"/>\n <path d=\"M14 2V8H20\" fill=\"#FFCDD2\"/>\n <path d=\"M9 13H10.5V14.5H9V16H7.5V11H10.5V12.5H9V13Z\" fill=\"white\"/>\n <path d=\"M11.5 11H13.5C14.05 11 14.5 11.45 14.5 12V14C14.5 14.55 14.05 15 13.5 15H12.5V16H11.5V11ZM13 14V12H12.5V14H13Z\" fill=\"white\"/>\n <path d=\"M15.5 11H17V12H16V13H17V14H16V16H15.5V11Z\" fill=\"white\"/>\n </svg>`,\n document: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#1976D2\"/>\n <path d=\"M14 2V8H20\" fill=\"#BBDEFB\"/>\n <path d=\"M8 12H16V13H8V12ZM8 15H14V16H8V15Z\" fill=\"white\"/>\n </svg>`,\n spreadsheet: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#388E3C\"/>\n <path d=\"M14 2V8H20\" fill=\"#C8E6C9\"/>\n <path d=\"M8 12H10V14H8V12ZM11 12H13V14H11V12ZM14 12H16V14H14V12ZM8 15H10V17H8V15ZM11 15H13V17H11V15Z\" fill=\"white\"/>\n </svg>`,\n presentation: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#F57C00\"/>\n <path d=\"M14 2V8H20\" fill=\"#FFE0B2\"/>\n <rect x=\"8\" y=\"12\" width=\"8\" height=\"5\" rx=\"1\" fill=\"white\"/>\n </svg>`,\n video: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#7B1FA2\"/>\n <path d=\"M14 2V8H20\" fill=\"#E1BEE7\"/>\n <path d=\"M10 11V17L15 14L10 11Z\" fill=\"white\"/>\n </svg>`,\n audio: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#00897B\"/>\n <path d=\"M14 2V8H20\" fill=\"#B2DFDB\"/>\n <path d=\"M12 11C10.9 11 10 11.9 10 13V15C10 16.1 10.9 17 12 17C13.1 17 14 16.1 14 15V13C14 11.9 13.1 11 12 11Z\" fill=\"white\"/>\n <path d=\"M15 14V15C15 16.66 13.66 18 12 18C10.34 18 9 16.66 9 15V14H8V15C8 17.03 9.53 18.71 11.5 18.96V20H10V21H14V20H12.5V18.96C14.47 18.71 16 17.03 16 15V14H15Z\" fill=\"white\"/>\n </svg>`,\n archive: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#795548\"/>\n <path d=\"M14 2V8H20\" fill=\"#D7CCC8\"/>\n <rect x=\"10\" y=\"11\" width=\"4\" height=\"2\" fill=\"white\"/>\n <rect x=\"10\" y=\"14\" width=\"4\" height=\"2\" fill=\"white\"/>\n <rect x=\"10\" y=\"17\" width=\"4\" height=\"2\" fill=\"white\"/>\n </svg>`,\n text: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#607D8B\"/>\n <path d=\"M14 2V8H20\" fill=\"#CFD8DC\"/>\n <path d=\"M8 12H16V13H8V12ZM8 15H14V16H8V15ZM8 18H16V19H8V18Z\" fill=\"white\"/>\n </svg>`,\n image: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#43A047\"/>\n <path d=\"M14 2V8H20\" fill=\"#C8E6C9\"/>\n <circle cx=\"10\" cy=\"13\" r=\"2\" fill=\"white\"/>\n <path d=\"M8 18L10 15L12 17L15 13L17 18H8Z\" fill=\"white\"/>\n </svg>`,\n file: `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2Z\" fill=\"#90A4AE\"/>\n <path d=\"M14 2V8H20\" fill=\"#CFD8DC\"/>\n </svg>`,\n };\n\n return icons[category] || icons.file;\n }\n\n /**\n * Format file size to human readable\n */\n private formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];\n }\n\n /**\n * Truncate filename if too long\n */\n private truncateFilename(filename: string, maxLength: number): string {\n if (filename.length <= maxLength) return filename;\n\n const ext = filename.split('.').pop() || '';\n const name = filename.slice(0, filename.length - ext.length - 1);\n const truncatedName = name.slice(0, maxLength - ext.length - 4) + '...';\n return truncatedName + '.' + ext;\n }\n\n /**\n * Create bot avatar SVG\n */\n private createBotAvatarSvg(): string {\n return `\n <svg width=\"28\" height=\"28\" viewBox=\"0 0 28 28\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"14\" cy=\"10\" r=\"4\" fill=\"white\"/>\n <path d=\"M7 22c0-3.866 3.134-7 7-7s7 3.134 7 7\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\"/>\n </svg>\n `;\n }\n\n /**\n * Get status icon\n * - sending: single checkmark (message is being sent)\n * - sent: double checkmark (message delivered to server)\n * - delivered: double checkmark (same as sent)\n * - read: double checkmark filled (message was read)\n * - failed: X icon in red\n */\n private getStatusIcon(status: string): string {\n // Single checkmark\n const singleCheck = '<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>';\n // Double checkmark\n const doubleCheck = '<svg width=\"16\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"18 7 9.5 17 5 12\"/><polyline points=\"23 7 14.5 17 12 14\"/></svg>';\n // Double checkmark filled (for read)\n const doubleCheckRead = '<svg width=\"16\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#8B5CF6\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"18 7 9.5 17 5 12\"/><polyline points=\"23 7 14.5 17 12 14\"/></svg>';\n\n switch (status) {\n case 'sending':\n return singleCheck;\n case 'sent':\n case 'delivered':\n return doubleCheck;\n case 'read':\n return doubleCheckRead;\n case 'failed':\n return '<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ef4444\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/></svg>';\n default:\n return '';\n }\n }\n\n /**\n * Show typing indicator\n */\n showTypingIndicator(): void {\n if (!this.messagesContainer) return;\n\n // Remove existing typing indicator\n this.hideTypingIndicator();\n\n const indicator = createElement('div', {\n className: 'cevro-typing-indicator',\n id: 'cevro-typing-indicator',\n 'data-testid': 'typing-indicator',\n });\n\n indicator.innerHTML = `\n <div class=\"cevro-typing-indicator__avatar\">\n ${this.createBotAvatarSvg()}\n </div>\n <div class=\"cevro-typing-indicator__dots\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n `;\n\n this.messagesContainer.appendChild(indicator);\n\n if (this.autoScroll) {\n scrollToBottom(this.messagesContainer);\n }\n }\n\n /**\n * Hide typing indicator\n */\n hideTypingIndicator(): void {\n // Use querySelector on container (works with Shadow DOM)\n const indicator = this.messagesContainer?.querySelector('#cevro-typing-indicator');\n if (indicator) {\n indicator.remove();\n }\n }\n\n /**\n * Clear all messages\n */\n clear(): void {\n if (this.messagesContainer) {\n this.messagesContainer.innerHTML = '';\n }\n this.messages.clear();\n this.messageData.clear();\n this.firstAdminMessageId = null;\n this.lastMessageBody = undefined;\n this.lastMessageAt = undefined;\n this.autoScroll = true;\n this.resetTopLoading();\n // Also remove closed message if present\n if (this.closedMessageElement) {\n this.closedMessageElement.remove();\n this.closedMessageElement = null;\n }\n }\n\n /**\n * Show closed chat message at the bottom of messages area\n * This displays when a ticket is closed (e.g., escalated and resolved)\n * @param message - Custom message text (optional)\n */\n showClosedMessage(message?: string): void {\n if (!this.messagesContainer) return;\n\n // Remove existing closed message\n this.hideClosedMessage();\n\n this.closedMessageElement = createElement('div', {\n className: 'cevro-messages__closed-notice',\n 'data-testid': 'closed-chat-message',\n });\n\n const displayMessage = message || 'The agent closed the chat. If you need assistance please start a new chat.';\n this.closedMessageElement.innerHTML = `\n <p class=\"cevro-messages__closed-text\">\n ${displayMessage}\n </p>\n `;\n\n this.messagesContainer.appendChild(this.closedMessageElement);\n\n // Scroll to show the closed message\n if (this.autoScroll) {\n scrollToBottom(this.messagesContainer);\n }\n }\n\n /**\n * Hide closed chat message\n */\n hideClosedMessage(): void {\n if (this.closedMessageElement) {\n this.closedMessageElement.remove();\n this.closedMessageElement = null;\n }\n }\n\n /**\n * Scroll to bottom\n */\n scrollToBottom(): void {\n if (this.messagesContainer) {\n scrollToBottom(this.messagesContainer, false);\n }\n }\n\n /**\n * Destroy the component\n */\n destroy(): void {\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n this.messagesContainer = null;\n this.messages.clear();\n this.messageData.clear();\n this.firstAdminMessageId = null;\n }\n}\n","import type { CevroMessengerConfig, Message, QuickAction, Agent, LocaleStrings } from '../types';\nimport { createElement, generateId } from '../utils/dom';\nimport { generateAcceptAttribute } from '../utils/file-validation';\nimport { defaultStrings, getStrings } from '../i18n/strings';\nimport { MessageList } from './MessageList';\n\nexport interface ChatWindowCallbacks {\n onClose: () => void;\n onSendMessage: (message: string) => void;\n onQuickAction: (action: QuickAction) => void;\n onFileUpload?: (file: File) => void;\n onCSATSubmit?: (rating: number, feedback?: string) => Promise<void>;\n onStartNewChat?: () => void;\n onPreChatSubmit?: (data: { firstName: string; email: string }) => void;\n onShowHistory?: () => void;\n}\n\n/**\n * Chat window component\n */\nexport class ChatWindow {\n private config: CevroMessengerConfig;\n private callbacks: ChatWindowCallbacks;\n private element: HTMLElement | null = null;\n private messageList: MessageList;\n private inputElement: HTMLTextAreaElement | null = null;\n private sendButton: HTMLButtonElement | null = null;\n private fileInput: HTMLInputElement | null = null;\n private fileButton: HTMLButtonElement | null = null;\n private isVisible = false;\n private logoElement: HTMLElement | null = null;\n private brandNameElement: HTMLElement | null = null;\n private headerSubtitleElement: HTMLElement | null = null;\n private inputWrapper: HTMLElement | null = null;\n private closedFooter: HTMLElement | null = null;\n private csatContainer: HTMLElement | null = null;\n\n // Localization\n private strings: LocaleStrings = defaultStrings;\n\n // CSAT state\n private csatRating: number = 0;\n private csatFeedback: string = '';\n private csatSubmitting: boolean = false;\n\n // Pre-chat form state\n private preChatContainer: HTMLElement | null = null;\n private preChatCompleted: boolean = false;\n\n private customLogoUrl?: string;\n\n constructor(\n config: CevroMessengerConfig,\n callbacks: ChatWindowCallbacks,\n strings?: LocaleStrings,\n customLogoUrl?: string\n ) {\n this.config = config;\n this.callbacks = callbacks;\n this.strings = strings || getStrings(config.locale);\n this.customLogoUrl = customLogoUrl;\n this.messageList = new MessageList();\n this.messageList.setQuickActionHandler((action) => {\n this.callbacks.onQuickAction(action);\n });\n }\n\n /**\n * Update locale strings (e.g., after receiving from backend)\n */\n setStrings(backendStrings?: Partial<LocaleStrings>): void {\n this.strings = getStrings(this.config.locale, backendStrings);\n this.updateUIStrings();\n }\n\n /**\n * Update UI elements with current strings\n */\n private updateUIStrings(): void {\n if (this.headerSubtitleElement) {\n this.headerSubtitleElement.textContent = this.strings.headerSubtitle;\n }\n if (this.inputElement) {\n this.inputElement.placeholder = this.strings.inputPlaceholder;\n }\n }\n\n /**\n * Render the chat window\n */\n render(): HTMLElement {\n if (this.element) {\n return this.element;\n }\n\n // Main container\n this.element = createElement('div', {\n className: 'cevro-chat-window',\n id: generateId(),\n });\n\n // Apply positioning\n this.applyPositioning();\n\n // Header\n const header = this.createHeader();\n this.element.appendChild(header);\n\n // Messages area\n const messagesArea = this.messageList.render();\n this.element.appendChild(messagesArea);\n\n // Input area\n this.inputWrapper = this.createInputArea();\n this.element.appendChild(this.inputWrapper);\n\n return this.element;\n }\n\n /**\n * Apply positioning styles\n */\n private applyPositioning(): void {\n if (!this.element) return;\n\n const alignment = this.config.alignment || 'right';\n const vPadding = this.config.verticalPadding ?? 20;\n const hPadding = this.config.horizontalPadding ?? 20;\n\n // Position above launcher\n this.element.style.bottom = `${vPadding + 70}px`;\n\n if (alignment === 'left') {\n this.element.style.left = `${hPadding}px`;\n this.element.style.right = 'auto';\n } else {\n this.element.style.right = `${hPadding}px`;\n this.element.style.left = 'auto';\n }\n\n if (this.config.zIndex) {\n this.element.style.zIndex = String(this.config.zIndex - 1);\n }\n }\n\n /**\n * Create header element\n */\n private createHeader(): HTMLElement {\n const header = createElement('div', {\n className: 'cevro-chat-window__header',\n });\n\n this.logoElement = createElement('div', {\n className: 'cevro-chat-window__logo',\n 'data-testid': 'company-logo',\n });\n if (this.customLogoUrl) {\n const logoImg = createElement('img', {\n src: this.customLogoUrl,\n alt: 'Logo',\n className: 'cevro-chat-window__logo-img',\n }) as HTMLImageElement;\n logoImg.style.width = '40px';\n logoImg.style.height = '40px';\n logoImg.style.objectFit = 'contain';\n logoImg.style.borderRadius = '8px';\n this.logoElement.appendChild(logoImg);\n } else {\n this.logoElement.innerHTML = this.createCompanyLogoSvg();\n }\n\n // History button (back chevron on the left)\n const historyButton = createElement('button', {\n className: 'cevro-chat-window__history-button',\n 'aria-label': 'Conversation history',\n 'data-testid': 'history-button',\n });\n historyButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"15 18 9 12 15 6\"/>\n </svg>\n `;\n historyButton.addEventListener('click', () => {\n if (this.callbacks.onShowHistory) {\n this.callbacks.onShowHistory();\n }\n });\n header.appendChild(historyButton);\n\n header.appendChild(this.logoElement);\n\n // Title section\n const titleSection = createElement('div', {\n className: 'cevro-chat-window__title-section',\n });\n\n this.brandNameElement = createElement('h2', {\n className: 'cevro-chat-window__title',\n 'data-testid': 'brand-name',\n }, [this.strings.headerTitle]);\n\n this.headerSubtitleElement = createElement('p', {\n className: 'cevro-chat-window__subtitle',\n }, [this.strings.headerSubtitle]);\n\n titleSection.appendChild(this.brandNameElement);\n titleSection.appendChild(this.headerSubtitleElement);\n header.appendChild(titleSection);\n\n // Close button\n const closeButton = createElement('button', {\n className: 'cevro-chat-window__close',\n 'aria-label': 'Close chat',\n 'data-testid': 'close-button',\n });\n closeButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n `;\n closeButton.addEventListener('click', () => {\n this.callbacks.onClose();\n });\n header.appendChild(closeButton);\n\n return header;\n }\n\n /**\n * Create company logo SVG\n */\n private createCompanyLogoSvg(): string {\n return `\n <svg width=\"40\" height=\"40\" viewBox=\"0 0 40 40\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect width=\"40\" height=\"40\" rx=\"8\" fill=\"url(#cevro-logo-gradient)\"/>\n <svg x=\"6\" y=\"6\" width=\"28\" height=\"28\" viewBox=\"0 0 512 498\">\n <g>\n <path fill=\"#FFFFFF\" d=\"M298.97,91.19l-32.23-32.23c-6.12-6.12-6.12-16.03,0-22.15l32.23-32.23c6.12-6.12,16.03-6.12,22.15,0\n l30.06,30.06c2.94,2.94,6.92,4.59,11.07,4.59h48.31v17.32h-48.31c-4.15,0-8.14,1.65-11.07,4.59l-30.05,30.06\n C315,97.3,305.09,97.31,298.97,91.19z\"/>\n <path fill=\"#FFFFFF\" d=\"M260.84,157h96.5c4.15,0,8.14,1.65,11.07,4.59l30.05,30.05c6.12,6.12,16.03,6.12,22.15,0l30.06-30.06\n c2.94-2.94,6.92-4.59,11.07-4.59h50.21v-17.32h-50.21c-4.15,0-8.14-1.65-11.07-4.59l-30.06-30.06\n c-6.12-6.12-16.03-6.12-22.15,0l-30.06,30.05c-2.94,2.94-6.92,4.59-11.07,4.59h-96.5c-4.15,0-8.14-1.65-11.07-4.59\n l-30.06-30.05c-6.12-6.12-16.03-6.12-22.15,0l-32.23,32.23c-6.12,6.12-6.12,16.03,0,22.15l32.23,32.23\n c6.12,6.12,16.03,6.12,22.15,0l30.06-30.05C252.7,158.65,256.69,157,260.84,157z\"/>\n <path fill=\"#FFFFFF\" d=\"M260.84,340.58h96.5c4.15,0,8.14-1.65,11.07-4.59l30.06-30.06c6.12-6.12,16.03-6.12,22.15,0L450.67,336\n c2.94,2.94,6.92,4.59,11.07,4.59h50.21v17.32h-50.21c-4.15,0-8.14,1.65-11.07,4.59l-30.05,30.06\n c-6.12,6.12-16.03,6.12-22.15,0l-30.06-30.06c-2.94-2.94-6.92-4.59-11.07-4.59h-96.5c-4.15,0-8.14,1.65-11.07,4.59\n l-30.05,30.06c-6.12,6.12-16.03,6.12-22.15,0l-32.23-32.23c-6.12-6.12-6.12-16.03,0-22.15l32.23-32.23\n c6.12,6.12,16.03-6.12,22.15,0L249.77,336C252.7,338.93,256.69,340.58,260.84,340.58z\"/>\n <path fill=\"#FFFFFF\" d=\"M343.17,259.89l-1.13,1.13l-31.09,31.09c-1.9,1.9-4.16,3.21-6.6,3.92c-3.92,1.19-8.2,0.83-11.83-1.13\n c-0.89-0.54-1.72-1.07-2.56-1.72c-0.42-0.3-0.83-0.65-1.25-1.07l-30.02-30.08h-0.06c-2.91-2.91-6.9-4.58-11.06-4.58h-86.71\n c-2.62,0-5.11,0.65-7.37,1.84c-0.89,0.53-1.72,1.07-2.5,1.72c-0.06-0.06-0.06-0.06-0.06,0c-0.36,0.36-0.71,0.65-1.07,1.01\n l-30.08,30.08h-0.06c-0.36,0.36-0.77,0.71-1.19,1.07c-0.77,0.71-1.66,1.25-2.56,1.72c-3.63,1.9-7.91,2.32-11.83,1.13\n c-0.95-0.3-1.84-0.71-2.73-1.13c-0.06,0-0.06,0-0.06,0c-1.31-0.77-2.56-1.66-3.69-2.79l-30.08-30.08h-0.06\n c-0.71-0.77-1.49-1.37-2.32-1.96c-0.06,0.06-0.06,0.06-0.06,0c-1.31-0.89-2.68-1.55-4.16-1.96\n c-1.49-0.42-3.03-0.65-4.58-0.65H6.3v-17.3h50.12c1.55,0,3.09-0.24,4.58-0.65c1.49-0.42,2.85-1.07,4.16-1.96\n c0-0.06,0-0.06,0.06,0c0.83-0.59,1.61-1.19,2.32-1.96h0.06l30.08-30.08c1.13-1.13,2.38-2.08,3.69-2.79c0,0,0-0.06,0.06,0\n c0.47-0.24,0.95-0.48,1.43-0.65c0.48-0.18,0.95-0.36,1.43-0.48c3.86-1.19,8.08-0.77,11.71,1.13\n c0.89,0.48,1.79,1.01,2.56,1.72c0.42,0.36,0.83,0.71,1.19,1.07h0.06l30.08,30.08c0.36,0.36,0.71,0.65,1.07,1.01\n c0,0.06,0,0.06,0.06,0c0.77,0.65,1.61,1.19,2.5,1.72c2.26,1.19,4.76,1.84,7.37,1.84h86.71c4.16,0,8.14-1.66,11.06-4.58h0.06\n l30.08-30.08c0.36-0.42,0.77-0.77,1.19-1.07c0.83-0.65,1.66-1.25,2.56-1.72c3.63-1.9,7.85-2.32,11.71-1.13\n c0.48,0.12,0.95,0.3,1.43,0.48c1.96,0.71,3.74,1.84,5.29,3.45l32.22,32.22C349.23,243.83,349.23,253.76,343.17,259.89z\"/>\n <path fill=\"#FFFFFF\" d=\"M298.02,406.39l-32.23,32.23c-6.12,6.12-6.12,16.03,0,22.15L298.02,493c6.12,6.12,16.03,6.12,22.15,0\n l30.06-30.06c2.94-2.94,6.92-4.59,11.07-4.59h50.21v-17.32h-50.21c-4.15,0-8.14-1.65-11.07-4.59l-30.06-30.06\n C314.05,400.28,304.13,400.28,298.02,406.39z\"/>\n </g>\n </svg>\n <defs>\n <linearGradient id=\"cevro-logo-gradient\" x1=\"0\" y1=\"0\" x2=\"40\" y2=\"40\" gradientUnits=\"userSpaceOnUse\">\n <stop offset=\"0%\" stop-color=\"#8B5CF6\"/>\n <stop offset=\"100%\" stop-color=\"#7C3AED\"/>\n </linearGradient>\n </defs>\n </svg>\n `;\n }\n\n /**\n * Set agent info (used for message avatars)\n */\n setAgent(agent: Agent): void {\n // Pass agent info to MessageList for message avatars\n this.messageList.setAgent(agent);\n }\n\n /**\n * Create input area element\n */\n private createInputArea(): HTMLElement {\n const wrapper = createElement('div', {\n className: 'cevro-chat-window__input-wrapper',\n });\n\n const inputArea = createElement('div', {\n className: 'cevro-chat-window__input-area',\n });\n\n // File upload button (paperclip icon)\n this.fileButton = createElement('button', {\n className: 'cevro-chat-window__file-button',\n 'aria-label': 'Attach file',\n 'data-testid': 'file-button',\n }) as HTMLButtonElement;\n this.fileButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M16.5 6V17.5C16.5 19.71 14.71 21.5 12.5 21.5C10.29 21.5 8.5 19.71 8.5 17.5V5C8.5 3.62 9.62 2.5 11 2.5C12.38 2.5 13.5 3.62 13.5 5V16.5C13.5 17.05 13.05 17.5 12.5 17.5C11.95 17.5 11.5 17.05 11.5 16.5V6H10V16.5C10 17.88 11.12 19 12.5 19C13.88 19 15 17.88 15 16.5V5C15 2.79 13.21 1 11 1C8.79 1 7 2.79 7 5V17.5C7 20.54 9.46 23 12.5 23C15.54 23 18 20.54 18 17.5V6H16.5Z\" fill=\"currentColor\"/>\n </svg>\n `;\n\n // Hidden file input\n this.fileInput = createElement('input', {\n className: 'cevro-chat-window__file-input',\n }) as HTMLInputElement;\n this.fileInput.type = 'file';\n this.fileInput.accept = generateAcceptAttribute();\n this.fileInput.addEventListener('change', () => {\n if (this.fileInput?.files?.length && this.callbacks.onFileUpload) {\n this.callbacks.onFileUpload(this.fileInput.files[0]);\n this.fileInput.value = '';\n }\n });\n\n this.fileButton.addEventListener('click', () => {\n this.fileInput?.click();\n });\n\n inputArea.appendChild(this.fileButton);\n inputArea.appendChild(this.fileInput);\n\n // Text input (max 2000 characters)\n this.inputElement = createElement('textarea', {\n className: 'cevro-chat-window__input',\n 'data-testid': 'chat-input',\n }) as HTMLTextAreaElement;\n this.inputElement.placeholder = this.strings.inputPlaceholder;\n this.inputElement.rows = 1;\n this.inputElement.setAttribute('maxlength', '2000');\n\n // Auto-resize textarea\n this.inputElement.addEventListener('input', () => {\n this.resizeInput();\n this.updateSendButtonState();\n });\n\n // Handle enter key\n this.inputElement.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n this.handleSend();\n }\n });\n\n inputArea.appendChild(this.inputElement);\n\n // Send button - arrow icon\n this.sendButton = createElement('button', {\n className: 'cevro-chat-window__send-button',\n 'aria-label': 'Send message',\n 'data-testid': 'send-button',\n }) as HTMLButtonElement;\n this.sendButton.disabled = true;\n this.sendButton.innerHTML = `\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 19V5M5 12L12 5L19 12\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n `;\n\n this.sendButton.addEventListener('click', () => {\n this.handleSend();\n });\n\n inputArea.appendChild(this.sendButton);\n wrapper.appendChild(inputArea);\n\n // Powered by footer\n const footer = createElement('div', {\n className: 'cevro-chat-window__footer',\n });\n footer.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n wrapper.appendChild(footer);\n\n return wrapper;\n }\n\n /**\n * Handle send message\n */\n private handleSend(): void {\n if (!this.inputElement) return;\n\n const message = this.inputElement.value.trim();\n if (!message) return;\n\n this.callbacks.onSendMessage(message);\n this.inputElement.value = '';\n this.resizeInput();\n this.updateSendButtonState();\n this.inputElement.focus({ preventScroll: true });\n }\n\n /**\n * Update send button state\n */\n private updateSendButtonState(): void {\n if (this.sendButton && this.inputElement) {\n this.sendButton.disabled = !this.inputElement.value.trim();\n }\n }\n\n /**\n * Resize textarea to fit its content, capped at 100px\n */\n private resizeInput(): void {\n if (!this.inputElement) return;\n this.inputElement.style.height = 'auto';\n this.inputElement.style.height = Math.min(this.inputElement.scrollHeight, 100) + 'px';\n }\n\n /**\n * Set draft message in the textarea without sending\n */\n setDraft(message: string): void {\n if (!this.inputElement) return;\n const maxLength = Number(this.inputElement.getAttribute('maxlength')) || 2000;\n this.inputElement.value = message.slice(0, maxLength);\n this.resizeInput();\n this.updateSendButtonState();\n this.inputElement.focus({ preventScroll: true });\n }\n\n /**\n * Set callback for when user scrolls to the top (for loading older messages)\n */\n setScrollTopHandler(handler: (() => boolean | void | Promise<boolean | void>) | null): void {\n this.messageList.setScrollTopHandler(handler);\n }\n\n /**\n * Prepend a message at the top (for loading older messages)\n */\n prependMessage(message: Message): void {\n this.messageList.prependMessage(message);\n }\n\n /**\n * Prepend multiple messages at the top (for loading older messages)\n */\n prependMessages(messages: Message[]): void {\n this.messageList.prependMessages(messages);\n }\n\n /**\n * Signal that top-loading is complete\n */\n finishLoadingTop(): void {\n this.messageList.finishLoadingTop();\n }\n\n /**\n * Add message to the chat\n */\n addMessage(message: Message, animate = true): void {\n this.messageList.addMessage(message, animate);\n }\n\n /**\n * Update message\n */\n updateMessage(message: Message, oldId?: string): void {\n this.messageList.updateMessage(message, oldId);\n }\n\n /**\n * Update upload progress for a message\n */\n updateMessageProgress(messageId: string, progress: number): void {\n this.messageList.updateMessageProgress(messageId, progress);\n }\n\n /**\n * Remove a message from the chat\n */\n removeMessage(messageId: string): void {\n this.messageList.removeMessage(messageId);\n }\n\n /**\n * Show typing indicator\n */\n showTypingIndicator(): void {\n this.messageList.showTypingIndicator();\n }\n\n /**\n * Hide typing indicator\n */\n hideTypingIndicator(): void {\n this.messageList.hideTypingIndicator();\n }\n\n /**\n * Clear messages\n */\n clearMessages(): void {\n this.messageList.clear();\n }\n\n /**\n * Show the chat window\n */\n show(): void {\n if (this.element) {\n this.element.classList.add('cevro-chat-window--visible');\n this.isVisible = true;\n this.inputElement?.focus({ preventScroll: true });\n this.messageList.scrollToBottom();\n }\n }\n\n /**\n * Hide the chat window\n */\n hide(): void {\n if (this.element) {\n this.element.classList.remove('cevro-chat-window--visible');\n this.isVisible = false;\n }\n }\n\n /**\n * Check if visible\n */\n isWindowVisible(): boolean {\n return this.isVisible;\n }\n\n /**\n * Focus input\n */\n focusInput(): void {\n this.inputElement?.focus({ preventScroll: true });\n }\n\n /**\n * Set ticket closed state\n * Shows CSAT form inline (replacing input area), preserving message history\n *\n * @param closed - Whether the ticket is closed\n * @param onStartNewChat - Callback when user clicks \"New Conversation\"\n * @param options - Additional options\n * @param options.showHistory - Show message history (always true now for better UX)\n * @param options.skipCSAT - Skip CSAT and show new chat directly\n * @param options.ticketId - Ticket ID for CSAT localStorage tracking\n */\n setTicketClosed(\n closed: boolean,\n onStartNewChat?: () => void,\n options?: { showHistory?: boolean; skipCSAT?: boolean; ticketId?: string }\n ): void {\n const skipCSAT = options?.skipCSAT ?? false;\n const ticketId = options?.ticketId;\n\n if (closed) {\n // Clean up any existing closed UI first\n this.removeClosedUI();\n\n // IMPORTANT: Keep message history visible so users can see what they missed\n // Show \"Chat closed\" message in the message list\n this.messageList.showClosedMessage(this.strings.closedMessage);\n\n // Hide input area (will be replaced by CSAT or new chat button)\n if (this.inputWrapper) {\n this.inputWrapper.style.display = 'none';\n }\n\n // Check if CSAT already submitted for this ticket\n const csatSubmitted = ticketId && localStorage.getItem(`cevro_csat_${ticketId}`);\n\n if (skipCSAT || csatSubmitted) {\n this.showClosedFooter(onStartNewChat);\n } else {\n this.showInlineCSATForm(onStartNewChat, ticketId);\n }\n } else {\n this.removeClosedUI();\n\n // Show input area — unless pre-chat form is currently displayed\n // (during startNewChat from history, input must stay hidden behind pre-chat)\n if (this.inputWrapper && !this.preChatContainer) {\n this.inputWrapper.style.display = '';\n }\n\n // Hide closed message\n this.messageList.hideClosedMessage();\n }\n }\n\n private showInlineCSATForm(onStartNewChat?: () => void, ticketId?: string): void {\n this.removeClosedUI();\n this.csatRating = 0;\n this.csatFeedback = '';\n\n if (!this.element) return;\n\n this.csatContainer = createElement('div', {\n className: 'cevro-csat-inline',\n });\n\n const headerRow = createElement('div', {\n className: 'cevro-csat-inline__header',\n });\n\n const title = createElement('span', {\n className: 'cevro-csat-inline__title',\n }, [this.strings.csatTitle]);\n\n const skipButton = createElement('button', {\n className: 'cevro-csat-inline__skip',\n 'aria-label': 'Skip feedback',\n }, ['Skip']);\n skipButton.addEventListener('click', () => {\n // Save skip to localStorage so it persists across page reloads\n if (ticketId) {\n localStorage.setItem(`cevro_csat_${ticketId}`, 'skipped');\n }\n this.showClosedFooter(onStartNewChat);\n });\n\n headerRow.appendChild(title);\n headerRow.appendChild(skipButton);\n\n const starsRow = createElement('div', {\n className: 'cevro-csat-inline__stars',\n });\n\n for (let i = 1; i <= 5; i++) {\n const star = createElement('button', {\n className: 'cevro-csat-inline__star',\n 'data-rating': String(i),\n 'aria-label': `Rate ${i} stars`,\n });\n star.innerHTML = this.createStarSvg(false);\n star.addEventListener('click', () => this.selectInlineRating(i, starsRow));\n star.addEventListener('mouseenter', () => this.previewRating(i, starsRow));\n star.addEventListener('mouseleave', () => this.previewRating(this.csatRating, starsRow));\n starsRow.appendChild(star);\n }\n\n // Feedback textarea - shown immediately\n const feedbackInput = createElement('textarea', {\n className: 'cevro-csat-inline__feedback',\n placeholder: this.strings.csatPlaceholder,\n }) as HTMLTextAreaElement;\n feedbackInput.rows = 2;\n feedbackInput.addEventListener('input', () => {\n this.csatFeedback = feedbackInput.value;\n });\n\n // Submit button\n const submitButton = createElement('button', {\n className: 'cevro-csat-inline__submit',\n }, [this.strings.csatSubmit || 'Submit']);\n submitButton.addEventListener('click', () => this.submitInlineCSAT(onStartNewChat, ticketId));\n\n const poweredBy = createElement('div', {\n className: 'cevro-csat-inline__powered-by',\n });\n poweredBy.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n this.csatContainer.appendChild(headerRow);\n this.csatContainer.appendChild(starsRow);\n this.csatContainer.appendChild(feedbackInput);\n this.csatContainer.appendChild(submitButton);\n this.csatContainer.appendChild(poweredBy);\n\n this.element.appendChild(this.csatContainer);\n }\n\n private selectInlineRating(rating: number, container: HTMLElement): void {\n if (this.csatSubmitting) return;\n this.csatRating = rating;\n this.updateStars(rating, container);\n\n const feedbackInput = container.parentElement?.querySelector('.cevro-csat-inline__feedback') as HTMLTextAreaElement;\n if (feedbackInput) {\n if (rating <= 2) {\n feedbackInput.placeholder = this.strings.csatPlaceholderNegative || this.strings.csatPlaceholder;\n } else if (rating === 3) {\n feedbackInput.placeholder = this.strings.csatPlaceholderNeutral || this.strings.csatPlaceholder;\n } else {\n feedbackInput.placeholder = this.strings.csatPlaceholder;\n }\n }\n }\n\n private async submitInlineCSAT(onStartNewChat?: () => void, ticketId?: string): Promise<void> {\n if (this.csatSubmitting || this.csatRating === 0) return;\n\n this.csatSubmitting = true;\n\n const submitButton = this.csatContainer?.querySelector('.cevro-csat-inline__submit') as HTMLButtonElement;\n if (submitButton) {\n submitButton.disabled = true;\n submitButton.textContent = 'Submitting...';\n }\n\n try {\n if (this.callbacks.onCSATSubmit) {\n await this.callbacks.onCSATSubmit(this.csatRating, this.csatFeedback || undefined);\n }\n\n if (ticketId) {\n localStorage.setItem(`cevro_csat_${ticketId}`, '1');\n }\n\n this.showInlineThankYou(onStartNewChat);\n } catch {\n if (submitButton) {\n submitButton.disabled = false;\n submitButton.textContent = this.strings.csatSubmit || 'Submit';\n }\n } finally {\n this.csatSubmitting = false;\n }\n }\n\n /**\n * Show inline thank you message\n */\n private showInlineThankYou(onStartNewChat?: () => void): void {\n this.removeClosedUI();\n\n if (!this.element) return;\n\n this.csatContainer = createElement('div', {\n className: 'cevro-csat-inline cevro-csat-inline--thank-you',\n });\n\n // Thank you row\n const thankYouRow = createElement('div', {\n className: 'cevro-csat-inline__thank-you-row',\n });\n\n const checkIcon = createElement('span', {\n className: 'cevro-csat-inline__check',\n });\n checkIcon.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#10B981\"/>\n <path d=\"M7 12L10 15L17 8\" stroke=\"white\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n `;\n\n const message = createElement('span', {\n className: 'cevro-csat-inline__message',\n }, [this.strings.csatThankYou]);\n\n thankYouRow.appendChild(checkIcon);\n thankYouRow.appendChild(message);\n\n // New conversation button\n const newChatButton = createElement('button', {\n className: 'cevro-csat-inline__new-chat',\n }, [this.strings.newConversation]);\n\n newChatButton.addEventListener('click', () => {\n if (onStartNewChat) {\n onStartNewChat();\n }\n });\n\n // Powered by footer\n const poweredBy = createElement('div', {\n className: 'cevro-csat-inline__powered-by',\n });\n poweredBy.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n this.csatContainer.appendChild(thankYouRow);\n this.csatContainer.appendChild(newChatButton);\n this.csatContainer.appendChild(poweredBy);\n\n this.element.appendChild(this.csatContainer);\n }\n\n /**\n * Show closed footer with new conversation button (after CSAT skip or when CSAT already submitted)\n */\n private showClosedFooter(onStartNewChat?: () => void): void {\n this.removeClosedUI();\n\n if (this.element) {\n this.closedFooter = createElement('div', {\n className: 'cevro-chat-window__closed-footer',\n });\n\n const newChatButton = createElement('button', {\n className: 'cevro-chat-window__new-chat-button',\n }, [this.strings.newConversation]);\n\n newChatButton.addEventListener('click', () => {\n if (onStartNewChat) {\n onStartNewChat();\n }\n });\n\n const poweredBy = createElement('div', {\n className: 'cevro-chat-window__powered-by',\n });\n poweredBy.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n this.closedFooter.appendChild(newChatButton);\n this.closedFooter.appendChild(poweredBy);\n this.element.appendChild(this.closedFooter);\n }\n }\n\n /**\n * Remove all closed-state UI (CSAT form, thank-you, closed footer)\n */\n private removeClosedUI(): void {\n if (this.csatContainer && this.csatContainer.parentNode) {\n this.csatContainer.parentNode.removeChild(this.csatContainer);\n this.csatContainer = null;\n }\n if (this.closedFooter && this.closedFooter.parentNode) {\n this.closedFooter.parentNode.removeChild(this.closedFooter);\n this.closedFooter = null;\n }\n }\n\n /**\n * Preview star rating on hover\n */\n private previewRating(rating: number, container: HTMLElement): void {\n this.updateStars(rating, container);\n }\n\n /**\n * Update stars display (works for both old and inline CSAT)\n */\n private updateStars(rating: number, container: HTMLElement): void {\n // Support both old and new star classes\n const stars = container.querySelectorAll('.cevro-csat__star, .cevro-csat-inline__star');\n stars.forEach((star, index) => {\n const filled = index < rating;\n star.innerHTML = this.createStarSvg(filled);\n star.classList.toggle('cevro-csat__star--filled', filled);\n star.classList.toggle('cevro-csat-inline__star--filled', filled);\n });\n }\n\n /**\n * Create star SVG\n */\n private createStarSvg(filled: boolean): string {\n if (filled) {\n return `\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"#FBBF24\" stroke=\"#FBBF24\" stroke-width=\"1\">\n <polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\"/>\n </svg>\n `;\n }\n return `\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#D1D5DB\" stroke-width=\"1.5\">\n <polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\"/>\n </svg>\n `;\n }\n\n /**\n * Show pre-chat form for visitors\n */\n showPreChatForm(): void {\n if (this.preChatCompleted || this.preChatContainer) return;\n if (!this.element) return;\n\n // Add compact mode class for smaller modal\n this.element.classList.add('cevro-chat-window--prechat');\n\n // Hide messages and input\n const messagesArea = this.element.querySelector('.cevro-messages');\n if (messagesArea) {\n (messagesArea as HTMLElement).style.display = 'none';\n }\n if (this.inputWrapper) {\n this.inputWrapper.style.display = 'none';\n }\n\n // Create pre-chat form\n this.preChatContainer = createElement('div', {\n className: 'cevro-prechat',\n });\n\n // Title\n const title = createElement('h3', {\n className: 'cevro-prechat__title',\n }, [this.strings.preChatTitle]);\n\n // Subtitle\n const subtitle = createElement('p', {\n className: 'cevro-prechat__subtitle',\n }, [this.strings.preChatSubtitle]);\n\n // Form\n const form = createElement('form', {\n className: 'cevro-prechat__form',\n });\n\n // First name field\n const firstNameGroup = createElement('div', {\n className: 'cevro-prechat__field',\n });\n const firstNameLabel = createElement('label', {\n className: 'cevro-prechat__label',\n for: 'cevro-prechat-firstname',\n }, [this.strings.preChatFirstNameLabel]);\n const firstNameInput = createElement('input', {\n className: 'cevro-prechat__input',\n id: 'cevro-prechat-firstname',\n type: 'text',\n 'data-testid': 'prechat-firstname',\n }) as HTMLInputElement;\n firstNameInput.placeholder = this.strings.preChatFirstNamePlaceholder;\n const firstNameError = createElement('span', {\n className: 'cevro-prechat__error',\n 'data-field': 'firstName',\n });\n\n // Highlight invalid fields on blur (no text — avoids extra localization)\n firstNameInput.addEventListener('blur', () => {\n firstNameInput.classList.toggle('cevro-prechat__input--error', !firstNameInput.value.trim());\n });\n\n firstNameGroup.appendChild(firstNameLabel);\n firstNameGroup.appendChild(firstNameInput);\n firstNameGroup.appendChild(firstNameError);\n\n // Email field\n const emailGroup = createElement('div', {\n className: 'cevro-prechat__field',\n });\n const emailLabel = createElement('label', {\n className: 'cevro-prechat__label',\n for: 'cevro-prechat-email',\n }, [this.strings.preChatEmailLabel]);\n const emailInput = createElement('input', {\n className: 'cevro-prechat__input',\n id: 'cevro-prechat-email',\n type: 'text',\n autocomplete: 'email',\n 'data-testid': 'prechat-email',\n }) as HTMLInputElement;\n emailInput.placeholder = this.strings.preChatEmailPlaceholder;\n const emailError = createElement('span', {\n className: 'cevro-prechat__error',\n 'data-field': 'email',\n });\n\n // Highlight invalid fields on blur (no text — avoids extra localization)\n emailInput.addEventListener('blur', () => {\n const email = emailInput.value.trim();\n emailInput.classList.toggle('cevro-prechat__input--error', !email || !this.isValidEmail(email));\n });\n\n emailGroup.appendChild(emailLabel);\n emailGroup.appendChild(emailInput);\n emailGroup.appendChild(emailError);\n\n // Submit button\n const submitButton = createElement('button', {\n className: 'cevro-prechat__submit',\n type: 'submit',\n 'data-testid': 'prechat-submit',\n }, [this.strings.preChatSubmit]) as HTMLButtonElement;\n\n // Form validation and submit\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n\n // Clear previous errors\n firstNameError.textContent = '';\n emailError.textContent = '';\n firstNameInput.classList.remove('cevro-prechat__input--error');\n emailInput.classList.remove('cevro-prechat__input--error');\n\n const firstName = firstNameInput.value.trim();\n const email = emailInput.value.trim();\n\n let hasError = false;\n\n if (!firstName) {\n firstNameError.textContent = this.strings.preChatFirstNameRequired;\n firstNameInput.classList.add('cevro-prechat__input--error');\n hasError = true;\n }\n\n if (!email) {\n emailError.textContent = this.strings.preChatEmailRequired;\n emailInput.classList.add('cevro-prechat__input--error');\n hasError = true;\n } else if (!this.isValidEmail(email)) {\n emailError.textContent = this.strings.preChatEmailInvalid;\n emailInput.classList.add('cevro-prechat__input--error');\n hasError = true;\n }\n\n if (hasError) return;\n\n // Submit successful\n this.preChatCompleted = true;\n\n if (this.callbacks.onPreChatSubmit) {\n this.callbacks.onPreChatSubmit({ firstName, email });\n }\n });\n\n form.appendChild(firstNameGroup);\n form.appendChild(emailGroup);\n form.appendChild(submitButton);\n\n // Powered by footer\n const poweredBy = createElement('div', {\n className: 'cevro-prechat__powered-by',\n });\n poweredBy.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n this.preChatContainer.appendChild(title);\n this.preChatContainer.appendChild(subtitle);\n this.preChatContainer.appendChild(form);\n this.preChatContainer.appendChild(poweredBy);\n\n this.element.appendChild(this.preChatContainer);\n\n // Focus on name input\n firstNameInput.focus({ preventScroll: true });\n }\n\n /**\n * Hide pre-chat form and show chat\n */\n hidePreChatForm(): void {\n if (this.preChatContainer && this.preChatContainer.parentNode) {\n this.preChatContainer.parentNode.removeChild(this.preChatContainer);\n this.preChatContainer = null;\n }\n\n // Remove compact mode class\n this.element?.classList.remove('cevro-chat-window--prechat');\n\n // Show messages and input with fade-in\n if (this.element) {\n const messagesArea = this.element.querySelector('.cevro-messages');\n if (messagesArea) {\n (messagesArea as HTMLElement).style.display = '';\n messagesArea.classList.add('cevro-messages--fade-in');\n }\n }\n if (this.inputWrapper) {\n this.inputWrapper.style.display = '';\n }\n\n // Focus input\n this.inputElement?.focus({ preventScroll: true });\n }\n\n /**\n * Validate email format\n */\n private isValidEmail(email: string): boolean {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n }\n\n /**\n * Set the brand logo shown as the avatar of the conversation's first message only.\n * Distinct from the header logo (`updateCustomLogo`) — callers decide independently\n * whether the first-message avatar should follow the header logo.\n */\n setBrandLogoUrl(logoUrl?: string): void {\n this.messageList.setBrandLogoUrl(logoUrl);\n }\n\n updateCustomLogo(logoUrl?: string): void {\n this.customLogoUrl = logoUrl;\n\n if (!this.logoElement) return;\n\n // Clear existing logo content\n this.logoElement.innerHTML = '';\n\n if (logoUrl) {\n const logoImg = document.createElement('img');\n logoImg.src = logoUrl;\n logoImg.alt = 'Logo';\n logoImg.className = 'cevro-chat-window__logo-img';\n logoImg.style.width = '40px';\n logoImg.style.height = '40px';\n logoImg.style.objectFit = 'contain';\n logoImg.style.borderRadius = '8px';\n this.logoElement.appendChild(logoImg);\n } else {\n this.logoElement.innerHTML = this.createCompanyLogoSvg();\n }\n }\n\n /**\n * Get the body of the last message (for conversation list preview)\n */\n getLastMessageBody(): string | undefined {\n return this.messageList.getLastMessageBody();\n }\n\n getLastMessageAt(): string | undefined {\n return this.messageList.getLastMessageAt();\n }\n\n getAgentMessagesSinceLastUserMessage(): number {\n return this.messageList.getAgentMessagesSinceLastUserMessage();\n }\n\n /**\n * Destroy the component\n */\n destroy(): void {\n this.messageList.destroy();\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n this.inputElement = null;\n this.sendButton = null;\n this.fileInput = null;\n this.fileButton = null;\n this.closedFooter = null;\n this.csatContainer = null;\n this.preChatContainer = null;\n this.preChatCompleted = false;\n }\n}\n","import type { ConversationHistoryItem, LocaleStrings } from '../types';\nimport { createElement } from '../utils/dom';\n\nexport interface ActiveConversationInfo {\n ticketId: string;\n lastMessageBody?: string;\n lastMessageAt?: string;\n agentName?: string;\n unreadCount?: number;\n}\n\nexport interface ConversationListCallbacks {\n onClose: () => void;\n onNewConversation: () => void;\n onSelectActive: () => void;\n onSelectPast: (ticketId: string, title: string) => void;\n onLoadConversations: (cursor?: string) => Promise<{\n conversations: ConversationHistoryItem[];\n hasMore: boolean;\n cursor?: string;\n }>;\n}\n\n/**\n * Conversation history list screen\n */\nexport class ConversationList {\n private element: HTMLElement | null = null;\n private listContainer: HTMLElement | null = null;\n private titleElement: HTMLElement | null = null;\n private callbacks: ConversationListCallbacks;\n private strings: LocaleStrings;\n private activeInfo: ActiveConversationInfo | null = null;\n private cursor: string | undefined = undefined;\n private hasMore = false;\n private loadMoreButton: HTMLElement | null = null;\n private isLoadingMore = false;\n\n constructor(callbacks: ConversationListCallbacks, strings: LocaleStrings) {\n this.callbacks = callbacks;\n this.strings = strings;\n }\n\n setStrings(strings: LocaleStrings): void {\n this.strings = strings;\n if (this.titleElement) {\n this.titleElement.textContent = strings.conversationsTitle;\n }\n }\n\n setActiveConversation(info: ActiveConversationInfo | null): void {\n this.activeInfo = info;\n }\n\n render(): HTMLElement {\n if (this.element) return this.element;\n\n this.element = createElement('div', {\n className: 'cevro-conversation-list',\n });\n\n // Header\n const header = createElement('div', {\n className: 'cevro-conversation-list__header',\n });\n\n this.titleElement = createElement('h2', {\n className: 'cevro-conversation-list__title',\n }, [this.strings.conversationsTitle]);\n\n const closeButton = createElement('button', {\n className: 'cevro-conversation-list__close',\n 'aria-label': 'Close',\n });\n closeButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n `;\n closeButton.addEventListener('click', () => this.callbacks.onClose());\n\n header.appendChild(this.titleElement);\n header.appendChild(closeButton);\n this.element.appendChild(header);\n\n // Scrollable list container\n this.listContainer = createElement('div', {\n className: 'cevro-conversation-list__items',\n });\n this.element.appendChild(this.listContainer);\n\n // New Conversation button\n const newConvButton = createElement('button', {\n className: 'cevro-conversation-list__new-conversation',\n }, [this.strings.newConversationButton]);\n newConvButton.addEventListener('click', () => this.callbacks.onNewConversation());\n\n // Footer\n const footer = createElement('div', {\n className: 'cevro-conversation-list__footer',\n });\n footer.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n // Action panel wrapping button + powered-by (per design)\n const actionPanel = createElement('div', { className: 'cevro-action-panel' });\n actionPanel.appendChild(newConvButton);\n actionPanel.appendChild(footer);\n this.element.appendChild(actionPanel);\n\n return this.element;\n }\n\n /**\n * Load and display conversations\n */\n async load(): Promise<void> {\n if (!this.listContainer) return;\n\n // Reset pagination state\n this.cursor = undefined;\n this.hasMore = false;\n this.loadMoreButton = null;\n\n // Show loading\n this.listContainer.innerHTML = '';\n const loading = createElement('div', {\n className: 'cevro-conversation-list__loading',\n }, [this.strings.loadingConversations]);\n this.listContainer.appendChild(loading);\n\n try {\n const result = await this.callbacks.onLoadConversations();\n\n this.listContainer.innerHTML = '';\n this.cursor = result.cursor;\n this.hasMore = result.hasMore;\n\n // Active conversation card (if exists) — shows last message preview\n if (this.activeInfo) {\n const activeCard = this.createActiveCard();\n this.listContainer.appendChild(activeCard);\n }\n\n // Past conversations\n if (result.conversations.length === 0 && !this.activeInfo) {\n this.showEmptyState();\n return;\n }\n\n for (const conv of result.conversations) {\n // Skip if this is the active ticket\n if (conv.ticketId === this.activeInfo?.ticketId) continue;\n const card = this.createConversationCard(conv);\n this.listContainer.appendChild(card);\n }\n\n this.renderLoadMoreButton();\n } catch {\n this.listContainer.innerHTML = '';\n if (this.activeInfo) {\n const activeCard = this.createActiveCard();\n this.listContainer.appendChild(activeCard);\n }\n this.showEmptyState();\n }\n }\n\n private async loadMore(): Promise<void> {\n if (!this.listContainer || !this.hasMore || this.isLoadingMore) return;\n\n this.isLoadingMore = true;\n if (this.loadMoreButton) {\n this.loadMoreButton.textContent = this.strings.loadingConversations;\n (this.loadMoreButton as HTMLButtonElement).disabled = true;\n }\n\n try {\n const result = await this.callbacks.onLoadConversations(this.cursor);\n this.cursor = result.cursor;\n this.hasMore = result.hasMore;\n\n // Remove old load-more button before appending new cards\n this.loadMoreButton?.remove();\n this.loadMoreButton = null;\n\n for (const conv of result.conversations) {\n if (conv.ticketId === this.activeInfo?.ticketId) continue;\n const card = this.createConversationCard(conv);\n this.listContainer!.appendChild(card);\n }\n\n this.renderLoadMoreButton();\n } catch {\n // Restore button on error\n if (this.loadMoreButton) {\n this.loadMoreButton.textContent = this.strings.loadMoreConversations;\n (this.loadMoreButton as HTMLButtonElement).disabled = false;\n }\n } finally {\n this.isLoadingMore = false;\n }\n }\n\n private renderLoadMoreButton(): void {\n if (!this.hasMore || !this.listContainer) return;\n\n this.loadMoreButton = createElement('button', {\n className: 'cevro-conversation-list__load-more',\n }, [this.strings.loadMoreConversations]);\n this.loadMoreButton.addEventListener('click', () => this.loadMore());\n this.listContainer.appendChild(this.loadMoreButton);\n }\n\n private createActiveCard(): HTMLElement {\n const unread = this.activeInfo?.unreadCount ?? 0;\n const card = createElement('div', {\n className: `cevro-conversation-card cevro-conversation-card--active${unread > 0 ? ' cevro-conversation-card--unread' : ''}`,\n });\n\n const content = createElement('div', {\n className: 'cevro-conversation-card__content',\n });\n\n const titleRow = createElement('div', {\n className: 'cevro-conversation-card__title-row',\n });\n\n const agentName = createElement('span', {\n className: 'cevro-conversation-card__title',\n }, [this.activeInfo?.agentName || 'Support']);\n\n const date = createElement('span', {\n className: 'cevro-conversation-card__date',\n }, [this.activeInfo?.lastMessageAt ? this.formatDate(this.activeInfo.lastMessageAt) : '']);\n\n titleRow.appendChild(agentName);\n titleRow.appendChild(date);\n\n const previewRow = createElement('div', {\n className: 'cevro-conversation-card__preview-row',\n });\n\n const preview = createElement('div', {\n className: 'cevro-conversation-card__preview',\n }, [this.activeInfo?.lastMessageBody || this.strings.inputPlaceholder]);\n previewRow.appendChild(preview);\n\n if (unread > 0) {\n const unreadBadge = createElement('span', {\n className: 'cevro-conversation-card__unread',\n }, [unread > 99 ? '99+' : String(unread)]);\n previewRow.appendChild(unreadBadge);\n }\n\n content.appendChild(titleRow);\n content.appendChild(previewRow);\n card.appendChild(content);\n\n card.addEventListener('click', () => this.callbacks.onSelectActive());\n return card;\n }\n\n private createConversationCard(conv: ConversationHistoryItem): HTMLElement {\n const card = createElement('div', {\n className: 'cevro-conversation-card',\n });\n\n const content = createElement('div', {\n className: 'cevro-conversation-card__content',\n });\n\n const titleRow = createElement('div', {\n className: 'cevro-conversation-card__title-row',\n });\n\n const titleText = createElement('span', {\n className: 'cevro-conversation-card__title',\n }, [conv.title || this.strings.defaultConversationTitle]);\n\n const date = createElement('span', {\n className: 'cevro-conversation-card__date',\n }, [this.formatDate(conv.lastMessageAt || conv.createdAt)]);\n\n titleRow.appendChild(titleText);\n titleRow.appendChild(date);\n\n const preview = createElement('div', {\n className: 'cevro-conversation-card__preview',\n }, [conv.lastMessageBody || `${conv.messageCount} ${this.strings.messagesCount}`]);\n\n content.appendChild(titleRow);\n content.appendChild(preview);\n card.appendChild(content);\n\n card.addEventListener('click', () => {\n this.callbacks.onSelectPast(conv.ticketId, conv.title);\n });\n\n return card;\n }\n\n private showEmptyState(): void {\n if (!this.listContainer) return;\n\n const empty = createElement('div', {\n className: 'cevro-conversation-list__empty',\n });\n\n const emptyTitle = createElement('p', {\n className: 'cevro-conversation-list__empty-title',\n }, [this.strings.noConversations]);\n\n const emptySubtitle = createElement('p', {\n className: 'cevro-conversation-list__empty-subtitle',\n }, [this.strings.noConversationsSubtitle]);\n\n empty.appendChild(emptyTitle);\n empty.appendChild(emptySubtitle);\n this.listContainer.appendChild(empty);\n }\n\n private formatDate(dateStr: string): string {\n try {\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays === 0) {\n return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n } else if (diffDays === 1) {\n return this.strings.yesterday;\n } else if (diffDays < 7) {\n return date.toLocaleDateString([], { weekday: 'short' });\n } else {\n return date.toLocaleDateString([], { month: 'short', day: 'numeric' });\n }\n } catch {\n return '';\n }\n }\n\n show(): void {\n if (this.element) {\n this.element.style.display = 'flex';\n }\n }\n\n hide(): void {\n if (this.element) {\n this.element.style.display = 'none';\n }\n }\n\n destroy(): void {\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n this.listContainer = null;\n }\n}\n","import type { Message, LocaleStrings, Agent } from '../types';\nimport { createElement } from '../utils/dom';\nimport { MessageList } from './MessageList';\n\nexport interface PastConversationCallbacks {\n onBack: () => void;\n onClose: () => void;\n onNewConversation: () => void;\n onLoadMessages: (ticketId: string, cursor?: string) => Promise<{\n messages: Message[];\n hasMore: boolean;\n cursor?: string;\n }>;\n}\n\n/**\n * Read-only view of a past conversation\n */\nexport class PastConversation {\n private element: HTMLElement | null = null;\n private avatarElement: HTMLElement | null = null;\n private titleElement: HTMLElement | null = null;\n private avatarUrl: string | undefined;\n private messageList: MessageList;\n private callbacks: PastConversationCallbacks;\n private strings: LocaleStrings;\n private currentTicketId: string | null = null;\n private cursor: string | undefined;\n private hasMore = false;\n private isLoadingMore = false;\n\n constructor(callbacks: PastConversationCallbacks, strings: LocaleStrings) {\n this.callbacks = callbacks;\n this.strings = strings;\n this.messageList = new MessageList();\n }\n\n setStrings(strings: LocaleStrings): void {\n this.strings = strings;\n }\n\n setAvatarUrl(url: string | undefined): void {\n this.avatarUrl = url;\n this.renderAvatar();\n }\n\n /**\n * Set agent info for message avatars (the AI-persona photo fallback when\n * no brand logo applies)\n */\n setAgent(agent: Agent): void {\n this.messageList.setAgent(agent);\n }\n\n /**\n * Set the brand logo shown as the avatar of the conversation's first message only\n */\n setBrandLogoUrl(url: string | undefined): void {\n this.messageList.setBrandLogoUrl(url);\n }\n\n private renderAvatar(): void {\n if (!this.avatarElement) return;\n if (this.avatarUrl) {\n this.avatarElement.innerHTML = `<img src=\"${this.avatarUrl}\" alt=\"Agent\" class=\"cevro-past-conversation__avatar-img\" />`;\n this.avatarElement.style.display = '';\n } else {\n this.avatarElement.innerHTML = '';\n this.avatarElement.style.display = 'none';\n }\n }\n\n render(): HTMLElement {\n if (this.element) return this.element;\n\n this.element = createElement('div', {\n className: 'cevro-past-conversation',\n });\n\n // Header (will be populated on load)\n const header = createElement('div', {\n className: 'cevro-past-conversation__header',\n });\n\n const backButton = createElement('button', {\n className: 'cevro-past-conversation__back',\n 'aria-label': 'Back',\n });\n backButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"15 18 9 12 15 6\"/>\n </svg>\n `;\n backButton.addEventListener('click', () => this.callbacks.onBack());\n\n // Agent avatar\n this.avatarElement = createElement('div', {\n className: 'cevro-past-conversation__avatar',\n });\n this.renderAvatar();\n\n // Title\n this.titleElement = createElement('h2', {\n className: 'cevro-past-conversation__title',\n });\n\n const closeButton = createElement('button', {\n className: 'cevro-past-conversation__close',\n 'aria-label': 'Close',\n });\n closeButton.innerHTML = `\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n `;\n closeButton.addEventListener('click', () => this.callbacks.onClose());\n\n header.appendChild(backButton);\n header.appendChild(this.avatarElement);\n header.appendChild(this.titleElement);\n header.appendChild(closeButton);\n this.element.appendChild(header);\n\n // Messages area (read-only)\n const messagesArea = this.messageList.render();\n this.messageList.setScrollTopHandler(() => this.loadMoreMessages());\n this.element.appendChild(messagesArea);\n\n // New Conversation button\n const newConvButton = createElement('button', {\n className: 'cevro-past-conversation__new-conversation',\n }, [this.strings.newConversationButton]);\n newConvButton.addEventListener('click', () => this.callbacks.onNewConversation());\n\n // Footer (Powered by)\n const footer = createElement('div', {\n className: 'cevro-past-conversation__footer',\n });\n footer.innerHTML = `${this.strings.poweredBy.replace('Cevro AI', '<a href=\"https://cevro.ai\" target=\"_blank\" rel=\"noopener\">Cevro AI</a>')}`;\n\n // Action panel wrapping button + powered-by (per design)\n const actionPanel = createElement('div', { className: 'cevro-action-panel' });\n actionPanel.appendChild(newConvButton);\n actionPanel.appendChild(footer);\n this.element.appendChild(actionPanel);\n\n return this.element;\n }\n\n /**\n * Load a past conversation\n */\n async loadConversation(ticketId: string, title: string): Promise<void> {\n if (this.titleElement) {\n this.titleElement.textContent = title;\n }\n // Reset pagination state\n this.currentTicketId = ticketId;\n this.cursor = undefined;\n this.hasMore = false;\n this.messageList.clear();\n\n try {\n // Load latest page (no cursor = most recent messages)\n const result = await this.callbacks.onLoadMessages(ticketId);\n\n // Guard: user may have switched to another conversation while we were loading\n if (this.currentTicketId !== ticketId) return;\n\n this.cursor = result.cursor;\n this.hasMore = result.hasMore;\n\n // Bulk load: no animation, no scroll per message\n for (const msg of result.messages) {\n this.messageList.addMessage(msg, false, true);\n }\n // Scroll to bottom — show latest messages\n this.messageList.scrollToBottom();\n } catch (error) {\n console.error('[Cevro] Failed to load conversation messages:', error);\n }\n }\n\n private async loadMoreMessages(): Promise<boolean> {\n if (!this.currentTicketId || !this.hasMore || this.isLoadingMore) return false;\n\n const requestedTicketId = this.currentTicketId;\n this.isLoadingMore = true;\n try {\n const result = await this.callbacks.onLoadMessages(\n requestedTicketId,\n this.cursor,\n );\n\n // Guard: user may have switched conversations while loading\n if (this.currentTicketId !== requestedTicketId) return false;\n\n this.cursor = result.cursor;\n this.hasMore = result.hasMore;\n\n // Prepend older messages at the top\n this.messageList.prependMessages(result.messages);\n return true;\n } catch (error) {\n console.error('[Cevro] Failed to load more messages:', error);\n return false;\n } finally {\n this.isLoadingMore = false;\n this.messageList.finishLoadingTop();\n }\n }\n\n show(): void {\n if (this.element) {\n this.element.style.display = 'flex';\n }\n }\n\n hide(): void {\n if (this.element) {\n this.element.style.display = 'none';\n }\n }\n\n destroy(): void {\n this.messageList.destroy();\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n this.avatarElement = null;\n this.titleElement = null;\n }\n}\n","import type {\n CevroMessengerConfig,\n PlayerData,\n Message,\n QuickAction,\n ThemeConfig,\n WidgetAppearanceConfig,\n} from '../types';\nimport { EventEmitter } from './EventEmitter';\nimport { ApiClient } from './ApiClient';\nimport { WebSocketClient } from './WebSocketClient';\nimport { Launcher } from '../ui/Launcher';\nimport { ChatWindow } from '../ui/ChatWindow';\nimport { ConversationList } from '../ui/ConversationList';\nimport { PastConversation } from '../ui/PastConversation';\nimport {\n generateVisitorId,\n getStoredSession,\n storeSession,\n clearStoredSession,\n clearStoredVisitorToken,\n getStoredVisitorToken,\n storeVisitorToken,\n recoverVisitorToken,\n detectAndRecordPlayerSwitch,\n clearActivePlayer,\n} from '../utils/session';\nimport { isValidUrl } from '../utils/dom';\nimport { getStrings } from '../i18n/strings';\nimport styles from '../styles/index.css?inline';\n\n/**\n * Main Cevro Messenger SDK class\n */\nexport class CevroMessenger {\n private static instance: CevroMessenger | null = null;\n\n private config: CevroMessengerConfig;\n private events: EventEmitter;\n private api: ApiClient;\n private ws: WebSocketClient;\n private launcher: Launcher | null = null;\n private chatWindow: ChatWindow | null = null;\n private conversationList: ConversationList | null = null;\n private pastConversation: PastConversation | null = null;\n private currentScreen: 'chat' | 'history' | 'past-conversation' = 'chat';\n private container: HTMLElement | null = null;\n private shadowRoot: ShadowRoot | null = null;\n private isBooted = false;\n private isVisible = false;\n private unreadCount = 0;\n private visitorId: string | null;\n\n private isSessionInitialized = false;\n private isInitializingSession: Promise<void> | null = null;\n private connectingPromise: Promise<void> | null = null;\n private typingCycleTimeout: ReturnType<typeof setTimeout> | null = null;\n private isTypingVisible = false;\n private typingConfig = { onDurationMs: 7000, offDurationMs: 4000 };\n private escapeHandler: ((e: KeyboardEvent) => void) | null = null;\n private visitorContactInfo: { firstName: string; email: string } | null = null;\n private widgetAppearance: WidgetAppearanceConfig = {};\n private customLauncherHandler: (() => void) | null = null;\n private customLauncherElement: Element | null = null;\n private isDestroyed = false;\n\n constructor(config: CevroMessengerConfig) {\n this.config = this.normalizeConfig(config);\n this.events = new EventEmitter();\n this.api = new ApiClient(this.config);\n this.ws = new WebSocketClient(this.config, this.events);\n this.visitorId = generateVisitorId();\n\n // Setup token refresh callback for WebSocket\n this.ws.setTokenRefreshCallback(async () => {\n return this.refreshConnectionToken();\n });\n\n // Setup internal event handlers\n this.setupEventHandlers();\n\n // Singleton pattern\n CevroMessenger.instance = this;\n }\n\n /**\n * Get singleton instance\n */\n static getInstance(): CevroMessenger | null {\n return CevroMessenger.instance;\n }\n\n /**\n * Normalize and validate config\n */\n private normalizeConfig(config: CevroMessengerConfig): CevroMessengerConfig {\n return {\n ...config,\n apiBase: config.apiBase.replace(/\\/$/, ''), // Remove trailing slash\n alignment: config.alignment || 'right',\n verticalPadding: config.verticalPadding ?? 20,\n horizontalPadding: config.horizontalPadding ?? 20,\n zIndex: config.zIndex ?? 2147483647,\n };\n }\n\n /**\n * Setup internal event handlers\n */\n private setupEventHandlers(): void {\n // Handle incoming messages\n this.events.on('message:received', (data: { ticketId: string; message: Message }) => {\n // Stop typing cycle and hide indicator when message arrives\n this.stopTypingCycle();\n\n if (this.chatWindow) {\n this.chatWindow.addMessage(data.message);\n }\n\n // Update unread count if window is not visible\n if (!this.isVisible) {\n this.setUnreadCount(this.unreadCount + 1);\n }\n });\n\n // Handle typing indicators from backend\n this.events.on('typing:start', (data: { ticketId: string; actor: string }) => {\n if (data.ticketId === this.api.getCurrentTicketId()) {\n this.startTypingCycle();\n }\n });\n\n this.events.on('typing:stop', () => {\n this.stopTypingCycle();\n });\n\n // Handle conversation/ticket status updates (real-time close from admin)\n this.events.on('conversation:updated', (data: { ticketId: string; status: string; message?: string; agentName?: string }) => {\n // Ignore events for tickets that aren't the current one\n if (data.ticketId !== this.api.getCurrentTicketId()) return;\n\n if (data.status === 'escalated') {\n // Show system message that a human agent joined\n const agentName = data.agentName || 'Support';\n const escalationMsg = data.message || `${agentName} has joined the conversation.`;\n this.chatWindow?.addMessage({\n id: `escalation-${Date.now()}`,\n body: escalationMsg,\n inbound: false,\n outbound: true,\n createdAt: new Date().toISOString(),\n type: 'text',\n senderType: 'human',\n agentName,\n });\n }\n\n if (data.status === 'closed') {\n const skipCSAT = this.widgetAppearance.csatEnabled !== true;\n this.chatWindow?.setTicketClosed(true, () => this.startNewChat(), {\n ticketId: data.ticketId,\n skipCSAT,\n });\n }\n });\n }\n\n /**\n * Boot the messenger\n */\n async boot(): Promise<void> {\n if (this.isBooted) {\n return;\n }\n\n this.isDestroyed = false;\n\n // Recover visitor identity from cookie/IndexedDB if localStorage was cleared\n if (!this.config.preview) {\n const recovered = await recoverVisitorToken();\n if (recovered) {\n this.api.setVisitorToken(recovered);\n }\n }\n\n // Fetch widget config from backend (non-blocking for UI)\n if (!this.config.preview) {\n try {\n this.widgetAppearance = await this.api.getWidgetConfig();\n } catch {\n this.widgetAppearance = {};\n }\n }\n\n // Guard again after async — another boot() or shutdown() may have run\n if (this.isBooted || this.isDestroyed) {\n return;\n }\n\n // Create container with Shadow DOM for style isolation\n const host = document.createElement('div');\n host.id = 'cevro-messenger-host';\n document.body.appendChild(host);\n\n // Create Shadow DOM\n this.shadowRoot = host.attachShadow({ mode: 'open' });\n\n // Inject styles into Shadow DOM\n const styleEl = document.createElement('style');\n styleEl.textContent = styles;\n this.shadowRoot.appendChild(styleEl);\n\n // Create inner container for CSS variables\n this.container = document.createElement('div');\n this.container.id = 'cevro-messenger-container';\n this.shadowRoot.appendChild(this.container);\n\n this.applyPrimaryColor();\n\n // Create launcher (skip if hideDefaultLauncher is set)\n if (!this.config.hideDefaultLauncher) {\n this.createAndMountLauncher();\n }\n\n // Create chat window with merged locale strings\n const strings = getStrings(this.config.locale);\n this.chatWindow = new ChatWindow(\n this.config,\n {\n onClose: () => this.hide(),\n onSendMessage: (message) => this.sendMessage(message),\n onQuickAction: (action) => this.handleQuickAction(action),\n onFileUpload: (file) => this.handleFileUpload(file),\n onCSATSubmit: async (rating, feedback) => this.submitCSAT(rating, feedback),\n onStartNewChat: () => this.startNewChat(),\n onPreChatSubmit: (data) => this.handlePreChatSubmit(data),\n onShowHistory: () => this.navigateTo('history'),\n },\n strings,\n this.widgetAppearance.customLogoUrl\n );\n this.chatWindow.setBrandLogoUrl(this.firstMessageBrandLogoUrl());\n this.container.appendChild(this.chatWindow.render());\n\n // Create conversation history screens\n this.createConversationList(strings);\n this.createPastConversation(strings);\n\n // Check for existing session (will be properly restored on show())\n const storedSession = getStoredSession();\n if (storedSession?.ticketId) {\n this.api.setCurrentTicketId(storedSession.ticketId);\n }\n\n // Bind custom launcher element if selector provided\n if (this.config.customLauncherSelector) {\n this.bindCustomLauncher(this.config.customLauncherSelector);\n }\n\n this.isBooted = true;\n this.events.emit('boot');\n\n if (this.widgetAppearance.autoOpen) {\n setTimeout(() => this.show(), 100);\n }\n }\n\n private applyPrimaryColor(): void {\n const color = this.widgetAppearance.primaryColor || this.config.primaryColor;\n if (color && this.container) {\n // Set CSS custom property on container\n this.container.style.setProperty('--cevro-primary', color);\n\n // Generate hover (darker) and light variants\n const hoverColor = this.adjustColorBrightness(color, -20);\n const lightColor = this.adjustColorBrightness(color, 40);\n\n this.container.style.setProperty('--cevro-primary-hover', hoverColor);\n this.container.style.setProperty('--cevro-primary-light', lightColor);\n }\n\n // Apply theme (from config or backend)\n this.applyTheme();\n }\n\n /**\n * Apply theme configuration\n * Backend theme is applied first, then local config overrides\n */\n private applyTheme(): void {\n if (!this.container) return;\n\n const backendTheme = this.widgetAppearance.theme;\n const localTheme = this.config.theme;\n\n if (!backendTheme && !localTheme) return;\n\n const mergedTheme: ThemeConfig = {\n ...backendTheme,\n ...localTheme,\n };\n\n this.applyCustomTheme(mergedTheme);\n }\n\n /**\n * Apply custom theme configuration\n */\n private applyCustomTheme(theme: ThemeConfig): void {\n if (!this.container) return;\n\n // Remove all theme CSS vars first so unset properties fall back to CSS defaults\n const themeVars = [\n '--cevro-bg', '--cevro-bg-secondary', '--cevro-text', '--cevro-text-secondary',\n '--cevro-border', '--cevro-user-msg-bg', '--cevro-user-msg-text',\n '--cevro-header-bg', '--cevro-header-text', '--cevro-bg-input',\n '--cevro-radius', '--cevro-radius-sm', '--cevro-shadow', '--cevro-shadow-sm',\n '--cevro-launcher-bg', '--cevro-launcher-icon', '--cevro-launcher-hover-shadow',\n '--cevro-send-btn-bg', '--cevro-send-btn-icon',\n '--cevro-file-btn-bg', '--cevro-file-btn-icon',\n '--cevro-agent-msg-bg', '--cevro-agent-msg-text',\n ];\n for (const v of themeVars) {\n this.container.style.removeProperty(v);\n }\n\n if (theme.backgroundColor) {\n this.container.style.setProperty('--cevro-bg', theme.backgroundColor);\n }\n if (theme.backgroundSecondaryColor) {\n this.container.style.setProperty('--cevro-bg-secondary', theme.backgroundSecondaryColor);\n }\n if (theme.textColor) {\n this.container.style.setProperty('--cevro-text', theme.textColor);\n }\n if (theme.textSecondaryColor) {\n this.container.style.setProperty('--cevro-text-secondary', theme.textSecondaryColor);\n }\n if (theme.borderColor) {\n this.container.style.setProperty('--cevro-border', theme.borderColor);\n }\n if (theme.userMessageBackgroundColor) {\n this.container.style.setProperty('--cevro-user-msg-bg', theme.userMessageBackgroundColor);\n }\n if (theme.userMessageTextColor) {\n this.container.style.setProperty('--cevro-user-msg-text', theme.userMessageTextColor);\n }\n if (theme.headerBackgroundColor) {\n this.container.style.setProperty('--cevro-header-bg', theme.headerBackgroundColor);\n }\n if (theme.headerTextColor) {\n this.container.style.setProperty('--cevro-header-text', theme.headerTextColor);\n }\n if (theme.inputBackgroundColor) {\n this.container.style.setProperty('--cevro-bg-input', theme.inputBackgroundColor);\n }\n if (theme.borderRadius !== undefined) {\n this.container.style.setProperty('--cevro-radius', `${theme.borderRadius}px`);\n this.container.style.setProperty('--cevro-radius-sm', `${Math.max(4, theme.borderRadius - 4)}px`);\n }\n if (theme.shadowColor) {\n this.container.style.setProperty('--cevro-shadow', `0 10px 40px ${theme.shadowColor}`);\n this.container.style.setProperty('--cevro-shadow-sm', `0 2px 8px ${theme.shadowColor}`);\n }\n // Launcher styling\n if (theme.launcherBackgroundColor) {\n this.container.style.setProperty('--cevro-launcher-bg', theme.launcherBackgroundColor);\n }\n if (theme.launcherIconColor) {\n this.container.style.setProperty('--cevro-launcher-icon', theme.launcherIconColor);\n }\n if (theme.launcherHoverShadowColor) {\n this.container.style.setProperty('--cevro-launcher-hover-shadow', theme.launcherHoverShadowColor);\n }\n // Send button styling\n if (theme.sendButtonBackgroundColor) {\n this.container.style.setProperty('--cevro-send-btn-bg', theme.sendButtonBackgroundColor);\n }\n if (theme.sendButtonIconColor) {\n this.container.style.setProperty('--cevro-send-btn-icon', theme.sendButtonIconColor);\n }\n // File button styling\n if (theme.fileButtonBackgroundColor) {\n this.container.style.setProperty('--cevro-file-btn-bg', theme.fileButtonBackgroundColor);\n }\n if (theme.fileButtonIconColor) {\n this.container.style.setProperty('--cevro-file-btn-icon', theme.fileButtonIconColor);\n }\n // Agent message styling\n if (theme.agentMessageBackgroundColor) {\n this.container.style.setProperty('--cevro-agent-msg-bg', theme.agentMessageBackgroundColor);\n }\n if (theme.agentMessageTextColor) {\n this.container.style.setProperty('--cevro-agent-msg-text', theme.agentMessageTextColor);\n }\n }\n\n /**\n * Adjust color brightness\n * @param hex - Hex color string\n * @param percent - Positive to lighten, negative to darken\n */\n private adjustColorBrightness(hex: string, percent: number): string {\n // Remove # if present\n hex = hex.replace(/^#/, '');\n\n // Parse RGB\n const num = parseInt(hex, 16);\n let r = (num >> 16) + percent;\n let g = ((num >> 8) & 0x00ff) + percent;\n let b = (num & 0x0000ff) + percent;\n\n // Clamp values\n r = Math.max(0, Math.min(255, r));\n g = Math.max(0, Math.min(255, g));\n b = Math.max(0, Math.min(255, b));\n\n return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0')}`;\n }\n\n /**\n * Create and mount the launcher into the container\n */\n private createAndMountLauncher(): void {\n if (!this.container) return;\n this.launcher = new Launcher(\n this.config,\n () => this.toggle(),\n this.widgetAppearance.bubbleIconUrl\n );\n this.container.appendChild(this.launcher.render());\n }\n\n /**\n * Create and mount conversation list screen\n */\n private createConversationList(strings: ReturnType<typeof getStrings>): void {\n if (!this.container) return;\n\n this.conversationList = new ConversationList(\n {\n onClose: () => this.hide(),\n onNewConversation: async () => {\n this.navigateTo('chat');\n await this.startNewChat();\n },\n onSelectActive: () => {\n this.navigateTo('chat');\n },\n onSelectPast: (ticketId, title) => {\n this.navigateTo('past-conversation');\n this.pastConversation?.loadConversation(ticketId, title);\n },\n onLoadConversations: (cursor) => this.api.getConversations(cursor),\n },\n strings\n );\n\n const el = this.conversationList.render();\n el.style.display = 'none';\n this.container.appendChild(el);\n }\n\n /**\n * Create and mount past conversation view\n */\n private createPastConversation(strings: ReturnType<typeof getStrings>): void {\n if (!this.container) return;\n\n this.pastConversation = new PastConversation(\n {\n onBack: () => this.navigateTo('history'),\n onClose: () => this.hide(),\n onNewConversation: async () => {\n this.navigateTo('chat');\n await this.startNewChat();\n },\n onLoadMessages: (ticketId, cursor) => this.api.getConversationMessages(ticketId, cursor),\n },\n strings\n );\n\n const el = this.pastConversation.render();\n this.pastConversation.setAvatarUrl(this.widgetAppearance.customLogoUrl);\n this.pastConversation.setBrandLogoUrl(this.firstMessageBrandLogoUrl());\n el.style.display = 'none';\n this.container.appendChild(el);\n }\n\n /**\n * Navigate between screens\n */\n private navigateTo(screen: 'chat' | 'history' | 'past-conversation'): void {\n this.currentScreen = screen;\n\n // Hide all screens\n this.chatWindow?.hide();\n this.conversationList?.hide();\n this.pastConversation?.hide();\n\n // Show target screen\n switch (screen) {\n case 'chat':\n this.chatWindow?.show();\n break;\n case 'history':\n if (this.isSessionInitialized && this.api.getCurrentTicketId()) {\n this.conversationList?.setActiveConversation({\n ticketId: this.api.getCurrentTicketId()!,\n lastMessageBody: this.chatWindow?.getLastMessageBody(),\n lastMessageAt: this.chatWindow?.getLastMessageAt(),\n agentName: this.api.getCurrentAgent()?.name,\n unreadCount: this.chatWindow?.getAgentMessagesSinceLastUserMessage() ?? 0,\n });\n } else {\n this.conversationList?.setActiveConversation(null);\n }\n this.conversationList?.show();\n this.conversationList?.load();\n break;\n case 'past-conversation':\n this.pastConversation?.show();\n break;\n }\n }\n\n /**\n * Bind a custom launcher element by CSS selector\n */\n private bindCustomLauncher(selector: string): void {\n const el = document.querySelector(selector);\n if (!el) {\n console.warn(`[CevroMessenger] customLauncherSelector \"${selector}\" did not match any element`);\n return;\n }\n\n this.customLauncherHandler = () => this.toggle();\n this.customLauncherElement = el;\n el.addEventListener('click', this.customLauncherHandler);\n }\n\n /**\n * Connect to Centrifugo WebSocket server\n * Fetches connection token from API first\n *\n * Security: Uses signed visitorToken to prevent visitor spoofing\n */\n private async connectWebSocket(): Promise<void> {\n // If already connecting, wait for existing promise\n if (this.connectingPromise) {\n return this.connectingPromise;\n }\n\n this.connectingPromise = this.doConnectWebSocket();\n return this.connectingPromise;\n }\n\n private async doConnectWebSocket(): Promise<void> {\n try {\n const storedVisitorToken = getStoredVisitorToken();\n const result = await this.api.getConnectionToken(storedVisitorToken);\n\n this.visitorId = result.visitorId;\n\n if (result.visitorToken) {\n storeVisitorToken(result.visitorToken);\n this.api.setVisitorToken(result.visitorToken);\n }\n\n this.ws.connect(result.visitorId, result.token);\n this.events.emit('ready');\n } catch (error) {\n // Still emit ready - SDK works without real-time, just with polling\n this.events.emit('ready');\n this.events.emit('error', { type: 'websocket_connect', error });\n } finally {\n this.connectingPromise = null;\n }\n }\n\n /**\n * Refresh connection token for Centrifugo\n * Called automatically when token expires or on reconnect\n */\n private async refreshConnectionToken(): Promise<string> {\n const storedVisitorToken = getStoredVisitorToken();\n const result = await this.api.getConnectionToken(storedVisitorToken);\n\n if (result.visitorToken) {\n storeVisitorToken(result.visitorToken);\n this.api.setVisitorToken(result.visitorToken);\n }\n\n return result.token;\n }\n\n /**\n * Shutdown the messenger\n * @param options.clearVisitorData - If true, clears visitor token (visitor will get new identity on next init)\n */\n shutdown(options?: { clearVisitorData?: boolean }): void {\n this.isDestroyed = true;\n\n if (!this.isBooted) {\n // Even pre-boot, clear stored data if requested — the caller\n // explicitly wants a clean slate (e.g. logout flow).\n if (options?.clearVisitorData) {\n clearStoredSession();\n clearStoredVisitorToken();\n clearActivePlayer();\n this.visitorId = null;\n }\n return;\n }\n\n // Stop typing cycle\n this.stopTypingCycle();\n\n // Disconnect WebSocket\n this.ws.disconnect();\n\n // Unbind custom launcher\n if (this.customLauncherElement && this.customLauncherHandler) {\n this.customLauncherElement.removeEventListener('click', this.customLauncherHandler);\n this.customLauncherElement = null;\n this.customLauncherHandler = null;\n }\n\n // Destroy UI components\n this.launcher?.destroy();\n this.chatWindow?.destroy();\n this.conversationList?.destroy();\n this.pastConversation?.destroy();\n\n // Remove Shadow DOM host element\n const host = this.shadowRoot?.host;\n if (host && host.parentNode) {\n host.parentNode.removeChild(host);\n }\n this.shadowRoot = null;\n\n // Clear stored data\n clearStoredSession();\n if (options?.clearVisitorData) {\n clearStoredVisitorToken();\n clearActivePlayer();\n this.visitorId = null;\n }\n this.api.clear();\n\n // Reset state\n this.launcher = null;\n this.chatWindow = null;\n this.conversationList = null;\n this.pastConversation = null;\n this.currentScreen = 'chat';\n this.container = null;\n this.isBooted = false;\n this.isVisible = false;\n this.unreadCount = 0;\n this.isSessionInitialized = false;\n this.isInitializingSession = null;\n this.connectingPromise = null;\n\n this.events.emit('shutdown');\n }\n\n /**\n * Show the messenger\n */\n async show(): Promise<void> {\n if (!this.isBooted) {\n await this.boot();\n }\n\n if (this.chatWindow) {\n // Show the current screen (default: chat)\n this.navigateTo(this.currentScreen);\n this.isVisible = true;\n this.launcher?.setState(true);\n this.setUnreadCount(0);\n this.events.emit('show');\n\n // Close on Escape key (desktop only)\n if (!this.escapeHandler) {\n this.escapeHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') this.hide();\n };\n document.addEventListener('keydown', this.escapeHandler);\n }\n\n // In preview mode, skip WebSocket and session initialization\n if (!this.config.preview) {\n await this.connectWebSocket();\n\n // Set visitor ID on API client for history requests\n if (this.visitorId) {\n this.api.setVisitorId(this.visitorId);\n }\n\n await this.initializeSession();\n }\n }\n }\n\n /**\n * Initialize session with backend\n * Creates/retrieves Contact and Ticket, loads existing messages\n * Uses promise pattern to ensure proper waiting when called concurrently\n */\n private async initializeSession(forceNew = false): Promise<void> {\n // If forcing new session, reset state\n if (forceNew) {\n this.isSessionInitialized = false;\n this.isInitializingSession = null;\n }\n\n // Already initialized - nothing to do\n if (this.isSessionInitialized) {\n return;\n }\n\n // If initialization is in progress, wait for it to complete\n if (this.isInitializingSession) {\n return this.isInitializingSession;\n }\n\n // Start new initialization - wrap with finally to ensure cleanup\n const initPromise = this.doInitializeSession().finally(() => {\n // Only clear if this is still the current initialization promise\n if (this.isInitializingSession === initPromise) {\n this.isInitializingSession = null;\n }\n });\n\n this.isInitializingSession = initPromise;\n return initPromise;\n }\n\n /**\n * Actual session initialization logic\n */\n private async doInitializeSession(options?: { forceNewTicket?: boolean }): Promise<void> {\n try {\n const result = await this.api.initSession(this.visitorId, this.visitorContactInfo, options);\n\n // Check if contact info is required but missing\n if (result.requireContactInfo && result.missingFields && result.missingFields.length > 0) {\n this.chatWindow?.showPreChatForm();\n return;\n }\n\n // Store session data\n storeSession(result.sessionId, result.contactId, result.ticketId);\n this.isSessionInitialized = true;\n\n // Set agent info in header\n if (result.agent && this.chatWindow) {\n this.chatWindow.setAgent(result.agent);\n }\n if (result.agent && this.pastConversation) {\n this.pastConversation.setAgent(result.agent);\n }\n\n // Store typing config from server\n if (result.typingConfig) {\n this.typingConfig = result.typingConfig;\n }\n\n // Apply backend locale strings (highest priority: backend > client config > defaults)\n if (result.locale && this.chatWindow) {\n const mergedStrings = getStrings(this.config.locale, result.locale);\n this.chatWindow.setStrings(mergedStrings);\n this.conversationList?.setStrings(mergedStrings);\n this.pastConversation?.setStrings(mergedStrings);\n }\n\n this.chatWindow?.setScrollTopHandler(null);\n\n // Load existing messages into chat window\n if (result.messages && result.messages.length > 0) {\n for (const message of result.messages) {\n this.chatWindow?.addMessage(message);\n }\n\n // Enable scroll-up loading for older messages.\n // Do not depend solely on /session hasMoreMessages, because some backends\n // return only the latest slice here and expose pagination only via\n // /conversations/:ticketId/messages.\n if (result.ticketId) {\n let olderMessagesCursor: string | undefined =\n result.cursor || result.messages[0]?.createdAt;\n let isLoadingOlder = false;\n\n this.chatWindow?.setScrollTopHandler(async () => {\n if (isLoadingOlder || !olderMessagesCursor) return;\n isLoadingOlder = true;\n try {\n const older = await this.api.getConversationMessages(\n result.ticketId,\n olderMessagesCursor,\n );\n this.chatWindow?.prependMessages(older.messages);\n olderMessagesCursor = older.hasMore\n ? (older.cursor || older.messages[0]?.createdAt)\n : undefined;\n } catch (error) {\n console.error('[Cevro] Failed to load older messages:', error);\n } finally {\n isLoadingOlder = false;\n this.chatWindow?.finishLoadingTop();\n }\n });\n }\n }\n\n // Handle closed ticket state\n if (result.ticketClosed) {\n const skipCSAT = this.widgetAppearance.csatEnabled !== true;\n this.chatWindow?.setTicketClosed(true, () => this.startNewChat(), {\n ticketId: result.ticketId,\n skipCSAT,\n });\n }\n\n this.events.emit('session:initialized', {\n sessionId: result.sessionId,\n contactId: result.contactId,\n ticketId: result.ticketId,\n isNewSession: result.isNewSession,\n isNewTicket: result.isNewTicket,\n ticketClosed: result.ticketClosed,\n messageCount: result.messages?.length || 0,\n });\n\n } catch (error) {\n this.events.emit('error', { type: 'session_init', error });\n throw error;\n }\n }\n\n /**\n * Submit CSAT rating for the current conversation\n */\n private async submitCSAT(rating: number, feedback?: string): Promise<void> {\n const ticketId = this.api.getCurrentTicketId();\n const contactId = this.api.getContactId();\n\n if (!ticketId || !contactId) {\n throw new Error('No active session');\n }\n\n await this.api.submitCSAT(ticketId, contactId, rating, feedback);\n }\n\n /**\n * Start a new chat (creates a new ticket)\n * Used when the previous chat was closed\n */\n async startNewChat(): Promise<void> {\n // Navigate to chat screen first\n this.navigateTo('chat');\n\n // Clear current chat window messages\n this.chatWindow?.clearMessages();\n this.chatWindow?.setTicketClosed(false);\n\n // Re-initialize session with forceNewTicket\n this.isSessionInitialized = false;\n await this.doInitializeSession({ forceNewTicket: true });\n\n this.events.emit('chat:new_started');\n }\n\n /**\n * Hide the messenger\n */\n hide(): void {\n if (this.chatWindow) {\n this.chatWindow.hide();\n this.conversationList?.hide();\n this.pastConversation?.hide();\n this.isVisible = false;\n this.launcher?.setState(false);\n this.events.emit('hide');\n\n if (this.escapeHandler) {\n document.removeEventListener('keydown', this.escapeHandler);\n this.escapeHandler = null;\n }\n }\n }\n\n /**\n * Show the default launcher bubble\n */\n showLauncher(): void {\n if (!this.isBooted) return;\n if (!this.launcher) {\n this.createAndMountLauncher();\n }\n this.launcher?.setVisible(true);\n }\n\n /**\n * Hide the default launcher bubble (widget remains functional via show())\n */\n hideLauncher(): void {\n if (!this.isBooted) return;\n this.launcher?.setVisible(false);\n }\n\n /**\n * Toggle messenger visibility\n */\n toggle(): void {\n if (this.isVisible) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n /**\n * Maximum message length (2000 characters)\n */\n private static readonly MAX_MESSAGE_LENGTH = 2000;\n\n /**\n * Set draft message in the textarea without sending\n */\n setDraft(message: string): void {\n this.chatWindow?.setDraft(message);\n }\n\n /**\n * Send a message\n */\n async sendMessage(message: string): Promise<void> {\n if (!message.trim()) return;\n\n // Validate message length\n if (message.length > CevroMessenger.MAX_MESSAGE_LENGTH) {\n this.events.emit('error', {\n type: 'validation',\n error: new Error(`Message is too long. Maximum ${CevroMessenger.MAX_MESSAGE_LENGTH} characters allowed.`),\n message: `Message is too long. Maximum ${CevroMessenger.MAX_MESSAGE_LENGTH} characters allowed.`,\n });\n return;\n }\n\n // Create optimistic message\n // inbound: true = user's message going TO backend (consistent with backend storage)\n const optimisticMessage: Message = {\n id: 'temp_' + Date.now(),\n body: message,\n inbound: true,\n outbound: false,\n createdAt: new Date().toISOString(),\n type: 'text',\n status: 'sending',\n };\n\n // Add to UI immediately\n this.chatWindow?.addMessage(optimisticMessage);\n\n // In preview mode, just show the message without API call\n if (this.config.preview) {\n optimisticMessage.status = 'sent';\n this.chatWindow?.updateMessage(optimisticMessage);\n return;\n }\n\n try {\n // Ensure session is initialized before sending\n if (!this.isSessionInitialized) {\n await this.initializeSession();\n }\n\n // Store original temp id for lookup\n const tempId = optimisticMessage.id;\n\n // Send message to existing conversation\n const result = await this.api.sendMessage(message);\n\n // Update optimistic message with real data\n optimisticMessage.id = result.id;\n optimisticMessage.status = 'sent';\n this.chatWindow?.updateMessage(optimisticMessage, tempId);\n\n this.events.emit('message:sent', { message: result });\n\n // Typing indicator will be shown by backend via WebSocket event\n\n } catch (error: any) {\n // Check if conversation is closed\n const isConversationClosed =\n error?.message?.includes('closed') ||\n error?.message?.includes('resolved') ||\n error?.message?.includes('escalated') ||\n error?.response?.data?.message?.includes('closed');\n\n if (isConversationClosed) {\n // Remove the failed optimistic message\n this.chatWindow?.removeMessage(optimisticMessage.id);\n\n // Show closed UI with \"New Conversation\" button\n const ticketId = this.api.getCurrentTicketId() || undefined;\n this.chatWindow?.setTicketClosed(true, () => this.startNewChat(), {\n ticketId,\n skipCSAT: this.widgetAppearance.csatEnabled !== true,\n });\n return;\n }\n\n // Update optimistic message with error status\n optimisticMessage.status = 'failed';\n this.chatWindow?.updateMessage(optimisticMessage);\n\n this.events.emit('error', { error, type: 'send_message' });\n }\n }\n\n /**\n * Handle quick action click\n */\n private async handleQuickAction(action: QuickAction): Promise<void> {\n if (action.type === 'link' && action.url) {\n // Validate URL to prevent XSS via javascript: protocol\n if (isValidUrl(action.url)) {\n window.open(action.url, '_blank');\n }\n } else {\n // Send the action value as a message\n await this.sendMessage(action.value || action.label);\n }\n }\n\n /**\n * Handle pre-chat form submission (for visitors)\n */\n private async handlePreChatSubmit(data: { firstName: string; email: string }): Promise<void> {\n this.visitorContactInfo = data;\n\n // Hide the form and re-initialize session with contact info\n this.chatWindow?.hidePreChatForm();\n await this.initializeSession();\n }\n\n /**\n * Handle file upload with progress tracking\n * Shows preview immediately, then uploads to S3, then sends to backend\n *\n * Security: File is validated before upload (size, type, extension)\n */\n private async handleFileUpload(file: File): Promise<void> {\n // Variables for cleanup on error\n let localPreviewUrl: string | undefined;\n let tempId: string | undefined;\n\n try {\n // Ensure session is initialized before uploading\n if (!this.isSessionInitialized) {\n await this.initializeSession();\n }\n\n // Determine file type for display\n const isImage = file.type.startsWith('image/');\n const fileCategory = this.getFileCategory(file.type);\n\n // Create local preview URL for images\n localPreviewUrl = isImage ? URL.createObjectURL(file) : undefined;\n\n // Create optimistic message IMMEDIATELY (before upload starts)\n tempId = 'temp_' + Date.now();\n const optimisticMessage: Message = {\n id: tempId,\n body: '',\n inbound: true,\n outbound: false,\n createdAt: new Date().toISOString(),\n type: isImage ? 'image' : 'file',\n mediaUrl: localPreviewUrl,\n mediaType: file.type,\n status: 'sending',\n attachment: {\n filename: file.name,\n contentType: file.type || 'application/octet-stream',\n size: file.size,\n category: fileCategory,\n },\n };\n\n // Show preview in chat immediately\n this.chatWindow?.addMessage(optimisticMessage);\n\n // Now start the upload with progress (validation happens inside uploadFile)\n const assetId = await this.api.uploadFile(file, (progress) => {\n // Update progress in the message itself\n this.chatWindow?.updateMessageProgress(tempId!, progress);\n });\n\n // Send message to backend\n const result = await this.api.sendMessage('', assetId);\n\n // Update with real data from server, keeping blob URL if server didn't return mediaUrl\n const serverHasMediaUrl = result.mediaUrl && isValidUrl(result.mediaUrl);\n\n const updatedMessage: Message = {\n ...result,\n status: 'sent',\n type: isImage ? 'image' : 'file',\n mediaUrl: serverHasMediaUrl ? result.mediaUrl : localPreviewUrl,\n attachment: optimisticMessage.attachment,\n };\n this.chatWindow?.updateMessage(updatedMessage, tempId);\n\n // Only revoke blob URL if server returned a real URL\n if (localPreviewUrl && serverHasMediaUrl) {\n URL.revokeObjectURL(localPreviewUrl);\n }\n\n this.events.emit('message:sent', { type: fileCategory, fileName: file.name });\n\n } catch (error: any) {\n // Clean up blob URL on error\n if (localPreviewUrl) {\n URL.revokeObjectURL(localPreviewUrl);\n }\n\n // Remove failed optimistic message from UI\n if (tempId) {\n this.chatWindow?.removeMessage(tempId);\n }\n\n // Determine error type for better UX\n const errorMessage = error?.message || 'File upload failed';\n const isValidationError =\n errorMessage.includes('too large') ||\n errorMessage.includes('too small') ||\n errorMessage.includes('not allowed') ||\n errorMessage.includes('Too many uploads');\n\n // Emit specific error event with details\n this.events.emit('error', {\n error,\n type: isValidationError ? 'file_validation' : 'file_upload',\n message: errorMessage,\n fileName: file.name,\n });\n }\n }\n\n /**\n * Get file category for display purposes\n */\n private getFileCategory(mimeType: string): 'image' | 'pdf' | 'document' | 'spreadsheet' | 'presentation' | 'video' | 'audio' | 'archive' | 'text' | 'file' {\n if (mimeType.startsWith('image/')) return 'image';\n if (mimeType === 'application/pdf') return 'pdf';\n if (mimeType.includes('word') || mimeType.includes('document')) return 'document';\n if (mimeType.includes('sheet') || mimeType.includes('excel')) return 'spreadsheet';\n if (mimeType.includes('presentation') || mimeType.includes('powerpoint')) return 'presentation';\n if (mimeType.startsWith('video/')) return 'video';\n if (mimeType.startsWith('audio/')) return 'audio';\n if (mimeType.includes('zip') || mimeType.includes('archive') || mimeType.includes('compressed')) return 'archive';\n if (mimeType.startsWith('text/')) return 'text';\n return 'file';\n }\n\n /**\n * Set unread count\n */\n private setUnreadCount(count: number): void {\n this.unreadCount = count;\n this.launcher?.setUnreadCount(count);\n this.events.emit('unread_count_change', { count });\n }\n\n /**\n * The brand logo pairs with the global, workspace-voiced welcome\n * (`instantGreeting`) — pairing it with the personalized \"Hi, I'm\n * {agentName}\" welcome would put a company avatar next to agent-attributed\n * text.\n */\n private firstMessageBrandLogoUrl(): string | undefined {\n return this.widgetAppearance.instantGreeting\n ? this.widgetAppearance.customLogoUrl\n : undefined;\n }\n\n updateAppearance(config: Partial<WidgetAppearanceConfig>): void {\n this.widgetAppearance = {\n ...this.widgetAppearance,\n ...config,\n };\n\n if ('primaryColor' in config) {\n this.applyPrimaryColor();\n }\n\n if ('theme' in config) {\n this.applyTheme();\n }\n\n if ('bubbleIconUrl' in config && this.launcher) {\n this.launcher.updateBubbleIcon(config.bubbleIconUrl);\n }\n\n // Update chat window logo if changed (check if key exists in config)\n if ('customLogoUrl' in config && this.chatWindow) {\n this.chatWindow.updateCustomLogo(config.customLogoUrl);\n }\n if (('customLogoUrl' in config || 'instantGreeting' in config) && this.chatWindow) {\n this.chatWindow.setBrandLogoUrl(this.firstMessageBrandLogoUrl());\n }\n if (('customLogoUrl' in config || 'instantGreeting' in config) && this.pastConversation) {\n this.pastConversation.setBrandLogoUrl(this.firstMessageBrandLogoUrl());\n }\n\n this.events.emit('appearance:updated', this.widgetAppearance);\n }\n\n /**\n * Get current appearance config\n */\n getAppearance(): WidgetAppearanceConfig {\n return { ...this.widgetAppearance };\n }\n\n /**\n * Subscribe to an event\n * @param event - Event type to listen for\n * @param handler - Callback function\n * @returns Unsubscribe function\n */\n on<T = any>(event: string, handler: (data: T) => void): () => void {\n return this.events.on(event as any, handler);\n }\n\n /**\n * Subscribe to an event (fires only once)\n */\n once<T = any>(event: string, handler: (data: T) => void): () => void {\n return this.events.once(event as any, handler);\n }\n\n /**\n * Unsubscribe from an event\n * @param event - Event type\n * @param handler - Handler to remove\n */\n off(event: string, handler: (data: any) => void): void {\n this.events.off(event as any, handler);\n }\n\n /**\n * Get current unread message count\n */\n getUnreadCount(): number {\n return this.unreadCount;\n }\n\n /**\n * Get current visitor ID\n */\n getVisitorId(): string | null {\n return this.visitorId;\n }\n\n /**\n * Update config with new data (merges into current config)\n * Used by the loader queue replay pattern: Cevro('update', { ... })\n */\n update(data: Partial<CevroMessengerConfig>): void {\n this.config = this.normalizeConfig({ ...this.config, ...data });\n // Propagate new config reference to ApiClient and WebSocketClient\n this.api.updateConfig(this.config);\n this.ws.updateConfig(this.config);\n }\n\n /**\n * Identify a player (sets player data on config)\n * Used by the loader queue replay pattern: Cevro('identify', { playerId: '...' })\n *\n * Performs a soft re-initialization: keeps the UI intact, only re-creates\n * the session (new token + new session with updated player data).\n * No DOM destruction — no flickering.\n */\n async identify(playerData: PlayerData): Promise<void> {\n this.config.player = { ...this.config.player, ...playerData };\n\n // Detect account switches. First identify() stores the player hash and\n // returns false (anonymous session is preserved for server-side merge).\n // Subsequent identify() with a DIFFERENT playerId returns true — clear\n // stale session data so the new identity doesn't see the old conversation.\n const isSwitch = playerData.playerId\n ? detectAndRecordPlayerSwitch(playerData.playerId)\n : false;\n\n if (isSwitch) {\n clearStoredSession();\n clearStoredVisitorToken();\n }\n\n // Propagate updated config to ApiClient and WebSocketClient\n this.api.updateConfig(this.config);\n this.ws.updateConfig(this.config);\n\n // If not booted yet, just store the data — boot() will use it.\n // On first identify: existing session/visitor data preserved (anonymous→identified merge).\n // On account switch: data was cleared above, boot() starts fresh.\n if (!this.isBooted) {\n return;\n }\n\n // Soft re-init: disconnect WS, clear session state, reconnect with new identity\n const wasVisible = this.isVisible;\n this.ws.disconnect();\n this.api.clear();\n clearStoredSession();\n this.isSessionInitialized = false;\n this.isInitializingSession = null;\n this.connectingPromise = null;\n\n try {\n // Reconnect and re-initialize session with new player data\n await this.connectWebSocket();\n\n // Clear old messages before loading new session's messages\n this.chatWindow?.clearMessages();\n\n await this.initializeSession(true);\n\n // Re-apply visibility (session init may have reset UI state)\n if (wasVisible && this.chatWindow) {\n this.chatWindow.show();\n }\n\n this.events.emit('identify', { playerId: playerData.playerId });\n } catch (error) {\n this.events.emit('error', { type: 'identify', error });\n }\n }\n\n /**\n * Add a preview message (only works in preview mode)\n * @param text - Message text\n * @param fromAgent - If true, message appears as from agent; if false, from user\n */\n addPreviewMessage(text: string, fromAgent = true): void {\n if (!this.config.preview || !this.chatWindow) return;\n\n const message: Message = {\n id: 'preview_' + Date.now(),\n body: text,\n inbound: !fromAgent,\n outbound: fromAgent,\n createdAt: new Date().toISOString(),\n type: 'text',\n status: 'sent',\n };\n\n this.chatWindow.addMessage(message);\n }\n\n /**\n * Show or hide typing indicator (only works in preview mode)\n * @param show - Whether to show or hide the typing indicator\n */\n setPreviewTyping(show: boolean): void {\n if (!this.config.preview || !this.chatWindow) return;\n\n if (show) {\n this.chatWindow.showTypingIndicator();\n } else {\n this.chatWindow.hideTypingIndicator();\n }\n }\n\n /**\n * Set agent info for preview mode (name and avatar)\n * @param name - Agent name\n * @param avatarUrl - Agent avatar URL (optional)\n */\n setPreviewAgent(name: string, avatarUrl?: string): void {\n if (!this.config.preview || !this.chatWindow) return;\n\n this.chatWindow.setAgent({ name, avatarUrl });\n this.pastConversation?.setAgent({ name, avatarUrl });\n }\n\n /**\n * Start typing indicator cycle (5s on, 5s off, repeat)\n */\n private startTypingCycle(): void {\n // Clear any existing cycle\n this.stopTypingCycle();\n\n const { onDurationMs, offDurationMs } = this.typingConfig;\n\n const runCycle = () => {\n if (this.isTypingVisible) {\n this.chatWindow?.hideTypingIndicator();\n this.isTypingVisible = false;\n this.typingCycleTimeout = setTimeout(runCycle, offDurationMs);\n } else {\n this.chatWindow?.showTypingIndicator();\n this.isTypingVisible = true;\n this.typingCycleTimeout = setTimeout(runCycle, onDurationMs);\n }\n };\n\n this.chatWindow?.showTypingIndicator();\n this.isTypingVisible = true;\n this.typingCycleTimeout = setTimeout(runCycle, onDurationMs);\n }\n\n /**\n * Stop typing indicator cycle\n */\n private stopTypingCycle(): void {\n if (this.typingCycleTimeout) {\n clearTimeout(this.typingCycleTimeout);\n this.typingCycleTimeout = null;\n }\n\n if (this.isTypingVisible) {\n this.chatWindow?.hideTypingIndicator();\n this.isTypingVisible = false;\n }\n }\n}\n","/**\n * Cevro Messenger SDK\n *\n * A customer support chat widget for web applications.\n *\n * @example\n * // ES Module\n * import CevroMessenger from '@cevro/messenger-sdk';\n *\n * const messenger = new CevroMessenger({\n * apiBase: 'https://chat.cevro.ai',\n * workspaceId: 'your-workspace-id',\n * });\n *\n * messenger.boot();\n *\n * @example\n * // UMD (Script tag)\n * <script src=\"https://cdn.jsdelivr.net/npm/@cevro/messenger-sdk\"></script>\n * <script>\n * const messenger = new CevroMessenger({\n * apiBase: 'https://api.yoursite.com',\n * workspaceId: 'your-workspace-id',\n * });\n * messenger.boot();\n * </script>\n */\n\n// Import styles as string for Shadow DOM injection\nimport styles from './styles/index.css?inline';\n\n// Export styles for Shadow DOM\nexport { styles as __styles };\n\n// Export main class\nexport { CevroMessenger } from './core/CevroMessenger';\n\n// Export types\nexport type {\n CevroMessengerConfig,\n PlayerData,\n SessionData,\n Message,\n Conversation,\n QuickAction,\n RichContent,\n} from './types';\n\n// Default export for convenience\nimport { CevroMessenger } from './core/CevroMessenger';\nexport default CevroMessenger;\n\n// Global instance management for UMD builds and loader pattern\ndeclare global {\n interface Window {\n CevroMessenger: typeof CevroMessenger;\n cevroMessenger?: CevroMessenger;\n /** Settings object set by partner embed snippet, read by loader.js */\n cevroSettings?: import('./types').CevroMessengerConfig;\n /** Command queue / live proxy created by embed snippet and replaced by loader */\n Cevro?: ((...args: unknown[]) => void) & { q?: unknown[][] };\n }\n}\n\n// Auto-attach to window for UMD builds\nif (typeof window !== 'undefined') {\n window.CevroMessenger = CevroMessenger;\n}\n"],"names":["EventEmitter$2","constructor","__publicField","this","Map","on","event","handler","listeners","has","set","Set","get","add","off","once","onceHandler","data","onceHandlers","delete","handlers","emit","forEach","removeAllListeners","clear","listenerCount","_a","size","VISITOR_TOKEN_KEY","SESSION_KEY","IDB_STORE_NAME","setCookie","name","value","document","cookie","encodeURIComponent","openIDB","Promise","resolve","reject","req","indexedDB","open","onupgradeneeded","db","result","objectStoreNames","contains","createObjectStore","onsuccess","onerror","error","getStoredVisitorToken","fromLS","localStorage","getItem","fromCookie","match","RegExp","decodeURIComponent","getCookie","setItem","async","recoverVisitorToken","sync","fromIDB","key","then","tx","transaction","objectStore","oncomplete","close","catch","storeVisitorToken","token","put","generateVisitorId","lastDotIndex","lastIndexOf","substring","extractVisitorIdFromToken","getStoredVisitorId","ACTIVE_PLAYER_KEY","detectAndRecordPlayerSwitch","playerId","playerHash","input","hash","i","length","charCodeAt","Math","abs","toString","hashForKey","stored","clearActivePlayer","removeItem","clearStoredSession","clearStoredVisitorToken","deleteCookie","ALLOWED_MIME_TYPES","BLOCKED_EXTENSIONS","DEFAULT_FILE_CONSTRAINTS","maxSizeBytes","minSizeBytes","maxFilenameLength","getFileExtension","filename","lastDot","toLowerCase","formatFileSize","bytes","floor","log","parseFloat","pow","toFixed","UploadRateLimiter","maxUploads","windowMs","canUpload","now","Date","uploadTimestamps","filter","timestamp","recordUpload","push","getRemainingUploads","max","getTimeUntilNextUpload","oldestTimestamp","min","reset","ApiClient","config","uploadRateLimiter","updateConfig","setVisitorToken","visitorToken","getVisitorToken","setAccessToken","accessToken","getContactId","contactId","getCurrentTicketId","currentTicketId","setCurrentTicketId","ticketId","getCurrentAgent","currentAgent","request","endpoint","options","url","apiBase","headers","workspaceId","brandId","player","_b","visitorId","response","fetch","ok","json","message","statusText","Error","status","initSession","visitorContactInfo","payload","session","window","navigator","userAgent","language","platform","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","currentPage","location","href","pageTitle","title","referrer","screenWidth","screen","width","screenHeight","height","viewportWidth","innerWidth","viewportHeight","innerHeight","devicePixelRatio","urlParams","URLSearchParams","search","utmSource","utmMedium","utmCampaign","utmContent","utmTerm","cookiesEnabled","cookieEnabled","touchSupport","maxTouchPoints","online","onLine","connection","connectionType","effectiveType","e","collectSessionData","firstName","lastName","email","_c","phone","_d","customAttributes","_e","forceNewTicket","_f","method","body","JSON","stringify","requireContactInfo","_g","missingFields","sessionId","isNewSession","isNewTicket","agent","ticketClosed","ticketClosedReason","typingConfig","messages","_h","map","msg","normalizeMessage","hasMoreMessages","cursor","locale","sendMessage","assetId","getMessages","targetTicketId","results","getMyTickets","tickets","ticket","normalizeConversation","uploadFile","file","onProgress","waitTime","ceil","validation","allowedMimeTypes","blockedExtensions","valid","errorCode","extension","mimeType","type","validateFile","sanitizedFilename","sanitized","replace","ext","nameWithoutExt","slice","maxNameLength","sanitizeFilename","uploadUrl","contentType","uploadToS3","xhr","XMLHttpRequest","upload","addEventListener","lengthComputable","progress","round","loaded","total","setRequestHeader","send","id","objectId","inbound","outbound","createdAt","toISOString","mediaUrl","mediaType","richContent","conversationId","updatedAt","resolved","escalated","unreadCount","lastMessage","latestMessage","getConnectionToken","refreshConnectionToken","submitCSAT","rating","feedback","getConversations","params","conversations","hasMore","getConversationMessages","base","setVisitorId","getWidgetConfig","__awaiter","thisArg","_arguments","P","generator","fulfilled","step","next","rejected","done","apply","getDefaultExportFromCjs","x","__esModule","Object","prototype","hasOwnProperty","call","SuppressedError","ReflectOwnKeys","events","exports","R","Reflect","ReflectApply","target","receiver","args","Function","ownKeys","getOwnPropertySymbols","getOwnPropertyNames","concat","NumberIsNaN","Number","isNaN","EventEmitter","init","emitter","errorListener","err","removeListener","resolver","arguments","eventTargetAgnosticAddListener","flags","addErrorHandlerIfEventEmitter","_events","_eventsCount","_maxListeners","defaultMaxListeners","checkListener","listener","TypeError","_getMaxListeners","that","_addListener","prepend","m","existing","warning","create","newListener","unshift","warned","w","String","count","console","warn","onceWrapper","fired","wrapFn","_onceWrap","state","wrapped","bind","_listeners","unwrap","evlistener","arr","ret","Array","unwrapListeners","arrayClone","n","copy","wrapListener","arg","removeEventListener","defineProperty","enumerable","RangeError","getPrototypeOf","setMaxListeners","getMaxListeners","doError","er","context","len","addListener","prependListener","prependOnceListener","list","position","originalListener","shift","index","pop","spliceOne","keys","rawListeners","eventNames","errorCodes","connectingCodes","disconnectedCodes","subscribingCodes","unsubscribedCodes","subscriptionFlags","State","SubscriptionState","EventEmitter$1","isFunction","backoff","interval","random","randomInt","ttlMilliseconds","ttl","Subscription","centrifuge","channel","super","_resubscribeTimeout","_refreshTimeout","Unsubscribed","_centrifuge","_token","_getToken","_data","_getData","_recover","_offset","_epoch","_id","_recoverable","_positioned","_joinLeave","_minResubscribeDelay","_maxResubscribeDelay","_resubscribeAttempts","_promises","_promiseId","_inflight","_delta","_delta_negotiated","_tagsFilter","_prevValue","_unsubPromise","_setOptions","_debugEnabled","ctx","_debug","oldState","newState","ready","timeout","code","subscriptionUnsubscribed","Subscribed","res","rej","setTimeout","_nextPromiseId","subscribe","_isSubscribed","_setSubscribing","subscribeCalled","unsubscribe","_setUnsubscribed","unsubscribeCalled","publish","_methodCall","presence","presenceStats","history","opts","setTagsFilter","tagsFilter","setData","_isUnsubscribed","timeoutDuration","_config","_needRecover","_isSubscribing","Subscribing","_setState","_usesToken","_clearSubscribingState","_clearResubscribeTimeout","_clearSubscribedState","_clearRefreshTimeout","_setSubscribed","recoverable","offset","epoch","delta","_getSubscribeContext","_resolvePromises","pubs","publications","_handlePublication","expires","_refresh","reason","_transport","emulation","_subscribe","_isTransportOpen","_canSubscribeWithoutGettingToken","_subscribeWithoutToken","_getSubscriptionToken","_handleTokenResponse","_handleTokenError","_transportIsOpen","_getDataAndSubscribe","_sendSubscribe","_handleGetDataError","UnauthorizedError","_failUnauthorized","badConfiguration","_scheduleResubscribe","subscriptionSubscribeToken","cmd","_buildSubscribeCommand","_call","resolveCtx","reply","_handleSubscribeResponse","rejectCtx","_handleSubscribeError","positioned","join_leave","flag","channelCompaction","recover","_getOffset","_getEpoch","tf","_subscribeError","_disconnect","subscribeTimeout","sendUnsubscribe","promise","_unsubscribe","_rejectPromises","pub","newData","newPrevValue","_codec","applyDeltaIfNeeded","_getPublicationContext","_handleJoin","join","info","_getJoinLeaveContext","_handleLeave","leave","clearTimeout","self","delay","_getResubscribeDelay","temporary","errContext","Connected","since","getData","minResubscribeDelay","maxResubscribeDelay","getToken","joinLeave","sub_refresh","_refreshResponse","_refreshError","subscriptionRefreshToken","_getRefreshRetryDelay","unauthorized","SockjsTransport","subName","transport","supported","sockjs","initialize","_protocol","callbacks","sockjsOptions","onopen","onOpen","onError","onclose","closeEvent","onClose","onmessage","onMessage","WebsocketTransport","websocket","protocol","subProtocol","binaryType","HttpStreamTransport","_abortController","_utf8decoder","TextDecoder","_handleErrors","_fetchEventTarget","eventTarget","EventTarget","fetchFunc","dispatchEvent","Event","jsonStreamBuf","jsonStreamPos","protoStreamBuf","Uint8Array","reader","getReader","readableStream","start","controller","pump","read","decode","line","MessageEvent","mergedArray","decoder","decodeReply","pos","detail","AbortController","initialData","Accept","fetchOptions","mode","credentials","signal","abort","node","encoder","encodeEmulationRequest","emulationEndpoint","SseTransport","_onClose","eventsource","globalThis","baseURI","URL","searchParams","append","eventSource","WebtransportTransport","_stream","_writer","webtransport","closed","stream","createBidirectionalStream","writable","getWriter","_startReading","readable","binary","TextEncoder","encode","write","zValue","Reader","array","a","haveBytes","getByte","b","getChar","fromCharCode","getInt","c","v","Writer","toByteArray","sourceType","isArray","putArray","end","checksum","sum0","sum1","sum2","sum3","z","N","JsonCodec","encodeCommands","commands","decodeReplies","trim","split","r","parse","prevValue","valueArray","source","zDelta","lenSrc","lenDelta","limit","zOut","cnt","ofst","out","applyDelta","defaults","debug","version","minReconnectDelay","maxReconnectDelay","maxServerPingDelay","networkEventTarget","Centrifuge","_reconnectTimeout","_serverPingTimeout","Disconnected","_endpoint","_emulation","_transports","_currentTransportIndex","_triedAllTransports","_transportWasOpen","_transportId","_deviceWentOffline","_transportClosed","_reconnecting","_reconnectAttempts","_client","_session","_node","_subs","_serverSubs","_commandId","_commands","_batching","_refreshRequired","_callbacks","_dispatchPromise","_serverPing","_sendPong","_networkEventsSet","assign","_configure","newSubscription","getSubscription","sub","_getSub","removeSubscription","_removeSubscription","subscriptions","clientDisconnected","connect","_isConnected","_isConnecting","_startConnecting","disconnect","disconnectCalled","setToken","setHeaders","_transportSendCommands","_createErrorObject","transportWriteError","rpc","_callPromise","_getHistoryRequest","clients","clientId","rawClient","connInfo","chanInfo","presence_stats","numUsers","num_users","numClients","num_clients","startBatching","stopBatching","_flush","level","logger","_codecName","_formatOverride","transportConfig","transportName","indexOf","_isDisconnected","Connecting","_nextCommandId","_setNetworkEvents","transportClosed","_clearReconnectTimeout","_startReconnecting","_getReconnectDelay","_clearOutgoingRequests","errback","connectionClosed","_clearConnectedState","_clearServerPingTimeout","_handleWriteError","command","_initializeTransport","WebSocket","SockJS","EventSource","ReadableStream","transportEndpoint","WebTransport","prefix","transportId","_nextTransportId","wasOpen","initialCommands","connectCommand","_sendConnect","connectTimeout","_sendSubscribeCommands","needReconnect","advice","reconnect","messageSizeLimit","_dataReceived","skipSending","_constructConnectCommand","_connectResponse","_connectError","emptyToken","clientConnectToken","_scheduleReconnect","isInitialHandshake","subs","hasSubs","reverse","resultCB","_waitServerPing","replies","finishDispatch","_dispatchSynchronized","p","_dispatchReply","_handleReply","_handlePush","_handleServerPing","_registerCall","_addCommand","connectCalled","previousState","needEvent","refresh","clientRefreshToken","client","_","unsubscribeError","ch","_isServerSub","_processServerSubs","ping","pong","subCtx","recovered","noPing","wasRecovering","hasRecoveredPublications","was_recovering","streamPosition","callback","_handleUnsubscribe","_handleSubscribe","_handleDisconnect","tags","clientInfo","user","_handleMessage","errObject","WebSocketClient","setTokenRefreshCallback","getTokenCallback","userId","connectionToken","wsUrl","getWebSocketUrl","setupClientEventListeners","centrifugoUrl","apiUrl","host","subscribeToPersonalChannel","channelName","existingSub","personalSub","handleMessage","senderType","agentName","isTyping","actor","closedAt","updateToken","newToken","isConnected","getUserId","createElement","tag","attributes","children","element","entries","className","startsWith","setAttribute","child","appendChild","createTextNode","isValidUrl","parsed","origin","includes","parseMarkdown","text","div","textContent","innerHTML","escapeHtml","_match","linkText","safeUrl","sanitizeUrl","scrollToBottom","smooth","scrollTo","top","scrollHeight","behavior","generateId","Launcher","onClick","bubbleIconUrl","render","applyPositioning","button","chatImg","src","alt","style","objectFit","chatIcon","createChatIcon","classList","closeIcon","createCloseIcon","unreadBadge","display","alignment","vPadding","verticalPadding","hPadding","horizontalPadding","bottom","left","right","zIndex","svg","createElementNS","path","line1","line2","setState","isOpen","remove","setUnreadCount","setVisible","visible","pulse","updateBubbleIcon","iconUrl","querySelector","existingIcon","cssText","insertBefore","firstChild","destroy","parentNode","removeChild","defaultStrings","headerTitle","headerSubtitle","inputPlaceholder","preChatTitle","preChatSubtitle","preChatFirstNameLabel","preChatFirstNamePlaceholder","preChatEmailLabel","preChatEmailPlaceholder","preChatSubmit","preChatFirstNameRequired","preChatEmailRequired","preChatEmailInvalid","closedMessage","newConversation","conversationsTitle","newConversationButton","activeConversation","noConversations","noConversationsSubtitle","loadingConversations","loadMoreConversations","messagesCount","yesterday","closedStatus","defaultConversationTitle","csatTitle","csatSubtitle","csatPlaceholder","csatPlaceholderNegative","csatPlaceholderNeutral","csatSubmit","csatThankYou","poweredBy","getStrings","clientOverrides","backendOverrides","MessageList","setQuickActionHandler","onQuickAction","setScrollTopHandler","onScrollTopCallback","finishLoadingTop","requestAnimationFrame","isLoadingTop","resetTopLoading","suppressScrollEvents","setAgent","setBrandLogoUrl","brandLogoUrl","refreshFirstAdminMessageAvatar","firstAdminMessageId","messageData","el","rebuiltEl","createMessageElement","replaceWith","messagesContainer","autoScroll","threshold","scrollTop","clientHeight","isScrolledToBottom","started","getLastMessageBody","lastMessageBody","getLastMessageAt","lastMessageAt","getAgentMessagesSinceLastUserMessage","nodes","querySelectorAll","addMessage","animate","skipScroll","updateMessage","isFirst","messageEl","typingIndicator","prependMessages","anchor","firstElementChild","anchorOffset","offsetTop","earliestAdminMessage","find","previousFirstId","previousFirstMessage","previousFirstEl","prependMessage","oldId","lookupId","existingEl","newEl","replaceChild","updateMessageProgress","messageId","progressFill","progressText","removeMessage","promoteNextAdminMessageToFirst","from","dataset","isMyMessage","wrapper","showBrandLogo","isHuman","avatar","initials","toUpperCase","initialsEl","validAgentAvatarUrl","avatarUrl","avatarSrc","img","createBotAvatarSvg","contentWrapper","senderLabel","bubble","isImage","attachment","category","imageContainer","loading","progressOverlay","createProgressOverlay","fileCard","createFileCard","link","rel","getFileIcon","quickActions","actionsContainer","action","label","meta","date","toLocaleTimeString","hour","minute","getStatusIcon","overlay","isUploading","card","iconWrapper","truncateFilename","details","icons","pdf","spreadsheet","presentation","video","audio","archive","image","maxLength","showTypingIndicator","hideTypingIndicator","indicator","closedMessageElement","showClosedMessage","hideClosedMessage","displayMessage","ChatWindow","strings","customLogoUrl","messageList","setStrings","backendStrings","updateUIStrings","headerSubtitleElement","inputElement","placeholder","header","createHeader","messagesArea","inputWrapper","createInputArea","logoElement","logoImg","borderRadius","createCompanyLogoSvg","historyButton","onShowHistory","titleSection","brandNameElement","closeButton","inputArea","fileButton","fileInput","accept","accepts","generateAcceptAttribute","files","onFileUpload","click","rows","resizeInput","updateSendButtonState","shiftKey","preventDefault","handleSend","sendButton","disabled","footer","onSendMessage","focus","preventScroll","setDraft","getAttribute","clearMessages","show","isVisible","hide","isWindowVisible","focusInput","setTicketClosed","onStartNewChat","skipCSAT","removeClosedUI","csatSubmitted","showClosedFooter","showInlineCSATForm","preChatContainer","csatRating","csatFeedback","csatContainer","headerRow","skipButton","starsRow","star","createStarSvg","selectInlineRating","previewRating","feedbackInput","submitButton","submitInlineCSAT","container","csatSubmitting","updateStars","parentElement","onCSATSubmit","showInlineThankYou","thankYouRow","checkIcon","newChatButton","closedFooter","filled","toggle","showPreChatForm","preChatCompleted","subtitle","form","firstNameGroup","firstNameLabel","for","firstNameInput","firstNameError","emailGroup","emailLabel","emailInput","autocomplete","emailError","isValidEmail","hasError","onPreChatSubmit","hidePreChatForm","test","logoUrl","updateCustomLogo","ConversationList","titleElement","setActiveConversation","activeInfo","listContainer","newConvButton","onNewConversation","actionPanel","load","loadMoreButton","onLoadConversations","activeCard","createActiveCard","showEmptyState","conv","createConversationCard","renderLoadMoreButton","loadMore","isLoadingMore","unread","content","titleRow","formatDate","previewRow","preview","onSelectActive","titleText","messageCount","onSelectPast","empty","emptyTitle","emptySubtitle","dateStr","diffMs","getTime","diffDays","toLocaleDateString","weekday","month","day","PastConversation","setAvatarUrl","renderAvatar","avatarElement","backButton","onBack","loadMoreMessages","loadConversation","onLoadMessages","requestedTicketId","_CevroMessenger","onDurationMs","offDurationMs","normalizeConfig","api","ws","setupEventHandlers","instance","getInstance","stopTypingCycle","chatWindow","startTypingCycle","escalationMsg","widgetAppearance","csatEnabled","startNewChat","boot","isBooted","isDestroyed","shadowRoot","attachShadow","styleEl","styles","applyPrimaryColor","hideDefaultLauncher","createAndMountLauncher","handleQuickAction","handleFileUpload","handlePreChatSubmit","navigateTo","firstMessageBrandLogoUrl","createConversationList","createPastConversation","storedSession","getStoredSession","customLauncherSelector","bindCustomLauncher","autoOpen","color","primaryColor","setProperty","hoverColor","adjustColorBrightness","lightColor","applyTheme","backendTheme","theme","localTheme","mergedTheme","applyCustomTheme","themeVars","removeProperty","backgroundColor","backgroundSecondaryColor","textColor","textSecondaryColor","borderColor","userMessageBackgroundColor","userMessageTextColor","headerBackgroundColor","headerTextColor","inputBackgroundColor","shadowColor","launcherBackgroundColor","launcherIconColor","launcherHoverShadowColor","sendButtonBackgroundColor","sendButtonIconColor","fileButtonBackgroundColor","fileButtonIconColor","agentMessageBackgroundColor","agentMessageTextColor","hex","percent","num","parseInt","g","padStart","launcher","conversationList","pastConversation","currentScreen","isSessionInitialized","_i","_j","_k","_l","_m","selector","customLauncherHandler","customLauncherElement","connectWebSocket","connectingPromise","doConnectWebSocket","storedVisitorToken","shutdown","clearVisitorData","isInitializingSession","escapeHandler","initializeSession","forceNew","initPromise","doInitializeSession","finally","storeSession","mergedStrings","olderMessagesCursor","isLoadingOlder","older","showLauncher","hideLauncher","MAX_MESSAGE_LENGTH","optimisticMessage","tempId","localPreviewUrl","fileCategory","getFileCategory","createObjectURL","serverHasMediaUrl","updatedMessage","revokeObjectURL","fileName","errorMessage","isValidationError","instantGreeting","updateAppearance","getAppearance","getUnreadCount","getVisitorId","update","identify","playerData","wasVisible","addPreviewMessage","fromAgent","setPreviewTyping","setPreviewAgent","runCycle","isTypingVisible","typingCycleTimeout","CevroMessenger"],"mappings":"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","x_google_ignoreList":[4]}
|