@elqnt/chat 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -13
- package/dist/api/index.d.mts +2 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/hooks/index.d.mts +7 -3
- package/dist/hooks/index.d.ts +7 -3
- package/dist/hooks/index.js +62 -30
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +62 -30
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +62 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +62 -30
- package/dist/index.mjs.map +1 -1
- package/dist/models/index.d.mts +3 -20
- package/dist/models/index.d.ts +3 -20
- package/dist/models/index.js.map +1 -1
- package/dist/models/index.mjs.map +1 -1
- package/dist/transport/index.d.mts +4 -2
- package/dist/transport/index.d.ts +4 -2
- package/dist/transport/index.js +99 -2
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +99 -2
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-BB5nRdZs.d.mts → types-7UNI1iYv.d.ts} +29 -1
- package/dist/{types-CNvuxtcv.d.ts → types-CQHtUQ6p.d.mts} +29 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# @elqnt/chat
|
|
2
2
|
|
|
3
|
-
Platform-agnostic chat SDK for React and React Native. Uses
|
|
3
|
+
Platform-agnostic chat SDK for React and React Native. Uses HTTP + SSE for reliable real-time communication.
|
|
4
|
+
|
|
5
|
+
**Key Features:**
|
|
6
|
+
- **Mutations via HTTP** - `startChat()`, `loadChat()` return data directly (no waiting for SSE events)
|
|
7
|
+
- **Events via SSE** - Real-time messages, typing indicators, agent updates
|
|
8
|
+
- **Multi-transport** - Browser EventSource, React Native fetch-based SSE, WhatsApp webhooks
|
|
9
|
+
- **TypeScript-first** - Full type definitions for all models and events
|
|
4
10
|
|
|
5
11
|
## Installation
|
|
6
12
|
|
|
@@ -18,9 +24,11 @@ function ChatComponent() {
|
|
|
18
24
|
connect,
|
|
19
25
|
disconnect,
|
|
20
26
|
sendMessage,
|
|
27
|
+
startChat,
|
|
28
|
+
loadChat,
|
|
21
29
|
messages,
|
|
22
30
|
isConnected,
|
|
23
|
-
|
|
31
|
+
currentChat,
|
|
24
32
|
} = useChat({
|
|
25
33
|
baseUrl: "https://api.example.com/chat",
|
|
26
34
|
orgId: "org-123",
|
|
@@ -32,6 +40,18 @@ function ChatComponent() {
|
|
|
32
40
|
return () => disconnect();
|
|
33
41
|
}, []);
|
|
34
42
|
|
|
43
|
+
// Start a new chat - returns chatKey immediately
|
|
44
|
+
const handleNewChat = async () => {
|
|
45
|
+
const chatKey = await startChat({ agentId: "support-agent" });
|
|
46
|
+
console.log("Created chat:", chatKey);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Load existing chat - returns Chat immediately
|
|
50
|
+
const handleLoadChat = async (chatKey: string) => {
|
|
51
|
+
const chat = await loadChat(chatKey);
|
|
52
|
+
console.log("Loaded chat with", chat.messages.length, "messages");
|
|
53
|
+
};
|
|
54
|
+
|
|
35
55
|
const handleSend = async (text: string) => {
|
|
36
56
|
await sendMessage(text);
|
|
37
57
|
};
|
|
@@ -107,29 +127,34 @@ interface UseChatReturn {
|
|
|
107
127
|
connectionState: TransportState;
|
|
108
128
|
isConnected: boolean;
|
|
109
129
|
|
|
110
|
-
// Chat Operations
|
|
111
|
-
startChat: (metadata?: Record<string, unknown>) => Promise<string>;
|
|
112
|
-
loadChat: (chatKey: string) => Promise<
|
|
130
|
+
// Chat Operations (return data directly via HTTP)
|
|
131
|
+
startChat: (metadata?: Record<string, unknown>) => Promise<string>; // Returns chatKey
|
|
132
|
+
loadChat: (chatKey: string) => Promise<Chat>; // Returns loaded Chat
|
|
113
133
|
sendMessage: (content: string, attachments?: unknown[]) => Promise<void>;
|
|
134
|
+
sendEvent: (event: Omit<ChatEvent, "timestamp">) => Promise<void>;
|
|
114
135
|
endChat: (reason?: string) => Promise<void>;
|
|
115
136
|
|
|
116
137
|
// Typing Indicators
|
|
117
138
|
startTyping: () => void;
|
|
118
139
|
stopTyping: () => void;
|
|
119
140
|
|
|
120
|
-
// State
|
|
141
|
+
// State (auto-updated by hook)
|
|
121
142
|
currentChat: Chat | null;
|
|
122
143
|
chatKey: string | null;
|
|
123
144
|
messages: ChatMessage[];
|
|
124
145
|
error: TransportError | null;
|
|
125
146
|
metrics: ConnectionMetrics;
|
|
126
147
|
|
|
127
|
-
// Events
|
|
148
|
+
// Events (SSE push events)
|
|
128
149
|
on: (eventType: string, handler: (event: ChatEvent) => void) => () => void;
|
|
129
150
|
clearError: () => void;
|
|
130
151
|
}
|
|
131
152
|
```
|
|
132
153
|
|
|
154
|
+
> **Note:** `startChat()` and `loadChat()` use direct HTTP calls and return data immediately.
|
|
155
|
+
> You don't need to listen for `new_chat_created` or `load_chat_response` events - those are
|
|
156
|
+
> only broadcast for multi-tab synchronization.
|
|
157
|
+
|
|
133
158
|
### `/api` - Low-Level API Functions
|
|
134
159
|
|
|
135
160
|
```typescript
|
|
@@ -182,6 +207,10 @@ import type {
|
|
|
182
207
|
TransportState,
|
|
183
208
|
TransportError,
|
|
184
209
|
ConnectionMetrics,
|
|
210
|
+
CreateChatOptions,
|
|
211
|
+
CreateChatResponse,
|
|
212
|
+
LoadChatOptions,
|
|
213
|
+
LoadChatResponse,
|
|
185
214
|
} from "@elqnt/chat/transport";
|
|
186
215
|
```
|
|
187
216
|
|
|
@@ -225,15 +254,26 @@ Implement the `ChatTransport` interface for custom integrations:
|
|
|
225
254
|
import type { ChatTransport } from "@elqnt/chat/transport";
|
|
226
255
|
|
|
227
256
|
const customTransport: ChatTransport = {
|
|
257
|
+
// Connection
|
|
228
258
|
async connect(config) { /* ... */ },
|
|
229
259
|
disconnect() { /* ... */ },
|
|
260
|
+
|
|
261
|
+
// Mutations (return data directly)
|
|
262
|
+
async createChat(options) { /* returns { chatKey } */ },
|
|
263
|
+
async loadChatData(options) { /* returns { chat, agentId? } */ },
|
|
264
|
+
|
|
265
|
+
// Fire-and-forget operations
|
|
230
266
|
async send(event) { /* ... */ },
|
|
231
267
|
async sendMessage(message) { /* ... */ },
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
268
|
+
|
|
269
|
+
// Event subscriptions
|
|
270
|
+
onMessage(handler) { /* returns unsubscribe */ },
|
|
271
|
+
on(eventType, handler) { /* returns unsubscribe */ },
|
|
272
|
+
|
|
273
|
+
// State
|
|
274
|
+
getState() { /* returns TransportState */ },
|
|
275
|
+
getMetrics() { /* returns ConnectionMetrics */ },
|
|
276
|
+
getError() { /* returns TransportError | undefined */ },
|
|
237
277
|
clearError() { /* ... */ },
|
|
238
278
|
};
|
|
239
279
|
```
|
|
@@ -314,13 +354,20 @@ events.forEach(event => publishToChatService(event));
|
|
|
314
354
|
|
|
315
355
|
## Migration from v2
|
|
316
356
|
|
|
317
|
-
### Breaking Changes
|
|
357
|
+
### Breaking Changes in v3.0
|
|
318
358
|
|
|
319
359
|
1. **UI Components Removed** - Build your own UI
|
|
320
360
|
2. **Contexts Removed** - Use `useChat` hook directly
|
|
321
361
|
3. **WebSocket Removed** - SSE only (more reliable)
|
|
322
362
|
4. **Redux Integration Removed** - Use hook state
|
|
323
363
|
|
|
364
|
+
### Changes in v3.0.1
|
|
365
|
+
|
|
366
|
+
1. **`loadChat()` returns `Promise<Chat>`** - Previously returned `Promise<void>`, now returns the loaded chat directly
|
|
367
|
+
2. **`startChat()` returns immediately** - No longer waits for SSE event, returns chatKey from HTTP response
|
|
368
|
+
3. **Transport interface extended** - Added `createChat()` and `loadChatData()` methods for direct HTTP responses
|
|
369
|
+
4. **Event handlers simplified** - `new_chat_created` and `load_chat_response` events are now only for multi-tab sync
|
|
370
|
+
|
|
324
371
|
### Migration Steps
|
|
325
372
|
|
|
326
373
|
```tsx
|
package/dist/api/index.d.mts
CHANGED
package/dist/api/index.d.ts
CHANGED
package/dist/hooks/index.d.mts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ChatEvent, Chat, ChatMessage } from '../models/index.mjs';
|
|
2
|
-
import { C as ChatTransport, e as TransportError, g as TransportState, R as RetryConfig, b as ConnectionMetrics, U as Unsubscribe } from '../types-
|
|
2
|
+
import { C as ChatTransport, e as TransportError, g as TransportState, R as RetryConfig, b as ConnectionMetrics, U as Unsubscribe } from '../types-CQHtUQ6p.mjs';
|
|
3
|
+
import '@elqnt/kg';
|
|
3
4
|
import '@elqnt/types';
|
|
5
|
+
import '@elqnt/docs';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Chat hook options
|
|
@@ -43,10 +45,12 @@ interface UseChatReturn {
|
|
|
43
45
|
isConnected: boolean;
|
|
44
46
|
/** Start a new chat session */
|
|
45
47
|
startChat: (metadata?: Record<string, unknown>) => Promise<string>;
|
|
46
|
-
/** Load an existing chat */
|
|
47
|
-
loadChat: (chatKey: string) => Promise<
|
|
48
|
+
/** Load an existing chat, returns the loaded chat */
|
|
49
|
+
loadChat: (chatKey: string) => Promise<Chat>;
|
|
48
50
|
/** Send a text message */
|
|
49
51
|
sendMessage: (content: string, attachments?: unknown[]) => Promise<void>;
|
|
52
|
+
/** Send a raw chat event (for custom event types) */
|
|
53
|
+
sendEvent: (event: Omit<ChatEvent, "timestamp">) => Promise<void>;
|
|
50
54
|
/** End the current chat */
|
|
51
55
|
endChat: (reason?: string) => Promise<void>;
|
|
52
56
|
/** Signal that user is typing */
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ChatEvent, Chat, ChatMessage } from '../models/index.js';
|
|
2
|
-
import { C as ChatTransport, e as TransportError, g as TransportState, R as RetryConfig, b as ConnectionMetrics, U as Unsubscribe } from '../types-
|
|
2
|
+
import { C as ChatTransport, e as TransportError, g as TransportState, R as RetryConfig, b as ConnectionMetrics, U as Unsubscribe } from '../types-7UNI1iYv.js';
|
|
3
|
+
import '@elqnt/kg';
|
|
3
4
|
import '@elqnt/types';
|
|
5
|
+
import '@elqnt/docs';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Chat hook options
|
|
@@ -43,10 +45,12 @@ interface UseChatReturn {
|
|
|
43
45
|
isConnected: boolean;
|
|
44
46
|
/** Start a new chat session */
|
|
45
47
|
startChat: (metadata?: Record<string, unknown>) => Promise<string>;
|
|
46
|
-
/** Load an existing chat */
|
|
47
|
-
loadChat: (chatKey: string) => Promise<
|
|
48
|
+
/** Load an existing chat, returns the loaded chat */
|
|
49
|
+
loadChat: (chatKey: string) => Promise<Chat>;
|
|
48
50
|
/** Send a text message */
|
|
49
51
|
sendMessage: (content: string, attachments?: unknown[]) => Promise<void>;
|
|
52
|
+
/** Send a raw chat event (for custom event types) */
|
|
53
|
+
sendEvent: (event: Omit<ChatEvent, "timestamp">) => Promise<void>;
|
|
50
54
|
/** End the current chat */
|
|
51
55
|
endChat: (reason?: string) => Promise<void>;
|
|
52
56
|
/** Signal that user is typing */
|
package/dist/hooks/index.js
CHANGED
|
@@ -118,7 +118,11 @@ function createSSETransport(options = {}) {
|
|
|
118
118
|
const errorText = await response.text();
|
|
119
119
|
throw new Error(`API error: ${response.status} - ${errorText}`);
|
|
120
120
|
}
|
|
121
|
-
|
|
121
|
+
const json = await response.json();
|
|
122
|
+
if (json && typeof json === "object" && "data" in json) {
|
|
123
|
+
return json.data;
|
|
124
|
+
}
|
|
125
|
+
return json;
|
|
122
126
|
}
|
|
123
127
|
function handleMessage(event) {
|
|
124
128
|
if (!event.data || event.data === "") return;
|
|
@@ -327,6 +331,37 @@ function createSSETransport(options = {}) {
|
|
|
327
331
|
});
|
|
328
332
|
metrics.messagesSent++;
|
|
329
333
|
},
|
|
334
|
+
async createChat(options2) {
|
|
335
|
+
if (!config) {
|
|
336
|
+
throw new Error("Transport not connected");
|
|
337
|
+
}
|
|
338
|
+
const response = await sendRest("create", {
|
|
339
|
+
orgId: options2.orgId,
|
|
340
|
+
userId: options2.userId,
|
|
341
|
+
metadata: options2.metadata
|
|
342
|
+
});
|
|
343
|
+
if (!response?.chatKey) {
|
|
344
|
+
throw new Error("Failed to create chat: no chatKey returned");
|
|
345
|
+
}
|
|
346
|
+
return { chatKey: response.chatKey };
|
|
347
|
+
},
|
|
348
|
+
async loadChatData(options2) {
|
|
349
|
+
if (!config) {
|
|
350
|
+
throw new Error("Transport not connected");
|
|
351
|
+
}
|
|
352
|
+
const response = await sendRest("load", {
|
|
353
|
+
orgId: options2.orgId,
|
|
354
|
+
chatKey: options2.chatKey,
|
|
355
|
+
userId: options2.userId
|
|
356
|
+
});
|
|
357
|
+
if (!response?.chat) {
|
|
358
|
+
throw new Error("Failed to load chat: no chat data returned");
|
|
359
|
+
}
|
|
360
|
+
return {
|
|
361
|
+
chat: response.chat,
|
|
362
|
+
agentId: response.agentId
|
|
363
|
+
};
|
|
364
|
+
},
|
|
330
365
|
onMessage(handler) {
|
|
331
366
|
globalHandlers.add(handler);
|
|
332
367
|
return () => globalHandlers.delete(handler);
|
|
@@ -396,7 +431,6 @@ function useChat(options) {
|
|
|
396
431
|
const mountedRef = (0, import_react.useRef)(false);
|
|
397
432
|
const onMessageRef = (0, import_react.useRef)(onMessage);
|
|
398
433
|
const onErrorRef = (0, import_react.useRef)(onError);
|
|
399
|
-
const chatCreationResolverRef = (0, import_react.useRef)(null);
|
|
400
434
|
const typingTimeoutRef = (0, import_react.useRef)(null);
|
|
401
435
|
(0, import_react.useEffect)(() => {
|
|
402
436
|
onMessageRef.current = onMessage;
|
|
@@ -424,10 +458,6 @@ function useChat(options) {
|
|
|
424
458
|
const newChatKey = event.data?.chatKey;
|
|
425
459
|
if (newChatKey) {
|
|
426
460
|
setChatKey(newChatKey);
|
|
427
|
-
if (chatCreationResolverRef.current) {
|
|
428
|
-
chatCreationResolverRef.current.resolve(newChatKey);
|
|
429
|
-
chatCreationResolverRef.current = null;
|
|
430
|
-
}
|
|
431
461
|
}
|
|
432
462
|
break;
|
|
433
463
|
case "load_chat_response":
|
|
@@ -516,26 +546,13 @@ function useChat(options) {
|
|
|
516
546
|
if (!transport) {
|
|
517
547
|
throw new Error("Transport not initialized");
|
|
518
548
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
orgId,
|
|
524
|
-
chatKey: "",
|
|
525
|
-
userId,
|
|
526
|
-
timestamp: Date.now(),
|
|
527
|
-
data: metadata
|
|
528
|
-
}).catch((err) => {
|
|
529
|
-
chatCreationResolverRef.current = null;
|
|
530
|
-
reject(err);
|
|
531
|
-
});
|
|
532
|
-
setTimeout(() => {
|
|
533
|
-
if (chatCreationResolverRef.current) {
|
|
534
|
-
chatCreationResolverRef.current = null;
|
|
535
|
-
reject(new Error("Chat creation timed out"));
|
|
536
|
-
}
|
|
537
|
-
}, 3e4);
|
|
549
|
+
const response = await transport.createChat({
|
|
550
|
+
orgId,
|
|
551
|
+
userId,
|
|
552
|
+
metadata
|
|
538
553
|
});
|
|
554
|
+
setChatKey(response.chatKey);
|
|
555
|
+
return response.chatKey;
|
|
539
556
|
},
|
|
540
557
|
[orgId, userId]
|
|
541
558
|
);
|
|
@@ -545,14 +562,15 @@ function useChat(options) {
|
|
|
545
562
|
if (!transport) {
|
|
546
563
|
throw new Error("Transport not initialized");
|
|
547
564
|
}
|
|
548
|
-
|
|
549
|
-
await transport.send({
|
|
550
|
-
type: "load_chat",
|
|
565
|
+
const response = await transport.loadChatData({
|
|
551
566
|
orgId,
|
|
552
567
|
chatKey: key,
|
|
553
|
-
userId
|
|
554
|
-
timestamp: Date.now()
|
|
568
|
+
userId
|
|
555
569
|
});
|
|
570
|
+
setCurrentChat(response.chat);
|
|
571
|
+
setChatKey(response.chat.key);
|
|
572
|
+
setMessages(response.chat.messages || []);
|
|
573
|
+
return response.chat;
|
|
556
574
|
},
|
|
557
575
|
[orgId, userId]
|
|
558
576
|
);
|
|
@@ -613,6 +631,19 @@ function useChat(options) {
|
|
|
613
631
|
},
|
|
614
632
|
[orgId, chatKey, userId]
|
|
615
633
|
);
|
|
634
|
+
const sendEvent = (0, import_react.useCallback)(
|
|
635
|
+
async (event) => {
|
|
636
|
+
const transport = transportRef.current;
|
|
637
|
+
if (!transport) {
|
|
638
|
+
throw new Error("Transport not initialized");
|
|
639
|
+
}
|
|
640
|
+
await transport.send({
|
|
641
|
+
...event,
|
|
642
|
+
timestamp: Date.now()
|
|
643
|
+
});
|
|
644
|
+
},
|
|
645
|
+
[]
|
|
646
|
+
);
|
|
616
647
|
const startTyping = (0, import_react.useCallback)(() => {
|
|
617
648
|
const transport = transportRef.current;
|
|
618
649
|
if (!transport || !chatKey) return;
|
|
@@ -687,6 +718,7 @@ function useChat(options) {
|
|
|
687
718
|
startChat,
|
|
688
719
|
loadChat,
|
|
689
720
|
sendMessage,
|
|
721
|
+
sendEvent,
|
|
690
722
|
endChat,
|
|
691
723
|
// Typing
|
|
692
724
|
startTyping,
|
package/dist/hooks/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../hooks/index.ts","../../hooks/use-chat.ts","../../transport/types.ts","../../transport/sse.ts"],"sourcesContent":["/**\n * Chat Hooks\n *\n * React hooks for chat functionality.\n *\n * @example\n * ```tsx\n * import { useChat } from \"@elqnt/chat/hooks\";\n *\n * function ChatComponent() {\n * const {\n * connect,\n * sendMessage,\n * messages,\n * isConnected,\n * } = useChat({\n * baseUrl: \"https://api.example.com/chat\",\n * orgId: \"org-123\",\n * userId: \"user-456\",\n * });\n *\n * // ...\n * }\n * ```\n */\n\nexport { useChat } from \"./use-chat\";\nexport type { UseChatOptions, UseChatReturn } from \"./use-chat\";\n","\"use client\";\n\n/**\n * useChat Hook\n *\n * A unified React hook for chat functionality with support for\n * multiple transport types (SSE, fetch-based SSE, custom transports).\n *\n * @example Basic usage\n * ```tsx\n * function ChatComponent() {\n * const {\n * connect,\n * sendMessage,\n * messages,\n * isConnected,\n * } = useChat({\n * baseUrl: \"https://api.example.com/chat\",\n * orgId: \"org-123\",\n * userId: \"user-456\",\n * });\n *\n * useEffect(() => {\n * connect();\n * return () => disconnect();\n * }, []);\n *\n * return (\n * <div>\n * {messages.map(msg => <Message key={msg.id} {...msg} />)}\n * <input onSubmit={(content) => sendMessage(content)} />\n * </div>\n * );\n * }\n * ```\n *\n * @example With custom transport\n * ```tsx\n * import { createFetchSSETransport } from \"@elqnt/chat/transport\";\n *\n * const transport = createFetchSSETransport();\n *\n * function App() {\n * const chat = useChat({\n * baseUrl: \"...\",\n * orgId: \"...\",\n * userId: \"...\",\n * transport,\n * });\n * }\n * ```\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { Chat, ChatEvent, ChatMessage } from \"../models\";\nimport type {\n ChatTransport,\n TransportState,\n TransportError,\n ConnectionMetrics,\n RetryConfig,\n Unsubscribe,\n} from \"../transport/types\";\nimport { createSSETransport } from \"../transport/sse\";\n\n/**\n * Chat hook options\n */\nexport interface UseChatOptions {\n /** Base URL for the chat server (e.g., \"https://api.example.com/chat\") */\n baseUrl: string;\n /** Organization ID */\n orgId: string;\n /** User ID */\n userId: string;\n /** Client type for routing */\n clientType?: \"customer\" | \"humanAgent\" | \"observer\";\n /** Transport instance or type */\n transport?: ChatTransport | \"sse\" | \"sse-fetch\";\n /** Callback for all incoming events */\n onMessage?: (event: ChatEvent) => void;\n /** Callback for errors */\n onError?: (error: TransportError) => void;\n /** Callback when connection state changes */\n onConnectionChange?: (state: TransportState) => void;\n /** Auto-connect on mount */\n autoConnect?: boolean;\n /** Retry configuration */\n retryConfig?: RetryConfig;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Chat hook return type\n */\nexport interface UseChatReturn {\n // Connection\n /** Connect to the chat server */\n connect: () => Promise<void>;\n /** Disconnect from the server */\n disconnect: () => void;\n /** Current connection state */\n connectionState: TransportState;\n /** Whether currently connected */\n isConnected: boolean;\n\n // Chat operations\n /** Start a new chat session */\n startChat: (metadata?: Record<string, unknown>) => Promise<string>;\n /** Load an existing chat */\n loadChat: (chatKey: string) => Promise<void>;\n /** Send a text message */\n sendMessage: (content: string, attachments?: unknown[]) => Promise<void>;\n /** End the current chat */\n endChat: (reason?: string) => Promise<void>;\n\n // Typing indicators\n /** Signal that user is typing */\n startTyping: () => void;\n /** Signal that user stopped typing */\n stopTyping: () => void;\n\n // State\n /** Current chat object */\n currentChat: Chat | null;\n /** Current chat key */\n chatKey: string | null;\n /** Chat messages */\n messages: ChatMessage[];\n /** Current error */\n error: TransportError | null;\n /** Connection metrics */\n metrics: ConnectionMetrics;\n\n // Event subscription\n /** Subscribe to specific event type */\n on: (eventType: string, handler: (event: ChatEvent) => void) => Unsubscribe;\n /** Clear current error */\n clearError: () => void;\n}\n\n/**\n * Default transport factory\n */\nfunction getDefaultTransport(\n type: \"sse\" | \"sse-fetch\" | undefined,\n debug: boolean\n): ChatTransport {\n // For now, always use SSE. In the future, detect environment\n // and use fetch-based SSE for React Native\n return createSSETransport({ debug });\n}\n\n/**\n * useChat Hook\n *\n * Platform-agnostic chat hook with SSE transport support.\n */\nexport function useChat(options: UseChatOptions): UseChatReturn {\n const {\n baseUrl,\n orgId,\n userId,\n clientType = \"customer\",\n transport: transportOption,\n onMessage,\n onError,\n onConnectionChange,\n autoConnect = false,\n retryConfig,\n debug = false,\n } = options;\n\n // State\n const [connectionState, setConnectionState] = useState<TransportState>(\"disconnected\");\n const [currentChat, setCurrentChat] = useState<Chat | null>(null);\n const [chatKey, setChatKey] = useState<string | null>(null);\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [error, setError] = useState<TransportError | null>(null);\n const [metrics, setMetrics] = useState<ConnectionMetrics>({\n latency: 0,\n messagesSent: 0,\n messagesReceived: 0,\n messagesQueued: 0,\n reconnectCount: 0,\n });\n\n // Refs\n const transportRef = useRef<ChatTransport | null>(null);\n const mountedRef = useRef(false);\n const onMessageRef = useRef(onMessage);\n const onErrorRef = useRef(onError);\n const chatCreationResolverRef = useRef<{\n resolve: (chatKey: string) => void;\n reject: (error: Error) => void;\n } | null>(null);\n const typingTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Update callback refs\n useEffect(() => {\n onMessageRef.current = onMessage;\n onErrorRef.current = onError;\n }, [onMessage, onError]);\n\n // Initialize transport\n useEffect(() => {\n if (typeof transportOption === \"object\") {\n transportRef.current = transportOption;\n } else {\n transportRef.current = getDefaultTransport(\n transportOption as \"sse\" | \"sse-fetch\" | undefined,\n debug\n );\n }\n }, [transportOption, debug]);\n\n // Handle incoming events\n const handleEvent = useCallback((event: ChatEvent) => {\n if (!mountedRef.current) return;\n\n // Update metrics\n setMetrics((prev) => ({\n ...prev,\n messagesReceived: prev.messagesReceived + 1,\n lastMessageAt: Date.now(),\n }));\n\n // Handle specific event types\n switch (event.type) {\n case \"new_chat_created\":\n const newChatKey = event.data?.chatKey as string;\n if (newChatKey) {\n setChatKey(newChatKey);\n if (chatCreationResolverRef.current) {\n chatCreationResolverRef.current.resolve(newChatKey);\n chatCreationResolverRef.current = null;\n }\n }\n break;\n\n case \"load_chat_response\":\n const chat = event.data?.chat as Chat;\n if (chat) {\n setCurrentChat(chat);\n setChatKey(chat.key);\n setMessages(chat.messages || []);\n }\n break;\n\n case \"message\":\n if (event.message) {\n setMessages((prev) => [...prev, event.message!]);\n }\n break;\n\n case \"chat_ended\":\n setCurrentChat(null);\n setChatKey(null);\n break;\n\n case \"error\":\n const errorMsg = event.data?.message as string;\n if (errorMsg) {\n const transportError: TransportError = {\n code: \"NETWORK_ERROR\",\n message: errorMsg,\n retryable: true,\n timestamp: Date.now(),\n };\n setError(transportError);\n onErrorRef.current?.(transportError);\n }\n break;\n }\n\n // Call user's onMessage handler\n onMessageRef.current?.(event);\n }, []);\n\n // Connect to the chat server\n const connect = useCallback(async (): Promise<void> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n\n if (!orgId) {\n const err: TransportError = {\n code: \"CONNECTION_FAILED\",\n message: \"orgId is required\",\n retryable: false,\n timestamp: Date.now(),\n };\n setError(err);\n throw err;\n }\n\n setConnectionState(\"connecting\");\n\n try {\n // Subscribe to events before connecting\n const unsubscribe = transport.onMessage(handleEvent);\n\n await transport.connect({\n baseUrl,\n orgId,\n userId,\n clientType,\n chatKey: chatKey || undefined,\n debug,\n });\n\n setConnectionState(\"connected\");\n setError(null);\n setMetrics(transport.getMetrics());\n onConnectionChange?.(\"connected\");\n\n // Return cleanup in case caller wants it\n return;\n } catch (err) {\n const transportError = err as TransportError;\n setConnectionState(\"disconnected\");\n setError(transportError);\n onErrorRef.current?.(transportError);\n throw err;\n }\n }, [baseUrl, orgId, userId, clientType, chatKey, debug, handleEvent, onConnectionChange]);\n\n // Disconnect from the server\n const disconnect = useCallback((): void => {\n const transport = transportRef.current;\n if (transport) {\n transport.disconnect(true);\n }\n setConnectionState(\"disconnected\");\n onConnectionChange?.(\"disconnected\");\n }, [onConnectionChange]);\n\n // Start a new chat\n const startChat = useCallback(\n async (metadata?: Record<string, unknown>): Promise<string> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n chatCreationResolverRef.current = { resolve, reject };\n\n transport\n .send({\n type: \"new_chat\",\n orgId,\n chatKey: \"\",\n userId,\n timestamp: Date.now(),\n data: metadata,\n })\n .catch((err) => {\n chatCreationResolverRef.current = null;\n reject(err);\n });\n\n // Timeout after 30 seconds\n setTimeout(() => {\n if (chatCreationResolverRef.current) {\n chatCreationResolverRef.current = null;\n reject(new Error(\"Chat creation timed out\"));\n }\n }, 30000);\n });\n },\n [orgId, userId]\n );\n\n // Load an existing chat\n const loadChat = useCallback(\n async (key: string): Promise<void> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n\n setChatKey(key);\n\n await transport.send({\n type: \"load_chat\",\n orgId,\n chatKey: key,\n userId,\n timestamp: Date.now(),\n });\n },\n [orgId, userId]\n );\n\n // Send a message\n const sendMessage = useCallback(\n async (content: string, attachments?: unknown[]): Promise<void> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n if (!chatKey) {\n throw new Error(\"No active chat\");\n }\n\n const message: ChatMessage = {\n id: `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`,\n role: \"user\",\n content,\n time: Date.now(),\n status: \"sending\",\n senderId: userId,\n createdAt: Date.now(),\n attachments: attachments as ChatMessage[\"attachments\"],\n };\n\n // Optimistically add message\n setMessages((prev) => [...prev, message]);\n\n await transport.send({\n type: \"message\",\n orgId,\n chatKey,\n userId,\n timestamp: Date.now(),\n message,\n });\n\n setMetrics((prev) => ({\n ...prev,\n messagesSent: prev.messagesSent + 1,\n }));\n },\n [orgId, chatKey, userId]\n );\n\n // End the current chat\n const endChat = useCallback(\n async (reason?: string): Promise<void> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n if (!chatKey) {\n return;\n }\n\n await transport.send({\n type: \"end_chat\",\n orgId,\n chatKey,\n userId,\n timestamp: Date.now(),\n data: reason ? { reason } : undefined,\n });\n\n setCurrentChat(null);\n setChatKey(null);\n },\n [orgId, chatKey, userId]\n );\n\n // Start typing indicator\n const startTyping = useCallback((): void => {\n const transport = transportRef.current;\n if (!transport || !chatKey) return;\n\n // Clear existing timeout\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n\n transport\n .send({\n type: \"typing\",\n orgId,\n chatKey,\n userId,\n timestamp: Date.now(),\n })\n .catch(() => {});\n\n // Auto-stop typing after 3 seconds\n typingTimeoutRef.current = setTimeout(() => {\n stopTyping();\n }, 3000);\n }, [orgId, chatKey, userId]);\n\n // Stop typing indicator\n const stopTyping = useCallback((): void => {\n const transport = transportRef.current;\n if (!transport || !chatKey) return;\n\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n typingTimeoutRef.current = null;\n }\n\n transport\n .send({\n type: \"stopped_typing\",\n orgId,\n chatKey,\n userId,\n timestamp: Date.now(),\n })\n .catch(() => {});\n }, [orgId, chatKey, userId]);\n\n // Subscribe to specific event type\n const on = useCallback(\n (eventType: string, handler: (event: ChatEvent) => void): Unsubscribe => {\n const transport = transportRef.current;\n if (!transport) {\n return () => {};\n }\n return transport.on(eventType, handler);\n },\n []\n );\n\n // Clear error\n const clearError = useCallback((): void => {\n setError(null);\n transportRef.current?.clearError();\n }, []);\n\n // Mount/unmount lifecycle\n useEffect(() => {\n mountedRef.current = true;\n\n if (autoConnect) {\n connect().catch(() => {});\n }\n\n return () => {\n mountedRef.current = false;\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n disconnect();\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Computed state\n const isConnected = connectionState === \"connected\";\n\n return {\n // Connection\n connect,\n disconnect,\n connectionState,\n isConnected,\n\n // Chat operations\n startChat,\n loadChat,\n sendMessage,\n endChat,\n\n // Typing\n startTyping,\n stopTyping,\n\n // State\n currentChat,\n chatKey,\n messages,\n error,\n metrics,\n\n // Events\n on,\n clearError,\n };\n}\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 { 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 * 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 * 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 { 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} 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 return response.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 const eventTypes = [\n \"reconnected\", \"typing\", \"stopped_typing\", \"waiting\",\n \"waiting_for_agent\", \"human_agent_joined\", \"human_agent_left\",\n \"chat_ended\", \"chat_updated\", \"load_chat_response\",\n \"new_chat_created\", \"show_csat_survey\", \"csat_response\",\n \"user_suggested_actions\", \"agent_execution_started\",\n \"agent_execution_ended\", \"agent_context_update\",\n \"plan_pending_approval\", \"step_started\", \"step_completed\",\n \"step_failed\", \"plan_completed\", \"skills_changed\", \"summary_update\",\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 const url = `${cfg.baseUrl}/stream?orgId=${cfg.orgId}&userId=${cfg.userId}&clientType=${cfg.clientType}${cfg.chatKey ? `&chatId=${cfg.chatKey}` : \"\"}`;\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 state = \"connected\";\n error = undefined;\n retryCount = 0;\n metrics.connectedAt = Date.now();\n metrics.latency = connectionTime;\n\n setupEventListeners(es);\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 });\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 // 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 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"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../hooks/index.ts","../../hooks/use-chat.ts","../../transport/types.ts","../../transport/sse.ts"],"sourcesContent":["/**\n * Chat Hooks\n *\n * React hooks for chat functionality.\n *\n * @example\n * ```tsx\n * import { useChat } from \"@elqnt/chat/hooks\";\n *\n * function ChatComponent() {\n * const {\n * connect,\n * sendMessage,\n * messages,\n * isConnected,\n * } = useChat({\n * baseUrl: \"https://api.example.com/chat\",\n * orgId: \"org-123\",\n * userId: \"user-456\",\n * });\n *\n * // ...\n * }\n * ```\n */\n\nexport { useChat } from \"./use-chat\";\nexport type { UseChatOptions, UseChatReturn } from \"./use-chat\";\n","\"use client\";\n\n/**\n * useChat Hook\n *\n * A unified React hook for chat functionality with support for\n * multiple transport types (SSE, fetch-based SSE, custom transports).\n *\n * @example Basic usage\n * ```tsx\n * function ChatComponent() {\n * const {\n * connect,\n * sendMessage,\n * messages,\n * isConnected,\n * } = useChat({\n * baseUrl: \"https://api.example.com/chat\",\n * orgId: \"org-123\",\n * userId: \"user-456\",\n * });\n *\n * useEffect(() => {\n * connect();\n * return () => disconnect();\n * }, []);\n *\n * return (\n * <div>\n * {messages.map(msg => <Message key={msg.id} {...msg} />)}\n * <input onSubmit={(content) => sendMessage(content)} />\n * </div>\n * );\n * }\n * ```\n *\n * @example With custom transport\n * ```tsx\n * import { createFetchSSETransport } from \"@elqnt/chat/transport\";\n *\n * const transport = createFetchSSETransport();\n *\n * function App() {\n * const chat = useChat({\n * baseUrl: \"...\",\n * orgId: \"...\",\n * userId: \"...\",\n * transport,\n * });\n * }\n * ```\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { Chat, ChatEvent, ChatMessage } from \"../models\";\nimport type {\n ChatTransport,\n TransportState,\n TransportError,\n ConnectionMetrics,\n RetryConfig,\n Unsubscribe,\n} from \"../transport/types\";\nimport { createSSETransport } from \"../transport/sse\";\n\n/**\n * Chat hook options\n */\nexport interface UseChatOptions {\n /** Base URL for the chat server (e.g., \"https://api.example.com/chat\") */\n baseUrl: string;\n /** Organization ID */\n orgId: string;\n /** User ID */\n userId: string;\n /** Client type for routing */\n clientType?: \"customer\" | \"humanAgent\" | \"observer\";\n /** Transport instance or type */\n transport?: ChatTransport | \"sse\" | \"sse-fetch\";\n /** Callback for all incoming events */\n onMessage?: (event: ChatEvent) => void;\n /** Callback for errors */\n onError?: (error: TransportError) => void;\n /** Callback when connection state changes */\n onConnectionChange?: (state: TransportState) => void;\n /** Auto-connect on mount */\n autoConnect?: boolean;\n /** Retry configuration */\n retryConfig?: RetryConfig;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Chat hook return type\n */\nexport interface UseChatReturn {\n // Connection\n /** Connect to the chat server */\n connect: () => Promise<void>;\n /** Disconnect from the server */\n disconnect: () => void;\n /** Current connection state */\n connectionState: TransportState;\n /** Whether currently connected */\n isConnected: boolean;\n\n // Chat operations\n /** Start a new chat session */\n startChat: (metadata?: Record<string, unknown>) => Promise<string>;\n /** Load an existing chat, returns the loaded chat */\n loadChat: (chatKey: string) => Promise<Chat>;\n /** Send a text message */\n sendMessage: (content: string, attachments?: unknown[]) => Promise<void>;\n /** Send a raw chat event (for custom event types) */\n sendEvent: (event: Omit<ChatEvent, \"timestamp\">) => Promise<void>;\n /** End the current chat */\n endChat: (reason?: string) => Promise<void>;\n\n // Typing indicators\n /** Signal that user is typing */\n startTyping: () => void;\n /** Signal that user stopped typing */\n stopTyping: () => void;\n\n // State\n /** Current chat object */\n currentChat: Chat | null;\n /** Current chat key */\n chatKey: string | null;\n /** Chat messages */\n messages: ChatMessage[];\n /** Current error */\n error: TransportError | null;\n /** Connection metrics */\n metrics: ConnectionMetrics;\n\n // Event subscription\n /** Subscribe to specific event type */\n on: (eventType: string, handler: (event: ChatEvent) => void) => Unsubscribe;\n /** Clear current error */\n clearError: () => void;\n}\n\n/**\n * Default transport factory\n */\nfunction getDefaultTransport(\n type: \"sse\" | \"sse-fetch\" | undefined,\n debug: boolean\n): ChatTransport {\n // For now, always use SSE. In the future, detect environment\n // and use fetch-based SSE for React Native\n return createSSETransport({ debug });\n}\n\n/**\n * useChat Hook\n *\n * Platform-agnostic chat hook with SSE transport support.\n */\nexport function useChat(options: UseChatOptions): UseChatReturn {\n const {\n baseUrl,\n orgId,\n userId,\n clientType = \"customer\",\n transport: transportOption,\n onMessage,\n onError,\n onConnectionChange,\n autoConnect = false,\n retryConfig,\n debug = false,\n } = options;\n\n // State\n const [connectionState, setConnectionState] = useState<TransportState>(\"disconnected\");\n const [currentChat, setCurrentChat] = useState<Chat | null>(null);\n const [chatKey, setChatKey] = useState<string | null>(null);\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [error, setError] = useState<TransportError | null>(null);\n const [metrics, setMetrics] = useState<ConnectionMetrics>({\n latency: 0,\n messagesSent: 0,\n messagesReceived: 0,\n messagesQueued: 0,\n reconnectCount: 0,\n });\n\n // Refs\n const transportRef = useRef<ChatTransport | null>(null);\n const mountedRef = useRef(false);\n const onMessageRef = useRef(onMessage);\n const onErrorRef = useRef(onError);\n const typingTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Update callback refs\n useEffect(() => {\n onMessageRef.current = onMessage;\n onErrorRef.current = onError;\n }, [onMessage, onError]);\n\n // Initialize transport\n useEffect(() => {\n if (typeof transportOption === \"object\") {\n transportRef.current = transportOption;\n } else {\n transportRef.current = getDefaultTransport(\n transportOption as \"sse\" | \"sse-fetch\" | undefined,\n debug\n );\n }\n }, [transportOption, debug]);\n\n // Handle incoming events\n const handleEvent = useCallback((event: ChatEvent) => {\n if (!mountedRef.current) return;\n\n // Update metrics\n setMetrics((prev) => ({\n ...prev,\n messagesReceived: prev.messagesReceived + 1,\n lastMessageAt: Date.now(),\n }));\n\n // Handle specific event types\n switch (event.type) {\n case \"new_chat_created\":\n // Handle multi-tab sync when another tab creates a chat\n const newChatKey = event.data?.chatKey as string;\n if (newChatKey) {\n setChatKey(newChatKey);\n }\n break;\n\n case \"load_chat_response\":\n const chat = event.data?.chat as Chat;\n if (chat) {\n setCurrentChat(chat);\n setChatKey(chat.key);\n setMessages(chat.messages || []);\n }\n break;\n\n case \"message\":\n if (event.message) {\n setMessages((prev) => [...prev, event.message!]);\n }\n break;\n\n case \"chat_ended\":\n setCurrentChat(null);\n setChatKey(null);\n break;\n\n case \"error\":\n const errorMsg = event.data?.message as string;\n if (errorMsg) {\n const transportError: TransportError = {\n code: \"NETWORK_ERROR\",\n message: errorMsg,\n retryable: true,\n timestamp: Date.now(),\n };\n setError(transportError);\n onErrorRef.current?.(transportError);\n }\n break;\n }\n\n // Call user's onMessage handler\n onMessageRef.current?.(event);\n }, []);\n\n // Connect to the chat server\n const connect = useCallback(async (): Promise<void> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n\n if (!orgId) {\n const err: TransportError = {\n code: \"CONNECTION_FAILED\",\n message: \"orgId is required\",\n retryable: false,\n timestamp: Date.now(),\n };\n setError(err);\n throw err;\n }\n\n setConnectionState(\"connecting\");\n\n try {\n // Subscribe to events before connecting\n const unsubscribe = transport.onMessage(handleEvent);\n\n await transport.connect({\n baseUrl,\n orgId,\n userId,\n clientType,\n chatKey: chatKey || undefined,\n debug,\n });\n\n setConnectionState(\"connected\");\n setError(null);\n setMetrics(transport.getMetrics());\n onConnectionChange?.(\"connected\");\n\n // Return cleanup in case caller wants it\n return;\n } catch (err) {\n const transportError = err as TransportError;\n setConnectionState(\"disconnected\");\n setError(transportError);\n onErrorRef.current?.(transportError);\n throw err;\n }\n }, [baseUrl, orgId, userId, clientType, chatKey, debug, handleEvent, onConnectionChange]);\n\n // Disconnect from the server\n const disconnect = useCallback((): void => {\n const transport = transportRef.current;\n if (transport) {\n transport.disconnect(true);\n }\n setConnectionState(\"disconnected\");\n onConnectionChange?.(\"disconnected\");\n }, [onConnectionChange]);\n\n // Start a new chat\n const startChat = useCallback(\n async (metadata?: Record<string, unknown>): Promise<string> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n\n // Use direct HTTP call - no waiting for SSE events\n const response = await transport.createChat({\n orgId,\n userId,\n metadata,\n });\n\n // Update state with the new chat key\n setChatKey(response.chatKey);\n\n return response.chatKey;\n },\n [orgId, userId]\n );\n\n // Load an existing chat\n const loadChat = useCallback(\n async (key: string): Promise<Chat> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n\n // Use direct HTTP call - no waiting for SSE events\n const response = await transport.loadChatData({\n orgId,\n chatKey: key,\n userId,\n });\n\n // Update state directly from HTTP response\n setCurrentChat(response.chat);\n setChatKey(response.chat.key);\n setMessages(response.chat.messages || []);\n\n // Return the chat for callers that need it\n return response.chat;\n },\n [orgId, userId]\n );\n\n // Send a message\n const sendMessage = useCallback(\n async (content: string, attachments?: unknown[]): Promise<void> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n if (!chatKey) {\n throw new Error(\"No active chat\");\n }\n\n const message: ChatMessage = {\n id: `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`,\n role: \"user\",\n content,\n time: Date.now(),\n status: \"sending\",\n senderId: userId,\n createdAt: Date.now(),\n attachments: attachments as ChatMessage[\"attachments\"],\n };\n\n // Optimistically add message\n setMessages((prev) => [...prev, message]);\n\n await transport.send({\n type: \"message\",\n orgId,\n chatKey,\n userId,\n timestamp: Date.now(),\n message,\n });\n\n setMetrics((prev) => ({\n ...prev,\n messagesSent: prev.messagesSent + 1,\n }));\n },\n [orgId, chatKey, userId]\n );\n\n // End the current chat\n const endChat = useCallback(\n async (reason?: string): Promise<void> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n if (!chatKey) {\n return;\n }\n\n await transport.send({\n type: \"end_chat\",\n orgId,\n chatKey,\n userId,\n timestamp: Date.now(),\n data: reason ? { reason } : undefined,\n });\n\n setCurrentChat(null);\n setChatKey(null);\n },\n [orgId, chatKey, userId]\n );\n\n // Send a raw chat event (for custom event types)\n const sendEvent = useCallback(\n async (event: Omit<ChatEvent, \"timestamp\">): Promise<void> => {\n const transport = transportRef.current;\n if (!transport) {\n throw new Error(\"Transport not initialized\");\n }\n\n await transport.send({\n ...event,\n timestamp: Date.now(),\n } as ChatEvent);\n },\n []\n );\n\n // Start typing indicator\n const startTyping = useCallback((): void => {\n const transport = transportRef.current;\n if (!transport || !chatKey) return;\n\n // Clear existing timeout\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n\n transport\n .send({\n type: \"typing\",\n orgId,\n chatKey,\n userId,\n timestamp: Date.now(),\n })\n .catch(() => {});\n\n // Auto-stop typing after 3 seconds\n typingTimeoutRef.current = setTimeout(() => {\n stopTyping();\n }, 3000);\n }, [orgId, chatKey, userId]);\n\n // Stop typing indicator\n const stopTyping = useCallback((): void => {\n const transport = transportRef.current;\n if (!transport || !chatKey) return;\n\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n typingTimeoutRef.current = null;\n }\n\n transport\n .send({\n type: \"stopped_typing\",\n orgId,\n chatKey,\n userId,\n timestamp: Date.now(),\n })\n .catch(() => {});\n }, [orgId, chatKey, userId]);\n\n // Subscribe to specific event type\n const on = useCallback(\n (eventType: string, handler: (event: ChatEvent) => void): Unsubscribe => {\n const transport = transportRef.current;\n if (!transport) {\n return () => {};\n }\n return transport.on(eventType, handler);\n },\n []\n );\n\n // Clear error\n const clearError = useCallback((): void => {\n setError(null);\n transportRef.current?.clearError();\n }, []);\n\n // Mount/unmount lifecycle\n useEffect(() => {\n mountedRef.current = true;\n\n if (autoConnect) {\n connect().catch(() => {});\n }\n\n return () => {\n mountedRef.current = false;\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n disconnect();\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Computed state\n const isConnected = connectionState === \"connected\";\n\n return {\n // Connection\n connect,\n disconnect,\n connectionState,\n isConnected,\n\n // Chat operations\n startChat,\n loadChat,\n sendMessage,\n sendEvent,\n endChat,\n\n // Typing\n startTyping,\n stopTyping,\n\n // State\n currentChat,\n chatKey,\n messages,\n error,\n metrics,\n\n // Events\n on,\n clearError,\n };\n}\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 const eventTypes = [\n \"reconnected\", \"typing\", \"stopped_typing\", \"waiting\",\n \"waiting_for_agent\", \"human_agent_joined\", \"human_agent_left\",\n \"chat_ended\", \"chat_updated\", \"load_chat_response\",\n \"new_chat_created\", \"show_csat_survey\", \"csat_response\",\n \"user_suggested_actions\", \"agent_execution_started\",\n \"agent_execution_ended\", \"agent_context_update\",\n \"plan_pending_approval\", \"step_started\", \"step_completed\",\n \"step_failed\", \"plan_completed\", \"skills_changed\", \"summary_update\",\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 const url = `${cfg.baseUrl}/stream?orgId=${cfg.orgId}&userId=${cfg.userId}&clientType=${cfg.clientType}${cfg.chatKey ? `&chatId=${cfg.chatKey}` : \"\"}`;\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 state = \"connected\";\n error = undefined;\n retryCount = 0;\n metrics.connectedAt = Date.now();\n metrics.latency = connectionTime;\n\n setupEventListeners(es);\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 });\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqDA,mBAAyD;;;AC6NlD,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;AAG5C,UAAM,aAAa;AAAA,MACjB;AAAA,MAAe;AAAA,MAAU;AAAA,MAAkB;AAAA,MAC3C;AAAA,MAAqB;AAAA,MAAsB;AAAA,MAC3C;AAAA,MAAc;AAAA,MAAgB;AAAA,MAC9B;AAAA,MAAoB;AAAA,MAAoB;AAAA,MACxC;AAAA,MAA0B;AAAA,MAC1B;AAAA,MAAyB;AAAA,MACzB;AAAA,MAAyB;AAAA,MAAgB;AAAA,MACzC;AAAA,MAAe;AAAA,MAAkB;AAAA,MAAkB;AAAA,IACrD;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;AACjC,cAAM,MAAM,GAAG,IAAI,OAAO,iBAAiB,IAAI,KAAK,WAAW,IAAI,MAAM,eAAe,IAAI,UAAU,GAAG,IAAI,UAAU,WAAW,IAAI,OAAO,KAAK,EAAE;AAEpJ,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,kBAAQ;AACR,kBAAQ;AACR,uBAAa;AACb,kBAAQ,cAAc,KAAK,IAAI;AAC/B,kBAAQ,UAAU;AAElB,8BAAoB,EAAE;AACtB,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,UACjB,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;;;AFpTA,SAAS,oBACP,MACA,OACe;AAGf,SAAO,mBAAmB,EAAE,MAAM,CAAC;AACrC;AAOO,SAAS,QAAQ,SAAwC;AAC9D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd;AAAA,IACA,QAAQ;AAAA,EACV,IAAI;AAGJ,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,uBAAyB,cAAc;AACrF,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAsB,IAAI;AAChE,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAwB,IAAI;AAC1D,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAwB,CAAC,CAAC;AAC1D,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAgC,IAAI;AAC9D,QAAM,CAAC,SAAS,UAAU,QAAI,uBAA4B;AAAA,IACxD,SAAS;AAAA,IACT,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,EAClB,CAAC;AAGD,QAAM,mBAAe,qBAA6B,IAAI;AACtD,QAAM,iBAAa,qBAAO,KAAK;AAC/B,QAAM,mBAAe,qBAAO,SAAS;AACrC,QAAM,iBAAa,qBAAO,OAAO;AACjC,QAAM,uBAAmB,qBAA6C,IAAI;AAG1E,8BAAU,MAAM;AACd,iBAAa,UAAU;AACvB,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,WAAW,OAAO,CAAC;AAGvB,8BAAU,MAAM;AACd,QAAI,OAAO,oBAAoB,UAAU;AACvC,mBAAa,UAAU;AAAA,IACzB,OAAO;AACL,mBAAa,UAAU;AAAA,QACrB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,iBAAiB,KAAK,CAAC;AAG3B,QAAM,kBAAc,0BAAY,CAAC,UAAqB;AACpD,QAAI,CAAC,WAAW,QAAS;AAGzB,eAAW,CAAC,UAAU;AAAA,MACpB,GAAG;AAAA,MACH,kBAAkB,KAAK,mBAAmB;AAAA,MAC1C,eAAe,KAAK,IAAI;AAAA,IAC1B,EAAE;AAGF,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AAEH,cAAM,aAAa,MAAM,MAAM;AAC/B,YAAI,YAAY;AACd,qBAAW,UAAU;AAAA,QACvB;AACA;AAAA,MAEF,KAAK;AACH,cAAM,OAAO,MAAM,MAAM;AACzB,YAAI,MAAM;AACR,yBAAe,IAAI;AACnB,qBAAW,KAAK,GAAG;AACnB,sBAAY,KAAK,YAAY,CAAC,CAAC;AAAA,QACjC;AACA;AAAA,MAEF,KAAK;AACH,YAAI,MAAM,SAAS;AACjB,sBAAY,CAAC,SAAS,CAAC,GAAG,MAAM,MAAM,OAAQ,CAAC;AAAA,QACjD;AACA;AAAA,MAEF,KAAK;AACH,uBAAe,IAAI;AACnB,mBAAW,IAAI;AACf;AAAA,MAEF,KAAK;AACH,cAAM,WAAW,MAAM,MAAM;AAC7B,YAAI,UAAU;AACZ,gBAAM,iBAAiC;AAAA,YACrC,MAAM;AAAA,YACN,SAAS;AAAA,YACT,WAAW;AAAA,YACX,WAAW,KAAK,IAAI;AAAA,UACtB;AACA,mBAAS,cAAc;AACvB,qBAAW,UAAU,cAAc;AAAA,QACrC;AACA;AAAA,IACJ;AAGA,iBAAa,UAAU,KAAK;AAAA,EAC9B,GAAG,CAAC,CAAC;AAGL,QAAM,cAAU,0BAAY,YAA2B;AACrD,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAEA,QAAI,CAAC,OAAO;AACV,YAAM,MAAsB;AAAA,QAC1B,MAAM;AAAA,QACN,SAAS;AAAA,QACT,WAAW;AAAA,QACX,WAAW,KAAK,IAAI;AAAA,MACtB;AACA,eAAS,GAAG;AACZ,YAAM;AAAA,IACR;AAEA,uBAAmB,YAAY;AAE/B,QAAI;AAEF,YAAM,cAAc,UAAU,UAAU,WAAW;AAEnD,YAAM,UAAU,QAAQ;AAAA,QACtB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,WAAW;AAAA,QACpB;AAAA,MACF,CAAC;AAED,yBAAmB,WAAW;AAC9B,eAAS,IAAI;AACb,iBAAW,UAAU,WAAW,CAAC;AACjC,2BAAqB,WAAW;AAGhC;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,iBAAiB;AACvB,yBAAmB,cAAc;AACjC,eAAS,cAAc;AACvB,iBAAW,UAAU,cAAc;AACnC,YAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,SAAS,OAAO,QAAQ,YAAY,SAAS,OAAO,aAAa,kBAAkB,CAAC;AAGxF,QAAM,iBAAa,0BAAY,MAAY;AACzC,UAAM,YAAY,aAAa;AAC/B,QAAI,WAAW;AACb,gBAAU,WAAW,IAAI;AAAA,IAC3B;AACA,uBAAmB,cAAc;AACjC,yBAAqB,cAAc;AAAA,EACrC,GAAG,CAAC,kBAAkB,CAAC;AAGvB,QAAM,gBAAY;AAAA,IAChB,OAAO,aAAwD;AAC7D,YAAM,YAAY,aAAa;AAC/B,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,MAAM,2BAA2B;AAAA,MAC7C;AAGA,YAAM,WAAW,MAAM,UAAU,WAAW;AAAA,QAC1C;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAGD,iBAAW,SAAS,OAAO;AAE3B,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,CAAC,OAAO,MAAM;AAAA,EAChB;AAGA,QAAM,eAAW;AAAA,IACf,OAAO,QAA+B;AACpC,YAAM,YAAY,aAAa;AAC/B,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,MAAM,2BAA2B;AAAA,MAC7C;AAGA,YAAM,WAAW,MAAM,UAAU,aAAa;AAAA,QAC5C;AAAA,QACA,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AAGD,qBAAe,SAAS,IAAI;AAC5B,iBAAW,SAAS,KAAK,GAAG;AAC5B,kBAAY,SAAS,KAAK,YAAY,CAAC,CAAC;AAGxC,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,CAAC,OAAO,MAAM;AAAA,EAChB;AAGA,QAAM,kBAAc;AAAA,IAClB,OAAO,SAAiB,gBAA2C;AACjE,YAAM,YAAY,aAAa;AAC/B,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,MAAM,2BAA2B;AAAA,MAC7C;AACA,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI,MAAM,gBAAgB;AAAA,MAClC;AAEA,YAAM,UAAuB;AAAA,QAC3B,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAAA,QAC5D,MAAM;AAAA,QACN;AAAA,QACA,MAAM,KAAK,IAAI;AAAA,QACf,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,WAAW,KAAK,IAAI;AAAA,QACpB;AAAA,MACF;AAGA,kBAAY,CAAC,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC;AAExC,YAAM,UAAU,KAAK;AAAA,QACnB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW,KAAK,IAAI;AAAA,QACpB;AAAA,MACF,CAAC;AAED,iBAAW,CAAC,UAAU;AAAA,QACpB,GAAG;AAAA,QACH,cAAc,KAAK,eAAe;AAAA,MACpC,EAAE;AAAA,IACJ;AAAA,IACA,CAAC,OAAO,SAAS,MAAM;AAAA,EACzB;AAGA,QAAM,cAAU;AAAA,IACd,OAAO,WAAmC;AACxC,YAAM,YAAY,aAAa;AAC/B,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,MAAM,2BAA2B;AAAA,MAC7C;AACA,UAAI,CAAC,SAAS;AACZ;AAAA,MACF;AAEA,YAAM,UAAU,KAAK;AAAA,QACnB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAW,KAAK,IAAI;AAAA,QACpB,MAAM,SAAS,EAAE,OAAO,IAAI;AAAA,MAC9B,CAAC;AAED,qBAAe,IAAI;AACnB,iBAAW,IAAI;AAAA,IACjB;AAAA,IACA,CAAC,OAAO,SAAS,MAAM;AAAA,EACzB;AAGA,QAAM,gBAAY;AAAA,IAChB,OAAO,UAAuD;AAC5D,YAAM,YAAY,aAAa;AAC/B,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,MAAM,2BAA2B;AAAA,MAC7C;AAEA,YAAM,UAAU,KAAK;AAAA,QACnB,GAAG;AAAA,QACH,WAAW,KAAK,IAAI;AAAA,MACtB,CAAc;AAAA,IAChB;AAAA,IACA,CAAC;AAAA,EACH;AAGA,QAAM,kBAAc,0BAAY,MAAY;AAC1C,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,aAAa,CAAC,QAAS;AAG5B,QAAI,iBAAiB,SAAS;AAC5B,mBAAa,iBAAiB,OAAO;AAAA,IACvC;AAEA,cACG,KAAK;AAAA,MACJ,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC,EACA,MAAM,MAAM;AAAA,IAAC,CAAC;AAGjB,qBAAiB,UAAU,WAAW,MAAM;AAC1C,iBAAW;AAAA,IACb,GAAG,GAAI;AAAA,EACT,GAAG,CAAC,OAAO,SAAS,MAAM,CAAC;AAG3B,QAAM,iBAAa,0BAAY,MAAY;AACzC,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,aAAa,CAAC,QAAS;AAE5B,QAAI,iBAAiB,SAAS;AAC5B,mBAAa,iBAAiB,OAAO;AACrC,uBAAiB,UAAU;AAAA,IAC7B;AAEA,cACG,KAAK;AAAA,MACJ,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC,EACA,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACnB,GAAG,CAAC,OAAO,SAAS,MAAM,CAAC;AAG3B,QAAM,SAAK;AAAA,IACT,CAAC,WAAmB,YAAqD;AACvE,YAAM,YAAY,aAAa;AAC/B,UAAI,CAAC,WAAW;AACd,eAAO,MAAM;AAAA,QAAC;AAAA,MAChB;AACA,aAAO,UAAU,GAAG,WAAW,OAAO;AAAA,IACxC;AAAA,IACA,CAAC;AAAA,EACH;AAGA,QAAM,iBAAa,0BAAY,MAAY;AACzC,aAAS,IAAI;AACb,iBAAa,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,CAAC;AAGL,8BAAU,MAAM;AACd,eAAW,UAAU;AAErB,QAAI,aAAa;AACf,cAAQ,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAC1B;AAEA,WAAO,MAAM;AACX,iBAAW,UAAU;AACrB,UAAI,iBAAiB,SAAS;AAC5B,qBAAa,iBAAiB,OAAO;AAAA,MACvC;AACA,iBAAW;AAAA,IACb;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,QAAM,cAAc,oBAAoB;AAExC,SAAO;AAAA;AAAA,IAEL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAGA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAGA;AAAA,IACA;AAAA;AAAA,IAGA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAGA;AAAA,IACA;AAAA,EACF;AACF;","names":["options"]}
|