@elqnt/chat 3.3.0 → 3.5.0

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.
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  "use strict";
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -32,6 +31,18 @@ __export(transport_exports, {
32
31
  module.exports = __toCommonJS(transport_exports);
33
32
 
34
33
  // transport/types.ts
34
+ async function resolveTransportToken(cfg) {
35
+ if (!cfg) return void 0;
36
+ if (cfg.getToken) {
37
+ try {
38
+ const t = await cfg.getToken();
39
+ return t ?? void 0;
40
+ } catch {
41
+ return void 0;
42
+ }
43
+ }
44
+ return cfg.token ?? void 0;
45
+ }
35
46
  function createLogger(debug = false) {
36
47
  return {
37
48
  debug: debug ? console.log.bind(console, "[chat]") : () => {
@@ -112,9 +123,12 @@ function createSSETransport(options = {}) {
112
123
  }
113
124
  const url = `${config.baseUrl}/${endpoint}`;
114
125
  logger.debug(`POST ${endpoint}`, body);
126
+ const token = await resolveTransportToken(config);
127
+ const headers = { "Content-Type": "application/json" };
128
+ if (token) headers["Authorization"] = `Bearer ${token}`;
115
129
  const response = await fetch(url, {
116
130
  method: "POST",
117
- headers: { "Content-Type": "application/json" },
131
+ headers,
118
132
  body: JSON.stringify(body)
119
133
  });
120
134
  if (!response.ok) {
@@ -241,6 +255,7 @@ function createSSETransport(options = {}) {
241
255
  reconnectTimeout = void 0;
242
256
  }
243
257
  state = retryCount > 0 ? "reconnecting" : "connecting";
258
+ const connectToken = await resolveTransportToken(cfg);
244
259
  return new Promise((resolve, reject) => {
245
260
  const connectionStart = Date.now();
246
261
  const streamParams = new URLSearchParams({
@@ -249,6 +264,7 @@ function createSSETransport(options = {}) {
249
264
  clientType: cfg.clientType
250
265
  });
251
266
  if (cfg.chatKey) streamParams.set("chatId", cfg.chatKey);
267
+ if (connectToken) streamParams.set("token", connectToken);
252
268
  const url = `${cfg.baseUrl}/stream?${streamParams.toString()}`;
253
269
  logger.debug("Connecting to:", url);
254
270
  const es = new EventSource(url);
@@ -502,9 +518,12 @@ function createFetchSSETransport(options = {}) {
502
518
  }
503
519
  const url = `${config.baseUrl}/${endpoint}`;
504
520
  logger.debug(`POST ${endpoint}`, body);
521
+ const token = await resolveTransportToken(config);
522
+ const headers = { "Content-Type": "application/json" };
523
+ if (token) headers["Authorization"] = `Bearer ${token}`;
505
524
  const response = await customFetch(url, {
506
525
  method: "POST",
507
- headers: { "Content-Type": "application/json" },
526
+ headers,
508
527
  body: JSON.stringify(body)
509
528
  });
510
529
  if (!response.ok) {
@@ -547,15 +566,19 @@ function createFetchSSETransport(options = {}) {
547
566
  clientType: cfg.clientType
548
567
  });
549
568
  if (cfg.chatKey) streamParams.set("chatId", cfg.chatKey);
569
+ const token = await resolveTransportToken(cfg);
570
+ if (token) streamParams.set("token", token);
550
571
  const url = `${cfg.baseUrl}/stream?${streamParams.toString()}`;
551
572
  logger.debug("Connecting to:", url);
552
573
  abortController = new AbortController();
574
+ const streamHeaders = {
575
+ Accept: "text/event-stream",
576
+ "Cache-Control": "no-cache"
577
+ };
578
+ if (token) streamHeaders["Authorization"] = `Bearer ${token}`;
553
579
  const response = await customFetch(url, {
554
580
  method: "GET",
555
- headers: {
556
- Accept: "text/event-stream",
557
- "Cache-Control": "no-cache"
558
- },
581
+ headers: streamHeaders,
559
582
  signal: abortController.signal
560
583
  });
561
584
  if (!response.ok) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../transport/index.ts","../../transport/types.ts","../../transport/sse.ts","../../transport/sse-fetch.ts","../../transport/whatsapp.ts"],"sourcesContent":["/**\n * Transport Layer\n *\n * Platform-agnostic transport abstractions for chat communication.\n *\n * @example Browser (SSE)\n * ```typescript\n * import { createSSETransport } from \"@elqnt/chat/transport\";\n *\n * const transport = createSSETransport({ debug: true });\n * await transport.connect({ baseUrl, orgId, userId, clientType: \"customer\" });\n *\n * transport.onMessage((event) => {\n * console.log(\"Received:\", event);\n * });\n * ```\n *\n * @example React Native (Fetch-based SSE)\n * ```typescript\n * import { createFetchSSETransport } from \"@elqnt/chat/transport\";\n *\n * const transport = createFetchSSETransport();\n * await transport.connect({ baseUrl, orgId, userId, clientType: \"customer\" });\n * ```\n *\n * @example Custom Transport\n * ```typescript\n * import type { ChatTransport } from \"@elqnt/chat/transport\";\n *\n * const customTransport: ChatTransport = {\n * connect: async (config) => { ... },\n * disconnect: () => { ... },\n * send: async (event) => { ... },\n * sendMessage: async (message) => { ... },\n * onMessage: (handler) => { ... },\n * on: (eventType, handler) => { ... },\n * getState: () => { ... },\n * getMetrics: () => { ... },\n * getError: () => { ... },\n * clearError: () => { ... },\n * };\n * ```\n */\n\n// Types\nexport type {\n ChatTransport,\n TransportConfig,\n TransportState,\n TransportError,\n TransportFactory,\n TransportLogger,\n ConnectionMetrics,\n EventHandler,\n Unsubscribe,\n RetryConfig,\n SendMessageOptions,\n CreateChatOptions,\n LoadChatOptions,\n EndChatOptions,\n} from \"./types\";\n\nexport {\n createLogger,\n calculateRetryInterval,\n DEFAULT_RETRY_CONFIG,\n} from \"./types\";\n\n// Browser SSE transport\nexport { createSSETransport } from \"./sse\";\nexport type { SSETransportOptions } from \"./sse\";\n\n// Fetch-based SSE transport (React Native)\nexport { createFetchSSETransport } from \"./sse-fetch\";\nexport type { FetchSSETransportOptions } from \"./sse-fetch\";\n\n// WhatsApp Business API transport (stub)\nexport {\n createWhatsAppTransport,\n mapWhatsAppToChatEvent,\n} from \"./whatsapp\";\nexport type {\n WhatsAppTransportConfig,\n WhatsAppTransportOptions,\n WhatsAppMessageType,\n WhatsAppWebhookPayload,\n} from \"./whatsapp\";\n","/**\n * Transport Abstraction Layer Types\n *\n * Platform-agnostic transport interfaces for chat communication.\n * Supports browser SSE, React Native fetch-based SSE, and extensible\n * transports like WhatsApp Business API.\n */\n\nimport type { Chat, ChatEvent, ChatMessage } from \"../models\";\n\n/**\n * Transport connection state\n */\nexport type TransportState =\n | \"disconnected\"\n | \"connecting\"\n | \"connected\"\n | \"reconnecting\";\n\n/**\n * Transport error with retry information\n */\nexport interface TransportError {\n code:\n | \"CONNECTION_FAILED\"\n | \"PARSE_ERROR\"\n | \"SEND_FAILED\"\n | \"TIMEOUT\"\n | \"NETWORK_ERROR\"\n | \"AUTH_FAILED\";\n message: string;\n retryable: boolean;\n timestamp: number;\n originalError?: unknown;\n}\n\n/**\n * Configuration for transport connection\n */\nexport interface TransportConfig {\n /** Base URL for the chat server */\n baseUrl: string;\n /** Organization ID */\n orgId: string;\n /** User ID for authentication */\n userId: string;\n /** Client type for routing */\n clientType: \"customer\" | \"humanAgent\" | \"observer\";\n /** Optional current chat key for reconnection */\n chatKey?: string;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Retry configuration for connection attempts\n */\nexport interface RetryConfig {\n /** Maximum number of retry attempts */\n maxRetries?: number;\n /** Initial retry intervals in milliseconds */\n intervals?: number[];\n /** Multiplier for exponential backoff */\n backoffMultiplier?: number;\n /** Maximum backoff time in milliseconds */\n maxBackoffTime?: number;\n}\n\n/**\n * Connection metrics for monitoring\n */\nexport interface ConnectionMetrics {\n /** Round-trip latency in milliseconds */\n latency: number;\n /** Total messages sent */\n messagesSent: number;\n /** Total messages received */\n messagesReceived: number;\n /** Messages waiting to be sent */\n messagesQueued: number;\n /** Number of reconnection attempts */\n reconnectCount: number;\n /** Last error encountered */\n lastError?: TransportError;\n /** Timestamp when connection was established */\n connectedAt?: number;\n /** Timestamp of last message */\n lastMessageAt?: number;\n /** Current transport type */\n transportType?: string;\n}\n\n/**\n * Event handler function type\n */\nexport type EventHandler<T = ChatEvent> = (event: T) => void;\n\n/**\n * Unsubscribe function returned by event subscription\n */\nexport type Unsubscribe = () => void;\n\n/**\n * Send message options\n */\nexport interface SendMessageOptions {\n /** Message content */\n content: string;\n /** Optional attachments */\n attachments?: unknown[];\n /** Optional message metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Create chat options\n */\nexport interface CreateChatOptions {\n /** Organization ID */\n orgId: string;\n /** User ID */\n userId: string;\n /** Optional chat metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Load chat options\n */\nexport interface LoadChatOptions {\n /** Organization ID */\n orgId: string;\n /** Chat key to load */\n chatKey: string;\n /** User ID */\n userId: string;\n}\n\n/**\n * End chat options\n */\nexport interface EndChatOptions {\n /** Organization ID */\n orgId: string;\n /** Chat key to end */\n chatKey: string;\n /** User ID */\n userId: string;\n /** Optional end reason */\n reason?: string;\n}\n\n/**\n * Response from creating a new chat\n */\nexport interface CreateChatResponse {\n /** The key of the created chat */\n chatKey: string;\n}\n\n/**\n * Response from loading a chat\n */\nexport interface LoadChatResponse {\n /** The loaded chat object */\n chat: Chat;\n /** Agent ID if applicable */\n agentId?: string;\n}\n\n/**\n * Core transport interface\n *\n * Implementations must handle:\n * - Connection lifecycle (connect, disconnect, reconnect)\n * - Message sending (POST requests)\n * - Event receiving (SSE stream)\n * - Error handling and recovery\n */\nexport interface ChatTransport {\n /**\n * Connect to the chat server\n * @param config - Transport configuration\n * @returns Promise that resolves when connected\n */\n connect(config: TransportConfig): Promise<void>;\n\n /**\n * Disconnect from the server\n * @param intentional - Whether disconnect was user-initiated\n */\n disconnect(intentional?: boolean): void;\n\n /**\n * Send a chat event to the server\n * @param event - Chat event to send\n */\n send(event: ChatEvent): Promise<void>;\n\n /**\n * Send a message in the current chat\n * @param message - Message to send\n */\n sendMessage(message: ChatMessage): Promise<void>;\n\n /**\n * Create a new chat and return the chat key directly\n * @param options - Create chat options\n * @returns Promise with the created chat key\n */\n createChat(options: CreateChatOptions): Promise<CreateChatResponse>;\n\n /**\n * Load an existing chat and return the chat data directly\n * @param options - Load chat options\n * @returns Promise with the loaded chat data\n */\n loadChatData(options: LoadChatOptions): Promise<LoadChatResponse>;\n\n /**\n * Subscribe to incoming events\n * @param handler - Event handler function\n * @returns Unsubscribe function\n */\n onMessage(handler: EventHandler): Unsubscribe;\n\n /**\n * Subscribe to specific event type\n * @param eventType - Type of event to listen for\n * @param handler - Event handler function\n * @returns Unsubscribe function\n */\n on(eventType: string, handler: EventHandler): Unsubscribe;\n\n /**\n * Get current connection state\n */\n getState(): TransportState;\n\n /**\n * Get connection metrics\n */\n getMetrics(): ConnectionMetrics;\n\n /**\n * Get last error\n */\n getError(): TransportError | undefined;\n\n /**\n * Clear error state\n */\n clearError(): void;\n}\n\n/**\n * Transport factory function type\n */\nexport type TransportFactory = (config?: Partial<TransportConfig>) => ChatTransport;\n\n/**\n * Logger interface for transport debugging\n */\nexport interface TransportLogger {\n debug: (message: string, ...args: unknown[]) => void;\n info: (message: string, ...args: unknown[]) => void;\n warn: (message: string, ...args: unknown[]) => void;\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Create a default logger\n * @param debug - Enable debug logging\n */\nexport function createLogger(debug: boolean = false): TransportLogger {\n return {\n debug: debug ? console.log.bind(console, \"[chat]\") : () => {},\n info: console.info.bind(console, \"[chat]\"),\n warn: console.warn.bind(console, \"[chat]\"),\n error: console.error.bind(console, \"[chat]\"),\n };\n}\n\n/**\n * Default retry configuration\n */\nexport const DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 10,\n intervals: [1000, 2000, 5000],\n backoffMultiplier: 1.5,\n maxBackoffTime: 30000,\n};\n\n/**\n * Calculate retry interval with exponential backoff\n * @param retryCount - Current retry attempt number\n * @param config - Retry configuration\n */\nexport function calculateRetryInterval(\n retryCount: number,\n config: RetryConfig = DEFAULT_RETRY_CONFIG\n): number {\n const {\n intervals = DEFAULT_RETRY_CONFIG.intervals,\n backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,\n maxBackoffTime = DEFAULT_RETRY_CONFIG.maxBackoffTime,\n } = config;\n\n if (retryCount < intervals.length) {\n return intervals[retryCount];\n }\n\n const baseInterval = intervals[intervals.length - 1] || 5000;\n const backoffTime =\n baseInterval * Math.pow(backoffMultiplier, retryCount - intervals.length + 1);\n return Math.min(backoffTime, maxBackoffTime);\n}\n","/**\n * SSE Transport (Browser)\n *\n * Uses native EventSource for receiving server events and fetch POST for sending.\n * This is the default transport for browser environments.\n *\n * @example\n * ```typescript\n * import { createSSETransport } from \"@elqnt/chat/transport\";\n *\n * const transport = createSSETransport();\n * await transport.connect({ baseUrl, orgId, userId, clientType: \"customer\" });\n * ```\n */\n\nimport type { Chat, ChatEvent, ChatMessage } from \"../models\";\nimport type {\n ChatTransport,\n TransportConfig,\n TransportState,\n TransportError,\n ConnectionMetrics,\n EventHandler,\n Unsubscribe,\n RetryConfig,\n TransportLogger,\n CreateChatOptions,\n CreateChatResponse,\n LoadChatOptions,\n LoadChatResponse,\n} from \"./types\";\nimport { createLogger, calculateRetryInterval, DEFAULT_RETRY_CONFIG } from \"./types\";\n\n/**\n * SSE Transport options\n */\nexport interface SSETransportOptions {\n /** Retry configuration */\n retryConfig?: RetryConfig;\n /** Enable debug logging */\n debug?: boolean;\n /** Custom logger */\n logger?: TransportLogger;\n}\n\n/**\n * Create an SSE transport for browser environments\n */\nexport function createSSETransport(options: SSETransportOptions = {}): ChatTransport {\n const {\n retryConfig = DEFAULT_RETRY_CONFIG,\n debug = false,\n logger = createLogger(debug),\n } = options;\n\n // Internal state\n let eventSource: EventSource | undefined;\n let config: TransportConfig | undefined;\n let state: TransportState = \"disconnected\";\n let error: TransportError | undefined;\n let retryCount = 0;\n let reconnectTimeout: ReturnType<typeof setTimeout> | undefined;\n let intentionalDisconnect = false;\n\n // Metrics\n const metrics: ConnectionMetrics = {\n latency: 0,\n messagesSent: 0,\n messagesReceived: 0,\n messagesQueued: 0,\n reconnectCount: 0,\n transportType: \"sse\",\n };\n\n // Event handlers\n const globalHandlers = new Set<EventHandler>();\n const typeHandlers = new Map<string, Set<EventHandler>>();\n\n // Helper to emit events\n function emit(event: ChatEvent): void {\n // Update metrics\n metrics.messagesReceived++;\n metrics.lastMessageAt = Date.now();\n\n // Call global handlers\n globalHandlers.forEach((handler) => {\n try {\n handler(event);\n } catch (err) {\n logger.error(\"Error in message handler:\", err);\n }\n });\n\n // Call type-specific handlers\n const handlers = typeHandlers.get(event.type);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(event);\n } catch (err) {\n logger.error(`Error in ${event.type} handler:`, err);\n }\n });\n }\n }\n\n // REST API helper\n async function sendRest(endpoint: string, body: Record<string, unknown>): Promise<unknown> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const url = `${config.baseUrl}/${endpoint}`;\n logger.debug(`POST ${endpoint}`, body);\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`API error: ${response.status} - ${errorText}`);\n }\n\n const json = await response.json() as { success?: boolean; data?: unknown };\n\n // Backend wraps responses in { success: true, data: {...} }\n // Unwrap to return just the data\n if (json && typeof json === \"object\" && \"data\" in json) {\n return json.data;\n }\n\n return json;\n }\n\n // Handle SSE message\n function handleMessage(event: MessageEvent): void {\n if (!event.data || event.data === \"\") return;\n\n try {\n const data = JSON.parse(event.data) as ChatEvent;\n logger.debug(\"Received:\", data.type);\n emit(data);\n } catch (err) {\n logger.error(\"Failed to parse SSE message:\", err);\n }\n }\n\n // Setup SSE event listeners\n function setupEventListeners(es: EventSource): void {\n // Generic message handler\n es.addEventListener(\"message\", handleMessage);\n\n // Add handlers for known event types.\n // Note \"error\": the server emits failed-turn notices as named `event:\n // error` SSE events. EventSource also fires a native data-less \"error\"\n // event on connection problems — handleMessage's empty-data guard\n // filters those out, so registering here is safe.\n // The server names EVERY SSE event (event: <type>), and EventSource\n // only fires listeners that were registered by name — any type missing\n // here is silently dropped. Keep this in sync with the server→client\n // types in ChatEventTypeTS; registering an unused name is harmless.\n const eventTypes = [\n \"error\",\n \"reconnected\", \"typing\", \"stopped_typing\", \"waiting\",\n \"waiting_for_agent\", \"human_agent_joined\", \"human_agent_left\",\n \"chat_ended\", \"chat_updated\", \"chat_removed\", \"load_chat_response\",\n \"new_chat_created\", \"show_csat_survey\", \"csat_response\",\n \"user_suggested_actions\", \"user_suggested_action_selected\",\n \"agent_execution_started\", \"agent_execution_ended\",\n \"agent_context_update\", \"load_agent_context_response\",\n \"plan_pending_approval\", \"plan_approved\", \"plan_rejected\",\n \"step_started\", \"step_completed\", \"step_failed\", \"plan_completed\",\n \"skills_changed\", \"summary_update\",\n \"message_status_update\", \"delivered\", \"read\",\n \"sync_metadata_response\", \"sync_user_session_response\",\n \"client_action\", \"client_action_callback\",\n \"attachment_processing_started\", \"attachment_processing_progress\",\n \"attachment_processing_complete\", \"attachment_processing_error\",\n \"observer_joined\", \"observer_left\", \"block_user\",\n \"message_edited\", \"message_deleted\", \"message_reaction\",\n \"user_presence_changed\", \"online_users\", \"get_agents_response\",\n \"room_created\", \"room_updated\", \"room_deleted\", \"rooms_response\",\n \"room_user_joined\", \"room_user_left\", \"user_invited\",\n ];\n\n eventTypes.forEach((type) => {\n es.addEventListener(type, handleMessage);\n });\n }\n\n // Schedule reconnect\n function scheduleReconnect(): void {\n if (intentionalDisconnect || !config) return;\n\n const maxRetries = retryConfig.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries;\n if (retryCount >= maxRetries) {\n logger.error(`Max retries (${maxRetries}) exceeded`);\n error = {\n code: \"CONNECTION_FAILED\",\n message: `Max retries (${maxRetries}) exceeded`,\n retryable: false,\n timestamp: Date.now(),\n };\n return;\n }\n\n const interval = calculateRetryInterval(retryCount, retryConfig);\n retryCount++;\n metrics.reconnectCount++;\n\n logger.info(`Reconnecting in ${interval}ms (attempt ${retryCount})`);\n state = \"reconnecting\";\n\n reconnectTimeout = setTimeout(() => {\n if (config) {\n transport.connect(config).catch((err) => {\n logger.error(\"Reconnect failed:\", err);\n });\n }\n }, interval);\n }\n\n const transport: ChatTransport = {\n async connect(cfg: TransportConfig): Promise<void> {\n config = cfg;\n intentionalDisconnect = false;\n\n // Clean up existing connection\n if (eventSource) {\n eventSource.close();\n eventSource = undefined;\n }\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout);\n reconnectTimeout = undefined;\n }\n\n state = retryCount > 0 ? \"reconnecting\" : \"connecting\";\n\n return new Promise((resolve, reject) => {\n const connectionStart = Date.now();\n // URLSearchParams encodes reserved characters — a raw \"+\" in a\n // userId email decodes server-side to a space, silently breaking\n // targeted delivery (connection registered under the wrong user).\n const streamParams = new URLSearchParams({\n orgId: cfg.orgId,\n userId: cfg.userId,\n clientType: cfg.clientType,\n });\n if (cfg.chatKey) streamParams.set(\"chatId\", cfg.chatKey);\n const url = `${cfg.baseUrl}/stream?${streamParams.toString()}`;\n\n logger.debug(\"Connecting to:\", url);\n const es = new EventSource(url);\n\n es.onopen = () => {\n const connectionTime = Date.now() - connectionStart;\n logger.info(`Connected in ${connectionTime}ms`);\n\n const wasReconnect = retryCount > 0;\n state = \"connected\";\n error = undefined;\n retryCount = 0;\n metrics.connectedAt = Date.now();\n metrics.latency = connectionTime;\n\n setupEventListeners(es);\n\n // Synthetic event so the app layer can re-sync chat state —\n // broadcasts emitted while the stream was down are gone for good.\n if (wasReconnect) {\n emit({\n type: \"transport_reconnected\",\n orgId: cfg.orgId,\n chatKey: cfg.chatKey || \"\",\n userId: cfg.userId,\n timestamp: Date.now(),\n } as ChatEvent);\n }\n\n resolve();\n };\n\n es.onerror = () => {\n if (es.readyState === EventSource.CLOSED) {\n const sseError: TransportError = {\n code: \"CONNECTION_FAILED\",\n message: \"SSE connection failed\",\n retryable: true,\n timestamp: Date.now(),\n };\n error = sseError;\n metrics.lastError = sseError;\n state = \"disconnected\";\n\n if (!intentionalDisconnect) {\n scheduleReconnect();\n }\n\n // Only reject if this is the initial connection attempt\n if (retryCount === 0) {\n reject(sseError);\n }\n }\n };\n\n eventSource = es;\n });\n },\n\n disconnect(intentional = true): void {\n logger.info(\"Disconnecting\", { intentional });\n intentionalDisconnect = intentional;\n\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout);\n reconnectTimeout = undefined;\n }\n\n if (eventSource) {\n eventSource.close();\n eventSource = undefined;\n }\n\n state = \"disconnected\";\n retryCount = 0;\n },\n\n async send(event: ChatEvent): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n // Map event types to REST endpoints\n switch (event.type) {\n case \"message\":\n await sendRest(\"send\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n message: event.message,\n ...(event.data ? { data: event.data } : {}),\n });\n break;\n\n case \"typing\":\n await sendRest(\"typing\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n typing: true,\n });\n break;\n\n case \"stopped_typing\":\n await sendRest(\"typing\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n typing: false,\n });\n break;\n\n case \"load_chat\":\n // Deprecated: Use loadChatData() instead for direct response\n await sendRest(\"load\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n });\n break;\n\n case \"new_chat\":\n // Deprecated: Use createChat() instead for direct response\n await sendRest(\"create\", {\n orgId: event.orgId,\n userId: event.userId,\n metadata: event.data,\n });\n break;\n\n case \"end_chat\":\n await sendRest(\"end\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n data: event.data,\n });\n break;\n\n default:\n // Generic event endpoint for other types\n await sendRest(\"event\", {\n type: event.type,\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n data: event.data,\n });\n }\n\n metrics.messagesSent++;\n },\n\n async sendMessage(message: ChatMessage): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n await sendRest(\"send\", {\n orgId: config.orgId,\n chatKey: config.chatKey,\n userId: config.userId,\n message,\n });\n\n metrics.messagesSent++;\n },\n\n async createChat(options: CreateChatOptions): Promise<CreateChatResponse> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const response = await sendRest(\"create\", {\n orgId: options.orgId,\n userId: options.userId,\n metadata: options.metadata,\n }) as { chatKey?: string };\n\n if (!response?.chatKey) {\n throw new Error(\"Failed to create chat: no chatKey returned\");\n }\n\n return { chatKey: response.chatKey };\n },\n\n async loadChatData(options: LoadChatOptions): Promise<LoadChatResponse> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const response = await sendRest(\"load\", {\n orgId: options.orgId,\n chatKey: options.chatKey,\n userId: options.userId,\n }) as { chat?: unknown; agentId?: string };\n\n if (!response?.chat) {\n throw new Error(\"Failed to load chat: no chat data returned\");\n }\n\n return {\n chat: response.chat as Chat,\n agentId: response.agentId,\n };\n },\n\n onMessage(handler: EventHandler): Unsubscribe {\n globalHandlers.add(handler);\n return () => globalHandlers.delete(handler);\n },\n\n on(eventType: string, handler: EventHandler): Unsubscribe {\n if (!typeHandlers.has(eventType)) {\n typeHandlers.set(eventType, new Set());\n }\n typeHandlers.get(eventType)!.add(handler);\n return () => {\n const handlers = typeHandlers.get(eventType);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n typeHandlers.delete(eventType);\n }\n }\n };\n },\n\n getState(): TransportState {\n return state;\n },\n\n getMetrics(): ConnectionMetrics {\n return { ...metrics };\n },\n\n getError(): TransportError | undefined {\n return error;\n },\n\n clearError(): void {\n error = undefined;\n },\n };\n\n return transport;\n}\n","/**\n * SSE Transport (Fetch-based)\n *\n * Uses fetch with ReadableStream for receiving server events and fetch POST for sending.\n * Designed for React Native and environments without native EventSource support.\n *\n * @example\n * ```typescript\n * import { createFetchSSETransport } from \"@elqnt/chat/transport\";\n *\n * const transport = createFetchSSETransport();\n * await transport.connect({ baseUrl, orgId, userId, clientType: \"customer\" });\n * ```\n */\n\nimport type { Chat, ChatEvent, ChatMessage } from \"../models\";\nimport type {\n ChatTransport,\n TransportConfig,\n TransportState,\n TransportError,\n ConnectionMetrics,\n EventHandler,\n Unsubscribe,\n RetryConfig,\n TransportLogger,\n CreateChatOptions,\n CreateChatResponse,\n LoadChatOptions,\n LoadChatResponse,\n} from \"./types\";\nimport { createLogger, calculateRetryInterval, DEFAULT_RETRY_CONFIG } from \"./types\";\n\n/**\n * Fetch SSE Transport options\n */\nexport interface FetchSSETransportOptions {\n /** Retry configuration */\n retryConfig?: RetryConfig;\n /** Enable debug logging */\n debug?: boolean;\n /** Custom logger */\n logger?: TransportLogger;\n /** Custom fetch implementation (useful for React Native) */\n customFetch?: typeof fetch;\n}\n\n/**\n * Create a fetch-based SSE transport for React Native and polyfill environments\n */\nexport function createFetchSSETransport(options: FetchSSETransportOptions = {}): ChatTransport {\n const {\n retryConfig = DEFAULT_RETRY_CONFIG,\n debug = false,\n logger = createLogger(debug),\n customFetch = fetch,\n } = options;\n\n // Internal state\n let abortController: AbortController | undefined;\n let config: TransportConfig | undefined;\n let state: TransportState = \"disconnected\";\n let error: TransportError | undefined;\n let retryCount = 0;\n let reconnectTimeout: ReturnType<typeof setTimeout> | undefined;\n let intentionalDisconnect = false;\n\n // Metrics\n const metrics: ConnectionMetrics = {\n latency: 0,\n messagesSent: 0,\n messagesReceived: 0,\n messagesQueued: 0,\n reconnectCount: 0,\n transportType: \"sse-fetch\",\n };\n\n // Event handlers\n const globalHandlers = new Set<EventHandler>();\n const typeHandlers = new Map<string, Set<EventHandler>>();\n\n // Helper to emit events\n function emit(event: ChatEvent): void {\n metrics.messagesReceived++;\n metrics.lastMessageAt = Date.now();\n\n globalHandlers.forEach((handler) => {\n try {\n handler(event);\n } catch (err) {\n logger.error(\"Error in message handler:\", err);\n }\n });\n\n const handlers = typeHandlers.get(event.type);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(event);\n } catch (err) {\n logger.error(`Error in ${event.type} handler:`, err);\n }\n });\n }\n }\n\n // REST API helper\n async function sendRest(endpoint: string, body: Record<string, unknown>): Promise<unknown> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const url = `${config.baseUrl}/${endpoint}`;\n logger.debug(`POST ${endpoint}`, body);\n\n const response = await customFetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`API error: ${response.status} - ${errorText}`);\n }\n\n const json = await response.json() as { success?: boolean; data?: unknown };\n\n // Backend wraps responses in { success: true, data: {...} }\n // Unwrap to return just the data\n if (json && typeof json === \"object\" && \"data\" in json) {\n return json.data;\n }\n\n return json;\n }\n\n // Parse SSE data from a text chunk\n function parseSSEChunk(chunk: string): ChatEvent[] {\n const events: ChatEvent[] = [];\n const lines = chunk.split(\"\\n\");\n\n let eventType = \"message\";\n let data = \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n data = line.slice(5).trim();\n } else if (line === \"\" && data) {\n // End of event\n try {\n const parsed = JSON.parse(data) as ChatEvent;\n events.push(parsed);\n } catch {\n logger.warn(\"Failed to parse SSE data:\", data);\n }\n eventType = \"message\";\n data = \"\";\n }\n }\n\n return events;\n }\n\n // Start SSE stream using fetch\n async function startStream(cfg: TransportConfig): Promise<void> {\n // URLSearchParams encodes reserved characters — a raw \"+\" in a userId\n // email decodes server-side to a space, silently breaking targeted\n // delivery (connection registered under the wrong user).\n const streamParams = new URLSearchParams({\n orgId: cfg.orgId,\n userId: cfg.userId,\n clientType: cfg.clientType,\n });\n if (cfg.chatKey) streamParams.set(\"chatId\", cfg.chatKey);\n const url = `${cfg.baseUrl}/stream?${streamParams.toString()}`;\n\n logger.debug(\"Connecting to:\", url);\n\n abortController = new AbortController();\n\n const response = await customFetch(url, {\n method: \"GET\",\n headers: {\n Accept: \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n },\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Stream connection failed: ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error(\"Response body is null - ReadableStream not supported\");\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n // Read stream in background\n const readStream = async () => {\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n logger.info(\"Stream ended\");\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete events in buffer\n const lastNewline = buffer.lastIndexOf(\"\\n\\n\");\n if (lastNewline !== -1) {\n const complete = buffer.slice(0, lastNewline + 2);\n buffer = buffer.slice(lastNewline + 2);\n\n const events = parseSSEChunk(complete);\n events.forEach(emit);\n }\n }\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n logger.debug(\"Stream aborted\");\n return;\n }\n logger.error(\"Stream error:\", err);\n throw err;\n }\n\n // Stream closed - handle reconnection\n if (!intentionalDisconnect) {\n state = \"disconnected\";\n scheduleReconnect();\n }\n };\n\n // Start reading in background\n readStream().catch((err) => {\n if (!intentionalDisconnect) {\n error = {\n code: \"CONNECTION_FAILED\",\n message: err.message,\n retryable: true,\n timestamp: Date.now(),\n originalError: err,\n };\n metrics.lastError = error;\n state = \"disconnected\";\n scheduleReconnect();\n }\n });\n }\n\n // Schedule reconnect\n function scheduleReconnect(): void {\n if (intentionalDisconnect || !config) return;\n\n const maxRetries = retryConfig.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries;\n if (retryCount >= maxRetries) {\n logger.error(`Max retries (${maxRetries}) exceeded`);\n error = {\n code: \"CONNECTION_FAILED\",\n message: `Max retries (${maxRetries}) exceeded`,\n retryable: false,\n timestamp: Date.now(),\n };\n return;\n }\n\n const interval = calculateRetryInterval(retryCount, retryConfig);\n retryCount++;\n metrics.reconnectCount++;\n\n logger.info(`Reconnecting in ${interval}ms (attempt ${retryCount})`);\n state = \"reconnecting\";\n\n reconnectTimeout = setTimeout(() => {\n if (config) {\n transport.connect(config).catch((err) => {\n logger.error(\"Reconnect failed:\", err);\n });\n }\n }, interval);\n }\n\n const transport: ChatTransport = {\n async connect(cfg: TransportConfig): Promise<void> {\n config = cfg;\n intentionalDisconnect = false;\n\n // Clean up existing connection\n if (abortController) {\n abortController.abort();\n abortController = undefined;\n }\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout);\n reconnectTimeout = undefined;\n }\n\n state = retryCount > 0 ? \"reconnecting\" : \"connecting\";\n const connectionStart = Date.now();\n\n try {\n const wasReconnect = retryCount > 0;\n await startStream(cfg);\n\n const connectionTime = Date.now() - connectionStart;\n logger.info(`Connected in ${connectionTime}ms`);\n\n state = \"connected\";\n error = undefined;\n retryCount = 0;\n metrics.connectedAt = Date.now();\n metrics.latency = connectionTime;\n\n // Synthetic event so the app layer can re-sync chat state —\n // broadcasts emitted while the stream was down are gone for good.\n if (wasReconnect) {\n emit({\n type: \"transport_reconnected\",\n orgId: cfg.orgId,\n chatKey: cfg.chatKey || \"\",\n userId: cfg.userId,\n timestamp: Date.now(),\n } as ChatEvent);\n }\n } catch (err) {\n const connectError: TransportError = {\n code: \"CONNECTION_FAILED\",\n message: (err as Error).message,\n retryable: true,\n timestamp: Date.now(),\n originalError: err,\n };\n error = connectError;\n metrics.lastError = connectError;\n state = \"disconnected\";\n\n if (!intentionalDisconnect) {\n scheduleReconnect();\n }\n\n throw connectError;\n }\n },\n\n disconnect(intentional = true): void {\n logger.info(\"Disconnecting\", { intentional });\n intentionalDisconnect = intentional;\n\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout);\n reconnectTimeout = undefined;\n }\n\n if (abortController) {\n abortController.abort();\n abortController = undefined;\n }\n\n state = \"disconnected\";\n retryCount = 0;\n },\n\n async send(event: ChatEvent): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n switch (event.type) {\n case \"message\":\n await sendRest(\"send\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n message: event.message,\n ...(event.data ? { data: event.data } : {}),\n });\n break;\n\n case \"typing\":\n await sendRest(\"typing\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n typing: true,\n });\n break;\n\n case \"stopped_typing\":\n await sendRest(\"typing\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n typing: false,\n });\n break;\n\n case \"load_chat\":\n await sendRest(\"load\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n });\n break;\n\n case \"new_chat\":\n await sendRest(\"create\", {\n orgId: event.orgId,\n userId: event.userId,\n metadata: event.data,\n });\n break;\n\n case \"end_chat\":\n await sendRest(\"end\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n data: event.data,\n });\n break;\n\n default:\n await sendRest(\"event\", {\n type: event.type,\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n data: event.data,\n });\n }\n\n metrics.messagesSent++;\n },\n\n async sendMessage(message: ChatMessage): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n await sendRest(\"send\", {\n orgId: config.orgId,\n chatKey: config.chatKey,\n userId: config.userId,\n message,\n });\n\n metrics.messagesSent++;\n },\n\n async createChat(options: CreateChatOptions): Promise<CreateChatResponse> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const response = await sendRest(\"create\", {\n orgId: options.orgId,\n userId: options.userId,\n metadata: options.metadata,\n }) as { chatKey?: string };\n\n if (!response?.chatKey) {\n throw new Error(\"Failed to create chat: no chatKey returned\");\n }\n\n return { chatKey: response.chatKey };\n },\n\n async loadChatData(options: LoadChatOptions): Promise<LoadChatResponse> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const response = await sendRest(\"load\", {\n orgId: options.orgId,\n chatKey: options.chatKey,\n userId: options.userId,\n }) as { chat?: unknown; agentId?: string };\n\n if (!response?.chat) {\n throw new Error(\"Failed to load chat: no chat data returned\");\n }\n\n return {\n chat: response.chat as Chat,\n agentId: response.agentId,\n };\n },\n\n onMessage(handler: EventHandler): Unsubscribe {\n globalHandlers.add(handler);\n return () => globalHandlers.delete(handler);\n },\n\n on(eventType: string, handler: EventHandler): Unsubscribe {\n if (!typeHandlers.has(eventType)) {\n typeHandlers.set(eventType, new Set());\n }\n typeHandlers.get(eventType)!.add(handler);\n return () => {\n const handlers = typeHandlers.get(eventType);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n typeHandlers.delete(eventType);\n }\n }\n };\n },\n\n getState(): TransportState {\n return state;\n },\n\n getMetrics(): ConnectionMetrics {\n return { ...metrics };\n },\n\n getError(): TransportError | undefined {\n return error;\n },\n\n clearError(): void {\n error = undefined;\n },\n };\n\n return transport;\n}\n","/**\n * WhatsApp Business API Transport (Stub)\n *\n * This module provides the interface for integrating with WhatsApp Business API.\n * The implementation connects to a webhook receiver that bridges WhatsApp messages\n * to the chat system.\n *\n * ## Integration Architecture\n *\n * ```\n * WhatsApp User → WhatsApp Cloud API → Your Webhook → Chat Service → SSE to Admin\n * ↓\n * NATS Events\n * ```\n *\n * ## Setup Requirements\n *\n * 1. Register a WhatsApp Business Account\n * 2. Create a Meta Business App with WhatsApp integration\n * 3. Configure webhook URL pointing to your chat service\n * 4. Set up message templates for outbound messages\n *\n * ## Backend Integration\n *\n * Your backend should expose webhook endpoints that:\n * - Verify webhook (GET /webhook with hub.verify_token)\n * - Receive messages (POST /webhook with message payload)\n * - Map WhatsApp user IDs to chat users\n * - Create/load chats for new conversations\n *\n * @example Backend Webhook Handler (Go)\n * ```go\n * func HandleWhatsAppWebhook(w http.ResponseWriter, r *http.Request) {\n * if r.Method == \"GET\" {\n * // Webhook verification\n * verifyToken := r.URL.Query().Get(\"hub.verify_token\")\n * if verifyToken == os.Getenv(\"WHATSAPP_VERIFY_TOKEN\") {\n * w.Write([]byte(r.URL.Query().Get(\"hub.challenge\")))\n * return\n * }\n * http.Error(w, \"Invalid verify token\", 403)\n * return\n * }\n *\n * // Handle incoming message\n * var payload WhatsAppPayload\n * json.NewDecoder(r.Body).Decode(&payload)\n *\n * // Map to chat event and publish to NATS\n * chatEvent := mapWhatsAppToChatEvent(payload)\n * natsClient.Publish(\"chat.events\", chatEvent)\n * }\n * ```\n *\n * @see https://developers.facebook.com/docs/whatsapp/cloud-api\n */\n\nimport type {\n ChatTransport,\n TransportConfig,\n TransportState,\n TransportError,\n ConnectionMetrics,\n EventHandler,\n Unsubscribe,\n TransportLogger,\n CreateChatOptions,\n CreateChatResponse,\n LoadChatOptions,\n LoadChatResponse,\n} from \"./types\";\nimport type { Chat, ChatEvent, ChatMessage, Attachment, AttachmentTypeTS } from \"../models\";\nimport { createLogger } from \"./types\";\n\n/**\n * WhatsApp transport configuration\n */\nexport interface WhatsAppTransportConfig extends TransportConfig {\n /** WhatsApp Business API access token */\n accessToken: string;\n /** Phone number ID from Meta Business */\n phoneNumberId: string;\n /** Webhook verify token for setup */\n verifyToken?: string;\n}\n\n/**\n * WhatsApp transport options\n */\nexport interface WhatsAppTransportOptions {\n /** Enable debug logging */\n debug?: boolean;\n /** Custom logger */\n logger?: TransportLogger;\n}\n\n/**\n * WhatsApp message types\n */\nexport type WhatsAppMessageType =\n | \"text\"\n | \"image\"\n | \"document\"\n | \"audio\"\n | \"video\"\n | \"sticker\"\n | \"location\"\n | \"contacts\"\n | \"interactive\"\n | \"template\";\n\n/**\n * Create a WhatsApp Business API transport\n *\n * NOTE: This is a stub implementation. The actual WhatsApp integration\n * happens on the backend via webhooks. This transport is for:\n * - Type definitions\n * - Documentation\n * - Future client-side WhatsApp Web integration\n */\nexport function createWhatsAppTransport(\n options: WhatsAppTransportOptions = {}\n): ChatTransport {\n const { debug = false, logger = createLogger(debug) } = options;\n\n let state: TransportState = \"disconnected\";\n let error: TransportError | undefined;\n let config: WhatsAppTransportConfig | undefined;\n\n const metrics: ConnectionMetrics = {\n latency: 0,\n messagesSent: 0,\n messagesReceived: 0,\n messagesQueued: 0,\n reconnectCount: 0,\n transportType: \"whatsapp\",\n };\n\n const globalHandlers = new Set<EventHandler>();\n const typeHandlers = new Map<string, Set<EventHandler>>();\n\n const transport: ChatTransport = {\n async connect(cfg: TransportConfig): Promise<void> {\n logger.warn(\n \"WhatsApp transport is a stub. WhatsApp integration happens via backend webhooks.\"\n );\n logger.info(\n \"See transport/whatsapp.ts for integration documentation.\"\n );\n\n config = cfg as WhatsAppTransportConfig;\n\n // In a real implementation, this would:\n // 1. Validate WhatsApp Business API credentials\n // 2. Register webhook endpoints\n // 3. Set up SSE connection to receive webhook-relayed events\n\n state = \"connected\";\n metrics.connectedAt = Date.now();\n },\n\n disconnect(): void {\n state = \"disconnected\";\n },\n\n async send(event: ChatEvent): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n logger.warn(\"WhatsApp send is a stub. Implement backend webhook relay.\");\n\n // In a real implementation, this would:\n // 1. Convert ChatEvent to WhatsApp message format\n // 2. Call WhatsApp Cloud API to send message\n // 3. Handle delivery receipts\n\n metrics.messagesSent++;\n },\n\n async sendMessage(message: ChatMessage): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n logger.warn(\n \"WhatsApp sendMessage is a stub. Implement backend webhook relay.\"\n );\n\n // In a real implementation:\n // POST https://graph.facebook.com/v17.0/{phone_number_id}/messages\n // {\n // \"messaging_product\": \"whatsapp\",\n // \"to\": \"{recipient_phone}\",\n // \"type\": \"text\",\n // \"text\": { \"body\": message.content }\n // }\n\n metrics.messagesSent++;\n },\n\n async createChat(options: CreateChatOptions): Promise<CreateChatResponse> {\n logger.warn(\n \"WhatsApp createChat is a stub. WhatsApp chats are created via incoming webhooks.\"\n );\n\n // In WhatsApp, chats are typically initiated by users messaging first.\n // This stub returns a placeholder - real implementation would create\n // a chat record on the backend for outbound messaging.\n return { chatKey: `whatsapp_${options.userId}_${Date.now()}` };\n },\n\n async loadChatData(options: LoadChatOptions): Promise<LoadChatResponse> {\n logger.warn(\n \"WhatsApp loadChatData is a stub. Implement backend API call.\"\n );\n\n // In a real implementation, this would fetch chat data from the backend\n return {\n chat: {\n orgId: options.orgId,\n key: options.chatKey,\n title: \"WhatsApp Chat\",\n messages: [],\n lastUpdated: Date.now(),\n startTime: Date.now(),\n users: [],\n status: \"active\",\n aiEngaged: false,\n humanAgentEngaged: false,\n isWaiting: false,\n isWaitingForAgent: false,\n } as Chat,\n };\n },\n\n onMessage(handler: EventHandler): Unsubscribe {\n globalHandlers.add(handler);\n return () => globalHandlers.delete(handler);\n },\n\n on(eventType: string, handler: EventHandler): Unsubscribe {\n if (!typeHandlers.has(eventType)) {\n typeHandlers.set(eventType, new Set());\n }\n typeHandlers.get(eventType)!.add(handler);\n return () => {\n const handlers = typeHandlers.get(eventType);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n typeHandlers.delete(eventType);\n }\n }\n };\n },\n\n getState(): TransportState {\n return state;\n },\n\n getMetrics(): ConnectionMetrics {\n return { ...metrics };\n },\n\n getError(): TransportError | undefined {\n return error;\n },\n\n clearError(): void {\n error = undefined;\n },\n };\n\n return transport;\n}\n\n/**\n * Helper: Convert WhatsApp webhook payload to ChatEvent\n *\n * Use this in your backend webhook handler to map incoming\n * WhatsApp messages to the chat system format.\n */\nexport interface WhatsAppWebhookPayload {\n object: \"whatsapp_business_account\";\n entry: Array<{\n id: string;\n changes: Array<{\n value: {\n messaging_product: \"whatsapp\";\n metadata: {\n display_phone_number: string;\n phone_number_id: string;\n };\n contacts?: Array<{\n profile: { name: string };\n wa_id: string;\n }>;\n messages?: Array<{\n from: string;\n id: string;\n timestamp: string;\n type: WhatsAppMessageType;\n text?: { body: string };\n image?: { id: string; mime_type: string; sha256: string };\n document?: { id: string; mime_type: string; filename: string };\n audio?: { id: string; mime_type: string };\n video?: { id: string; mime_type: string };\n location?: { latitude: number; longitude: number; name?: string };\n }>;\n statuses?: Array<{\n id: string;\n status: \"sent\" | \"delivered\" | \"read\" | \"failed\";\n timestamp: string;\n recipient_id: string;\n }>;\n };\n }>;\n }>;\n}\n\n/**\n * Example: Map WhatsApp payload to ChatEvent (for backend use)\n *\n * @example\n * ```typescript\n * // In your backend webhook handler\n * import { mapWhatsAppToChatEvent } from \"@elqnt/chat/transport\";\n *\n * app.post(\"/webhook/whatsapp\", (req, res) => {\n * const events = mapWhatsAppToChatEvent(req.body, orgId);\n * events.forEach(event => publishToChatService(event));\n * res.sendStatus(200);\n * });\n * ```\n */\nexport function mapWhatsAppToChatEvent(\n payload: WhatsAppWebhookPayload,\n orgId: string\n): ChatEvent[] {\n const events: ChatEvent[] = [];\n\n for (const entry of payload.entry) {\n for (const change of entry.changes) {\n const value = change.value;\n\n // Handle incoming messages\n if (value.messages) {\n for (const msg of value.messages) {\n const contact = value.contacts?.find((c) => c.wa_id === msg.from);\n\n events.push({\n type: \"message\",\n orgId,\n chatKey: `wa_${msg.from}`, // Use phone number as chat key\n userId: msg.from,\n timestamp: parseInt(msg.timestamp) * 1000,\n message: {\n id: msg.id,\n role: \"user\",\n content: msg.text?.body || \"\",\n time: parseInt(msg.timestamp) * 1000,\n status: \"delivered\",\n senderId: msg.from,\n senderName: contact?.profile.name,\n createdAt: parseInt(msg.timestamp) * 1000,\n // Map attachments if present\n attachments: mapWhatsAppAttachments(msg),\n },\n });\n }\n }\n\n // Handle message status updates\n if (value.statuses) {\n for (const status of value.statuses) {\n events.push({\n type: \"message_status_update\",\n orgId,\n chatKey: `wa_${status.recipient_id}`,\n userId: status.recipient_id,\n timestamp: parseInt(status.timestamp) * 1000,\n data: {\n messageId: status.id,\n status: status.status,\n },\n });\n }\n }\n }\n }\n\n return events;\n}\n\n// Helper to map WhatsApp attachments\nfunction mapWhatsAppAttachments(msg: {\n type: WhatsAppMessageType;\n image?: { id: string };\n document?: { id: string; filename: string };\n audio?: { id: string };\n video?: { id: string };\n location?: { latitude: number; longitude: number; name?: string };\n}): Attachment[] | undefined {\n switch (msg.type) {\n case \"image\":\n return msg.image\n ? [{ type: \"image\" as AttachmentTypeTS, url: `whatsapp://media/${msg.image.id}` }]\n : undefined;\n case \"document\":\n return msg.document\n ? [\n {\n type: \"document\" as AttachmentTypeTS,\n url: `whatsapp://media/${msg.document.id}`,\n },\n ]\n : undefined;\n case \"audio\":\n return msg.audio\n ? [{ type: \"audio\" as AttachmentTypeTS, url: `whatsapp://media/${msg.audio.id}` }]\n : undefined;\n case \"video\":\n return msg.video\n ? [{ type: \"video\" as AttachmentTypeTS, url: `whatsapp://media/${msg.video.id}` }]\n : undefined;\n case \"location\":\n return msg.location\n ? [\n {\n type: \"location\" as AttachmentTypeTS,\n url: `geo:${msg.location.latitude},${msg.location.longitude}`,\n },\n ]\n : undefined;\n default:\n return undefined;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACkRO,SAAS,aAAa,QAAiB,OAAwB;AACpE,SAAO;AAAA,IACL,OAAO,QAAQ,QAAQ,IAAI,KAAK,SAAS,QAAQ,IAAI,MAAM;AAAA,IAAC;AAAA,IAC5D,MAAM,QAAQ,KAAK,KAAK,SAAS,QAAQ;AAAA,IACzC,MAAM,QAAQ,KAAK,KAAK,SAAS,QAAQ;AAAA,IACzC,OAAO,QAAQ,MAAM,KAAK,SAAS,QAAQ;AAAA,EAC7C;AACF;AAKO,IAAM,uBAA8C;AAAA,EACzD,YAAY;AAAA,EACZ,WAAW,CAAC,KAAM,KAAM,GAAI;AAAA,EAC5B,mBAAmB;AAAA,EACnB,gBAAgB;AAClB;AAOO,SAAS,uBACd,YACA,SAAsB,sBACd;AACR,QAAM;AAAA,IACJ,YAAY,qBAAqB;AAAA,IACjC,oBAAoB,qBAAqB;AAAA,IACzC,iBAAiB,qBAAqB;AAAA,EACxC,IAAI;AAEJ,MAAI,aAAa,UAAU,QAAQ;AACjC,WAAO,UAAU,UAAU;AAAA,EAC7B;AAEA,QAAM,eAAe,UAAU,UAAU,SAAS,CAAC,KAAK;AACxD,QAAM,cACJ,eAAe,KAAK,IAAI,mBAAmB,aAAa,UAAU,SAAS,CAAC;AAC9E,SAAO,KAAK,IAAI,aAAa,cAAc;AAC7C;;;AC5QO,SAAS,mBAAmB,UAA+B,CAAC,GAAkB;AACnF,QAAM;AAAA,IACJ,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,SAAS,aAAa,KAAK;AAAA,EAC7B,IAAI;AAGJ,MAAI;AACJ,MAAI;AACJ,MAAI,QAAwB;AAC5B,MAAI;AACJ,MAAI,aAAa;AACjB,MAAI;AACJ,MAAI,wBAAwB;AAG5B,QAAM,UAA6B;AAAA,IACjC,SAAS;AAAA,IACT,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,eAAe;AAAA,EACjB;AAGA,QAAM,iBAAiB,oBAAI,IAAkB;AAC7C,QAAM,eAAe,oBAAI,IAA+B;AAGxD,WAAS,KAAK,OAAwB;AAEpC,YAAQ;AACR,YAAQ,gBAAgB,KAAK,IAAI;AAGjC,mBAAe,QAAQ,CAAC,YAAY;AAClC,UAAI;AACF,gBAAQ,KAAK;AAAA,MACf,SAAS,KAAK;AACZ,eAAO,MAAM,6BAA6B,GAAG;AAAA,MAC/C;AAAA,IACF,CAAC;AAGD,UAAM,WAAW,aAAa,IAAI,MAAM,IAAI;AAC5C,QAAI,UAAU;AACZ,eAAS,QAAQ,CAAC,YAAY;AAC5B,YAAI;AACF,kBAAQ,KAAK;AAAA,QACf,SAAS,KAAK;AACZ,iBAAO,MAAM,YAAY,MAAM,IAAI,aAAa,GAAG;AAAA,QACrD;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAGA,iBAAe,SAAS,UAAkB,MAAiD;AACzF,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,UAAM,MAAM,GAAG,OAAO,OAAO,IAAI,QAAQ;AACzC,WAAO,MAAM,QAAQ,QAAQ,IAAI,IAAI;AAErC,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,YAAY,MAAM,SAAS,KAAK;AACtC,YAAM,IAAI,MAAM,cAAc,SAAS,MAAM,MAAM,SAAS,EAAE;AAAA,IAChE;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AAIjC,QAAI,QAAQ,OAAO,SAAS,YAAY,UAAU,MAAM;AACtD,aAAO,KAAK;AAAA,IACd;AAEA,WAAO;AAAA,EACT;AAGA,WAAS,cAAc,OAA2B;AAChD,QAAI,CAAC,MAAM,QAAQ,MAAM,SAAS,GAAI;AAEtC,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,MAAM,IAAI;AAClC,aAAO,MAAM,aAAa,KAAK,IAAI;AACnC,WAAK,IAAI;AAAA,IACX,SAAS,KAAK;AACZ,aAAO,MAAM,gCAAgC,GAAG;AAAA,IAClD;AAAA,EACF;AAGA,WAAS,oBAAoB,IAAuB;AAElD,OAAG,iBAAiB,WAAW,aAAa;AAW5C,UAAM,aAAa;AAAA,MACjB;AAAA,MACA;AAAA,MAAe;AAAA,MAAU;AAAA,MAAkB;AAAA,MAC3C;AAAA,MAAqB;AAAA,MAAsB;AAAA,MAC3C;AAAA,MAAc;AAAA,MAAgB;AAAA,MAAgB;AAAA,MAC9C;AAAA,MAAoB;AAAA,MAAoB;AAAA,MACxC;AAAA,MAA0B;AAAA,MAC1B;AAAA,MAA2B;AAAA,MAC3B;AAAA,MAAwB;AAAA,MACxB;AAAA,MAAyB;AAAA,MAAiB;AAAA,MAC1C;AAAA,MAAgB;AAAA,MAAkB;AAAA,MAAe;AAAA,MACjD;AAAA,MAAkB;AAAA,MAClB;AAAA,MAAyB;AAAA,MAAa;AAAA,MACtC;AAAA,MAA0B;AAAA,MAC1B;AAAA,MAAiB;AAAA,MACjB;AAAA,MAAiC;AAAA,MACjC;AAAA,MAAkC;AAAA,MAClC;AAAA,MAAmB;AAAA,MAAiB;AAAA,MACpC;AAAA,MAAkB;AAAA,MAAmB;AAAA,MACrC;AAAA,MAAyB;AAAA,MAAgB;AAAA,MACzC;AAAA,MAAgB;AAAA,MAAgB;AAAA,MAAgB;AAAA,MAChD;AAAA,MAAoB;AAAA,MAAkB;AAAA,IACxC;AAEA,eAAW,QAAQ,CAAC,SAAS;AAC3B,SAAG,iBAAiB,MAAM,aAAa;AAAA,IACzC,CAAC;AAAA,EACH;AAGA,WAAS,oBAA0B;AACjC,QAAI,yBAAyB,CAAC,OAAQ;AAEtC,UAAM,aAAa,YAAY,cAAc,qBAAqB;AAClE,QAAI,cAAc,YAAY;AAC5B,aAAO,MAAM,gBAAgB,UAAU,YAAY;AACnD,cAAQ;AAAA,QACN,MAAM;AAAA,QACN,SAAS,gBAAgB,UAAU;AAAA,QACnC,WAAW;AAAA,QACX,WAAW,KAAK,IAAI;AAAA,MACtB;AACA;AAAA,IACF;AAEA,UAAM,WAAW,uBAAuB,YAAY,WAAW;AAC/D;AACA,YAAQ;AAER,WAAO,KAAK,mBAAmB,QAAQ,eAAe,UAAU,GAAG;AACnE,YAAQ;AAER,uBAAmB,WAAW,MAAM;AAClC,UAAI,QAAQ;AACV,kBAAU,QAAQ,MAAM,EAAE,MAAM,CAAC,QAAQ;AACvC,iBAAO,MAAM,qBAAqB,GAAG;AAAA,QACvC,CAAC;AAAA,MACH;AAAA,IACF,GAAG,QAAQ;AAAA,EACb;AAEA,QAAM,YAA2B;AAAA,IAC/B,MAAM,QAAQ,KAAqC;AACjD,eAAS;AACT,8BAAwB;AAGxB,UAAI,aAAa;AACf,oBAAY,MAAM;AAClB,sBAAc;AAAA,MAChB;AACA,UAAI,kBAAkB;AACpB,qBAAa,gBAAgB;AAC7B,2BAAmB;AAAA,MACrB;AAEA,cAAQ,aAAa,IAAI,iBAAiB;AAE1C,aAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,cAAM,kBAAkB,KAAK,IAAI;AAIjC,cAAM,eAAe,IAAI,gBAAgB;AAAA,UACvC,OAAO,IAAI;AAAA,UACX,QAAQ,IAAI;AAAA,UACZ,YAAY,IAAI;AAAA,QAClB,CAAC;AACD,YAAI,IAAI,QAAS,cAAa,IAAI,UAAU,IAAI,OAAO;AACvD,cAAM,MAAM,GAAG,IAAI,OAAO,WAAW,aAAa,SAAS,CAAC;AAE5D,eAAO,MAAM,kBAAkB,GAAG;AAClC,cAAM,KAAK,IAAI,YAAY,GAAG;AAE9B,WAAG,SAAS,MAAM;AAChB,gBAAM,iBAAiB,KAAK,IAAI,IAAI;AACpC,iBAAO,KAAK,gBAAgB,cAAc,IAAI;AAE9C,gBAAM,eAAe,aAAa;AAClC,kBAAQ;AACR,kBAAQ;AACR,uBAAa;AACb,kBAAQ,cAAc,KAAK,IAAI;AAC/B,kBAAQ,UAAU;AAElB,8BAAoB,EAAE;AAItB,cAAI,cAAc;AAChB,iBAAK;AAAA,cACH,MAAM;AAAA,cACN,OAAO,IAAI;AAAA,cACX,SAAS,IAAI,WAAW;AAAA,cACxB,QAAQ,IAAI;AAAA,cACZ,WAAW,KAAK,IAAI;AAAA,YACtB,CAAc;AAAA,UAChB;AAEA,kBAAQ;AAAA,QACV;AAEA,WAAG,UAAU,MAAM;AACjB,cAAI,GAAG,eAAe,YAAY,QAAQ;AACxC,kBAAM,WAA2B;AAAA,cAC/B,MAAM;AAAA,cACN,SAAS;AAAA,cACT,WAAW;AAAA,cACX,WAAW,KAAK,IAAI;AAAA,YACtB;AACA,oBAAQ;AACR,oBAAQ,YAAY;AACpB,oBAAQ;AAER,gBAAI,CAAC,uBAAuB;AAC1B,gCAAkB;AAAA,YACpB;AAGA,gBAAI,eAAe,GAAG;AACpB,qBAAO,QAAQ;AAAA,YACjB;AAAA,UACF;AAAA,QACF;AAEA,sBAAc;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,IAEA,WAAW,cAAc,MAAY;AACnC,aAAO,KAAK,iBAAiB,EAAE,YAAY,CAAC;AAC5C,8BAAwB;AAExB,UAAI,kBAAkB;AACpB,qBAAa,gBAAgB;AAC7B,2BAAmB;AAAA,MACrB;AAEA,UAAI,aAAa;AACf,oBAAY,MAAM;AAClB,sBAAc;AAAA,MAChB;AAEA,cAAQ;AACR,mBAAa;AAAA,IACf;AAAA,IAEA,MAAM,KAAK,OAAiC;AAC1C,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAGA,cAAQ,MAAM,MAAM;AAAA,QAClB,KAAK;AACH,gBAAM,SAAS,QAAQ;AAAA,YACrB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,SAAS,MAAM;AAAA,YACf,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,UAC3C,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,SAAS,UAAU;AAAA,YACvB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,QAAQ;AAAA,UACV,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,SAAS,UAAU;AAAA,YACvB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,QAAQ;AAAA,UACV,CAAC;AACD;AAAA,QAEF,KAAK;AAEH,gBAAM,SAAS,QAAQ;AAAA,YACrB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,UAChB,CAAC;AACD;AAAA,QAEF,KAAK;AAEH,gBAAM,SAAS,UAAU;AAAA,YACvB,OAAO,MAAM;AAAA,YACb,QAAQ,MAAM;AAAA,YACd,UAAU,MAAM;AAAA,UAClB,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,SAAS,OAAO;AAAA,YACpB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,MAAM,MAAM;AAAA,UACd,CAAC;AACD;AAAA,QAEF;AAEE,gBAAM,SAAS,SAAS;AAAA,YACtB,MAAM,MAAM;AAAA,YACZ,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,MAAM,MAAM;AAAA,UACd,CAAC;AAAA,MACL;AAEA,cAAQ;AAAA,IACV;AAAA,IAEA,MAAM,YAAY,SAAqC;AACrD,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,YAAM,SAAS,QAAQ;AAAA,QACrB,OAAO,OAAO;AAAA,QACd,SAAS,OAAO;AAAA,QAChB,QAAQ,OAAO;AAAA,QACf;AAAA,MACF,CAAC;AAED,cAAQ;AAAA,IACV;AAAA,IAEA,MAAM,WAAWA,UAAyD;AACxE,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,YAAM,WAAW,MAAM,SAAS,UAAU;AAAA,QACxC,OAAOA,SAAQ;AAAA,QACf,QAAQA,SAAQ;AAAA,QAChB,UAAUA,SAAQ;AAAA,MACpB,CAAC;AAED,UAAI,CAAC,UAAU,SAAS;AACtB,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAC9D;AAEA,aAAO,EAAE,SAAS,SAAS,QAAQ;AAAA,IACrC;AAAA,IAEA,MAAM,aAAaA,UAAqD;AACtE,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,YAAM,WAAW,MAAM,SAAS,QAAQ;AAAA,QACtC,OAAOA,SAAQ;AAAA,QACf,SAASA,SAAQ;AAAA,QACjB,QAAQA,SAAQ;AAAA,MAClB,CAAC;AAED,UAAI,CAAC,UAAU,MAAM;AACnB,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAC9D;AAEA,aAAO;AAAA,QACL,MAAM,SAAS;AAAA,QACf,SAAS,SAAS;AAAA,MACpB;AAAA,IACF;AAAA,IAEA,UAAU,SAAoC;AAC5C,qBAAe,IAAI,OAAO;AAC1B,aAAO,MAAM,eAAe,OAAO,OAAO;AAAA,IAC5C;AAAA,IAEA,GAAG,WAAmB,SAAoC;AACxD,UAAI,CAAC,aAAa,IAAI,SAAS,GAAG;AAChC,qBAAa,IAAI,WAAW,oBAAI,IAAI,CAAC;AAAA,MACvC;AACA,mBAAa,IAAI,SAAS,EAAG,IAAI,OAAO;AACxC,aAAO,MAAM;AACX,cAAM,WAAW,aAAa,IAAI,SAAS;AAC3C,YAAI,UAAU;AACZ,mBAAS,OAAO,OAAO;AACvB,cAAI,SAAS,SAAS,GAAG;AACvB,yBAAa,OAAO,SAAS;AAAA,UAC/B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,WAA2B;AACzB,aAAO;AAAA,IACT;AAAA,IAEA,aAAgC;AAC9B,aAAO,EAAE,GAAG,QAAQ;AAAA,IACtB;AAAA,IAEA,WAAuC;AACrC,aAAO;AAAA,IACT;AAAA,IAEA,aAAmB;AACjB,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AACT;;;AClcO,SAAS,wBAAwB,UAAoC,CAAC,GAAkB;AAC7F,QAAM;AAAA,IACJ,cAAc;AAAA,IACd,QAAQ;AAAA,IACR,SAAS,aAAa,KAAK;AAAA,IAC3B,cAAc;AAAA,EAChB,IAAI;AAGJ,MAAI;AACJ,MAAI;AACJ,MAAI,QAAwB;AAC5B,MAAI;AACJ,MAAI,aAAa;AACjB,MAAI;AACJ,MAAI,wBAAwB;AAG5B,QAAM,UAA6B;AAAA,IACjC,SAAS;AAAA,IACT,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,eAAe;AAAA,EACjB;AAGA,QAAM,iBAAiB,oBAAI,IAAkB;AAC7C,QAAM,eAAe,oBAAI,IAA+B;AAGxD,WAAS,KAAK,OAAwB;AACpC,YAAQ;AACR,YAAQ,gBAAgB,KAAK,IAAI;AAEjC,mBAAe,QAAQ,CAAC,YAAY;AAClC,UAAI;AACF,gBAAQ,KAAK;AAAA,MACf,SAAS,KAAK;AACZ,eAAO,MAAM,6BAA6B,GAAG;AAAA,MAC/C;AAAA,IACF,CAAC;AAED,UAAM,WAAW,aAAa,IAAI,MAAM,IAAI;AAC5C,QAAI,UAAU;AACZ,eAAS,QAAQ,CAAC,YAAY;AAC5B,YAAI;AACF,kBAAQ,KAAK;AAAA,QACf,SAAS,KAAK;AACZ,iBAAO,MAAM,YAAY,MAAM,IAAI,aAAa,GAAG;AAAA,QACrD;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAGA,iBAAe,SAAS,UAAkB,MAAiD;AACzF,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AAEA,UAAM,MAAM,GAAG,OAAO,OAAO,IAAI,QAAQ;AACzC,WAAO,MAAM,QAAQ,QAAQ,IAAI,IAAI;AAErC,UAAM,WAAW,MAAM,YAAY,KAAK;AAAA,MACtC,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,YAAY,MAAM,SAAS,KAAK;AACtC,YAAM,IAAI,MAAM,cAAc,SAAS,MAAM,MAAM,SAAS,EAAE;AAAA,IAChE;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AAIjC,QAAI,QAAQ,OAAO,SAAS,YAAY,UAAU,MAAM;AACtD,aAAO,KAAK;AAAA,IACd;AAEA,WAAO;AAAA,EACT;AAGA,WAAS,cAAc,OAA4B;AACjD,UAAM,SAAsB,CAAC;AAC7B,UAAM,QAAQ,MAAM,MAAM,IAAI;AAE9B,QAAI,YAAY;AAChB,QAAI,OAAO;AAEX,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,oBAAY,KAAK,MAAM,CAAC,EAAE,KAAK;AAAA,MACjC,WAAW,KAAK,WAAW,OAAO,GAAG;AACnC,eAAO,KAAK,MAAM,CAAC,EAAE,KAAK;AAAA,MAC5B,WAAW,SAAS,MAAM,MAAM;AAE9B,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,iBAAO,KAAK,MAAM;AAAA,QACpB,QAAQ;AACN,iBAAO,KAAK,6BAA6B,IAAI;AAAA,QAC/C;AACA,oBAAY;AACZ,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAGA,iBAAe,YAAY,KAAqC;AAI9D,UAAM,eAAe,IAAI,gBAAgB;AAAA,MACvC,OAAO,IAAI;AAAA,MACX,QAAQ,IAAI;AAAA,MACZ,YAAY,IAAI;AAAA,IAClB,CAAC;AACD,QAAI,IAAI,QAAS,cAAa,IAAI,UAAU,IAAI,OAAO;AACvD,UAAM,MAAM,GAAG,IAAI,OAAO,WAAW,aAAa,SAAS,CAAC;AAE5D,WAAO,MAAM,kBAAkB,GAAG;AAElC,sBAAkB,IAAI,gBAAgB;AAEtC,UAAM,WAAW,MAAM,YAAY,KAAK;AAAA,MACtC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,iBAAiB;AAAA,MACnB;AAAA,MACA,QAAQ,gBAAgB;AAAA,IAC1B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,6BAA6B,SAAS,MAAM,EAAE;AAAA,IAChE;AAEA,QAAI,CAAC,SAAS,MAAM;AAClB,YAAM,IAAI,MAAM,sDAAsD;AAAA,IACxE;AAEA,UAAM,SAAS,SAAS,KAAK,UAAU;AACvC,UAAM,UAAU,IAAI,YAAY;AAChC,QAAI,SAAS;AAGb,UAAM,aAAa,YAAY;AAC7B,UAAI;AACF,eAAO,MAAM;AACX,gBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAE1C,cAAI,MAAM;AACR,mBAAO,KAAK,cAAc;AAC1B;AAAA,UACF;AAEA,oBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAGhD,gBAAM,cAAc,OAAO,YAAY,MAAM;AAC7C,cAAI,gBAAgB,IAAI;AACtB,kBAAM,WAAW,OAAO,MAAM,GAAG,cAAc,CAAC;AAChD,qBAAS,OAAO,MAAM,cAAc,CAAC;AAErC,kBAAM,SAAS,cAAc,QAAQ;AACrC,mBAAO,QAAQ,IAAI;AAAA,UACrB;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,YAAK,IAAc,SAAS,cAAc;AACxC,iBAAO,MAAM,gBAAgB;AAC7B;AAAA,QACF;AACA,eAAO,MAAM,iBAAiB,GAAG;AACjC,cAAM;AAAA,MACR;AAGA,UAAI,CAAC,uBAAuB;AAC1B,gBAAQ;AACR,0BAAkB;AAAA,MACpB;AAAA,IACF;AAGA,eAAW,EAAE,MAAM,CAAC,QAAQ;AAC1B,UAAI,CAAC,uBAAuB;AAC1B,gBAAQ;AAAA,UACN,MAAM;AAAA,UACN,SAAS,IAAI;AAAA,UACb,WAAW;AAAA,UACX,WAAW,KAAK,IAAI;AAAA,UACpB,eAAe;AAAA,QACjB;AACA,gBAAQ,YAAY;AACpB,gBAAQ;AACR,0BAAkB;AAAA,MACpB;AAAA,IACF,CAAC;AAAA,EACH;AAGA,WAAS,oBAA0B;AACjC,QAAI,yBAAyB,CAAC,OAAQ;AAEtC,UAAM,aAAa,YAAY,cAAc,qBAAqB;AAClE,QAAI,cAAc,YAAY;AAC5B,aAAO,MAAM,gBAAgB,UAAU,YAAY;AACnD,cAAQ;AAAA,QACN,MAAM;AAAA,QACN,SAAS,gBAAgB,UAAU;AAAA,QACnC,WAAW;AAAA,QACX,WAAW,KAAK,IAAI;AAAA,MACtB;AACA;AAAA,IACF;AAEA,UAAM,WAAW,uBAAuB,YAAY,WAAW;AAC/D;AACA,YAAQ;AAER,WAAO,KAAK,mBAAmB,QAAQ,eAAe,UAAU,GAAG;AACnE,YAAQ;AAER,uBAAmB,WAAW,MAAM;AAClC,UAAI,QAAQ;AACV,kBAAU,QAAQ,MAAM,EAAE,MAAM,CAAC,QAAQ;AACvC,iBAAO,MAAM,qBAAqB,GAAG;AAAA,QACvC,CAAC;AAAA,MACH;AAAA,IACF,GAAG,QAAQ;AAAA,EACb;AAEA,QAAM,YAA2B;AAAA,IAC/B,MAAM,QAAQ,KAAqC;AACjD,eAAS;AACT,8BAAwB;AAGxB,UAAI,iBAAiB;AACnB,wBAAgB,MAAM;AACtB,0BAAkB;AAAA,MACpB;AACA,UAAI,kBAAkB;AACpB,qBAAa,gBAAgB;AAC7B,2BAAmB;AAAA,MACrB;AAEA,cAAQ,aAAa,IAAI,iBAAiB;AAC1C,YAAM,kBAAkB,KAAK,IAAI;AAEjC,UAAI;AACF,cAAM,eAAe,aAAa;AAClC,cAAM,YAAY,GAAG;AAErB,cAAM,iBAAiB,KAAK,IAAI,IAAI;AACpC,eAAO,KAAK,gBAAgB,cAAc,IAAI;AAE9C,gBAAQ;AACR,gBAAQ;AACR,qBAAa;AACb,gBAAQ,cAAc,KAAK,IAAI;AAC/B,gBAAQ,UAAU;AAIlB,YAAI,cAAc;AAChB,eAAK;AAAA,YACH,MAAM;AAAA,YACN,OAAO,IAAI;AAAA,YACX,SAAS,IAAI,WAAW;AAAA,YACxB,QAAQ,IAAI;AAAA,YACZ,WAAW,KAAK,IAAI;AAAA,UACtB,CAAc;AAAA,QAChB;AAAA,MACF,SAAS,KAAK;AACZ,cAAM,eAA+B;AAAA,UACnC,MAAM;AAAA,UACN,SAAU,IAAc;AAAA,UACxB,WAAW;AAAA,UACX,WAAW,KAAK,IAAI;AAAA,UACpB,eAAe;AAAA,QACjB;AACA,gBAAQ;AACR,gBAAQ,YAAY;AACpB,gBAAQ;AAER,YAAI,CAAC,uBAAuB;AAC1B,4BAAkB;AAAA,QACpB;AAEA,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IAEA,WAAW,cAAc,MAAY;AACnC,aAAO,KAAK,iBAAiB,EAAE,YAAY,CAAC;AAC5C,8BAAwB;AAExB,UAAI,kBAAkB;AACpB,qBAAa,gBAAgB;AAC7B,2BAAmB;AAAA,MACrB;AAEA,UAAI,iBAAiB;AACnB,wBAAgB,MAAM;AACtB,0BAAkB;AAAA,MACpB;AAEA,cAAQ;AACR,mBAAa;AAAA,IACf;AAAA,IAEA,MAAM,KAAK,OAAiC;AAC1C,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,cAAQ,MAAM,MAAM;AAAA,QAClB,KAAK;AACH,gBAAM,SAAS,QAAQ;AAAA,YACrB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,SAAS,MAAM;AAAA,YACf,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,UAC3C,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,SAAS,UAAU;AAAA,YACvB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,QAAQ;AAAA,UACV,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,SAAS,UAAU;AAAA,YACvB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,QAAQ;AAAA,UACV,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,SAAS,QAAQ;AAAA,YACrB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,UAChB,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,SAAS,UAAU;AAAA,YACvB,OAAO,MAAM;AAAA,YACb,QAAQ,MAAM;AAAA,YACd,UAAU,MAAM;AAAA,UAClB,CAAC;AACD;AAAA,QAEF,KAAK;AACH,gBAAM,SAAS,OAAO;AAAA,YACpB,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,MAAM,MAAM;AAAA,UACd,CAAC;AACD;AAAA,QAEF;AACE,gBAAM,SAAS,SAAS;AAAA,YACtB,MAAM,MAAM;AAAA,YACZ,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf,QAAQ,MAAM;AAAA,YACd,MAAM,MAAM;AAAA,UACd,CAAC;AAAA,MACL;AAEA,cAAQ;AAAA,IACV;AAAA,IAEA,MAAM,YAAY,SAAqC;AACrD,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,YAAM,SAAS,QAAQ;AAAA,QACrB,OAAO,OAAO;AAAA,QACd,SAAS,OAAO;AAAA,QAChB,QAAQ,OAAO;AAAA,QACf;AAAA,MACF,CAAC;AAED,cAAQ;AAAA,IACV;AAAA,IAEA,MAAM,WAAWC,UAAyD;AACxE,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,YAAM,WAAW,MAAM,SAAS,UAAU;AAAA,QACxC,OAAOA,SAAQ;AAAA,QACf,QAAQA,SAAQ;AAAA,QAChB,UAAUA,SAAQ;AAAA,MACpB,CAAC;AAED,UAAI,CAAC,UAAU,SAAS;AACtB,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAC9D;AAEA,aAAO,EAAE,SAAS,SAAS,QAAQ;AAAA,IACrC;AAAA,IAEA,MAAM,aAAaA,UAAqD;AACtE,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,YAAM,WAAW,MAAM,SAAS,QAAQ;AAAA,QACtC,OAAOA,SAAQ;AAAA,QACf,SAASA,SAAQ;AAAA,QACjB,QAAQA,SAAQ;AAAA,MAClB,CAAC;AAED,UAAI,CAAC,UAAU,MAAM;AACnB,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAC9D;AAEA,aAAO;AAAA,QACL,MAAM,SAAS;AAAA,QACf,SAAS,SAAS;AAAA,MACpB;AAAA,IACF;AAAA,IAEA,UAAU,SAAoC;AAC5C,qBAAe,IAAI,OAAO;AAC1B,aAAO,MAAM,eAAe,OAAO,OAAO;AAAA,IAC5C;AAAA,IAEA,GAAG,WAAmB,SAAoC;AACxD,UAAI,CAAC,aAAa,IAAI,SAAS,GAAG;AAChC,qBAAa,IAAI,WAAW,oBAAI,IAAI,CAAC;AAAA,MACvC;AACA,mBAAa,IAAI,SAAS,EAAG,IAAI,OAAO;AACxC,aAAO,MAAM;AACX,cAAM,WAAW,aAAa,IAAI,SAAS;AAC3C,YAAI,UAAU;AACZ,mBAAS,OAAO,OAAO;AACvB,cAAI,SAAS,SAAS,GAAG;AACvB,yBAAa,OAAO,SAAS;AAAA,UAC/B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,WAA2B;AACzB,aAAO;AAAA,IACT;AAAA,IAEA,aAAgC;AAC9B,aAAO,EAAE,GAAG,QAAQ;AAAA,IACtB;AAAA,IAEA,WAAuC;AACrC,aAAO;AAAA,IACT;AAAA,IAEA,aAAmB;AACjB,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AACT;;;ACjaO,SAAS,wBACd,UAAoC,CAAC,GACtB;AACf,QAAM,EAAE,QAAQ,OAAO,SAAS,aAAa,KAAK,EAAE,IAAI;AAExD,MAAI,QAAwB;AAC5B,MAAI;AACJ,MAAI;AAEJ,QAAM,UAA6B;AAAA,IACjC,SAAS;AAAA,IACT,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,eAAe;AAAA,EACjB;AAEA,QAAM,iBAAiB,oBAAI,IAAkB;AAC7C,QAAM,eAAe,oBAAI,IAA+B;AAExD,QAAM,YAA2B;AAAA,IAC/B,MAAM,QAAQ,KAAqC;AACjD,aAAO;AAAA,QACL;AAAA,MACF;AACA,aAAO;AAAA,QACL;AAAA,MACF;AAEA,eAAS;AAOT,cAAQ;AACR,cAAQ,cAAc,KAAK,IAAI;AAAA,IACjC;AAAA,IAEA,aAAmB;AACjB,cAAQ;AAAA,IACV;AAAA,IAEA,MAAM,KAAK,OAAiC;AAC1C,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,aAAO,KAAK,2DAA2D;AAOvE,cAAQ;AAAA,IACV;AAAA,IAEA,MAAM,YAAY,SAAqC;AACrD,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,aAAO;AAAA,QACL;AAAA,MACF;AAWA,cAAQ;AAAA,IACV;AAAA,IAEA,MAAM,WAAWC,UAAyD;AACxE,aAAO;AAAA,QACL;AAAA,MACF;AAKA,aAAO,EAAE,SAAS,YAAYA,SAAQ,MAAM,IAAI,KAAK,IAAI,CAAC,GAAG;AAAA,IAC/D;AAAA,IAEA,MAAM,aAAaA,UAAqD;AACtE,aAAO;AAAA,QACL;AAAA,MACF;AAGA,aAAO;AAAA,QACL,MAAM;AAAA,UACJ,OAAOA,SAAQ;AAAA,UACf,KAAKA,SAAQ;AAAA,UACb,OAAO;AAAA,UACP,UAAU,CAAC;AAAA,UACX,aAAa,KAAK,IAAI;AAAA,UACtB,WAAW,KAAK,IAAI;AAAA,UACpB,OAAO,CAAC;AAAA,UACR,QAAQ;AAAA,UACR,WAAW;AAAA,UACX,mBAAmB;AAAA,UACnB,WAAW;AAAA,UACX,mBAAmB;AAAA,QACrB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,UAAU,SAAoC;AAC5C,qBAAe,IAAI,OAAO;AAC1B,aAAO,MAAM,eAAe,OAAO,OAAO;AAAA,IAC5C;AAAA,IAEA,GAAG,WAAmB,SAAoC;AACxD,UAAI,CAAC,aAAa,IAAI,SAAS,GAAG;AAChC,qBAAa,IAAI,WAAW,oBAAI,IAAI,CAAC;AAAA,MACvC;AACA,mBAAa,IAAI,SAAS,EAAG,IAAI,OAAO;AACxC,aAAO,MAAM;AACX,cAAM,WAAW,aAAa,IAAI,SAAS;AAC3C,YAAI,UAAU;AACZ,mBAAS,OAAO,OAAO;AACvB,cAAI,SAAS,SAAS,GAAG;AACvB,yBAAa,OAAO,SAAS;AAAA,UAC/B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,WAA2B;AACzB,aAAO;AAAA,IACT;AAAA,IAEA,aAAgC;AAC9B,aAAO,EAAE,GAAG,QAAQ;AAAA,IACtB;AAAA,IAEA,WAAuC;AACrC,aAAO;AAAA,IACT;AAAA,IAEA,aAAmB;AACjB,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,SAAO;AACT;AA6DO,SAAS,uBACd,SACA,OACa;AACb,QAAM,SAAsB,CAAC;AAE7B,aAAW,SAAS,QAAQ,OAAO;AACjC,eAAW,UAAU,MAAM,SAAS;AAClC,YAAM,QAAQ,OAAO;AAGrB,UAAI,MAAM,UAAU;AAClB,mBAAW,OAAO,MAAM,UAAU;AAChC,gBAAM,UAAU,MAAM,UAAU,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,IAAI;AAEhE,iBAAO,KAAK;AAAA,YACV,MAAM;AAAA,YACN;AAAA,YACA,SAAS,MAAM,IAAI,IAAI;AAAA;AAAA,YACvB,QAAQ,IAAI;AAAA,YACZ,WAAW,SAAS,IAAI,SAAS,IAAI;AAAA,YACrC,SAAS;AAAA,cACP,IAAI,IAAI;AAAA,cACR,MAAM;AAAA,cACN,SAAS,IAAI,MAAM,QAAQ;AAAA,cAC3B,MAAM,SAAS,IAAI,SAAS,IAAI;AAAA,cAChC,QAAQ;AAAA,cACR,UAAU,IAAI;AAAA,cACd,YAAY,SAAS,QAAQ;AAAA,cAC7B,WAAW,SAAS,IAAI,SAAS,IAAI;AAAA;AAAA,cAErC,aAAa,uBAAuB,GAAG;AAAA,YACzC;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAGA,UAAI,MAAM,UAAU;AAClB,mBAAW,UAAU,MAAM,UAAU;AACnC,iBAAO,KAAK;AAAA,YACV,MAAM;AAAA,YACN;AAAA,YACA,SAAS,MAAM,OAAO,YAAY;AAAA,YAClC,QAAQ,OAAO;AAAA,YACf,WAAW,SAAS,OAAO,SAAS,IAAI;AAAA,YACxC,MAAM;AAAA,cACJ,WAAW,OAAO;AAAA,cAClB,QAAQ,OAAO;AAAA,YACjB;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAGA,SAAS,uBAAuB,KAOH;AAC3B,UAAQ,IAAI,MAAM;AAAA,IAChB,KAAK;AACH,aAAO,IAAI,QACP,CAAC,EAAE,MAAM,SAA6B,KAAK,oBAAoB,IAAI,MAAM,EAAE,GAAG,CAAC,IAC/E;AAAA,IACN,KAAK;AACH,aAAO,IAAI,WACP;AAAA,QACE;AAAA,UACE,MAAM;AAAA,UACN,KAAK,oBAAoB,IAAI,SAAS,EAAE;AAAA,QAC1C;AAAA,MACF,IACA;AAAA,IACN,KAAK;AACH,aAAO,IAAI,QACP,CAAC,EAAE,MAAM,SAA6B,KAAK,oBAAoB,IAAI,MAAM,EAAE,GAAG,CAAC,IAC/E;AAAA,IACN,KAAK;AACH,aAAO,IAAI,QACP,CAAC,EAAE,MAAM,SAA6B,KAAK,oBAAoB,IAAI,MAAM,EAAE,GAAG,CAAC,IAC/E;AAAA,IACN,KAAK;AACH,aAAO,IAAI,WACP;AAAA,QACE;AAAA,UACE,MAAM;AAAA,UACN,KAAK,OAAO,IAAI,SAAS,QAAQ,IAAI,IAAI,SAAS,SAAS;AAAA,QAC7D;AAAA,MACF,IACA;AAAA,IACN;AACE,aAAO;AAAA,EACX;AACF;","names":["options","options","options"]}
1
+ {"version":3,"sources":["../../transport/index.ts","../../transport/types.ts","../../transport/sse.ts","../../transport/sse-fetch.ts","../../transport/whatsapp.ts"],"sourcesContent":["/**\n * Transport Layer\n *\n * Platform-agnostic transport abstractions for chat communication.\n *\n * @example Browser (SSE)\n * ```typescript\n * import { createSSETransport } from \"@elqnt/chat/transport\";\n *\n * const transport = createSSETransport({ debug: true });\n * await transport.connect({ baseUrl, orgId, userId, clientType: \"customer\" });\n *\n * transport.onMessage((event) => {\n * console.log(\"Received:\", event);\n * });\n * ```\n *\n * @example React Native (Fetch-based SSE)\n * ```typescript\n * import { createFetchSSETransport } from \"@elqnt/chat/transport\";\n *\n * const transport = createFetchSSETransport();\n * await transport.connect({ baseUrl, orgId, userId, clientType: \"customer\" });\n * ```\n *\n * @example Custom Transport\n * ```typescript\n * import type { ChatTransport } from \"@elqnt/chat/transport\";\n *\n * const customTransport: ChatTransport = {\n * connect: async (config) => { ... },\n * disconnect: () => { ... },\n * send: async (event) => { ... },\n * sendMessage: async (message) => { ... },\n * onMessage: (handler) => { ... },\n * on: (eventType, handler) => { ... },\n * getState: () => { ... },\n * getMetrics: () => { ... },\n * getError: () => { ... },\n * clearError: () => { ... },\n * };\n * ```\n */\n\n// Types\nexport type {\n ChatTransport,\n TransportConfig,\n TransportState,\n TransportError,\n TransportFactory,\n TransportLogger,\n ConnectionMetrics,\n EventHandler,\n Unsubscribe,\n RetryConfig,\n SendMessageOptions,\n CreateChatOptions,\n LoadChatOptions,\n EndChatOptions,\n} from \"./types\";\n\nexport {\n createLogger,\n calculateRetryInterval,\n DEFAULT_RETRY_CONFIG,\n} from \"./types\";\n\n// Browser SSE transport\nexport { createSSETransport } from \"./sse\";\nexport type { SSETransportOptions } from \"./sse\";\n\n// Fetch-based SSE transport (React Native)\nexport { createFetchSSETransport } from \"./sse-fetch\";\nexport type { FetchSSETransportOptions } from \"./sse-fetch\";\n\n// WhatsApp Business API transport (stub)\nexport {\n createWhatsAppTransport,\n mapWhatsAppToChatEvent,\n} from \"./whatsapp\";\nexport type {\n WhatsAppTransportConfig,\n WhatsAppTransportOptions,\n WhatsAppMessageType,\n WhatsAppWebhookPayload,\n} from \"./whatsapp\";\n","/**\n * Transport Abstraction Layer Types\n *\n * Platform-agnostic transport interfaces for chat communication.\n * Supports browser SSE, React Native fetch-based SSE, and extensible\n * transports like WhatsApp Business API.\n */\n\nimport type { Chat, ChatEvent, ChatMessage } from \"../models\";\n\n/**\n * Transport connection state\n */\nexport type TransportState =\n | \"disconnected\"\n | \"connecting\"\n | \"connected\"\n | \"reconnecting\";\n\n/**\n * Transport error with retry information\n */\nexport interface TransportError {\n code:\n | \"CONNECTION_FAILED\"\n | \"PARSE_ERROR\"\n | \"SEND_FAILED\"\n | \"TIMEOUT\"\n | \"NETWORK_ERROR\"\n | \"AUTH_FAILED\";\n message: string;\n retryable: boolean;\n timestamp: number;\n originalError?: unknown;\n}\n\n/**\n * Configuration for transport connection\n */\nexport interface TransportConfig {\n /** Base URL for the chat server */\n baseUrl: string;\n /** Organization ID */\n orgId: string;\n /** User ID for authentication */\n userId: string;\n /** Client type for routing */\n clientType: \"customer\" | \"humanAgent\" | \"observer\";\n /** Optional current chat key for reconnection */\n chatKey?: string;\n /** Enable debug logging */\n debug?: boolean;\n /**\n * Tier-2 authorization (REQUIRED in production). Chat realtime talks to the\n * chat service DIRECTLY, bypassing the API gateway — so the service has no\n * gateway JWT to trust and authorizes each connection from this signed\n * token instead. The service derives orgId/userId/product from the token's\n * claims, so the token MUST be scoped to the same org/user as this config.\n *\n * Prefer `getToken`: it is invoked before every connect and every REST send,\n * so a long-lived stream keeps working as short-lived tokens roll over. Use\n * the static `token` only for one-shot/non-refreshing callers. Obtain the\n * token from a server route that mints a gateway-shaped JWT (e.g. the app's\n * /api/gateway-token or a dedicated chat-token route). See SKILL.md.\n */\n getToken?: () => Promise<string | null | undefined> | string | null | undefined;\n /** Static signed token. Ignored when `getToken` is provided. */\n token?: string;\n}\n\n/**\n * Resolve the connect/send token from a transport config. Prefers the\n * `getToken` provider (so tokens refresh) and falls back to the static\n * `token`. Never throws — a failing provider resolves to undefined and the\n * request goes out tokenless (the service rejects it when enforcing).\n */\nexport async function resolveTransportToken(\n cfg: { getToken?: TransportConfig[\"getToken\"]; token?: string } | undefined\n): Promise<string | undefined> {\n if (!cfg) return undefined;\n if (cfg.getToken) {\n try {\n const t = await cfg.getToken();\n return t ?? undefined;\n } catch {\n return undefined;\n }\n }\n return cfg.token ?? undefined;\n}\n\n/**\n * Retry configuration for connection attempts\n */\nexport interface RetryConfig {\n /** Maximum number of retry attempts */\n maxRetries?: number;\n /** Initial retry intervals in milliseconds */\n intervals?: number[];\n /** Multiplier for exponential backoff */\n backoffMultiplier?: number;\n /** Maximum backoff time in milliseconds */\n maxBackoffTime?: number;\n}\n\n/**\n * Connection metrics for monitoring\n */\nexport interface ConnectionMetrics {\n /** Round-trip latency in milliseconds */\n latency: number;\n /** Total messages sent */\n messagesSent: number;\n /** Total messages received */\n messagesReceived: number;\n /** Messages waiting to be sent */\n messagesQueued: number;\n /** Number of reconnection attempts */\n reconnectCount: number;\n /** Last error encountered */\n lastError?: TransportError;\n /** Timestamp when connection was established */\n connectedAt?: number;\n /** Timestamp of last message */\n lastMessageAt?: number;\n /** Current transport type */\n transportType?: string;\n}\n\n/**\n * Event handler function type\n */\nexport type EventHandler<T = ChatEvent> = (event: T) => void;\n\n/**\n * Unsubscribe function returned by event subscription\n */\nexport type Unsubscribe = () => void;\n\n/**\n * Send message options\n */\nexport interface SendMessageOptions {\n /** Message content */\n content: string;\n /** Optional attachments */\n attachments?: unknown[];\n /** Optional message metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Create chat options\n */\nexport interface CreateChatOptions {\n /** Organization ID */\n orgId: string;\n /** User ID */\n userId: string;\n /** Optional chat metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Load chat options\n */\nexport interface LoadChatOptions {\n /** Organization ID */\n orgId: string;\n /** Chat key to load */\n chatKey: string;\n /** User ID */\n userId: string;\n}\n\n/**\n * End chat options\n */\nexport interface EndChatOptions {\n /** Organization ID */\n orgId: string;\n /** Chat key to end */\n chatKey: string;\n /** User ID */\n userId: string;\n /** Optional end reason */\n reason?: string;\n}\n\n/**\n * Response from creating a new chat\n */\nexport interface CreateChatResponse {\n /** The key of the created chat */\n chatKey: string;\n}\n\n/**\n * Response from loading a chat\n */\nexport interface LoadChatResponse {\n /** The loaded chat object */\n chat: Chat;\n /** Agent ID if applicable */\n agentId?: string;\n}\n\n/**\n * Core transport interface\n *\n * Implementations must handle:\n * - Connection lifecycle (connect, disconnect, reconnect)\n * - Message sending (POST requests)\n * - Event receiving (SSE stream)\n * - Error handling and recovery\n */\nexport interface ChatTransport {\n /**\n * Connect to the chat server\n * @param config - Transport configuration\n * @returns Promise that resolves when connected\n */\n connect(config: TransportConfig): Promise<void>;\n\n /**\n * Disconnect from the server\n * @param intentional - Whether disconnect was user-initiated\n */\n disconnect(intentional?: boolean): void;\n\n /**\n * Send a chat event to the server\n * @param event - Chat event to send\n */\n send(event: ChatEvent): Promise<void>;\n\n /**\n * Send a message in the current chat\n * @param message - Message to send\n */\n sendMessage(message: ChatMessage): Promise<void>;\n\n /**\n * Create a new chat and return the chat key directly\n * @param options - Create chat options\n * @returns Promise with the created chat key\n */\n createChat(options: CreateChatOptions): Promise<CreateChatResponse>;\n\n /**\n * Load an existing chat and return the chat data directly\n * @param options - Load chat options\n * @returns Promise with the loaded chat data\n */\n loadChatData(options: LoadChatOptions): Promise<LoadChatResponse>;\n\n /**\n * Subscribe to incoming events\n * @param handler - Event handler function\n * @returns Unsubscribe function\n */\n onMessage(handler: EventHandler): Unsubscribe;\n\n /**\n * Subscribe to specific event type\n * @param eventType - Type of event to listen for\n * @param handler - Event handler function\n * @returns Unsubscribe function\n */\n on(eventType: string, handler: EventHandler): Unsubscribe;\n\n /**\n * Get current connection state\n */\n getState(): TransportState;\n\n /**\n * Get connection metrics\n */\n getMetrics(): ConnectionMetrics;\n\n /**\n * Get last error\n */\n getError(): TransportError | undefined;\n\n /**\n * Clear error state\n */\n clearError(): void;\n}\n\n/**\n * Transport factory function type\n */\nexport type TransportFactory = (config?: Partial<TransportConfig>) => ChatTransport;\n\n/**\n * Logger interface for transport debugging\n */\nexport interface TransportLogger {\n debug: (message: string, ...args: unknown[]) => void;\n info: (message: string, ...args: unknown[]) => void;\n warn: (message: string, ...args: unknown[]) => void;\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Create a default logger\n * @param debug - Enable debug logging\n */\nexport function createLogger(debug: boolean = false): TransportLogger {\n return {\n debug: debug ? console.log.bind(console, \"[chat]\") : () => {},\n info: console.info.bind(console, \"[chat]\"),\n warn: console.warn.bind(console, \"[chat]\"),\n error: console.error.bind(console, \"[chat]\"),\n };\n}\n\n/**\n * Default retry configuration\n */\nexport const DEFAULT_RETRY_CONFIG: Required<RetryConfig> = {\n maxRetries: 10,\n intervals: [1000, 2000, 5000],\n backoffMultiplier: 1.5,\n maxBackoffTime: 30000,\n};\n\n/**\n * Calculate retry interval with exponential backoff\n * @param retryCount - Current retry attempt number\n * @param config - Retry configuration\n */\nexport function calculateRetryInterval(\n retryCount: number,\n config: RetryConfig = DEFAULT_RETRY_CONFIG\n): number {\n const {\n intervals = DEFAULT_RETRY_CONFIG.intervals,\n backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,\n maxBackoffTime = DEFAULT_RETRY_CONFIG.maxBackoffTime,\n } = config;\n\n if (retryCount < intervals.length) {\n return intervals[retryCount];\n }\n\n const baseInterval = intervals[intervals.length - 1] || 5000;\n const backoffTime =\n baseInterval * Math.pow(backoffMultiplier, retryCount - intervals.length + 1);\n return Math.min(backoffTime, maxBackoffTime);\n}\n","/**\n * SSE Transport (Browser)\n *\n * Uses native EventSource for receiving server events and fetch POST for sending.\n * This is the default transport for browser environments.\n *\n * @example\n * ```typescript\n * import { createSSETransport } from \"@elqnt/chat/transport\";\n *\n * const transport = createSSETransport();\n * await transport.connect({ baseUrl, orgId, userId, clientType: \"customer\" });\n * ```\n */\n\nimport type { Chat, ChatEvent, ChatMessage } from \"../models\";\nimport type {\n ChatTransport,\n TransportConfig,\n TransportState,\n TransportError,\n ConnectionMetrics,\n EventHandler,\n Unsubscribe,\n RetryConfig,\n TransportLogger,\n CreateChatOptions,\n CreateChatResponse,\n LoadChatOptions,\n LoadChatResponse,\n} from \"./types\";\nimport { createLogger, calculateRetryInterval, DEFAULT_RETRY_CONFIG, resolveTransportToken } from \"./types\";\n\n/**\n * SSE Transport options\n */\nexport interface SSETransportOptions {\n /** Retry configuration */\n retryConfig?: RetryConfig;\n /** Enable debug logging */\n debug?: boolean;\n /** Custom logger */\n logger?: TransportLogger;\n}\n\n/**\n * Create an SSE transport for browser environments\n */\nexport function createSSETransport(options: SSETransportOptions = {}): ChatTransport {\n const {\n retryConfig = DEFAULT_RETRY_CONFIG,\n debug = false,\n logger = createLogger(debug),\n } = options;\n\n // Internal state\n let eventSource: EventSource | undefined;\n let config: TransportConfig | undefined;\n let state: TransportState = \"disconnected\";\n let error: TransportError | undefined;\n let retryCount = 0;\n let reconnectTimeout: ReturnType<typeof setTimeout> | undefined;\n let intentionalDisconnect = false;\n\n // Metrics\n const metrics: ConnectionMetrics = {\n latency: 0,\n messagesSent: 0,\n messagesReceived: 0,\n messagesQueued: 0,\n reconnectCount: 0,\n transportType: \"sse\",\n };\n\n // Event handlers\n const globalHandlers = new Set<EventHandler>();\n const typeHandlers = new Map<string, Set<EventHandler>>();\n\n // Helper to emit events\n function emit(event: ChatEvent): void {\n // Update metrics\n metrics.messagesReceived++;\n metrics.lastMessageAt = Date.now();\n\n // Call global handlers\n globalHandlers.forEach((handler) => {\n try {\n handler(event);\n } catch (err) {\n logger.error(\"Error in message handler:\", err);\n }\n });\n\n // Call type-specific handlers\n const handlers = typeHandlers.get(event.type);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(event);\n } catch (err) {\n logger.error(`Error in ${event.type} handler:`, err);\n }\n });\n }\n }\n\n // REST API helper\n async function sendRest(endpoint: string, body: Record<string, unknown>): Promise<unknown> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const url = `${config.baseUrl}/${endpoint}`;\n logger.debug(`POST ${endpoint}`, body);\n\n // Tier-2 authorization: attach the signed token as a bearer header.\n const token = await resolveTransportToken(config);\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`API error: ${response.status} - ${errorText}`);\n }\n\n const json = await response.json() as { success?: boolean; data?: unknown };\n\n // Backend wraps responses in { success: true, data: {...} }\n // Unwrap to return just the data\n if (json && typeof json === \"object\" && \"data\" in json) {\n return json.data;\n }\n\n return json;\n }\n\n // Handle SSE message\n function handleMessage(event: MessageEvent): void {\n if (!event.data || event.data === \"\") return;\n\n try {\n const data = JSON.parse(event.data) as ChatEvent;\n logger.debug(\"Received:\", data.type);\n emit(data);\n } catch (err) {\n logger.error(\"Failed to parse SSE message:\", err);\n }\n }\n\n // Setup SSE event listeners\n function setupEventListeners(es: EventSource): void {\n // Generic message handler\n es.addEventListener(\"message\", handleMessage);\n\n // Add handlers for known event types.\n // Note \"error\": the server emits failed-turn notices as named `event:\n // error` SSE events. EventSource also fires a native data-less \"error\"\n // event on connection problems — handleMessage's empty-data guard\n // filters those out, so registering here is safe.\n // The server names EVERY SSE event (event: <type>), and EventSource\n // only fires listeners that were registered by name — any type missing\n // here is silently dropped. Keep this in sync with the server→client\n // types in ChatEventTypeTS; registering an unused name is harmless.\n const eventTypes = [\n \"error\",\n \"reconnected\", \"typing\", \"stopped_typing\", \"waiting\",\n \"waiting_for_agent\", \"human_agent_joined\", \"human_agent_left\",\n \"chat_ended\", \"chat_updated\", \"chat_removed\", \"load_chat_response\",\n \"new_chat_created\", \"show_csat_survey\", \"csat_response\",\n \"user_suggested_actions\", \"user_suggested_action_selected\",\n \"agent_execution_started\", \"agent_execution_ended\",\n \"agent_context_update\", \"load_agent_context_response\",\n \"plan_pending_approval\", \"plan_approved\", \"plan_rejected\",\n \"step_started\", \"step_completed\", \"step_failed\", \"plan_completed\",\n \"skills_changed\", \"summary_update\",\n \"message_status_update\", \"delivered\", \"read\",\n \"sync_metadata_response\", \"sync_user_session_response\",\n \"client_action\", \"client_action_callback\",\n \"attachment_processing_started\", \"attachment_processing_progress\",\n \"attachment_processing_complete\", \"attachment_processing_error\",\n \"observer_joined\", \"observer_left\", \"block_user\",\n \"message_edited\", \"message_deleted\", \"message_reaction\",\n \"user_presence_changed\", \"online_users\", \"get_agents_response\",\n \"room_created\", \"room_updated\", \"room_deleted\", \"rooms_response\",\n \"room_user_joined\", \"room_user_left\", \"user_invited\",\n ];\n\n eventTypes.forEach((type) => {\n es.addEventListener(type, handleMessage);\n });\n }\n\n // Schedule reconnect\n function scheduleReconnect(): void {\n if (intentionalDisconnect || !config) return;\n\n const maxRetries = retryConfig.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries;\n if (retryCount >= maxRetries) {\n logger.error(`Max retries (${maxRetries}) exceeded`);\n error = {\n code: \"CONNECTION_FAILED\",\n message: `Max retries (${maxRetries}) exceeded`,\n retryable: false,\n timestamp: Date.now(),\n };\n return;\n }\n\n const interval = calculateRetryInterval(retryCount, retryConfig);\n retryCount++;\n metrics.reconnectCount++;\n\n logger.info(`Reconnecting in ${interval}ms (attempt ${retryCount})`);\n state = \"reconnecting\";\n\n reconnectTimeout = setTimeout(() => {\n if (config) {\n transport.connect(config).catch((err) => {\n logger.error(\"Reconnect failed:\", err);\n });\n }\n }, interval);\n }\n\n const transport: ChatTransport = {\n async connect(cfg: TransportConfig): Promise<void> {\n config = cfg;\n intentionalDisconnect = false;\n\n // Clean up existing connection\n if (eventSource) {\n eventSource.close();\n eventSource = undefined;\n }\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout);\n reconnectTimeout = undefined;\n }\n\n state = retryCount > 0 ? \"reconnecting\" : \"connecting\";\n\n // Resolve a fresh token BEFORE opening the stream. EventSource cannot set\n // headers, so the token must ride as a ?token= query param — the chat\n // service reads it there (the gateway uses the same pattern for SSE).\n const connectToken = await resolveTransportToken(cfg);\n\n return new Promise((resolve, reject) => {\n const connectionStart = Date.now();\n // URLSearchParams encodes reserved characters — a raw \"+\" in a\n // userId email decodes server-side to a space, silently breaking\n // targeted delivery (connection registered under the wrong user).\n const streamParams = new URLSearchParams({\n orgId: cfg.orgId,\n userId: cfg.userId,\n clientType: cfg.clientType,\n });\n if (cfg.chatKey) streamParams.set(\"chatId\", cfg.chatKey);\n if (connectToken) streamParams.set(\"token\", connectToken);\n const url = `${cfg.baseUrl}/stream?${streamParams.toString()}`;\n\n logger.debug(\"Connecting to:\", url);\n const es = new EventSource(url);\n\n es.onopen = () => {\n const connectionTime = Date.now() - connectionStart;\n logger.info(`Connected in ${connectionTime}ms`);\n\n const wasReconnect = retryCount > 0;\n state = \"connected\";\n error = undefined;\n retryCount = 0;\n metrics.connectedAt = Date.now();\n metrics.latency = connectionTime;\n\n setupEventListeners(es);\n\n // Synthetic event so the app layer can re-sync chat state —\n // broadcasts emitted while the stream was down are gone for good.\n if (wasReconnect) {\n emit({\n type: \"transport_reconnected\",\n orgId: cfg.orgId,\n chatKey: cfg.chatKey || \"\",\n userId: cfg.userId,\n timestamp: Date.now(),\n } as ChatEvent);\n }\n\n resolve();\n };\n\n es.onerror = () => {\n if (es.readyState === EventSource.CLOSED) {\n const sseError: TransportError = {\n code: \"CONNECTION_FAILED\",\n message: \"SSE connection failed\",\n retryable: true,\n timestamp: Date.now(),\n };\n error = sseError;\n metrics.lastError = sseError;\n state = \"disconnected\";\n\n if (!intentionalDisconnect) {\n scheduleReconnect();\n }\n\n // Only reject if this is the initial connection attempt\n if (retryCount === 0) {\n reject(sseError);\n }\n }\n };\n\n eventSource = es;\n });\n },\n\n disconnect(intentional = true): void {\n logger.info(\"Disconnecting\", { intentional });\n intentionalDisconnect = intentional;\n\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout);\n reconnectTimeout = undefined;\n }\n\n if (eventSource) {\n eventSource.close();\n eventSource = undefined;\n }\n\n state = \"disconnected\";\n retryCount = 0;\n },\n\n async send(event: ChatEvent): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n // Map event types to REST endpoints\n switch (event.type) {\n case \"message\":\n await sendRest(\"send\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n message: event.message,\n ...(event.data ? { data: event.data } : {}),\n });\n break;\n\n case \"typing\":\n await sendRest(\"typing\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n typing: true,\n });\n break;\n\n case \"stopped_typing\":\n await sendRest(\"typing\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n typing: false,\n });\n break;\n\n case \"load_chat\":\n // Deprecated: Use loadChatData() instead for direct response\n await sendRest(\"load\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n });\n break;\n\n case \"new_chat\":\n // Deprecated: Use createChat() instead for direct response\n await sendRest(\"create\", {\n orgId: event.orgId,\n userId: event.userId,\n metadata: event.data,\n });\n break;\n\n case \"end_chat\":\n await sendRest(\"end\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n data: event.data,\n });\n break;\n\n default:\n // Generic event endpoint for other types\n await sendRest(\"event\", {\n type: event.type,\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n data: event.data,\n });\n }\n\n metrics.messagesSent++;\n },\n\n async sendMessage(message: ChatMessage): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n await sendRest(\"send\", {\n orgId: config.orgId,\n chatKey: config.chatKey,\n userId: config.userId,\n message,\n });\n\n metrics.messagesSent++;\n },\n\n async createChat(options: CreateChatOptions): Promise<CreateChatResponse> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const response = await sendRest(\"create\", {\n orgId: options.orgId,\n userId: options.userId,\n metadata: options.metadata,\n }) as { chatKey?: string };\n\n if (!response?.chatKey) {\n throw new Error(\"Failed to create chat: no chatKey returned\");\n }\n\n return { chatKey: response.chatKey };\n },\n\n async loadChatData(options: LoadChatOptions): Promise<LoadChatResponse> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const response = await sendRest(\"load\", {\n orgId: options.orgId,\n chatKey: options.chatKey,\n userId: options.userId,\n }) as { chat?: unknown; agentId?: string };\n\n if (!response?.chat) {\n throw new Error(\"Failed to load chat: no chat data returned\");\n }\n\n return {\n chat: response.chat as Chat,\n agentId: response.agentId,\n };\n },\n\n onMessage(handler: EventHandler): Unsubscribe {\n globalHandlers.add(handler);\n return () => globalHandlers.delete(handler);\n },\n\n on(eventType: string, handler: EventHandler): Unsubscribe {\n if (!typeHandlers.has(eventType)) {\n typeHandlers.set(eventType, new Set());\n }\n typeHandlers.get(eventType)!.add(handler);\n return () => {\n const handlers = typeHandlers.get(eventType);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n typeHandlers.delete(eventType);\n }\n }\n };\n },\n\n getState(): TransportState {\n return state;\n },\n\n getMetrics(): ConnectionMetrics {\n return { ...metrics };\n },\n\n getError(): TransportError | undefined {\n return error;\n },\n\n clearError(): void {\n error = undefined;\n },\n };\n\n return transport;\n}\n","/**\n * SSE Transport (Fetch-based)\n *\n * Uses fetch with ReadableStream for receiving server events and fetch POST for sending.\n * Designed for React Native and environments without native EventSource support.\n *\n * @example\n * ```typescript\n * import { createFetchSSETransport } from \"@elqnt/chat/transport\";\n *\n * const transport = createFetchSSETransport();\n * await transport.connect({ baseUrl, orgId, userId, clientType: \"customer\" });\n * ```\n */\n\nimport type { Chat, ChatEvent, ChatMessage } from \"../models\";\nimport type {\n ChatTransport,\n TransportConfig,\n TransportState,\n TransportError,\n ConnectionMetrics,\n EventHandler,\n Unsubscribe,\n RetryConfig,\n TransportLogger,\n CreateChatOptions,\n CreateChatResponse,\n LoadChatOptions,\n LoadChatResponse,\n} from \"./types\";\nimport { createLogger, calculateRetryInterval, DEFAULT_RETRY_CONFIG, resolveTransportToken } from \"./types\";\n\n/**\n * Fetch SSE Transport options\n */\nexport interface FetchSSETransportOptions {\n /** Retry configuration */\n retryConfig?: RetryConfig;\n /** Enable debug logging */\n debug?: boolean;\n /** Custom logger */\n logger?: TransportLogger;\n /** Custom fetch implementation (useful for React Native) */\n customFetch?: typeof fetch;\n}\n\n/**\n * Create a fetch-based SSE transport for React Native and polyfill environments\n */\nexport function createFetchSSETransport(options: FetchSSETransportOptions = {}): ChatTransport {\n const {\n retryConfig = DEFAULT_RETRY_CONFIG,\n debug = false,\n logger = createLogger(debug),\n customFetch = fetch,\n } = options;\n\n // Internal state\n let abortController: AbortController | undefined;\n let config: TransportConfig | undefined;\n let state: TransportState = \"disconnected\";\n let error: TransportError | undefined;\n let retryCount = 0;\n let reconnectTimeout: ReturnType<typeof setTimeout> | undefined;\n let intentionalDisconnect = false;\n\n // Metrics\n const metrics: ConnectionMetrics = {\n latency: 0,\n messagesSent: 0,\n messagesReceived: 0,\n messagesQueued: 0,\n reconnectCount: 0,\n transportType: \"sse-fetch\",\n };\n\n // Event handlers\n const globalHandlers = new Set<EventHandler>();\n const typeHandlers = new Map<string, Set<EventHandler>>();\n\n // Helper to emit events\n function emit(event: ChatEvent): void {\n metrics.messagesReceived++;\n metrics.lastMessageAt = Date.now();\n\n globalHandlers.forEach((handler) => {\n try {\n handler(event);\n } catch (err) {\n logger.error(\"Error in message handler:\", err);\n }\n });\n\n const handlers = typeHandlers.get(event.type);\n if (handlers) {\n handlers.forEach((handler) => {\n try {\n handler(event);\n } catch (err) {\n logger.error(`Error in ${event.type} handler:`, err);\n }\n });\n }\n }\n\n // REST API helper\n async function sendRest(endpoint: string, body: Record<string, unknown>): Promise<unknown> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const url = `${config.baseUrl}/${endpoint}`;\n logger.debug(`POST ${endpoint}`, body);\n\n // Tier-2 authorization: attach the signed token as a bearer header.\n const token = await resolveTransportToken(config);\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n\n const response = await customFetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`API error: ${response.status} - ${errorText}`);\n }\n\n const json = await response.json() as { success?: boolean; data?: unknown };\n\n // Backend wraps responses in { success: true, data: {...} }\n // Unwrap to return just the data\n if (json && typeof json === \"object\" && \"data\" in json) {\n return json.data;\n }\n\n return json;\n }\n\n // Parse SSE data from a text chunk\n function parseSSEChunk(chunk: string): ChatEvent[] {\n const events: ChatEvent[] = [];\n const lines = chunk.split(\"\\n\");\n\n let eventType = \"message\";\n let data = \"\";\n\n for (const line of lines) {\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n data = line.slice(5).trim();\n } else if (line === \"\" && data) {\n // End of event\n try {\n const parsed = JSON.parse(data) as ChatEvent;\n events.push(parsed);\n } catch {\n logger.warn(\"Failed to parse SSE data:\", data);\n }\n eventType = \"message\";\n data = \"\";\n }\n }\n\n return events;\n }\n\n // Start SSE stream using fetch\n async function startStream(cfg: TransportConfig): Promise<void> {\n // URLSearchParams encodes reserved characters — a raw \"+\" in a userId\n // email decodes server-side to a space, silently breaking targeted\n // delivery (connection registered under the wrong user).\n const streamParams = new URLSearchParams({\n orgId: cfg.orgId,\n userId: cfg.userId,\n clientType: cfg.clientType,\n });\n if (cfg.chatKey) streamParams.set(\"chatId\", cfg.chatKey);\n // Tier-2 authorization. fetch CAN set headers, but we also pass ?token=\n // for parity with EventSource and so the same server query path works.\n const token = await resolveTransportToken(cfg);\n if (token) streamParams.set(\"token\", token);\n const url = `${cfg.baseUrl}/stream?${streamParams.toString()}`;\n\n logger.debug(\"Connecting to:\", url);\n\n abortController = new AbortController();\n\n const streamHeaders: Record<string, string> = {\n Accept: \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n };\n if (token) streamHeaders[\"Authorization\"] = `Bearer ${token}`;\n\n const response = await customFetch(url, {\n method: \"GET\",\n headers: streamHeaders,\n signal: abortController.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Stream connection failed: ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error(\"Response body is null - ReadableStream not supported\");\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n // Read stream in background\n const readStream = async () => {\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n logger.info(\"Stream ended\");\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete events in buffer\n const lastNewline = buffer.lastIndexOf(\"\\n\\n\");\n if (lastNewline !== -1) {\n const complete = buffer.slice(0, lastNewline + 2);\n buffer = buffer.slice(lastNewline + 2);\n\n const events = parseSSEChunk(complete);\n events.forEach(emit);\n }\n }\n } catch (err) {\n if ((err as Error).name === \"AbortError\") {\n logger.debug(\"Stream aborted\");\n return;\n }\n logger.error(\"Stream error:\", err);\n throw err;\n }\n\n // Stream closed - handle reconnection\n if (!intentionalDisconnect) {\n state = \"disconnected\";\n scheduleReconnect();\n }\n };\n\n // Start reading in background\n readStream().catch((err) => {\n if (!intentionalDisconnect) {\n error = {\n code: \"CONNECTION_FAILED\",\n message: err.message,\n retryable: true,\n timestamp: Date.now(),\n originalError: err,\n };\n metrics.lastError = error;\n state = \"disconnected\";\n scheduleReconnect();\n }\n });\n }\n\n // Schedule reconnect\n function scheduleReconnect(): void {\n if (intentionalDisconnect || !config) return;\n\n const maxRetries = retryConfig.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries;\n if (retryCount >= maxRetries) {\n logger.error(`Max retries (${maxRetries}) exceeded`);\n error = {\n code: \"CONNECTION_FAILED\",\n message: `Max retries (${maxRetries}) exceeded`,\n retryable: false,\n timestamp: Date.now(),\n };\n return;\n }\n\n const interval = calculateRetryInterval(retryCount, retryConfig);\n retryCount++;\n metrics.reconnectCount++;\n\n logger.info(`Reconnecting in ${interval}ms (attempt ${retryCount})`);\n state = \"reconnecting\";\n\n reconnectTimeout = setTimeout(() => {\n if (config) {\n transport.connect(config).catch((err) => {\n logger.error(\"Reconnect failed:\", err);\n });\n }\n }, interval);\n }\n\n const transport: ChatTransport = {\n async connect(cfg: TransportConfig): Promise<void> {\n config = cfg;\n intentionalDisconnect = false;\n\n // Clean up existing connection\n if (abortController) {\n abortController.abort();\n abortController = undefined;\n }\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout);\n reconnectTimeout = undefined;\n }\n\n state = retryCount > 0 ? \"reconnecting\" : \"connecting\";\n const connectionStart = Date.now();\n\n try {\n const wasReconnect = retryCount > 0;\n await startStream(cfg);\n\n const connectionTime = Date.now() - connectionStart;\n logger.info(`Connected in ${connectionTime}ms`);\n\n state = \"connected\";\n error = undefined;\n retryCount = 0;\n metrics.connectedAt = Date.now();\n metrics.latency = connectionTime;\n\n // Synthetic event so the app layer can re-sync chat state —\n // broadcasts emitted while the stream was down are gone for good.\n if (wasReconnect) {\n emit({\n type: \"transport_reconnected\",\n orgId: cfg.orgId,\n chatKey: cfg.chatKey || \"\",\n userId: cfg.userId,\n timestamp: Date.now(),\n } as ChatEvent);\n }\n } catch (err) {\n const connectError: TransportError = {\n code: \"CONNECTION_FAILED\",\n message: (err as Error).message,\n retryable: true,\n timestamp: Date.now(),\n originalError: err,\n };\n error = connectError;\n metrics.lastError = connectError;\n state = \"disconnected\";\n\n if (!intentionalDisconnect) {\n scheduleReconnect();\n }\n\n throw connectError;\n }\n },\n\n disconnect(intentional = true): void {\n logger.info(\"Disconnecting\", { intentional });\n intentionalDisconnect = intentional;\n\n if (reconnectTimeout) {\n clearTimeout(reconnectTimeout);\n reconnectTimeout = undefined;\n }\n\n if (abortController) {\n abortController.abort();\n abortController = undefined;\n }\n\n state = \"disconnected\";\n retryCount = 0;\n },\n\n async send(event: ChatEvent): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n switch (event.type) {\n case \"message\":\n await sendRest(\"send\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n message: event.message,\n ...(event.data ? { data: event.data } : {}),\n });\n break;\n\n case \"typing\":\n await sendRest(\"typing\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n typing: true,\n });\n break;\n\n case \"stopped_typing\":\n await sendRest(\"typing\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n typing: false,\n });\n break;\n\n case \"load_chat\":\n await sendRest(\"load\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n });\n break;\n\n case \"new_chat\":\n await sendRest(\"create\", {\n orgId: event.orgId,\n userId: event.userId,\n metadata: event.data,\n });\n break;\n\n case \"end_chat\":\n await sendRest(\"end\", {\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n data: event.data,\n });\n break;\n\n default:\n await sendRest(\"event\", {\n type: event.type,\n orgId: event.orgId,\n chatKey: event.chatKey,\n userId: event.userId,\n data: event.data,\n });\n }\n\n metrics.messagesSent++;\n },\n\n async sendMessage(message: ChatMessage): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n await sendRest(\"send\", {\n orgId: config.orgId,\n chatKey: config.chatKey,\n userId: config.userId,\n message,\n });\n\n metrics.messagesSent++;\n },\n\n async createChat(options: CreateChatOptions): Promise<CreateChatResponse> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const response = await sendRest(\"create\", {\n orgId: options.orgId,\n userId: options.userId,\n metadata: options.metadata,\n }) as { chatKey?: string };\n\n if (!response?.chatKey) {\n throw new Error(\"Failed to create chat: no chatKey returned\");\n }\n\n return { chatKey: response.chatKey };\n },\n\n async loadChatData(options: LoadChatOptions): Promise<LoadChatResponse> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n const response = await sendRest(\"load\", {\n orgId: options.orgId,\n chatKey: options.chatKey,\n userId: options.userId,\n }) as { chat?: unknown; agentId?: string };\n\n if (!response?.chat) {\n throw new Error(\"Failed to load chat: no chat data returned\");\n }\n\n return {\n chat: response.chat as Chat,\n agentId: response.agentId,\n };\n },\n\n onMessage(handler: EventHandler): Unsubscribe {\n globalHandlers.add(handler);\n return () => globalHandlers.delete(handler);\n },\n\n on(eventType: string, handler: EventHandler): Unsubscribe {\n if (!typeHandlers.has(eventType)) {\n typeHandlers.set(eventType, new Set());\n }\n typeHandlers.get(eventType)!.add(handler);\n return () => {\n const handlers = typeHandlers.get(eventType);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n typeHandlers.delete(eventType);\n }\n }\n };\n },\n\n getState(): TransportState {\n return state;\n },\n\n getMetrics(): ConnectionMetrics {\n return { ...metrics };\n },\n\n getError(): TransportError | undefined {\n return error;\n },\n\n clearError(): void {\n error = undefined;\n },\n };\n\n return transport;\n}\n","/**\n * WhatsApp Business API Transport (Stub)\n *\n * This module provides the interface for integrating with WhatsApp Business API.\n * The implementation connects to a webhook receiver that bridges WhatsApp messages\n * to the chat system.\n *\n * ## Integration Architecture\n *\n * ```\n * WhatsApp User → WhatsApp Cloud API → Your Webhook → Chat Service → SSE to Admin\n * ↓\n * NATS Events\n * ```\n *\n * ## Setup Requirements\n *\n * 1. Register a WhatsApp Business Account\n * 2. Create a Meta Business App with WhatsApp integration\n * 3. Configure webhook URL pointing to your chat service\n * 4. Set up message templates for outbound messages\n *\n * ## Backend Integration\n *\n * Your backend should expose webhook endpoints that:\n * - Verify webhook (GET /webhook with hub.verify_token)\n * - Receive messages (POST /webhook with message payload)\n * - Map WhatsApp user IDs to chat users\n * - Create/load chats for new conversations\n *\n * @example Backend Webhook Handler (Go)\n * ```go\n * func HandleWhatsAppWebhook(w http.ResponseWriter, r *http.Request) {\n * if r.Method == \"GET\" {\n * // Webhook verification\n * verifyToken := r.URL.Query().Get(\"hub.verify_token\")\n * if verifyToken == os.Getenv(\"WHATSAPP_VERIFY_TOKEN\") {\n * w.Write([]byte(r.URL.Query().Get(\"hub.challenge\")))\n * return\n * }\n * http.Error(w, \"Invalid verify token\", 403)\n * return\n * }\n *\n * // Handle incoming message\n * var payload WhatsAppPayload\n * json.NewDecoder(r.Body).Decode(&payload)\n *\n * // Map to chat event and publish to NATS\n * chatEvent := mapWhatsAppToChatEvent(payload)\n * natsClient.Publish(\"chat.events\", chatEvent)\n * }\n * ```\n *\n * @see https://developers.facebook.com/docs/whatsapp/cloud-api\n */\n\nimport type {\n ChatTransport,\n TransportConfig,\n TransportState,\n TransportError,\n ConnectionMetrics,\n EventHandler,\n Unsubscribe,\n TransportLogger,\n CreateChatOptions,\n CreateChatResponse,\n LoadChatOptions,\n LoadChatResponse,\n} from \"./types\";\nimport type { Chat, ChatEvent, ChatMessage, Attachment, AttachmentTypeTS } from \"../models\";\nimport { createLogger } from \"./types\";\n\n/**\n * WhatsApp transport configuration\n */\nexport interface WhatsAppTransportConfig extends TransportConfig {\n /** WhatsApp Business API access token */\n accessToken: string;\n /** Phone number ID from Meta Business */\n phoneNumberId: string;\n /** Webhook verify token for setup */\n verifyToken?: string;\n}\n\n/**\n * WhatsApp transport options\n */\nexport interface WhatsAppTransportOptions {\n /** Enable debug logging */\n debug?: boolean;\n /** Custom logger */\n logger?: TransportLogger;\n}\n\n/**\n * WhatsApp message types\n */\nexport type WhatsAppMessageType =\n | \"text\"\n | \"image\"\n | \"document\"\n | \"audio\"\n | \"video\"\n | \"sticker\"\n | \"location\"\n | \"contacts\"\n | \"interactive\"\n | \"template\";\n\n/**\n * Create a WhatsApp Business API transport\n *\n * NOTE: This is a stub implementation. The actual WhatsApp integration\n * happens on the backend via webhooks. This transport is for:\n * - Type definitions\n * - Documentation\n * - Future client-side WhatsApp Web integration\n */\nexport function createWhatsAppTransport(\n options: WhatsAppTransportOptions = {}\n): ChatTransport {\n const { debug = false, logger = createLogger(debug) } = options;\n\n let state: TransportState = \"disconnected\";\n let error: TransportError | undefined;\n let config: WhatsAppTransportConfig | undefined;\n\n const metrics: ConnectionMetrics = {\n latency: 0,\n messagesSent: 0,\n messagesReceived: 0,\n messagesQueued: 0,\n reconnectCount: 0,\n transportType: \"whatsapp\",\n };\n\n const globalHandlers = new Set<EventHandler>();\n const typeHandlers = new Map<string, Set<EventHandler>>();\n\n const transport: ChatTransport = {\n async connect(cfg: TransportConfig): Promise<void> {\n logger.warn(\n \"WhatsApp transport is a stub. WhatsApp integration happens via backend webhooks.\"\n );\n logger.info(\n \"See transport/whatsapp.ts for integration documentation.\"\n );\n\n config = cfg as WhatsAppTransportConfig;\n\n // In a real implementation, this would:\n // 1. Validate WhatsApp Business API credentials\n // 2. Register webhook endpoints\n // 3. Set up SSE connection to receive webhook-relayed events\n\n state = \"connected\";\n metrics.connectedAt = Date.now();\n },\n\n disconnect(): void {\n state = \"disconnected\";\n },\n\n async send(event: ChatEvent): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n logger.warn(\"WhatsApp send is a stub. Implement backend webhook relay.\");\n\n // In a real implementation, this would:\n // 1. Convert ChatEvent to WhatsApp message format\n // 2. Call WhatsApp Cloud API to send message\n // 3. Handle delivery receipts\n\n metrics.messagesSent++;\n },\n\n async sendMessage(message: ChatMessage): Promise<void> {\n if (!config) {\n throw new Error(\"Transport not connected\");\n }\n\n logger.warn(\n \"WhatsApp sendMessage is a stub. Implement backend webhook relay.\"\n );\n\n // In a real implementation:\n // POST https://graph.facebook.com/v17.0/{phone_number_id}/messages\n // {\n // \"messaging_product\": \"whatsapp\",\n // \"to\": \"{recipient_phone}\",\n // \"type\": \"text\",\n // \"text\": { \"body\": message.content }\n // }\n\n metrics.messagesSent++;\n },\n\n async createChat(options: CreateChatOptions): Promise<CreateChatResponse> {\n logger.warn(\n \"WhatsApp createChat is a stub. WhatsApp chats are created via incoming webhooks.\"\n );\n\n // In WhatsApp, chats are typically initiated by users messaging first.\n // This stub returns a placeholder - real implementation would create\n // a chat record on the backend for outbound messaging.\n return { chatKey: `whatsapp_${options.userId}_${Date.now()}` };\n },\n\n async loadChatData(options: LoadChatOptions): Promise<LoadChatResponse> {\n logger.warn(\n \"WhatsApp loadChatData is a stub. Implement backend API call.\"\n );\n\n // In a real implementation, this would fetch chat data from the backend\n return {\n chat: {\n orgId: options.orgId,\n key: options.chatKey,\n title: \"WhatsApp Chat\",\n messages: [],\n lastUpdated: Date.now(),\n startTime: Date.now(),\n users: [],\n status: \"active\",\n aiEngaged: false,\n humanAgentEngaged: false,\n isWaiting: false,\n isWaitingForAgent: false,\n } as Chat,\n };\n },\n\n onMessage(handler: EventHandler): Unsubscribe {\n globalHandlers.add(handler);\n return () => globalHandlers.delete(handler);\n },\n\n on(eventType: string, handler: EventHandler): Unsubscribe {\n if (!typeHandlers.has(eventType)) {\n typeHandlers.set(eventType, new Set());\n }\n typeHandlers.get(eventType)!.add(handler);\n return () => {\n const handlers = typeHandlers.get(eventType);\n if (handlers) {\n handlers.delete(handler);\n if (handlers.size === 0) {\n typeHandlers.delete(eventType);\n }\n }\n };\n },\n\n getState(): TransportState {\n return state;\n },\n\n getMetrics(): ConnectionMetrics {\n return { ...metrics };\n },\n\n getError(): TransportError | undefined {\n return error;\n },\n\n clearError(): void {\n error = undefined;\n },\n };\n\n return transport;\n}\n\n/**\n * Helper: Convert WhatsApp webhook payload to ChatEvent\n *\n * Use this in your backend webhook handler to map incoming\n * WhatsApp messages to the chat system format.\n */\nexport interface WhatsAppWebhookPayload {\n object: \"whatsapp_business_account\";\n entry: Array<{\n id: string;\n changes: Array<{\n value: {\n messaging_product: \"whatsapp\";\n metadata: {\n display_phone_number: string;\n phone_number_id: string;\n };\n contacts?: Array<{\n profile: { name: string };\n wa_id: string;\n }>;\n messages?: Array<{\n from: string;\n id: string;\n timestamp: string;\n type: WhatsAppMessageType;\n text?: { body: string };\n image?: { id: string; mime_type: string; sha256: string };\n document?: { id: string; mime_type: string; filename: string };\n audio?: { id: string; mime_type: string };\n video?: { id: string; mime_type: string };\n location?: { latitude: number; longitude: number; name?: string };\n }>;\n statuses?: Array<{\n id: string;\n status: \"sent\" | \"delivered\" | \"read\" | \"failed\";\n timestamp: string;\n recipient_id: string;\n }>;\n };\n }>;\n }>;\n}\n\n/**\n * Example: Map WhatsApp payload to ChatEvent (for backend use)\n *\n * @example\n * ```typescript\n * // In your backend webhook handler\n * import { mapWhatsAppToChatEvent } from \"@elqnt/chat/transport\";\n *\n * app.post(\"/webhook/whatsapp\", (req, res) => {\n * const events = mapWhatsAppToChatEvent(req.body, orgId);\n * events.forEach(event => publishToChatService(event));\n * res.sendStatus(200);\n * });\n * ```\n */\nexport function mapWhatsAppToChatEvent(\n payload: WhatsAppWebhookPayload,\n orgId: string\n): ChatEvent[] {\n const events: ChatEvent[] = [];\n\n for (const entry of payload.entry) {\n for (const change of entry.changes) {\n const value = change.value;\n\n // Handle incoming messages\n if (value.messages) {\n for (const msg of value.messages) {\n const contact = value.contacts?.find((c) => c.wa_id === msg.from);\n\n events.push({\n type: \"message\",\n orgId,\n chatKey: `wa_${msg.from}`, // Use phone number as chat key\n userId: msg.from,\n timestamp: parseInt(msg.timestamp) * 1000,\n message: {\n id: msg.id,\n role: \"user\",\n content: msg.text?.body || \"\",\n time: parseInt(msg.timestamp) * 1000,\n status: \"delivered\",\n senderId: msg.from,\n senderName: contact?.profile.name,\n createdAt: parseInt(msg.timestamp) * 1000,\n // Map attachments if present\n attachments: mapWhatsAppAttachments(msg),\n },\n });\n }\n }\n\n // Handle message status updates\n if (value.statuses) {\n for (const status of value.statuses) {\n events.push({\n type: \"message_status_update\",\n orgId,\n chatKey: `wa_${status.recipient_id}`,\n userId: status.recipient_id,\n timestamp: parseInt(status.timestamp) * 1000,\n data: {\n messageId: status.id,\n status: status.status,\n },\n });\n }\n }\n }\n }\n\n return events;\n}\n\n// Helper to map WhatsApp attachments\nfunction mapWhatsAppAttachments(msg: {\n type: WhatsAppMessageType;\n image?: { id: string };\n document?: { id: string; filename: string };\n audio?: { id: string };\n video?: { id: string };\n location?: { latitude: number; longitude: number; name?: string };\n}): Attachment[] | undefined {\n switch (msg.type) {\n case \"image\":\n return msg.image\n ? [{ type: \"image\" as AttachmentTypeTS, url: `whatsapp://media/${msg.image.id}` }]\n : undefined;\n case \"document\":\n return msg.document\n ? [\n {\n type: \"document\" as AttachmentTypeTS,\n url: `whatsapp://media/${msg.document.id}`,\n },\n ]\n : undefined;\n case \"audio\":\n return msg.audio\n ? [{ type: \"audio\" as AttachmentTypeTS, url: `whatsapp://media/${msg.audio.id}` }]\n : undefined;\n case \"video\":\n return msg.video\n ? [{ type: \"video\" as AttachmentTypeTS, url: `whatsapp://media/${msg.video.id}` }]\n : undefined;\n case \"location\":\n return msg.location\n ? [\n {\n type: \"location\" as AttachmentTypeTS,\n url: `geo:${msg.location.latitude},${msg.location.longitude}`,\n },\n ]\n : undefined;\n default:\n return undefined;\n }\n}\n"],"mappings":"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","names":["options","options","options"]}
@@ -1,6 +1,16 @@
1
- "use client";
2
-
3
1
  // transport/types.ts
2
+ async function resolveTransportToken(cfg) {
3
+ if (!cfg) return void 0;
4
+ if (cfg.getToken) {
5
+ try {
6
+ const t = await cfg.getToken();
7
+ return t ?? void 0;
8
+ } catch {
9
+ return void 0;
10
+ }
11
+ }
12
+ return cfg.token ?? void 0;
13
+ }
4
14
  function createLogger(debug = false) {
5
15
  return {
6
16
  debug: debug ? console.log.bind(console, "[chat]") : () => {
@@ -81,9 +91,12 @@ function createSSETransport(options = {}) {
81
91
  }
82
92
  const url = `${config.baseUrl}/${endpoint}`;
83
93
  logger.debug(`POST ${endpoint}`, body);
94
+ const token = await resolveTransportToken(config);
95
+ const headers = { "Content-Type": "application/json" };
96
+ if (token) headers["Authorization"] = `Bearer ${token}`;
84
97
  const response = await fetch(url, {
85
98
  method: "POST",
86
- headers: { "Content-Type": "application/json" },
99
+ headers,
87
100
  body: JSON.stringify(body)
88
101
  });
89
102
  if (!response.ok) {
@@ -210,6 +223,7 @@ function createSSETransport(options = {}) {
210
223
  reconnectTimeout = void 0;
211
224
  }
212
225
  state = retryCount > 0 ? "reconnecting" : "connecting";
226
+ const connectToken = await resolveTransportToken(cfg);
213
227
  return new Promise((resolve, reject) => {
214
228
  const connectionStart = Date.now();
215
229
  const streamParams = new URLSearchParams({
@@ -218,6 +232,7 @@ function createSSETransport(options = {}) {
218
232
  clientType: cfg.clientType
219
233
  });
220
234
  if (cfg.chatKey) streamParams.set("chatId", cfg.chatKey);
235
+ if (connectToken) streamParams.set("token", connectToken);
221
236
  const url = `${cfg.baseUrl}/stream?${streamParams.toString()}`;
222
237
  logger.debug("Connecting to:", url);
223
238
  const es = new EventSource(url);
@@ -471,9 +486,12 @@ function createFetchSSETransport(options = {}) {
471
486
  }
472
487
  const url = `${config.baseUrl}/${endpoint}`;
473
488
  logger.debug(`POST ${endpoint}`, body);
489
+ const token = await resolveTransportToken(config);
490
+ const headers = { "Content-Type": "application/json" };
491
+ if (token) headers["Authorization"] = `Bearer ${token}`;
474
492
  const response = await customFetch(url, {
475
493
  method: "POST",
476
- headers: { "Content-Type": "application/json" },
494
+ headers,
477
495
  body: JSON.stringify(body)
478
496
  });
479
497
  if (!response.ok) {
@@ -516,15 +534,19 @@ function createFetchSSETransport(options = {}) {
516
534
  clientType: cfg.clientType
517
535
  });
518
536
  if (cfg.chatKey) streamParams.set("chatId", cfg.chatKey);
537
+ const token = await resolveTransportToken(cfg);
538
+ if (token) streamParams.set("token", token);
519
539
  const url = `${cfg.baseUrl}/stream?${streamParams.toString()}`;
520
540
  logger.debug("Connecting to:", url);
521
541
  abortController = new AbortController();
542
+ const streamHeaders = {
543
+ Accept: "text/event-stream",
544
+ "Cache-Control": "no-cache"
545
+ };
546
+ if (token) streamHeaders["Authorization"] = `Bearer ${token}`;
522
547
  const response = await customFetch(url, {
523
548
  method: "GET",
524
- headers: {
525
- Accept: "text/event-stream",
526
- "Cache-Control": "no-cache"
527
- },
549
+ headers: streamHeaders,
528
550
  signal: abortController.signal
529
551
  });
530
552
  if (!response.ok) {