@elqnt/chat 2.0.7 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +386 -0
  2. package/dist/api/index.d.mts +308 -0
  3. package/dist/api/index.d.ts +308 -0
  4. package/dist/api/index.js +220 -0
  5. package/dist/api/index.js.map +1 -0
  6. package/dist/api/index.mjs +183 -0
  7. package/dist/api/index.mjs.map +1 -0
  8. package/dist/hooks/index.d.mts +78 -0
  9. package/dist/hooks/index.d.ts +78 -0
  10. package/dist/hooks/index.js +709 -0
  11. package/dist/hooks/index.js.map +1 -0
  12. package/dist/hooks/index.mjs +683 -0
  13. package/dist/hooks/index.mjs.map +1 -0
  14. package/dist/index.d.mts +4 -109
  15. package/dist/index.d.ts +4 -109
  16. package/dist/index.js +699 -3607
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +690 -3584
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/models/index.d.mts +76 -6
  21. package/dist/models/index.d.ts +76 -6
  22. package/dist/models/index.js +21 -0
  23. package/dist/models/index.js.map +1 -1
  24. package/dist/models/index.mjs +14 -0
  25. package/dist/models/index.mjs.map +1 -1
  26. package/dist/transport/index.d.mts +243 -0
  27. package/dist/transport/index.d.ts +243 -0
  28. package/dist/transport/index.js +875 -0
  29. package/dist/transport/index.js.map +1 -0
  30. package/dist/transport/index.mjs +843 -0
  31. package/dist/transport/index.mjs.map +1 -0
  32. package/dist/types-BB5nRdZs.d.mts +222 -0
  33. package/dist/types-CNvuxtcv.d.ts +222 -0
  34. package/package.json +32 -40
  35. package/dist/hooks/use-websocket-chat-admin.d.mts +0 -17
  36. package/dist/hooks/use-websocket-chat-admin.d.ts +0 -17
  37. package/dist/hooks/use-websocket-chat-admin.js +0 -1196
  38. package/dist/hooks/use-websocket-chat-admin.js.map +0 -1
  39. package/dist/hooks/use-websocket-chat-admin.mjs +0 -1172
  40. package/dist/hooks/use-websocket-chat-admin.mjs.map +0 -1
  41. package/dist/hooks/use-websocket-chat-base.d.mts +0 -81
  42. package/dist/hooks/use-websocket-chat-base.d.ts +0 -81
  43. package/dist/hooks/use-websocket-chat-base.js +0 -1025
  44. package/dist/hooks/use-websocket-chat-base.js.map +0 -1
  45. package/dist/hooks/use-websocket-chat-base.mjs +0 -1001
  46. package/dist/hooks/use-websocket-chat-base.mjs.map +0 -1
  47. package/dist/hooks/use-websocket-chat-customer.d.mts +0 -24
  48. package/dist/hooks/use-websocket-chat-customer.d.ts +0 -24
  49. package/dist/hooks/use-websocket-chat-customer.js +0 -1092
  50. package/dist/hooks/use-websocket-chat-customer.js.map +0 -1
  51. package/dist/hooks/use-websocket-chat-customer.mjs +0 -1068
  52. package/dist/hooks/use-websocket-chat-customer.mjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,10 +1,8 @@
1
1
  "use client";
2
2
  "use strict";
3
- var __create = Object.create;
4
3
  var __defProp = Object.defineProperty;
5
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
7
  var __export = (target, all) => {
10
8
  for (var name in all)
@@ -18,23 +16,11 @@ var __copyProps = (to, from, except, desc) => {
18
16
  }
19
17
  return to;
20
18
  };
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
- // If the importer is in node compatibility mode or this is not an ESM
23
- // file that has been converted to a CommonJS file using a Babel-
24
- // compatible transform (i.e. "__esModule" has not been set), then set
25
- // "default" to the CommonJS "module.exports" for node compatibility.
26
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
- mod
28
- ));
29
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
20
 
31
- // index.tsx
21
+ // index.ts
32
22
  var index_exports = {};
33
23
  __export(index_exports, {
34
- AdminChatHeader: () => AdminChatHeader,
35
- AdminChatInput: () => AdminChatInput,
36
- AdminChatList: () => AdminChatList,
37
- AdminChatListItem: () => AdminChatListItem,
38
24
  AgentStatusAway: () => AgentStatusAway,
39
25
  AgentStatusBusy: () => AgentStatusBusy,
40
26
  AgentStatusOffline: () => AgentStatusOffline,
@@ -45,6 +31,7 @@ __export(index_exports, {
45
31
  AttachmentTypeAudio: () => AttachmentTypeAudio,
46
32
  AttachmentTypeBullets: () => AttachmentTypeBullets,
47
33
  AttachmentTypeData: () => AttachmentTypeData,
34
+ AttachmentTypeDataFile: () => AttachmentTypeDataFile,
48
35
  AttachmentTypeDocument: () => AttachmentTypeDocument,
49
36
  AttachmentTypeDocumentAnalysis: () => AttachmentTypeDocumentAnalysis,
50
37
  AttachmentTypeDocumentSources: () => AttachmentTypeDocumentSources,
@@ -53,6 +40,7 @@ __export(index_exports, {
53
40
  AttachmentTypeLocation: () => AttachmentTypeLocation,
54
41
  AttachmentTypeRecords: () => AttachmentTypeRecords,
55
42
  AttachmentTypeReferences: () => AttachmentTypeReferences,
43
+ AttachmentTypeSpreadsheet: () => AttachmentTypeSpreadsheet,
56
44
  AttachmentTypeSticker: () => AttachmentTypeSticker,
57
45
  AttachmentTypeSubsections: () => AttachmentTypeSubsections,
58
46
  AttachmentTypeVideo: () => AttachmentTypeVideo,
@@ -66,6 +54,10 @@ __export(index_exports, {
66
54
  ChatEventTypeAgentSessionEnd: () => ChatEventTypeAgentSessionEnd,
67
55
  ChatEventTypeAgentSessionStart: () => ChatEventTypeAgentSessionStart,
68
56
  ChatEventTypeAgentStatusChange: () => ChatEventTypeAgentStatusChange,
57
+ ChatEventTypeAttachmentProcessingComplete: () => ChatEventTypeAttachmentProcessingComplete,
58
+ ChatEventTypeAttachmentProcessingError: () => ChatEventTypeAttachmentProcessingError,
59
+ ChatEventTypeAttachmentProcessingProgress: () => ChatEventTypeAttachmentProcessingProgress,
60
+ ChatEventTypeAttachmentProcessingStarted: () => ChatEventTypeAttachmentProcessingStarted,
69
61
  ChatEventTypeBlockUser: () => ChatEventTypeBlockUser,
70
62
  ChatEventTypeCSATRequest: () => ChatEventTypeCSATRequest,
71
63
  ChatEventTypeCSATResponse: () => ChatEventTypeCSATResponse,
@@ -117,6 +109,7 @@ __export(index_exports, {
117
109
  ChatEventTypePong: () => ChatEventTypePong,
118
110
  ChatEventTypeRead: () => ChatEventTypeRead,
119
111
  ChatEventTypeReconnected: () => ChatEventTypeReconnected,
112
+ ChatEventTypeRetryAttachment: () => ChatEventTypeRetryAttachment,
120
113
  ChatEventTypeRoomCreated: () => ChatEventTypeRoomCreated,
121
114
  ChatEventTypeRoomDeleted: () => ChatEventTypeRoomDeleted,
122
115
  ChatEventTypeRoomUpdated: () => ChatEventTypeRoomUpdated,
@@ -151,10 +144,6 @@ __export(index_exports, {
151
144
  ChatEventTypeUserSuggestedActions: () => ChatEventTypeUserSuggestedActions,
152
145
  ChatEventTypeWaiting: () => ChatEventTypeWaiting,
153
146
  ChatEventTypeWaitingForAgent: () => ChatEventTypeWaitingForAgent,
154
- ChatHeader: () => ChatHeader,
155
- ChatHumanAgentActions: () => ChatHumanAgentActions,
156
- ChatInput: () => ChatInput,
157
- ChatMessages: () => ChatMessages,
158
147
  ChatRoleAI: () => ChatRoleAI,
159
148
  ChatRoleDataQuery: () => ChatRoleDataQuery,
160
149
  ChatRoleEvent: () => ChatRoleEvent,
@@ -170,19 +159,16 @@ __export(index_exports, {
170
159
  ChatStatusActive: () => ChatStatusActive,
171
160
  ChatStatusArchived: () => ChatStatusArchived,
172
161
  ChatStatusClosed: () => ChatStatusClosed,
173
- ChatStatusCustomerUI: () => ChatStatusCustomerUI,
174
162
  ChatStatusDisconnected: () => ChatStatusDisconnected,
175
163
  ChatTypeCustomerSupport: () => ChatTypeCustomerSupport,
176
164
  ChatTypeDirect: () => ChatTypeDirect,
177
165
  ChatTypeGroup: () => ChatTypeGroup,
178
166
  ChatTypePrivateRoom: () => ChatTypePrivateRoom,
179
167
  ChatTypePublicRoom: () => ChatTypePublicRoom,
180
- ChatTypingIndicator: () => ChatTypingIndicator,
181
168
  CompleteChatByAgentSubject: () => CompleteChatByAgentSubject,
182
169
  CreateAgentQueueSubject: () => CreateAgentQueueSubject,
183
170
  DeleteAgentQueueSubject: () => DeleteAgentQueueSubject,
184
171
  EndAgentSessionSubject: () => EndAgentSessionSubject,
185
- GenericChatWidget: () => GenericChatWidget,
186
172
  GetActiveChatCountSubject: () => GetActiveChatCountSubject,
187
173
  GetActiveChatsSubject: () => GetActiveChatsSubject,
188
174
  GetAgentQueuesSubject: () => GetAgentQueuesSubject,
@@ -218,28 +204,687 @@ __export(index_exports, {
218
204
  UserStatusBusy: () => UserStatusBusy,
219
205
  UserStatusOffline: () => UserStatusOffline,
220
206
  UserStatusOnline: () => UserStatusOnline,
221
- WebSocketChatAdminContext: () => WebSocketChatAdminContext,
222
- WebSocketChatAdminProvider: () => WebSocketChatAdminProvider,
223
- WebSocketChatCustomerContext: () => WebSocketChatCustomerContext,
224
- WebSocketChatCustomerProvider: () => WebSocketChatCustomerProvider,
225
- useWebSocketChatAdmin: () => useWebSocketChatAdmin,
226
- useWebSocketChatAdminContext: () => useWebSocketChatAdminContext,
227
- useWebSocketChatBase: () => useWebSocketChatBase,
228
- useWebSocketChatCustomer: () => useWebSocketChatCustomer,
229
- useWebSocketChatCustomerContext: () => useWebSocketChatCustomerContext
207
+ useChat: () => useChat
230
208
  });
231
209
  module.exports = __toCommonJS(index_exports);
232
210
 
233
- // components/admin/admin-chat-input.tsx
234
- var import_ksuid = __toESM(require("ksuid"));
235
- var import_lucide_react = require("lucide-react");
236
- var import_react5 = require("react");
211
+ // hooks/use-chat.ts
212
+ var import_react = require("react");
213
+
214
+ // transport/types.ts
215
+ function createLogger(debug = false) {
216
+ return {
217
+ debug: debug ? console.log.bind(console, "[chat]") : () => {
218
+ },
219
+ info: console.info.bind(console, "[chat]"),
220
+ warn: console.warn.bind(console, "[chat]"),
221
+ error: console.error.bind(console, "[chat]")
222
+ };
223
+ }
224
+ var DEFAULT_RETRY_CONFIG = {
225
+ maxRetries: 10,
226
+ intervals: [1e3, 2e3, 5e3],
227
+ backoffMultiplier: 1.5,
228
+ maxBackoffTime: 3e4
229
+ };
230
+ function calculateRetryInterval(retryCount, config = DEFAULT_RETRY_CONFIG) {
231
+ const {
232
+ intervals = DEFAULT_RETRY_CONFIG.intervals,
233
+ backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,
234
+ maxBackoffTime = DEFAULT_RETRY_CONFIG.maxBackoffTime
235
+ } = config;
236
+ if (retryCount < intervals.length) {
237
+ return intervals[retryCount];
238
+ }
239
+ const baseInterval = intervals[intervals.length - 1] || 5e3;
240
+ const backoffTime = baseInterval * Math.pow(backoffMultiplier, retryCount - intervals.length + 1);
241
+ return Math.min(backoffTime, maxBackoffTime);
242
+ }
237
243
 
238
- // context/websocket-chat-admin-context.tsx
239
- var import_react4 = require("react");
244
+ // transport/sse.ts
245
+ function createSSETransport(options = {}) {
246
+ const {
247
+ retryConfig = DEFAULT_RETRY_CONFIG,
248
+ debug = false,
249
+ logger = createLogger(debug)
250
+ } = options;
251
+ let eventSource;
252
+ let config;
253
+ let state = "disconnected";
254
+ let error;
255
+ let retryCount = 0;
256
+ let reconnectTimeout;
257
+ let intentionalDisconnect = false;
258
+ const metrics = {
259
+ latency: 0,
260
+ messagesSent: 0,
261
+ messagesReceived: 0,
262
+ messagesQueued: 0,
263
+ reconnectCount: 0,
264
+ transportType: "sse"
265
+ };
266
+ const globalHandlers = /* @__PURE__ */ new Set();
267
+ const typeHandlers = /* @__PURE__ */ new Map();
268
+ function emit(event) {
269
+ metrics.messagesReceived++;
270
+ metrics.lastMessageAt = Date.now();
271
+ globalHandlers.forEach((handler) => {
272
+ try {
273
+ handler(event);
274
+ } catch (err) {
275
+ logger.error("Error in message handler:", err);
276
+ }
277
+ });
278
+ const handlers = typeHandlers.get(event.type);
279
+ if (handlers) {
280
+ handlers.forEach((handler) => {
281
+ try {
282
+ handler(event);
283
+ } catch (err) {
284
+ logger.error(`Error in ${event.type} handler:`, err);
285
+ }
286
+ });
287
+ }
288
+ }
289
+ async function sendRest(endpoint, body) {
290
+ if (!config) {
291
+ throw new Error("Transport not connected");
292
+ }
293
+ const url = `${config.baseUrl}/${endpoint}`;
294
+ logger.debug(`POST ${endpoint}`, body);
295
+ const response = await fetch(url, {
296
+ method: "POST",
297
+ headers: { "Content-Type": "application/json" },
298
+ body: JSON.stringify(body)
299
+ });
300
+ if (!response.ok) {
301
+ const errorText = await response.text();
302
+ throw new Error(`API error: ${response.status} - ${errorText}`);
303
+ }
304
+ return response.json();
305
+ }
306
+ function handleMessage(event) {
307
+ if (!event.data || event.data === "") return;
308
+ try {
309
+ const data = JSON.parse(event.data);
310
+ logger.debug("Received:", data.type);
311
+ emit(data);
312
+ } catch (err) {
313
+ logger.error("Failed to parse SSE message:", err);
314
+ }
315
+ }
316
+ function setupEventListeners(es) {
317
+ es.addEventListener("message", handleMessage);
318
+ const eventTypes = [
319
+ "reconnected",
320
+ "typing",
321
+ "stopped_typing",
322
+ "waiting",
323
+ "waiting_for_agent",
324
+ "human_agent_joined",
325
+ "human_agent_left",
326
+ "chat_ended",
327
+ "chat_updated",
328
+ "load_chat_response",
329
+ "new_chat_created",
330
+ "show_csat_survey",
331
+ "csat_response",
332
+ "user_suggested_actions",
333
+ "agent_execution_started",
334
+ "agent_execution_ended",
335
+ "agent_context_update",
336
+ "plan_pending_approval",
337
+ "step_started",
338
+ "step_completed",
339
+ "step_failed",
340
+ "plan_completed",
341
+ "skills_changed",
342
+ "summary_update"
343
+ ];
344
+ eventTypes.forEach((type) => {
345
+ es.addEventListener(type, handleMessage);
346
+ });
347
+ }
348
+ function scheduleReconnect() {
349
+ if (intentionalDisconnect || !config) return;
350
+ const maxRetries = retryConfig.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries;
351
+ if (retryCount >= maxRetries) {
352
+ logger.error(`Max retries (${maxRetries}) exceeded`);
353
+ error = {
354
+ code: "CONNECTION_FAILED",
355
+ message: `Max retries (${maxRetries}) exceeded`,
356
+ retryable: false,
357
+ timestamp: Date.now()
358
+ };
359
+ return;
360
+ }
361
+ const interval = calculateRetryInterval(retryCount, retryConfig);
362
+ retryCount++;
363
+ metrics.reconnectCount++;
364
+ logger.info(`Reconnecting in ${interval}ms (attempt ${retryCount})`);
365
+ state = "reconnecting";
366
+ reconnectTimeout = setTimeout(() => {
367
+ if (config) {
368
+ transport.connect(config).catch((err) => {
369
+ logger.error("Reconnect failed:", err);
370
+ });
371
+ }
372
+ }, interval);
373
+ }
374
+ const transport = {
375
+ async connect(cfg) {
376
+ config = cfg;
377
+ intentionalDisconnect = false;
378
+ if (eventSource) {
379
+ eventSource.close();
380
+ eventSource = void 0;
381
+ }
382
+ if (reconnectTimeout) {
383
+ clearTimeout(reconnectTimeout);
384
+ reconnectTimeout = void 0;
385
+ }
386
+ state = retryCount > 0 ? "reconnecting" : "connecting";
387
+ return new Promise((resolve, reject) => {
388
+ const connectionStart = Date.now();
389
+ const url = `${cfg.baseUrl}/stream?orgId=${cfg.orgId}&userId=${cfg.userId}&clientType=${cfg.clientType}${cfg.chatKey ? `&chatId=${cfg.chatKey}` : ""}`;
390
+ logger.debug("Connecting to:", url);
391
+ const es = new EventSource(url);
392
+ es.onopen = () => {
393
+ const connectionTime = Date.now() - connectionStart;
394
+ logger.info(`Connected in ${connectionTime}ms`);
395
+ state = "connected";
396
+ error = void 0;
397
+ retryCount = 0;
398
+ metrics.connectedAt = Date.now();
399
+ metrics.latency = connectionTime;
400
+ setupEventListeners(es);
401
+ resolve();
402
+ };
403
+ es.onerror = () => {
404
+ if (es.readyState === EventSource.CLOSED) {
405
+ const sseError = {
406
+ code: "CONNECTION_FAILED",
407
+ message: "SSE connection failed",
408
+ retryable: true,
409
+ timestamp: Date.now()
410
+ };
411
+ error = sseError;
412
+ metrics.lastError = sseError;
413
+ state = "disconnected";
414
+ if (!intentionalDisconnect) {
415
+ scheduleReconnect();
416
+ }
417
+ if (retryCount === 0) {
418
+ reject(sseError);
419
+ }
420
+ }
421
+ };
422
+ eventSource = es;
423
+ });
424
+ },
425
+ disconnect(intentional = true) {
426
+ logger.info("Disconnecting", { intentional });
427
+ intentionalDisconnect = intentional;
428
+ if (reconnectTimeout) {
429
+ clearTimeout(reconnectTimeout);
430
+ reconnectTimeout = void 0;
431
+ }
432
+ if (eventSource) {
433
+ eventSource.close();
434
+ eventSource = void 0;
435
+ }
436
+ state = "disconnected";
437
+ retryCount = 0;
438
+ },
439
+ async send(event) {
440
+ if (!config) {
441
+ throw new Error("Transport not connected");
442
+ }
443
+ switch (event.type) {
444
+ case "message":
445
+ await sendRest("send", {
446
+ orgId: event.orgId,
447
+ chatKey: event.chatKey,
448
+ userId: event.userId,
449
+ message: event.message
450
+ });
451
+ break;
452
+ case "typing":
453
+ await sendRest("typing", {
454
+ orgId: event.orgId,
455
+ chatKey: event.chatKey,
456
+ userId: event.userId,
457
+ typing: true
458
+ });
459
+ break;
460
+ case "stopped_typing":
461
+ await sendRest("typing", {
462
+ orgId: event.orgId,
463
+ chatKey: event.chatKey,
464
+ userId: event.userId,
465
+ typing: false
466
+ });
467
+ break;
468
+ case "load_chat":
469
+ await sendRest("load", {
470
+ orgId: event.orgId,
471
+ chatKey: event.chatKey,
472
+ userId: event.userId
473
+ });
474
+ break;
475
+ case "new_chat":
476
+ await sendRest("create", {
477
+ orgId: event.orgId,
478
+ userId: event.userId,
479
+ metadata: event.data
480
+ });
481
+ break;
482
+ case "end_chat":
483
+ await sendRest("end", {
484
+ orgId: event.orgId,
485
+ chatKey: event.chatKey,
486
+ userId: event.userId,
487
+ data: event.data
488
+ });
489
+ break;
490
+ default:
491
+ await sendRest("event", {
492
+ type: event.type,
493
+ orgId: event.orgId,
494
+ chatKey: event.chatKey,
495
+ userId: event.userId,
496
+ data: event.data
497
+ });
498
+ }
499
+ metrics.messagesSent++;
500
+ },
501
+ async sendMessage(message) {
502
+ if (!config) {
503
+ throw new Error("Transport not connected");
504
+ }
505
+ await sendRest("send", {
506
+ orgId: config.orgId,
507
+ chatKey: config.chatKey,
508
+ userId: config.userId,
509
+ message
510
+ });
511
+ metrics.messagesSent++;
512
+ },
513
+ onMessage(handler) {
514
+ globalHandlers.add(handler);
515
+ return () => globalHandlers.delete(handler);
516
+ },
517
+ on(eventType, handler) {
518
+ if (!typeHandlers.has(eventType)) {
519
+ typeHandlers.set(eventType, /* @__PURE__ */ new Set());
520
+ }
521
+ typeHandlers.get(eventType).add(handler);
522
+ return () => {
523
+ const handlers = typeHandlers.get(eventType);
524
+ if (handlers) {
525
+ handlers.delete(handler);
526
+ if (handlers.size === 0) {
527
+ typeHandlers.delete(eventType);
528
+ }
529
+ }
530
+ };
531
+ },
532
+ getState() {
533
+ return state;
534
+ },
535
+ getMetrics() {
536
+ return { ...metrics };
537
+ },
538
+ getError() {
539
+ return error;
540
+ },
541
+ clearError() {
542
+ error = void 0;
543
+ }
544
+ };
545
+ return transport;
546
+ }
240
547
 
241
- // hooks/use-websocket-chat-admin.ts
242
- var import_react2 = require("react");
548
+ // hooks/use-chat.ts
549
+ function getDefaultTransport(type, debug) {
550
+ return createSSETransport({ debug });
551
+ }
552
+ function useChat(options) {
553
+ const {
554
+ baseUrl,
555
+ orgId,
556
+ userId,
557
+ clientType = "customer",
558
+ transport: transportOption,
559
+ onMessage,
560
+ onError,
561
+ onConnectionChange,
562
+ autoConnect = false,
563
+ retryConfig,
564
+ debug = false
565
+ } = options;
566
+ const [connectionState, setConnectionState] = (0, import_react.useState)("disconnected");
567
+ const [currentChat, setCurrentChat] = (0, import_react.useState)(null);
568
+ const [chatKey, setChatKey] = (0, import_react.useState)(null);
569
+ const [messages, setMessages] = (0, import_react.useState)([]);
570
+ const [error, setError] = (0, import_react.useState)(null);
571
+ const [metrics, setMetrics] = (0, import_react.useState)({
572
+ latency: 0,
573
+ messagesSent: 0,
574
+ messagesReceived: 0,
575
+ messagesQueued: 0,
576
+ reconnectCount: 0
577
+ });
578
+ const transportRef = (0, import_react.useRef)(null);
579
+ const mountedRef = (0, import_react.useRef)(false);
580
+ const onMessageRef = (0, import_react.useRef)(onMessage);
581
+ const onErrorRef = (0, import_react.useRef)(onError);
582
+ const chatCreationResolverRef = (0, import_react.useRef)(null);
583
+ const typingTimeoutRef = (0, import_react.useRef)(null);
584
+ (0, import_react.useEffect)(() => {
585
+ onMessageRef.current = onMessage;
586
+ onErrorRef.current = onError;
587
+ }, [onMessage, onError]);
588
+ (0, import_react.useEffect)(() => {
589
+ if (typeof transportOption === "object") {
590
+ transportRef.current = transportOption;
591
+ } else {
592
+ transportRef.current = getDefaultTransport(
593
+ transportOption,
594
+ debug
595
+ );
596
+ }
597
+ }, [transportOption, debug]);
598
+ const handleEvent = (0, import_react.useCallback)((event) => {
599
+ if (!mountedRef.current) return;
600
+ setMetrics((prev) => ({
601
+ ...prev,
602
+ messagesReceived: prev.messagesReceived + 1,
603
+ lastMessageAt: Date.now()
604
+ }));
605
+ switch (event.type) {
606
+ case "new_chat_created":
607
+ const newChatKey = event.data?.chatKey;
608
+ if (newChatKey) {
609
+ setChatKey(newChatKey);
610
+ if (chatCreationResolverRef.current) {
611
+ chatCreationResolverRef.current.resolve(newChatKey);
612
+ chatCreationResolverRef.current = null;
613
+ }
614
+ }
615
+ break;
616
+ case "load_chat_response":
617
+ const chat = event.data?.chat;
618
+ if (chat) {
619
+ setCurrentChat(chat);
620
+ setChatKey(chat.key);
621
+ setMessages(chat.messages || []);
622
+ }
623
+ break;
624
+ case "message":
625
+ if (event.message) {
626
+ setMessages((prev) => [...prev, event.message]);
627
+ }
628
+ break;
629
+ case "chat_ended":
630
+ setCurrentChat(null);
631
+ setChatKey(null);
632
+ break;
633
+ case "error":
634
+ const errorMsg = event.data?.message;
635
+ if (errorMsg) {
636
+ const transportError = {
637
+ code: "NETWORK_ERROR",
638
+ message: errorMsg,
639
+ retryable: true,
640
+ timestamp: Date.now()
641
+ };
642
+ setError(transportError);
643
+ onErrorRef.current?.(transportError);
644
+ }
645
+ break;
646
+ }
647
+ onMessageRef.current?.(event);
648
+ }, []);
649
+ const connect = (0, import_react.useCallback)(async () => {
650
+ const transport = transportRef.current;
651
+ if (!transport) {
652
+ throw new Error("Transport not initialized");
653
+ }
654
+ if (!orgId) {
655
+ const err = {
656
+ code: "CONNECTION_FAILED",
657
+ message: "orgId is required",
658
+ retryable: false,
659
+ timestamp: Date.now()
660
+ };
661
+ setError(err);
662
+ throw err;
663
+ }
664
+ setConnectionState("connecting");
665
+ try {
666
+ const unsubscribe = transport.onMessage(handleEvent);
667
+ await transport.connect({
668
+ baseUrl,
669
+ orgId,
670
+ userId,
671
+ clientType,
672
+ chatKey: chatKey || void 0,
673
+ debug
674
+ });
675
+ setConnectionState("connected");
676
+ setError(null);
677
+ setMetrics(transport.getMetrics());
678
+ onConnectionChange?.("connected");
679
+ return;
680
+ } catch (err) {
681
+ const transportError = err;
682
+ setConnectionState("disconnected");
683
+ setError(transportError);
684
+ onErrorRef.current?.(transportError);
685
+ throw err;
686
+ }
687
+ }, [baseUrl, orgId, userId, clientType, chatKey, debug, handleEvent, onConnectionChange]);
688
+ const disconnect = (0, import_react.useCallback)(() => {
689
+ const transport = transportRef.current;
690
+ if (transport) {
691
+ transport.disconnect(true);
692
+ }
693
+ setConnectionState("disconnected");
694
+ onConnectionChange?.("disconnected");
695
+ }, [onConnectionChange]);
696
+ const startChat = (0, import_react.useCallback)(
697
+ async (metadata) => {
698
+ const transport = transportRef.current;
699
+ if (!transport) {
700
+ throw new Error("Transport not initialized");
701
+ }
702
+ return new Promise((resolve, reject) => {
703
+ chatCreationResolverRef.current = { resolve, reject };
704
+ transport.send({
705
+ type: "new_chat",
706
+ orgId,
707
+ chatKey: "",
708
+ userId,
709
+ timestamp: Date.now(),
710
+ data: metadata
711
+ }).catch((err) => {
712
+ chatCreationResolverRef.current = null;
713
+ reject(err);
714
+ });
715
+ setTimeout(() => {
716
+ if (chatCreationResolverRef.current) {
717
+ chatCreationResolverRef.current = null;
718
+ reject(new Error("Chat creation timed out"));
719
+ }
720
+ }, 3e4);
721
+ });
722
+ },
723
+ [orgId, userId]
724
+ );
725
+ const loadChat = (0, import_react.useCallback)(
726
+ async (key) => {
727
+ const transport = transportRef.current;
728
+ if (!transport) {
729
+ throw new Error("Transport not initialized");
730
+ }
731
+ setChatKey(key);
732
+ await transport.send({
733
+ type: "load_chat",
734
+ orgId,
735
+ chatKey: key,
736
+ userId,
737
+ timestamp: Date.now()
738
+ });
739
+ },
740
+ [orgId, userId]
741
+ );
742
+ const sendMessage = (0, import_react.useCallback)(
743
+ async (content, attachments) => {
744
+ const transport = transportRef.current;
745
+ if (!transport) {
746
+ throw new Error("Transport not initialized");
747
+ }
748
+ if (!chatKey) {
749
+ throw new Error("No active chat");
750
+ }
751
+ const message = {
752
+ id: `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`,
753
+ role: "user",
754
+ content,
755
+ time: Date.now(),
756
+ status: "sending",
757
+ senderId: userId,
758
+ createdAt: Date.now(),
759
+ attachments
760
+ };
761
+ setMessages((prev) => [...prev, message]);
762
+ await transport.send({
763
+ type: "message",
764
+ orgId,
765
+ chatKey,
766
+ userId,
767
+ timestamp: Date.now(),
768
+ message
769
+ });
770
+ setMetrics((prev) => ({
771
+ ...prev,
772
+ messagesSent: prev.messagesSent + 1
773
+ }));
774
+ },
775
+ [orgId, chatKey, userId]
776
+ );
777
+ const endChat = (0, import_react.useCallback)(
778
+ async (reason) => {
779
+ const transport = transportRef.current;
780
+ if (!transport) {
781
+ throw new Error("Transport not initialized");
782
+ }
783
+ if (!chatKey) {
784
+ return;
785
+ }
786
+ await transport.send({
787
+ type: "end_chat",
788
+ orgId,
789
+ chatKey,
790
+ userId,
791
+ timestamp: Date.now(),
792
+ data: reason ? { reason } : void 0
793
+ });
794
+ setCurrentChat(null);
795
+ setChatKey(null);
796
+ },
797
+ [orgId, chatKey, userId]
798
+ );
799
+ const startTyping = (0, import_react.useCallback)(() => {
800
+ const transport = transportRef.current;
801
+ if (!transport || !chatKey) return;
802
+ if (typingTimeoutRef.current) {
803
+ clearTimeout(typingTimeoutRef.current);
804
+ }
805
+ transport.send({
806
+ type: "typing",
807
+ orgId,
808
+ chatKey,
809
+ userId,
810
+ timestamp: Date.now()
811
+ }).catch(() => {
812
+ });
813
+ typingTimeoutRef.current = setTimeout(() => {
814
+ stopTyping();
815
+ }, 3e3);
816
+ }, [orgId, chatKey, userId]);
817
+ const stopTyping = (0, import_react.useCallback)(() => {
818
+ const transport = transportRef.current;
819
+ if (!transport || !chatKey) return;
820
+ if (typingTimeoutRef.current) {
821
+ clearTimeout(typingTimeoutRef.current);
822
+ typingTimeoutRef.current = null;
823
+ }
824
+ transport.send({
825
+ type: "stopped_typing",
826
+ orgId,
827
+ chatKey,
828
+ userId,
829
+ timestamp: Date.now()
830
+ }).catch(() => {
831
+ });
832
+ }, [orgId, chatKey, userId]);
833
+ const on = (0, import_react.useCallback)(
834
+ (eventType, handler) => {
835
+ const transport = transportRef.current;
836
+ if (!transport) {
837
+ return () => {
838
+ };
839
+ }
840
+ return transport.on(eventType, handler);
841
+ },
842
+ []
843
+ );
844
+ const clearError = (0, import_react.useCallback)(() => {
845
+ setError(null);
846
+ transportRef.current?.clearError();
847
+ }, []);
848
+ (0, import_react.useEffect)(() => {
849
+ mountedRef.current = true;
850
+ if (autoConnect) {
851
+ connect().catch(() => {
852
+ });
853
+ }
854
+ return () => {
855
+ mountedRef.current = false;
856
+ if (typingTimeoutRef.current) {
857
+ clearTimeout(typingTimeoutRef.current);
858
+ }
859
+ disconnect();
860
+ };
861
+ }, []);
862
+ const isConnected = connectionState === "connected";
863
+ return {
864
+ // Connection
865
+ connect,
866
+ disconnect,
867
+ connectionState,
868
+ isConnected,
869
+ // Chat operations
870
+ startChat,
871
+ loadChat,
872
+ sendMessage,
873
+ endChat,
874
+ // Typing
875
+ startTyping,
876
+ stopTyping,
877
+ // State
878
+ currentChat,
879
+ chatKey,
880
+ messages,
881
+ error,
882
+ metrics,
883
+ // Events
884
+ on,
885
+ clearError
886
+ };
887
+ }
243
888
 
244
889
  // models/chat-models.ts
245
890
  var ChatStatusActive = "active";
@@ -358,6 +1003,11 @@ var ChatEventTypePong = "pong";
358
1003
  var ChatEventTypeSkillActivate = "skill_activate";
359
1004
  var ChatEventTypeSkillDeactivate = "skill_deactivate";
360
1005
  var ChatEventTypeSkillsChanged = "skills_changed";
1006
+ var ChatEventTypeAttachmentProcessingStarted = "attachment_processing_started";
1007
+ var ChatEventTypeAttachmentProcessingProgress = "attachment_processing_progress";
1008
+ var ChatEventTypeAttachmentProcessingComplete = "attachment_processing_complete";
1009
+ var ChatEventTypeAttachmentProcessingError = "attachment_processing_error";
1010
+ var ChatEventTypeRetryAttachment = "retry_attachment";
361
1011
  var MessageStatusSending = "sending";
362
1012
  var MessageStatusSent = "sent";
363
1013
  var MessageStatusDelivered = "delivered";
@@ -379,6 +1029,8 @@ var AttachmentTypeSticker = "sticker";
379
1029
  var AttachmentTypeData = "data";
380
1030
  var AttachmentTypeKGNodes = "kgNodes";
381
1031
  var AttachmentTypeDocumentSources = "document_sources";
1032
+ var AttachmentTypeSpreadsheet = "spreadsheet";
1033
+ var AttachmentTypeDataFile = "data_file";
382
1034
  var ChatSessionStatusActive = "active";
383
1035
  var ChatSessionStatusIdle = "idle";
384
1036
  var ChatSessionStatusExpired = "expired";
@@ -423,3560 +1075,8 @@ var UpdateUserStatusSubject = "chat.user.status.update";
423
1075
  var GetOnlineUsersSubject = "chat.users.online.get";
424
1076
  var TriggerAnalyticsScanSubject = "chat.analytics.trigger-scan";
425
1077
  var SetupOrgSubject = "chat.org.setup";
426
-
427
- // hooks/use-websocket-chat-base.ts
428
- var import_react = require("react");
429
- var createDefaultLogger = (debug) => ({
430
- debug: debug ? console.log : () => {
431
- },
432
- info: console.info,
433
- warn: console.warn,
434
- error: console.error
435
- });
436
- var DEFAULT_RETRY_CONFIG = {
437
- maxRetries: 10,
438
- intervals: [1e3, 2e3, 5e3],
439
- backoffMultiplier: 1.5,
440
- maxBackoffTime: 3e4
441
- };
442
- var DEFAULT_QUEUE_CONFIG = {
443
- maxSize: 100,
444
- dropStrategy: "oldest"
445
- };
446
- var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
447
- var DEFAULT_HEARTBEAT_TIMEOUT = 5e3;
448
- var DEFAULT_TRANSPORT = "websocket";
449
- function isChatEvent(data) {
450
- return data && typeof data === "object" && (typeof data.type === "string" || data.message);
451
- }
452
- var useWebSocketChatBase = ({
453
- serverBaseUrl,
454
- orgId,
455
- clientType,
456
- product,
457
- onMessage,
458
- retryConfig = DEFAULT_RETRY_CONFIG,
459
- queueConfig = DEFAULT_QUEUE_CONFIG,
460
- debug = false,
461
- logger = createDefaultLogger(debug),
462
- heartbeatInterval = DEFAULT_HEARTBEAT_INTERVAL,
463
- heartbeatTimeout = DEFAULT_HEARTBEAT_TIMEOUT,
464
- transport = DEFAULT_TRANSPORT
465
- }) => {
466
- const [connectionState, setConnectionState] = (0, import_react.useState)("disconnected");
467
- const [error, setError] = (0, import_react.useState)(void 0);
468
- const [startTime, setStartTime] = (0, import_react.useState)(void 0);
469
- const [metrics, setMetrics] = (0, import_react.useState)({
470
- latency: 0,
471
- messagesSent: 0,
472
- messagesReceived: 0,
473
- messagesQueued: 0,
474
- reconnectCount: 0,
475
- transportType: transport
476
- });
477
- const wsRef = (0, import_react.useRef)(void 0);
478
- const sseRef = (0, import_react.useRef)(void 0);
479
- const transportRef = (0, import_react.useRef)(transport);
480
- (0, import_react.useEffect)(() => {
481
- transportRef.current = transport;
482
- }, [transport]);
483
- const reconnectTimeoutRef = (0, import_react.useRef)(void 0);
484
- const retryCountRef = (0, import_react.useRef)(0);
485
- const messageQueueRef = (0, import_react.useRef)([]);
486
- const mountedRef = (0, import_react.useRef)(false);
487
- const currentChatKeyRef = (0, import_react.useRef)(void 0);
488
- const currentUserIdRef = (0, import_react.useRef)(void 0);
489
- const intentionalDisconnectRef = (0, import_react.useRef)(false);
490
- const eventHandlersRef = (0, import_react.useRef)(
491
- /* @__PURE__ */ new Map()
492
- );
493
- const onMessageRef = (0, import_react.useRef)(onMessage);
494
- const pendingMessagesRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
495
- const heartbeatIntervalRef = (0, import_react.useRef)(void 0);
496
- const heartbeatTimeoutRef = (0, import_react.useRef)(void 0);
497
- const lastPongRef = (0, import_react.useRef)(Date.now());
498
- const chatCreationPromiseRef = (0, import_react.useRef)(null);
499
- const loadChatRetryMapRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
500
- (0, import_react.useEffect)(() => {
501
- onMessageRef.current = onMessage;
502
- }, [onMessage]);
503
- const isConnected = connectionState === "connected";
504
- const on = (0, import_react.useCallback)((eventType, handler) => {
505
- if (!eventHandlersRef.current.has(eventType)) {
506
- eventHandlersRef.current.set(eventType, /* @__PURE__ */ new Set());
507
- }
508
- eventHandlersRef.current.get(eventType).add(handler);
509
- return () => off(eventType, handler);
510
- }, []);
511
- const off = (0, import_react.useCallback)((eventType, handler) => {
512
- const handlers = eventHandlersRef.current.get(eventType);
513
- if (handlers) {
514
- handlers.delete(handler);
515
- if (handlers.size === 0) {
516
- eventHandlersRef.current.delete(eventType);
517
- }
518
- }
519
- }, []);
520
- const emit = (0, import_react.useCallback)(
521
- (eventType, data) => {
522
- const handlers = eventHandlersRef.current.get(eventType);
523
- if (handlers) {
524
- handlers.forEach((handler) => {
525
- try {
526
- handler(data);
527
- } catch (error2) {
528
- logger.error(`Error in event handler for ${eventType}:`, error2);
529
- }
530
- });
531
- }
532
- },
533
- [logger]
534
- );
535
- const updateMetrics = (0, import_react.useCallback)((updates) => {
536
- setMetrics((prev) => ({ ...prev, ...updates }));
537
- }, []);
538
- const addToQueue = (0, import_react.useCallback)(
539
- (event) => {
540
- const currentQueueSize = messageQueueRef.current.length;
541
- const maxSize = queueConfig.maxSize || DEFAULT_QUEUE_CONFIG.maxSize;
542
- if (currentQueueSize >= maxSize) {
543
- if (queueConfig.dropStrategy === "newest") {
544
- logger.warn("Message queue full, dropping new message");
545
- return false;
546
- } else {
547
- const dropped = messageQueueRef.current.shift();
548
- logger.warn("Message queue full, dropped oldest message", dropped);
549
- }
550
- }
551
- messageQueueRef.current.push(event);
552
- updateMetrics({ messagesQueued: messageQueueRef.current.length });
553
- return true;
554
- },
555
- [queueConfig, logger, updateMetrics]
556
- );
557
- const calculateRetryInterval = (0, import_react.useCallback)(
558
- (retryCount) => {
559
- const config = { ...DEFAULT_RETRY_CONFIG, ...retryConfig };
560
- const {
561
- intervals = [],
562
- backoffMultiplier = 1.5,
563
- maxBackoffTime = 3e4
564
- } = config;
565
- if (retryCount < intervals.length) {
566
- return intervals[retryCount];
567
- }
568
- const baseInterval = intervals[intervals.length - 1] || 5e3;
569
- const backoffTime = baseInterval * Math.pow(backoffMultiplier, retryCount - intervals.length + 1);
570
- return Math.min(backoffTime, maxBackoffTime);
571
- },
572
- [retryConfig]
573
- );
574
- const startHeartbeat = (0, import_react.useCallback)(() => {
575
- if (!heartbeatInterval || heartbeatInterval <= 0) return;
576
- const sendPing = () => {
577
- if (wsRef.current?.readyState === WebSocket.OPEN) {
578
- const pingTime = Date.now();
579
- wsRef.current.send(
580
- JSON.stringify({ type: "ping", timestamp: pingTime })
581
- );
582
- heartbeatTimeoutRef.current = setTimeout(() => {
583
- logger.warn("Heartbeat timeout - no pong received");
584
- if (wsRef.current) {
585
- wsRef.current.close(4e3, "Heartbeat timeout");
586
- }
587
- }, heartbeatTimeout);
588
- }
589
- };
590
- if (heartbeatIntervalRef.current) {
591
- clearInterval(heartbeatIntervalRef.current);
592
- }
593
- heartbeatIntervalRef.current = setInterval(sendPing, heartbeatInterval);
594
- logger.debug("Heartbeat started");
595
- }, [heartbeatInterval, heartbeatTimeout, logger]);
596
- const stopHeartbeat = (0, import_react.useCallback)(() => {
597
- if (heartbeatIntervalRef.current) {
598
- clearInterval(heartbeatIntervalRef.current);
599
- heartbeatIntervalRef.current = void 0;
600
- }
601
- if (heartbeatTimeoutRef.current) {
602
- clearTimeout(heartbeatTimeoutRef.current);
603
- heartbeatTimeoutRef.current = void 0;
604
- }
605
- logger.debug("Heartbeat stopped");
606
- }, [logger]);
607
- const cleanup = (0, import_react.useCallback)(() => {
608
- if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
609
- wsRef.current.close(1e3, "Cleanup");
610
- }
611
- wsRef.current = void 0;
612
- if (sseRef.current) {
613
- sseRef.current.close();
614
- sseRef.current = void 0;
615
- }
616
- if (reconnectTimeoutRef.current) {
617
- clearTimeout(reconnectTimeoutRef.current);
618
- reconnectTimeoutRef.current = void 0;
619
- }
620
- stopHeartbeat();
621
- pendingMessagesRef.current.forEach(({ reject, timeout }) => {
622
- clearTimeout(timeout);
623
- reject(new Error("Connection closed"));
624
- });
625
- pendingMessagesRef.current.clear();
626
- loadChatRetryMapRef.current.forEach((retryState) => {
627
- if (retryState.timeoutId) {
628
- clearTimeout(retryState.timeoutId);
629
- }
630
- });
631
- loadChatRetryMapRef.current.clear();
632
- }, [stopHeartbeat]);
633
- const getRestApiUrl = (0, import_react.useCallback)((endpoint) => {
634
- return `${serverBaseUrl}/${endpoint}`;
635
- }, [serverBaseUrl]);
636
- const sendRestMessage = (0, import_react.useCallback)(
637
- async (endpoint, body) => {
638
- const url = getRestApiUrl(endpoint);
639
- logger.debug(`SSE REST API call: POST ${endpoint}`, body);
640
- try {
641
- const response = await fetch(url, {
642
- method: "POST",
643
- headers: {
644
- "Content-Type": "application/json"
645
- },
646
- body: JSON.stringify(body)
647
- });
648
- if (!response.ok) {
649
- const errorText = await response.text();
650
- throw new Error(`REST API error: ${response.status} - ${errorText}`);
651
- }
652
- const data = await response.json();
653
- return data;
654
- } catch (error2) {
655
- logger.error(`SSE REST API error for ${endpoint}:`, error2);
656
- throw error2;
657
- }
658
- },
659
- [getRestApiUrl, logger]
660
- );
661
- const connect = (0, import_react.useCallback)(
662
- async (userId) => {
663
- if (!mountedRef.current) {
664
- mountedRef.current = true;
665
- }
666
- if (!orgId) {
667
- const error2 = {
668
- code: "CONNECTION_FAILED",
669
- message: "Cannot connect: orgId is undefined",
670
- retryable: false,
671
- timestamp: Date.now()
672
- };
673
- logger.error("Cannot connect: orgId is undefined");
674
- setError(error2);
675
- return Promise.reject(error2);
676
- }
677
- if (wsRef.current?.readyState === WebSocket.OPEN) {
678
- logger.debug("Already connected (WebSocket)");
679
- return Promise.resolve();
680
- }
681
- if (sseRef.current?.readyState === EventSource.OPEN) {
682
- logger.debug("Already connected (SSE)");
683
- return Promise.resolve();
684
- }
685
- if (connectionState === "connecting" || connectionState === "reconnecting") {
686
- logger.debug("Connection already in progress");
687
- return Promise.resolve();
688
- }
689
- const maxRetries = retryConfig.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries;
690
- if (retryCountRef.current >= maxRetries && !intentionalDisconnectRef.current) {
691
- const error2 = {
692
- code: "CONNECTION_FAILED",
693
- message: `Max retries (${maxRetries}) exceeded`,
694
- retryable: false,
695
- timestamp: Date.now()
696
- };
697
- setError(error2);
698
- updateMetrics({ lastError: error2 });
699
- return Promise.reject(error2);
700
- }
701
- cleanup();
702
- setConnectionState(
703
- retryCountRef.current > 0 ? "reconnecting" : "connecting"
704
- );
705
- intentionalDisconnectRef.current = false;
706
- return new Promise((resolve, reject) => {
707
- try {
708
- const connectionStartTime = Date.now();
709
- logger.info(`\u{1F504} Connecting with transport: ${transportRef.current}`);
710
- if (transportRef.current === "sse") {
711
- const sseUrl = getRestApiUrl(`stream?orgId=${orgId}&userId=${userId}&clientType=${clientType}&chatId=${currentChatKeyRef.current || ""}`);
712
- logger.debug("Connecting to SSE:", sseUrl);
713
- console.log(`\u23F3 Initiating SSE connection to ${sseUrl}...`);
714
- const eventSource = new EventSource(sseUrl);
715
- eventSource.onopen = () => {
716
- if (!mountedRef.current) {
717
- eventSource.close();
718
- reject(new Error("Component unmounted"));
719
- return;
720
- }
721
- const connectionTimeMs = Date.now() - connectionStartTime;
722
- const connectionTimeSec = (connectionTimeMs / 1e3).toFixed(2);
723
- logger.info("\u2705 SSE connected", {
724
- userId,
725
- retryCount: retryCountRef.current,
726
- connectionTime: `${connectionTimeSec}s (${connectionTimeMs}ms)`
727
- });
728
- console.log(`\u{1F50C} SSE connection established in ${connectionTimeSec} seconds`);
729
- setConnectionState("connected");
730
- setError(void 0);
731
- const wasReconnecting = retryCountRef.current > 0;
732
- retryCountRef.current = 0;
733
- updateMetrics({
734
- connectedAt: Date.now(),
735
- latency: connectionTimeMs,
736
- transportType: "sse",
737
- reconnectCount: wasReconnecting ? metrics.reconnectCount + 1 : metrics.reconnectCount
738
- });
739
- currentUserIdRef.current = userId;
740
- if (currentChatKeyRef.current) {
741
- logger.info("Loading chat after SSE reconnection:", currentChatKeyRef.current);
742
- sendRestMessage("load", {
743
- orgId,
744
- chatKey: currentChatKeyRef.current,
745
- userId
746
- }).then((response) => {
747
- if (response.success && response.data?.chat) {
748
- const chatEvent = {
749
- type: "load_chat_response",
750
- orgId,
751
- chatKey: currentChatKeyRef.current,
752
- userId,
753
- timestamp: Date.now(),
754
- data: response.data
755
- };
756
- emit("load_chat_response", chatEvent);
757
- if (onMessageRef.current) {
758
- onMessageRef.current(chatEvent);
759
- }
760
- }
761
- }).catch((err) => {
762
- logger.error("Failed to load chat after SSE reconnection:", err);
763
- });
764
- }
765
- emit("connected", { userId, wasReconnecting, transport: "sse" });
766
- resolve();
767
- };
768
- const handleSSEMessage = (event) => {
769
- if (!mountedRef.current) return;
770
- if (!event.data || event.data === "") {
771
- return;
772
- }
773
- try {
774
- const data = JSON.parse(event.data);
775
- if (!isChatEvent(data)) {
776
- logger.warn("Received invalid SSE message format:", data);
777
- return;
778
- }
779
- const chatEvent = data;
780
- logger.debug("SSE message received:", chatEvent.type);
781
- updateMetrics({
782
- messagesReceived: metrics.messagesReceived + 1,
783
- lastMessageAt: Date.now()
784
- });
785
- switch (chatEvent.type) {
786
- case "new_chat_created":
787
- const newChatKey = chatEvent.data?.chatKey;
788
- if (newChatKey) {
789
- logger.info("New chat created with key:", newChatKey);
790
- currentChatKeyRef.current = newChatKey;
791
- if (chatCreationPromiseRef.current) {
792
- chatCreationPromiseRef.current.resolve(newChatKey);
793
- chatCreationPromiseRef.current = null;
794
- }
795
- }
796
- break;
797
- case "load_chat_response":
798
- const chat = chatEvent.data?.chat;
799
- if (chat && chat.key) {
800
- logger.info("Chat loaded with key:", chat.key);
801
- currentChatKeyRef.current = chat.key;
802
- }
803
- break;
804
- case "chat_ended":
805
- logger.info("Chat ended, clearing key");
806
- currentChatKeyRef.current = void 0;
807
- break;
808
- }
809
- emit(chatEvent.type || "message", chatEvent);
810
- if (onMessageRef.current) {
811
- onMessageRef.current(chatEvent);
812
- }
813
- } catch (error2) {
814
- logger.error("Failed to parse SSE message:", error2);
815
- }
816
- };
817
- eventSource.addEventListener("message", handleSSEMessage);
818
- eventSource.addEventListener("reconnected", handleSSEMessage);
819
- eventSource.addEventListener("typing", handleSSEMessage);
820
- eventSource.addEventListener("stopped_typing", handleSSEMessage);
821
- eventSource.addEventListener("waiting", handleSSEMessage);
822
- eventSource.addEventListener("waiting_for_agent", handleSSEMessage);
823
- eventSource.addEventListener("human_agent_joined", handleSSEMessage);
824
- eventSource.addEventListener("human_agent_left", handleSSEMessage);
825
- eventSource.addEventListener("chat_ended", handleSSEMessage);
826
- eventSource.addEventListener("chat_updated", handleSSEMessage);
827
- eventSource.addEventListener("load_chat_response", handleSSEMessage);
828
- eventSource.addEventListener("new_chat_created", handleSSEMessage);
829
- eventSource.addEventListener("show_csat_survey", handleSSEMessage);
830
- eventSource.addEventListener("csat_response", handleSSEMessage);
831
- eventSource.addEventListener("user_suggested_actions", handleSSEMessage);
832
- eventSource.addEventListener("agent_execution_started", handleSSEMessage);
833
- eventSource.addEventListener("agent_execution_ended", handleSSEMessage);
834
- eventSource.addEventListener("agent_context_update", handleSSEMessage);
835
- eventSource.addEventListener("plan_pending_approval", handleSSEMessage);
836
- eventSource.addEventListener("step_started", handleSSEMessage);
837
- eventSource.addEventListener("step_completed", handleSSEMessage);
838
- eventSource.addEventListener("step_failed", handleSSEMessage);
839
- eventSource.addEventListener("plan_completed", handleSSEMessage);
840
- eventSource.addEventListener("skills_changed", handleSSEMessage);
841
- eventSource.addEventListener("summary_update", handleSSEMessage);
842
- eventSource.onerror = (error2) => {
843
- logger.error("SSE error:", error2);
844
- if (!mountedRef.current) return;
845
- if (eventSource.readyState === EventSource.CLOSED) {
846
- const sseError = {
847
- code: "CONNECTION_FAILED",
848
- message: "SSE connection failed",
849
- retryable: true,
850
- timestamp: Date.now()
851
- };
852
- setError(sseError);
853
- updateMetrics({ lastError: sseError });
854
- setConnectionState("disconnected");
855
- emit("disconnected", { reason: "SSE error" });
856
- if (!intentionalDisconnectRef.current && mountedRef.current) {
857
- const retryInterval = calculateRetryInterval(retryCountRef.current);
858
- retryCountRef.current++;
859
- logger.info(`SSE reconnecting in ${retryInterval}ms (attempt ${retryCountRef.current})`);
860
- if (reconnectTimeoutRef.current) {
861
- clearTimeout(reconnectTimeoutRef.current);
862
- }
863
- reconnectTimeoutRef.current = setTimeout(() => {
864
- connect(userId);
865
- }, retryInterval);
866
- }
867
- }
868
- };
869
- sseRef.current = eventSource;
870
- return;
871
- }
872
- const wsUrl = `${serverBaseUrl}?orgId=${orgId}&userId=${userId}&clientType=${clientType}&product=${product}`;
873
- logger.debug("Connecting to WebSocket:", wsUrl);
874
- console.log(`\u23F3 Initiating WebSocket connection to ${serverBaseUrl}...`);
875
- const ws = new WebSocket(wsUrl);
876
- ws.onopen = () => {
877
- if (!mountedRef.current) {
878
- ws.close(1e3, "Component unmounted");
879
- reject(new Error("Component unmounted"));
880
- return;
881
- }
882
- const connectionTimeMs = Date.now() - connectionStartTime;
883
- const connectionTimeSec = (connectionTimeMs / 1e3).toFixed(2);
884
- logger.info("\u2705 WebSocket connected", {
885
- userId,
886
- retryCount: retryCountRef.current,
887
- connectionTime: `${connectionTimeSec}s (${connectionTimeMs}ms)`
888
- });
889
- console.log(`\u{1F50C} WebSocket connection established in ${connectionTimeSec} seconds`);
890
- setConnectionState("connected");
891
- setError(void 0);
892
- const wasReconnecting = retryCountRef.current > 0;
893
- retryCountRef.current = 0;
894
- updateMetrics({
895
- connectedAt: Date.now(),
896
- latency: connectionTimeMs,
897
- reconnectCount: wasReconnecting ? metrics.reconnectCount + 1 : metrics.reconnectCount
898
- });
899
- while (messageQueueRef.current.length > 0 && ws.readyState === WebSocket.OPEN) {
900
- const event = messageQueueRef.current.shift();
901
- if (event) {
902
- ws.send(JSON.stringify({ ...event, timestamp: Date.now() }));
903
- updateMetrics({
904
- messagesSent: metrics.messagesSent + 1,
905
- messagesQueued: messageQueueRef.current.length
906
- });
907
- }
908
- }
909
- currentUserIdRef.current = userId;
910
- if (currentChatKeyRef.current) {
911
- if (!orgId) {
912
- logger.error("Cannot resubscribe to chat: orgId is undefined");
913
- } else {
914
- logger.info(
915
- "Resubscribing to chat after reconnection:",
916
- currentChatKeyRef.current
917
- );
918
- const resubscribeEvent = {
919
- type: "load_chat",
920
- orgId,
921
- chatKey: currentChatKeyRef.current,
922
- userId,
923
- timestamp: Date.now(),
924
- data: {}
925
- };
926
- ws.send(JSON.stringify(resubscribeEvent));
927
- }
928
- }
929
- startHeartbeat();
930
- emit("connected", { userId, wasReconnecting });
931
- resolve();
932
- };
933
- ws.onmessage = (event) => {
934
- if (!mountedRef.current) return;
935
- try {
936
- const data = JSON.parse(event.data);
937
- if (!isChatEvent(data)) {
938
- logger.warn("Received invalid message format:", data);
939
- return;
940
- }
941
- const chatEvent = data;
942
- logger.debug("Message received:", chatEvent.type);
943
- updateMetrics({
944
- messagesReceived: metrics.messagesReceived + 1,
945
- lastMessageAt: Date.now()
946
- });
947
- if (chatEvent.type === "pong") {
948
- if (heartbeatTimeoutRef.current) {
949
- clearTimeout(heartbeatTimeoutRef.current);
950
- heartbeatTimeoutRef.current = void 0;
951
- }
952
- const latency = Date.now() - (chatEvent.timestamp || Date.now());
953
- lastPongRef.current = Date.now();
954
- updateMetrics({ latency });
955
- return;
956
- }
957
- switch (chatEvent.type) {
958
- case "new_chat_created":
959
- const newChatKey = chatEvent.data?.chatKey;
960
- if (newChatKey) {
961
- logger.info("New chat created with key:", newChatKey);
962
- currentChatKeyRef.current = newChatKey;
963
- if (chatCreationPromiseRef.current) {
964
- chatCreationPromiseRef.current.resolve(newChatKey);
965
- chatCreationPromiseRef.current = null;
966
- }
967
- if (!orgId) {
968
- logger.error("Cannot send load_chat: orgId is undefined");
969
- return;
970
- }
971
- const loadChatEvent = {
972
- type: "load_chat",
973
- orgId,
974
- chatKey: newChatKey,
975
- userId: currentUserIdRef.current || userId,
976
- timestamp: Date.now(),
977
- data: {}
978
- };
979
- ws.send(JSON.stringify(loadChatEvent));
980
- }
981
- break;
982
- case "load_chat_response":
983
- const chat = chatEvent.data?.chat;
984
- if (chat && chat.key) {
985
- logger.info("Chat loaded with key:", chat.key);
986
- currentChatKeyRef.current = chat.key;
987
- const retryState = loadChatRetryMapRef.current.get(chat.key);
988
- if (retryState) {
989
- if (retryState.timeoutId) {
990
- clearTimeout(retryState.timeoutId);
991
- }
992
- loadChatRetryMapRef.current.delete(chat.key);
993
- }
994
- } else if (!chat) {
995
- logger.warn("Chat load failed, clearing key");
996
- currentChatKeyRef.current = void 0;
997
- }
998
- break;
999
- case "chat_ended":
1000
- logger.info("Chat ended, clearing key");
1001
- currentChatKeyRef.current = void 0;
1002
- break;
1003
- case "error":
1004
- const errorMessage = chatEvent.data?.message || "Unknown error";
1005
- logger.error("Received error from server:", errorMessage);
1006
- if (errorMessage.includes("nats: key not found") || errorMessage.includes("Failed to load chat")) {
1007
- const chatKeyFromError = currentChatKeyRef.current;
1008
- if (chatKeyFromError) {
1009
- const maxRetries2 = 5;
1010
- let retryState = loadChatRetryMapRef.current.get(chatKeyFromError);
1011
- if (!retryState) {
1012
- retryState = { retryCount: 0, timeoutId: null };
1013
- loadChatRetryMapRef.current.set(chatKeyFromError, retryState);
1014
- }
1015
- if (retryState.retryCount < maxRetries2) {
1016
- const delay = 200 * Math.pow(2, retryState.retryCount);
1017
- retryState.retryCount++;
1018
- logger.info(
1019
- `Chat load failed, retrying (${retryState.retryCount}/${maxRetries2}) in ${delay}ms...`,
1020
- chatKeyFromError
1021
- );
1022
- retryState.timeoutId = setTimeout(() => {
1023
- if (!wsRef.current || !mountedRef.current) return;
1024
- if (!orgId) {
1025
- logger.error("Cannot retry load_chat: orgId is undefined", chatKeyFromError);
1026
- loadChatRetryMapRef.current.delete(chatKeyFromError);
1027
- return;
1028
- }
1029
- logger.debug("Retrying load_chat:", chatKeyFromError);
1030
- const retryLoadEvent = {
1031
- type: "load_chat",
1032
- orgId,
1033
- chatKey: chatKeyFromError,
1034
- userId: currentUserIdRef.current || "",
1035
- timestamp: Date.now(),
1036
- data: {}
1037
- };
1038
- ws.send(JSON.stringify(retryLoadEvent));
1039
- }, delay);
1040
- } else {
1041
- logger.error("Max retries reached for loading chat:", chatKeyFromError);
1042
- loadChatRetryMapRef.current.delete(chatKeyFromError);
1043
- }
1044
- }
1045
- }
1046
- const wsError = {
1047
- code: "NETWORK_ERROR",
1048
- message: errorMessage,
1049
- retryable: true,
1050
- timestamp: Date.now()
1051
- };
1052
- setError(wsError);
1053
- updateMetrics({ lastError: wsError });
1054
- break;
1055
- }
1056
- emit(chatEvent.type || "message", chatEvent);
1057
- if (onMessageRef.current) {
1058
- onMessageRef.current(chatEvent);
1059
- }
1060
- } catch (error2) {
1061
- logger.error("Failed to parse WebSocket message:", error2);
1062
- const parseError = {
1063
- code: "PARSE_ERROR",
1064
- message: "Failed to parse message",
1065
- retryable: false,
1066
- timestamp: Date.now()
1067
- };
1068
- setError(parseError);
1069
- updateMetrics({ lastError: parseError });
1070
- }
1071
- };
1072
- ws.onclose = (event) => {
1073
- if (!mountedRef.current) return;
1074
- logger.info("WebSocket closed", {
1075
- code: event.code,
1076
- reason: event.reason
1077
- });
1078
- setConnectionState("disconnected");
1079
- wsRef.current = void 0;
1080
- stopHeartbeat();
1081
- emit("disconnected", { code: event.code, reason: event.reason });
1082
- if (event.code !== 1e3 && !intentionalDisconnectRef.current && mountedRef.current) {
1083
- const retryInterval = calculateRetryInterval(
1084
- retryCountRef.current
1085
- );
1086
- retryCountRef.current++;
1087
- logger.info(
1088
- `Reconnecting in ${retryInterval}ms (attempt ${retryCountRef.current})`
1089
- );
1090
- if (reconnectTimeoutRef.current) {
1091
- clearTimeout(reconnectTimeoutRef.current);
1092
- }
1093
- reconnectTimeoutRef.current = setTimeout(() => {
1094
- connect(userId);
1095
- }, retryInterval);
1096
- }
1097
- };
1098
- ws.onerror = (error2) => {
1099
- logger.error("WebSocket error:", error2);
1100
- if (!mountedRef.current) return;
1101
- const wsError = {
1102
- code: "CONNECTION_FAILED",
1103
- message: "WebSocket connection failed",
1104
- retryable: true,
1105
- timestamp: Date.now()
1106
- };
1107
- setError(wsError);
1108
- updateMetrics({ lastError: wsError });
1109
- reject(wsError);
1110
- };
1111
- wsRef.current = ws;
1112
- } catch (error2) {
1113
- logger.error("Failed to create WebSocket:", error2);
1114
- const wsError = {
1115
- code: "CONNECTION_FAILED",
1116
- message: error2 instanceof Error ? error2.message : "Failed to create connection",
1117
- retryable: true,
1118
- timestamp: Date.now()
1119
- };
1120
- setError(wsError);
1121
- updateMetrics({ lastError: wsError });
1122
- reject(wsError);
1123
- }
1124
- });
1125
- },
1126
- [
1127
- serverBaseUrl,
1128
- orgId,
1129
- clientType,
1130
- product,
1131
- connectionState,
1132
- logger,
1133
- retryConfig,
1134
- metrics,
1135
- updateMetrics,
1136
- cleanup,
1137
- calculateRetryInterval,
1138
- startHeartbeat,
1139
- emit
1140
- ]
1141
- );
1142
- const sendMessage = (0, import_react.useCallback)(
1143
- (event, overrideUserId) => {
1144
- return new Promise(async (resolve, reject) => {
1145
- if (!mountedRef.current) {
1146
- reject(new Error("Component not mounted"));
1147
- return;
1148
- }
1149
- const fullEvent = {
1150
- ...event,
1151
- timestamp: Date.now()
1152
- };
1153
- logger.debug("Sending message:", fullEvent.type);
1154
- if (transportRef.current === "sse") {
1155
- if (!sseRef.current || sseRef.current.readyState !== EventSource.OPEN) {
1156
- logger.debug("SSE not connected, attempting to connect");
1157
- if (connectionState === "disconnected" && overrideUserId) {
1158
- try {
1159
- await connect(overrideUserId);
1160
- } catch (error2) {
1161
- reject(error2);
1162
- return;
1163
- }
1164
- } else {
1165
- reject(new Error("SSE not connected"));
1166
- return;
1167
- }
1168
- }
1169
- try {
1170
- switch (fullEvent.type) {
1171
- case "message":
1172
- await sendRestMessage("send", {
1173
- orgId: fullEvent.orgId || orgId,
1174
- chatKey: fullEvent.chatKey || currentChatKeyRef.current,
1175
- userId: fullEvent.userId || currentUserIdRef.current,
1176
- message: fullEvent.message
1177
- });
1178
- break;
1179
- case "typing":
1180
- await sendRestMessage("typing", {
1181
- orgId: fullEvent.orgId || orgId,
1182
- chatKey: fullEvent.chatKey || currentChatKeyRef.current,
1183
- userId: fullEvent.userId || currentUserIdRef.current,
1184
- typing: true
1185
- });
1186
- break;
1187
- case "stopped_typing":
1188
- await sendRestMessage("typing", {
1189
- orgId: fullEvent.orgId || orgId,
1190
- chatKey: fullEvent.chatKey || currentChatKeyRef.current,
1191
- userId: fullEvent.userId || currentUserIdRef.current,
1192
- typing: false
1193
- });
1194
- break;
1195
- case "load_chat":
1196
- const loadResponse = await sendRestMessage("load", {
1197
- orgId: fullEvent.orgId || orgId,
1198
- chatKey: fullEvent.chatKey,
1199
- userId: fullEvent.userId || currentUserIdRef.current
1200
- });
1201
- if (loadResponse.success && loadResponse.data?.chat) {
1202
- currentChatKeyRef.current = loadResponse.data.chat.key;
1203
- const chatEvent = {
1204
- type: "load_chat_response",
1205
- orgId: fullEvent.orgId,
1206
- chatKey: loadResponse.data.chat.key,
1207
- userId: fullEvent.userId,
1208
- timestamp: Date.now(),
1209
- data: loadResponse.data
1210
- };
1211
- emit("load_chat_response", chatEvent);
1212
- if (onMessageRef.current) {
1213
- onMessageRef.current(chatEvent);
1214
- }
1215
- }
1216
- break;
1217
- case "new_chat":
1218
- const createResponse = await sendRestMessage("create", {
1219
- orgId: fullEvent.orgId || orgId,
1220
- userId: fullEvent.userId || currentUserIdRef.current,
1221
- metadata: fullEvent.data
1222
- });
1223
- if (createResponse.success && createResponse.data?.chatKey) {
1224
- currentChatKeyRef.current = createResponse.data.chatKey;
1225
- const newChatEvent = {
1226
- type: "new_chat_created",
1227
- orgId: fullEvent.orgId,
1228
- chatKey: createResponse.data.chatKey,
1229
- userId: fullEvent.userId,
1230
- timestamp: Date.now(),
1231
- data: { chatKey: createResponse.data.chatKey }
1232
- };
1233
- emit("new_chat_created", newChatEvent);
1234
- if (onMessageRef.current) {
1235
- onMessageRef.current(newChatEvent);
1236
- }
1237
- if (chatCreationPromiseRef.current) {
1238
- chatCreationPromiseRef.current.resolve(createResponse.data.chatKey);
1239
- chatCreationPromiseRef.current = null;
1240
- }
1241
- }
1242
- break;
1243
- case "end_chat":
1244
- await sendRestMessage("end", {
1245
- orgId: fullEvent.orgId || orgId,
1246
- chatKey: fullEvent.chatKey || currentChatKeyRef.current,
1247
- userId: fullEvent.userId || currentUserIdRef.current,
1248
- data: fullEvent.data
1249
- });
1250
- break;
1251
- case "human_agent_joined":
1252
- await sendRestMessage("agent-join", {
1253
- orgId: fullEvent.orgId || orgId,
1254
- chatKey: fullEvent.chatKey || currentChatKeyRef.current,
1255
- user: fullEvent.data?.user
1256
- });
1257
- break;
1258
- case "human_agent_left":
1259
- await sendRestMessage("agent-leave", {
1260
- orgId: fullEvent.orgId || orgId,
1261
- chatKey: fullEvent.chatKey || currentChatKeyRef.current,
1262
- user: fullEvent.data?.user
1263
- });
1264
- break;
1265
- // Event types that use the generic /event endpoint
1266
- case "load_agent_context":
1267
- case "skill_activate":
1268
- case "skill_deactivate":
1269
- case "sync_metadata":
1270
- case "sync_user_session":
1271
- case "csat_response":
1272
- case "plan_approved":
1273
- case "plan_rejected":
1274
- await sendRestMessage("event", {
1275
- type: fullEvent.type,
1276
- orgId: fullEvent.orgId || orgId,
1277
- chatKey: fullEvent.chatKey || currentChatKeyRef.current,
1278
- userId: fullEvent.userId || currentUserIdRef.current,
1279
- data: fullEvent.data
1280
- });
1281
- break;
1282
- default:
1283
- logger.warn("Sending unrecognized event type via generic endpoint:", fullEvent.type);
1284
- await sendRestMessage("event", {
1285
- type: fullEvent.type,
1286
- orgId: fullEvent.orgId || orgId,
1287
- chatKey: fullEvent.chatKey || currentChatKeyRef.current,
1288
- userId: fullEvent.userId || currentUserIdRef.current,
1289
- data: fullEvent.data
1290
- });
1291
- break;
1292
- }
1293
- updateMetrics({ messagesSent: metrics.messagesSent + 1 });
1294
- logger.debug("SSE REST message sent successfully");
1295
- resolve();
1296
- } catch (error2) {
1297
- logger.error("Failed to send SSE REST message:", error2);
1298
- const sendError = {
1299
- code: "SEND_FAILED",
1300
- message: error2 instanceof Error ? error2.message : "Failed to send message",
1301
- retryable: true,
1302
- timestamp: Date.now()
1303
- };
1304
- setError(sendError);
1305
- updateMetrics({ lastError: sendError });
1306
- reject(sendError);
1307
- }
1308
- return;
1309
- }
1310
- if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
1311
- if (addToQueue(fullEvent)) {
1312
- logger.debug("Message queued, attempting to connect");
1313
- if (connectionState === "disconnected" && overrideUserId) {
1314
- connect(overrideUserId).then(() => resolve()).catch(reject);
1315
- } else {
1316
- resolve();
1317
- }
1318
- } else {
1319
- reject(new Error("Message queue full"));
1320
- }
1321
- return;
1322
- }
1323
- try {
1324
- wsRef.current.send(JSON.stringify(fullEvent));
1325
- updateMetrics({ messagesSent: metrics.messagesSent + 1 });
1326
- logger.debug("Message sent successfully");
1327
- resolve();
1328
- } catch (error2) {
1329
- logger.error("Failed to send message:", error2);
1330
- if (addToQueue(fullEvent)) {
1331
- resolve();
1332
- } else {
1333
- const sendError = {
1334
- code: "SEND_FAILED",
1335
- message: error2 instanceof Error ? error2.message : "Failed to send message",
1336
- retryable: true,
1337
- timestamp: Date.now()
1338
- };
1339
- setError(sendError);
1340
- updateMetrics({ lastError: sendError });
1341
- reject(sendError);
1342
- }
1343
- }
1344
- });
1345
- },
1346
- [connectionState, connect, addToQueue, logger, metrics, updateMetrics, sendRestMessage, emit, orgId]
1347
- );
1348
- const startNewChat = (0, import_react.useCallback)(
1349
- (userId, data) => {
1350
- return new Promise((resolve, reject) => {
1351
- if (!userId) {
1352
- reject(new Error("User ID is required"));
1353
- return;
1354
- }
1355
- logger.info("Requesting new chat from server with userId:", userId);
1356
- setStartTime(/* @__PURE__ */ new Date());
1357
- chatCreationPromiseRef.current = { resolve, reject };
1358
- sendMessage(
1359
- {
1360
- type: "new_chat",
1361
- orgId,
1362
- chatKey: "",
1363
- // Server will generate
1364
- userId,
1365
- data: data ?? {}
1366
- },
1367
- userId
1368
- ).catch((error2) => {
1369
- chatCreationPromiseRef.current = null;
1370
- reject(error2);
1371
- });
1372
- setTimeout(() => {
1373
- if (chatCreationPromiseRef.current) {
1374
- chatCreationPromiseRef.current = null;
1375
- reject(new Error("Chat creation timed out"));
1376
- }
1377
- }, 3e4);
1378
- });
1379
- },
1380
- [sendMessage, orgId, logger]
1381
- );
1382
- const disconnect = (0, import_react.useCallback)(
1383
- (intentional = true) => {
1384
- logger.info("Disconnecting", { intentional, transport: transportRef.current });
1385
- intentionalDisconnectRef.current = intentional;
1386
- cleanup();
1387
- setConnectionState("disconnected");
1388
- messageQueueRef.current = [];
1389
- retryCountRef.current = 0;
1390
- mountedRef.current = false;
1391
- currentChatKeyRef.current = void 0;
1392
- currentUserIdRef.current = void 0;
1393
- },
1394
- [cleanup, logger]
1395
- );
1396
- const clearError = (0, import_react.useCallback)(() => {
1397
- setError(void 0);
1398
- }, []);
1399
- (0, import_react.useEffect)(() => {
1400
- mountedRef.current = true;
1401
- return () => {
1402
- mountedRef.current = false;
1403
- disconnect(true);
1404
- };
1405
- }, []);
1406
- return {
1407
- connectionState,
1408
- isConnected,
1409
- sendMessage,
1410
- error,
1411
- connect,
1412
- startNewChat,
1413
- startTime,
1414
- disconnect,
1415
- metrics,
1416
- on,
1417
- off,
1418
- clearError
1419
- };
1420
- };
1421
-
1422
- // hooks/use-websocket-chat-admin.ts
1423
- var useWebSocketChatAdmin = ({
1424
- serverBaseUrl,
1425
- orgId,
1426
- product
1427
- }) => {
1428
- const [chats, setChats] = (0, import_react2.useState)(/* @__PURE__ */ new Map());
1429
- const [selectedChat, setSelectedChat] = (0, import_react2.useState)(void 0);
1430
- const handleMessage = (0, import_react2.useCallback)(
1431
- (chatEvent) => {
1432
- switch (chatEvent.type) {
1433
- case "message":
1434
- if (!selectedChat || !chatEvent.message) return;
1435
- setChats((prev) => {
1436
- const newMap = new Map(prev);
1437
- newMap.set(selectedChat.key, {
1438
- ...selectedChat,
1439
- messages: [...selectedChat.messages, chatEvent.message]
1440
- });
1441
- return newMap;
1442
- });
1443
- setSelectedChat((prev) => {
1444
- if (!prev) return prev;
1445
- return {
1446
- ...prev,
1447
- messages: [...prev.messages, chatEvent.message]
1448
- };
1449
- });
1450
- break;
1451
- case "list_chats":
1452
- const chatList = chatEvent.data?.chats;
1453
- if (!chatList) return;
1454
- setChats(new Map(chatList.map((chat) => [chat.key, chat])));
1455
- break;
1456
- case "chat_updated":
1457
- const updatedChat = chatEvent.data?.chat?.value;
1458
- if (updatedChat) {
1459
- setChats((prev) => new Map(prev).set(updatedChat.key, updatedChat));
1460
- }
1461
- break;
1462
- case "chat_removed":
1463
- const chatKey = chatEvent.data?.chatKey?.value;
1464
- if (chatKey) {
1465
- setChats((prev) => {
1466
- const newMap = new Map(prev);
1467
- newMap.delete(chatKey);
1468
- return newMap;
1469
- });
1470
- }
1471
- break;
1472
- case "load_chat":
1473
- const history = chatEvent.data?.chat?.value;
1474
- if (history) {
1475
- setChats((prev) => {
1476
- const existingChat = prev.get(history.key);
1477
- if (!existingChat) return prev;
1478
- return new Map(prev).set(history.key, {
1479
- ...existingChat,
1480
- messages: history.messages
1481
- });
1482
- });
1483
- }
1484
- break;
1485
- }
1486
- },
1487
- [selectedChat]
1488
- );
1489
- const base = useWebSocketChatBase({
1490
- serverBaseUrl,
1491
- orgId,
1492
- clientType: "humanAgent",
1493
- onMessage: handleMessage,
1494
- product
1495
- });
1496
- const selectChat = (0, import_react2.useCallback)(
1497
- (chatKey) => {
1498
- const chat = chats.get(chatKey);
1499
- if (!chat) {
1500
- console.error("Unable to select chat", chatKey);
1501
- return;
1502
- }
1503
- setSelectedChat(chat);
1504
- },
1505
- [chats, orgId, base.sendMessage]
1506
- );
1507
- const addUserToChat = (0, import_react2.useCallback)(
1508
- (orgId2, chatKey, user) => {
1509
- base.sendMessage({
1510
- type: "human_agent_joined",
1511
- orgId: orgId2,
1512
- chatKey,
1513
- userId: user.email,
1514
- data: { user }
1515
- });
1516
- setChats((prev) => {
1517
- const newMap = new Map(prev);
1518
- const chat = newMap.get(chatKey);
1519
- if (!chat) return prev;
1520
- newMap.set(chatKey, {
1521
- ...chat,
1522
- humanAgentEngaged: user.role === ChatRoleHumanAgent,
1523
- users: [...chat?.users ?? [], user]
1524
- });
1525
- return newMap;
1526
- });
1527
- setSelectedChat((prev) => {
1528
- if (!prev) return prev;
1529
- return {
1530
- ...prev,
1531
- humanAgentEngaged: user.role === ChatRoleHumanAgent,
1532
- users: [...prev.users ?? [], user]
1533
- };
1534
- });
1535
- },
1536
- [base.sendMessage]
1537
- );
1538
- const removeUserFromChat = (0, import_react2.useCallback)(
1539
- (orgId2, chatKey, userId) => {
1540
- const chat = chats.get(chatKey);
1541
- if (!chat) return;
1542
- const user = chat.users?.find((u) => u.id === userId);
1543
- if (!user) return;
1544
- base.sendMessage({
1545
- type: "human_agent_left",
1546
- orgId: orgId2,
1547
- chatKey,
1548
- userId,
1549
- data: { user }
1550
- });
1551
- setChats((prev) => {
1552
- const newMap = new Map(prev);
1553
- const chat2 = newMap.get(chatKey);
1554
- if (!chat2) return prev;
1555
- newMap.set(chatKey, {
1556
- ...chat2,
1557
- humanAgentEngaged: false,
1558
- users: chat2.users?.filter((u) => u.id !== userId)
1559
- });
1560
- return newMap;
1561
- });
1562
- },
1563
- [chats, base.sendMessage]
1564
- );
1565
- const blockUser = (0, import_react2.useCallback)(
1566
- (orgId2, chatKey, userId) => {
1567
- base.sendMessage({
1568
- type: "block_user",
1569
- orgId: orgId2,
1570
- chatKey,
1571
- userId
1572
- });
1573
- },
1574
- [base.sendMessage]
1575
- );
1576
- return {
1577
- ...base,
1578
- chats,
1579
- selectedChat,
1580
- selectChat,
1581
- addUserToChat,
1582
- removeUserFromChat,
1583
- blockUser
1584
- };
1585
- };
1586
-
1587
- // hooks/use-websocket-chat-customer.ts
1588
- var import_react3 = require("react");
1589
- var useWebSocketChatCustomer = ({
1590
- serverBaseUrl,
1591
- orgId,
1592
- chatKey,
1593
- product
1594
- }) => {
1595
- const [currentChat, setCurrentChat] = (0, import_react3.useState)(void 0);
1596
- const handleMessage = (0, import_react3.useCallback)((chatEvent) => {
1597
- console.log("Received event:", chatEvent.type);
1598
- switch (chatEvent.type) {
1599
- case "message":
1600
- if (!chatEvent.message) return;
1601
- console.log(
1602
- "got message:",
1603
- chatEvent.message.role,
1604
- ":",
1605
- chatEvent.message.content
1606
- );
1607
- setCurrentChat((prev) => {
1608
- if (!prev) return prev;
1609
- return {
1610
- ...prev,
1611
- messages: [...prev.messages, chatEvent.message]
1612
- };
1613
- });
1614
- break;
1615
- case "chat_updated":
1616
- const chat = chatEvent.data?.chat?.value;
1617
- if (chat) {
1618
- setCurrentChat(chat);
1619
- }
1620
- break;
1621
- case "load_chat":
1622
- const history = chatEvent.data?.chat;
1623
- if (!history) return;
1624
- setCurrentChat(history);
1625
- break;
1626
- default:
1627
- break;
1628
- }
1629
- }, []);
1630
- const base = useWebSocketChatBase({
1631
- serverBaseUrl,
1632
- orgId,
1633
- clientType: "customer",
1634
- onMessage: handleMessage,
1635
- product
1636
- });
1637
- return {
1638
- ...base,
1639
- chatKey,
1640
- title: currentChat?.title,
1641
- messages: currentChat?.messages ?? [],
1642
- users: currentChat?.users ?? [],
1643
- isWaiting: currentChat?.isWaiting ?? false,
1644
- isWaitingForAgent: currentChat?.isWaitingForAgent ?? false,
1645
- aiEngaged: currentChat?.aiEngaged ?? false,
1646
- humanAgentEngaged: currentChat?.humanAgentEngaged ?? false,
1647
- metadata: currentChat?.metadata ?? {},
1648
- status: currentChat?.status
1649
- };
1650
- };
1651
-
1652
- // context/websocket-chat-admin-context.tsx
1653
- var import_jsx_runtime = require("react/jsx-runtime");
1654
- var WebSocketChatAdminContext = (0, import_react4.createContext)(void 0);
1655
- function WebSocketChatAdminProvider(props) {
1656
- const { children, serverBaseUrl, orgId, userId, product } = props;
1657
- const webSocket = useWebSocketChatAdmin({
1658
- serverBaseUrl,
1659
- orgId,
1660
- product
1661
- });
1662
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WebSocketChatAdminContext.Provider, { value: webSocket, children });
1663
- }
1664
- var useWebSocketChatAdminContext = () => {
1665
- const context = (0, import_react4.useContext)(WebSocketChatAdminContext);
1666
- if (context === void 0) {
1667
- throw new Error(
1668
- "useWebSocketChatAdminContext must be used within a WebSocketChatAdminProvider"
1669
- );
1670
- }
1671
- return context;
1672
- };
1673
-
1674
- // components/admin/admin-chat-input.tsx
1675
- var import_jsx_runtime2 = require("react/jsx-runtime");
1676
- var AdminChatInput = ({
1677
- userId,
1678
- orgId,
1679
- onFileUpload,
1680
- chatKey
1681
- }) => {
1682
- const { sendMessage } = useWebSocketChatAdminContext();
1683
- const [input, setInput] = (0, import_react5.useState)("");
1684
- const [isUploading, setIsUploading] = (0, import_react5.useState)(false);
1685
- const [isSending, setIsSending] = (0, import_react5.useState)(false);
1686
- const fileInputRef = (0, import_react5.useRef)(null);
1687
- const MAX_FILE_SIZE = 5 * 1024 * 1024;
1688
- const handleSend = async () => {
1689
- if (!input.trim() && !isUploading || isSending) return;
1690
- if (!chatKey || !orgId || !userId) {
1691
- console.error("chatKey, orgId, or userId is not defined");
1692
- return;
1693
- }
1694
- try {
1695
- setIsSending(true);
1696
- sendMessage({
1697
- type: "message",
1698
- chatKey,
1699
- orgId,
1700
- userId,
1701
- message: {
1702
- id: import_ksuid.default.randomSync().string,
1703
- content: input,
1704
- role: "user",
1705
- senderId: userId,
1706
- time: Date.now(),
1707
- status: "sending",
1708
- createdAt: Date.now()
1709
- }
1710
- });
1711
- setInput("");
1712
- } finally {
1713
- setIsSending(false);
1714
- }
1715
- };
1716
- const handleFileUpload = async (event) => {
1717
- const files = event.target.files;
1718
- if (!files || !onFileUpload) return;
1719
- try {
1720
- setIsUploading(true);
1721
- const uploadedUrls = await Promise.all(
1722
- Array.from(files).map(async (file) => {
1723
- if (file.size > MAX_FILE_SIZE) {
1724
- throw new Error(
1725
- `File ${file.name} is too large. Maximum size is 5MB.`
1726
- );
1727
- }
1728
- const url = await onFileUpload(file);
1729
- return {
1730
- type: file.type,
1731
- url,
1732
- name: file.name
1733
- };
1734
- })
1735
- );
1736
- const attachments = uploadedUrls.map((file) => ({
1737
- type: "image",
1738
- url: file.url,
1739
- title: file.name
1740
- }));
1741
- if (!chatKey || !orgId || !userId) {
1742
- console.error("chatKey, orgId, or userId is not defined");
1743
- return;
1744
- }
1745
- } finally {
1746
- setIsUploading(false);
1747
- if (fileInputRef.current) {
1748
- fileInputRef.current.value = "";
1749
- }
1750
- }
1751
- };
1752
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "p-4 border-t bg-white rounded-b-lg", children: [
1753
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center space-x-2", children: [
1754
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1755
- "input",
1756
- {
1757
- type: "file",
1758
- ref: fileInputRef,
1759
- onChange: handleFileUpload,
1760
- className: "hidden",
1761
- multiple: true,
1762
- accept: "image/*,.pdf,.doc,.docx,.txt"
1763
- }
1764
- ),
1765
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1766
- "button",
1767
- {
1768
- onClick: () => fileInputRef.current?.click(),
1769
- className: "p-2 text-gray-500 hover:text-gray-700 rounded-full hover:bg-gray-100 transition-colors",
1770
- disabled: isUploading,
1771
- "aria-label": "Attach file",
1772
- children: isUploading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "w-5 h-5 animate-spin rounded-full border-2 border-gray-300 border-t-gray-600" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Paperclip, { className: "w-5 h-5" })
1773
- }
1774
- ),
1775
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 relative", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1776
- "textarea",
1777
- {
1778
- value: input,
1779
- onChange: (e) => setInput(e.target.value),
1780
- onKeyDown: (e) => {
1781
- if (e.key === "Enter" && !e.shiftKey) {
1782
- e.preventDefault();
1783
- handleSend();
1784
- }
1785
- },
1786
- className: "w-full p-3 border rounded-2xl focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none",
1787
- placeholder: "Type a message...",
1788
- rows: 1,
1789
- style: {
1790
- minHeight: "44px",
1791
- maxHeight: "200px"
1792
- }
1793
- }
1794
- ) }),
1795
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1796
- "button",
1797
- {
1798
- onClick: handleSend,
1799
- disabled: !input.trim() && !isUploading || isSending,
1800
- className: `p-2 rounded-full transition-colors ${!input.trim() && !isUploading || isSending ? "text-gray-400 bg-gray-100" : "text-white bg-blue-500 hover:bg-blue-600"}`,
1801
- "aria-label": "Send message",
1802
- children: isSending ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "w-5 h-5 animate-spin rounded-full border-2 border-gray-300 border-t-white" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react.Send, { className: "w-5 h-5" })
1803
- }
1804
- )
1805
- ] }),
1806
- isUploading && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-full bg-gray-200 rounded-full h-1", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "bg-blue-500 h-1 rounded-full animate-pulse" }) }) })
1807
- ] });
1808
- };
1809
-
1810
- // components/admin/chat-human-agent-actions.tsx
1811
- var import_lucide_react2 = require("lucide-react");
1812
-
1813
- // context/websocket-chat-customer-context.tsx
1814
- var import_react6 = require("react");
1815
- var import_jsx_runtime3 = require("react/jsx-runtime");
1816
- var WebSocketChatCustomerContext = (0, import_react6.createContext)(void 0);
1817
- function WebSocketChatCustomerProvider(props) {
1818
- const { children, serverBaseUrl, orgId, userId, chatKey, product } = props;
1819
- const webSocket = useWebSocketChatCustomer({
1820
- serverBaseUrl,
1821
- orgId,
1822
- chatKey,
1823
- product
1824
- });
1825
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(WebSocketChatCustomerContext.Provider, { value: webSocket, children });
1826
- }
1827
- var useWebSocketChatCustomerContext = () => {
1828
- const context = (0, import_react6.useContext)(WebSocketChatCustomerContext);
1829
- if (context === void 0) {
1830
- throw new Error(
1831
- "useWebSocketChatCustomerContext must be used within a WebSocketChatCustomerProvider"
1832
- );
1833
- }
1834
- return context;
1835
- };
1836
-
1837
- // components/admin/chat-human-agent-actions.tsx
1838
- var import_jsx_runtime4 = require("react/jsx-runtime");
1839
- var ChatHumanAgentActions = ({ user, orgId }) => {
1840
- const { selectedChat, addUserToChat, removeUserFromChat, blockUser } = useWebSocketChatAdminContext();
1841
- const handleJoinChat = () => {
1842
- if (!selectedChat || !user || !orgId) return;
1843
- addUserToChat(orgId, selectedChat.key, {
1844
- id: user.id,
1845
- role: "humanAgent",
1846
- name: [user.firstName, user.lastName].filter(Boolean).join(" ") || user.email,
1847
- email: user.email,
1848
- authProvider: "tbd",
1849
- authToken: "tbd"
1850
- });
1851
- };
1852
- const handleLeaveChat = () => {
1853
- if (!selectedChat || !user || !orgId) return;
1854
- removeUserFromChat(orgId, selectedChat.key, user.id);
1855
- };
1856
- const handleEndChat = () => {
1857
- if (!selectedChat || !user || !orgId) return;
1858
- };
1859
- const handleStartCall = () => {
1860
- if (!selectedChat || !user || !orgId) return;
1861
- };
1862
- const handleCreateCase = () => {
1863
- if (!selectedChat || !user || !orgId) return;
1864
- };
1865
- const handleBlockUser = () => {
1866
- if (!selectedChat || !user || !orgId) return;
1867
- blockUser(orgId, selectedChat.key, user.id);
1868
- };
1869
- if (!selectedChat) return null;
1870
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "p-4 border-b bg-white flex items-center justify-between", children: [
1871
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center space-x-4", children: [
1872
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "font-semibold text-lg", children: selectedChat.title || `Chat ${selectedChat.key}` }),
1873
- selectedChat.humanAgentEngaged && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "inline-flex items-center rounded-full bg-green-100 px-2.5 py-0.5 text-sm font-medium text-green-800", children: [
1874
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.User, { className: "mr-1 h-4 w-4" }),
1875
- "Agent Engaged"
1876
- ] })
1877
- ] }),
1878
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center space-x-2", children: [
1879
- !selectedChat.humanAgentEngaged ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1880
- "button",
1881
- {
1882
- onClick: handleJoinChat,
1883
- className: "bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center space-x-2 transition-colors",
1884
- children: [
1885
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.User, { className: "h-4 w-4" }),
1886
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Join Chat" })
1887
- ]
1888
- }
1889
- ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1890
- "button",
1891
- {
1892
- onClick: handleLeaveChat,
1893
- className: "bg-orange-500 hover:bg-orange-600 text-white px-4 py-2 rounded-lg flex items-center space-x-2 transition-colors",
1894
- children: [
1895
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.LogOut, { className: "h-4 w-4" }),
1896
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Leave Chat" })
1897
- ]
1898
- }
1899
- ),
1900
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1901
- "button",
1902
- {
1903
- onClick: handleEndChat,
1904
- className: "bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-lg flex items-center space-x-2 transition-colors",
1905
- children: [
1906
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.XCircle, { className: "h-4 w-4" }),
1907
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "End Chat" })
1908
- ]
1909
- }
1910
- ),
1911
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1912
- "button",
1913
- {
1914
- onClick: handleBlockUser,
1915
- className: "bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-lg flex items-center space-x-2 transition-colors",
1916
- children: [
1917
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.XCircle, { className: "h-4 w-4" }),
1918
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Block User" })
1919
- ]
1920
- }
1921
- ),
1922
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1923
- "button",
1924
- {
1925
- onClick: handleStartCall,
1926
- disabled: !selectedChat.humanAgentEngaged,
1927
- className: "bg-green-500 hover:bg-green-600 disabled:bg-gray-300 text-white px-4 py-2 rounded-lg flex items-center space-x-2 transition-colors",
1928
- children: [
1929
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Phone, { className: "h-4 w-4" }),
1930
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Start Call" })
1931
- ]
1932
- }
1933
- ),
1934
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1935
- "button",
1936
- {
1937
- onClick: handleCreateCase,
1938
- className: "bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded-lg flex items-center space-x-2 transition-colors",
1939
- children: [
1940
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Plus, { className: "h-4 w-4" }),
1941
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Create Case" })
1942
- ]
1943
- }
1944
- )
1945
- ] })
1946
- ] });
1947
- };
1948
-
1949
- // components/admin/admin-chat-list.tsx
1950
- var import_lucide_react3 = require("lucide-react");
1951
- var import_jsx_runtime5 = require("react/jsx-runtime");
1952
- var ScrollArea = ({ className, children }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: `overflow-auto ${className || ""}`, children });
1953
- var AdminChatList = ({ className }) => {
1954
- const { chats, selectedChat, selectChat } = useWebSocketChatAdminContext();
1955
- const sortedChats = Array.from(chats.values()).sort(
1956
- (a, b) => b.lastUpdated - a.lastUpdated
1957
- );
1958
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col h-full", children: [
1959
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-4 border-b", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { className: "font-semibold text-lg", children: "Active Chats" }) }),
1960
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex-1 overflow-y-auto", children: sortedChats.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-4 text-center text-gray-500", children: "No active chats" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "divide-y", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ScrollArea, { className: "h-[calc(100vh-15rem)]", children: sortedChats.map((chat, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1961
- AdminChatListItem,
1962
- {
1963
- chat,
1964
- isSelected: chat.key === selectedChat?.key,
1965
- onSelect: () => selectChat(chat.key)
1966
- },
1967
- index
1968
- )) }) }) })
1969
- ] });
1970
- };
1971
- var AdminChatListItem = ({
1972
- chat,
1973
- isSelected,
1974
- onSelect
1975
- }) => {
1976
- const lastMessage = chat.messages[chat.messages.length - 1];
1977
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1978
- "button",
1979
- {
1980
- onClick: onSelect,
1981
- className: `w-full p-4 text-left hover:bg-gray-50 focus:outline-none focus:bg-gray-50 ${isSelected ? "bg-blue-50" : ""}`,
1982
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-start space-x-3", children: [
1983
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "shrink-0", children: [
1984
- chat.aiEngaged && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react3.Bot, { className: "w-6 h-6 text-blue-500" }),
1985
- chat.isWaitingForAgent && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react3.Loader2, { className: "w-6 h-6 text-blue-500 animate-spin text-orange-500" }),
1986
- chat.humanAgentEngaged && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react3.UserCheck, { className: "w-6 h-6 text-blue-500 text-green-500" })
1987
- ] }),
1988
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex-1 min-w-0", children: [
1989
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-sm font-medium text-gray-900 truncate", children: chat.title || `Chat ${chat.key}` }) }),
1990
- lastMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "mt-1 text-sm text-gray-500 truncate", children: lastMessage.content }),
1991
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "mt-1 flex items-center space-x-2", children: [
1992
- chat.isWaiting && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "inline-flex items-center rounded-full bg-yellow-100 px-2 py-0.5 text-xs font-medium text-yellow-800", children: [
1993
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react3.AlertCircle, { className: "mr-1 h-3 w-3" }),
1994
- "Waiting"
1995
- ] }),
1996
- chat.humanAgentEngaged && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800", children: [
1997
- "Agent Engaged:",
1998
- " ",
1999
- chat.users?.find((u) => u.role === ChatRoleHumanAgent)?.name
2000
- ] }),
2001
- chat.isWaitingForAgent && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "inline-flex items-center rounded-full bg-orange-100 px-2 py-0.5 text-xs font-medium text-orange-800", children: "Waiting For Agent" })
2002
- ] })
2003
- ] })
2004
- ] })
2005
- }
2006
- );
2007
- };
2008
-
2009
- // components/admin/admin-chat-header.tsx
2010
- var import_jsx_runtime6 = require("react/jsx-runtime");
2011
- var AdminChatHeader = ({
2012
- className
2013
- }) => {
2014
- const { isConnected, chats } = useWebSocketChatAdminContext();
2015
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "p-4 border-b", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center space-x-2", children: [
2016
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2017
- "div",
2018
- {
2019
- className: `w-2 h-2 rounded-full ${isConnected ? "bg-green-500" : "bg-red-500"}`
2020
- }
2021
- ),
2022
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-sm text-gray-600", children: [
2023
- "Active Chats: ",
2024
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "font-bold", children: chats.size })
2025
- ] }),
2026
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-gray-500", children: "|" }),
2027
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-sm text-gray-600", children: [
2028
- "Waiting For Agent:",
2029
- " ",
2030
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "font-bold", children: Array.from(chats.values()).filter(
2031
- (chat) => chat.isWaitingForAgent
2032
- ).length })
2033
- ] })
2034
- ] }) });
2035
- };
2036
-
2037
- // components/customer/chat-status-customer-ui.tsx
2038
- var import_jsx_runtime7 = require("react/jsx-runtime");
2039
- var ChatStatusCustomerUI = ({ isConnected }) => {
2040
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center space-x-2", children: [
2041
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2042
- "span",
2043
- {
2044
- className: `w-3 h-3 rounded-full ${isConnected ? "bg-green-500" : "bg-red-500"}`,
2045
- role: "status",
2046
- "aria-label": isConnected ? "Connected" : "Disconnected"
2047
- }
2048
- ),
2049
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm text-gray-500", children: isConnected ? "Connected" : "Reconnecting..." })
2050
- ] });
2051
- };
2052
-
2053
- // components/customer/chat-header.tsx
2054
- var import_jsx_runtime8 = require("react/jsx-runtime");
2055
- var ChatHeader = () => {
2056
- const { isConnected, title } = useWebSocketChatCustomerContext();
2057
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "p-4 border-b bg-white rounded-t-lg", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between", children: [
2058
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { className: "font-bold text-lg", children: title || "Chat" }),
2059
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChatStatusCustomerUI, { isConnected })
2060
- ] }) });
2061
- };
2062
-
2063
- // components/customer/chat-input.tsx
2064
- var import_ksuid2 = __toESM(require("ksuid"));
2065
- var import_lucide_react4 = require("lucide-react");
2066
- var import_react7 = require("react");
2067
- var import_jsx_runtime9 = require("react/jsx-runtime");
2068
- var ChatInput = ({ userId, orgId, onFileUpload }) => {
2069
- const { sendMessage, chatKey } = useWebSocketChatCustomerContext();
2070
- const [input, setInput] = (0, import_react7.useState)("");
2071
- const [isUploading, setIsUploading] = (0, import_react7.useState)(false);
2072
- const [isSending, setIsSending] = (0, import_react7.useState)(false);
2073
- const fileInputRef = (0, import_react7.useRef)(null);
2074
- const MAX_FILE_SIZE = 5 * 1024 * 1024;
2075
- const handleSend = async () => {
2076
- if (!input.trim() && !isUploading || isSending) return;
2077
- if (!chatKey || !orgId || !userId) {
2078
- console.error("chatKey, orgId, or userId is not defined");
2079
- return;
2080
- }
2081
- try {
2082
- setIsSending(true);
2083
- sendMessage({
2084
- type: "message",
2085
- chatKey,
2086
- orgId,
2087
- userId,
2088
- message: {
2089
- id: import_ksuid2.default.randomSync().string,
2090
- content: input,
2091
- role: "user",
2092
- senderId: userId,
2093
- time: Date.now(),
2094
- status: "sending",
2095
- createdAt: Date.now()
2096
- }
2097
- });
2098
- setInput("");
2099
- } finally {
2100
- setIsSending(false);
2101
- }
2102
- };
2103
- const handleFileUpload = async (event) => {
2104
- const files = event.target.files;
2105
- if (!files || !onFileUpload) return;
2106
- try {
2107
- setIsUploading(true);
2108
- const uploadedUrls = await Promise.all(
2109
- Array.from(files).map(async (file) => {
2110
- if (file.size > MAX_FILE_SIZE) {
2111
- throw new Error(
2112
- `File ${file.name} is too large. Maximum size is 5MB.`
2113
- );
2114
- }
2115
- const url = await onFileUpload(file);
2116
- return {
2117
- type: file.type,
2118
- url,
2119
- name: file.name
2120
- };
2121
- })
2122
- );
2123
- const attachments = uploadedUrls.map((file) => ({
2124
- type: "image",
2125
- url: file.url,
2126
- title: file.name
2127
- }));
2128
- if (!chatKey || !orgId || !userId) {
2129
- console.error("chatKey, orgId, or userId is not defined");
2130
- return;
2131
- }
2132
- } finally {
2133
- setIsUploading(false);
2134
- if (fileInputRef.current) {
2135
- fileInputRef.current.value = "";
2136
- }
2137
- }
2138
- };
2139
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "p-4 border-t bg-white rounded-b-lg", children: [
2140
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center space-x-2", children: [
2141
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2142
- "input",
2143
- {
2144
- type: "file",
2145
- ref: fileInputRef,
2146
- onChange: handleFileUpload,
2147
- className: "hidden",
2148
- multiple: true,
2149
- accept: "image/*,.pdf,.doc,.docx,.txt"
2150
- }
2151
- ),
2152
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2153
- "button",
2154
- {
2155
- onClick: () => fileInputRef.current?.click(),
2156
- className: "p-2 text-gray-500 hover:text-gray-700 rounded-full hover:bg-gray-100 transition-colors",
2157
- disabled: isUploading,
2158
- "aria-label": "Attach file",
2159
- children: isUploading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "w-5 h-5 animate-spin rounded-full border-2 border-gray-300 border-t-gray-600" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react4.Paperclip, { className: "w-5 h-5" })
2160
- }
2161
- ),
2162
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex-1 relative", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2163
- "textarea",
2164
- {
2165
- value: input,
2166
- onChange: (e) => setInput(e.target.value),
2167
- onKeyDown: (e) => {
2168
- if (e.key === "Enter" && !e.shiftKey) {
2169
- e.preventDefault();
2170
- handleSend();
2171
- }
2172
- },
2173
- className: "w-full p-3 border rounded-2xl focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none",
2174
- placeholder: "Type a message...",
2175
- rows: 1,
2176
- style: {
2177
- minHeight: "44px",
2178
- maxHeight: "200px"
2179
- }
2180
- }
2181
- ) }),
2182
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2183
- "button",
2184
- {
2185
- onClick: handleSend,
2186
- disabled: !input.trim() && !isUploading || isSending,
2187
- className: `p-2 rounded-full transition-colors ${!input.trim() && !isUploading || isSending ? "text-gray-400 bg-gray-100" : "text-white bg-blue-500 hover:bg-blue-600"}`,
2188
- "aria-label": "Send message",
2189
- children: isSending ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "w-5 h-5 animate-spin rounded-full border-2 border-gray-300 border-t-white" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react4.Send, { className: "w-5 h-5" })
2190
- }
2191
- )
2192
- ] }),
2193
- isUploading && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-full bg-gray-200 rounded-full h-1", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "bg-blue-500 h-1 rounded-full animate-pulse" }) }) })
2194
- ] });
2195
- };
2196
-
2197
- // components/customer/chat-messages.tsx
2198
- var import_react8 = require("react");
2199
-
2200
- // ../../node_modules/date-fns/constants.js
2201
- var daysInYear = 365.2425;
2202
- var maxTime = Math.pow(10, 8) * 24 * 60 * 60 * 1e3;
2203
- var minTime = -maxTime;
2204
- var millisecondsInWeek = 6048e5;
2205
- var millisecondsInDay = 864e5;
2206
- var secondsInHour = 3600;
2207
- var secondsInDay = secondsInHour * 24;
2208
- var secondsInWeek = secondsInDay * 7;
2209
- var secondsInYear = secondsInDay * daysInYear;
2210
- var secondsInMonth = secondsInYear / 12;
2211
- var secondsInQuarter = secondsInMonth * 3;
2212
- var constructFromSymbol = /* @__PURE__ */ Symbol.for("constructDateFrom");
2213
-
2214
- // ../../node_modules/date-fns/constructFrom.js
2215
- function constructFrom(date, value) {
2216
- if (typeof date === "function") return date(value);
2217
- if (date && typeof date === "object" && constructFromSymbol in date)
2218
- return date[constructFromSymbol](value);
2219
- if (date instanceof Date) return new date.constructor(value);
2220
- return new Date(value);
2221
- }
2222
-
2223
- // ../../node_modules/date-fns/toDate.js
2224
- function toDate(argument, context) {
2225
- return constructFrom(context || argument, argument);
2226
- }
2227
-
2228
- // ../../node_modules/date-fns/_lib/defaultOptions.js
2229
- var defaultOptions = {};
2230
- function getDefaultOptions() {
2231
- return defaultOptions;
2232
- }
2233
-
2234
- // ../../node_modules/date-fns/startOfWeek.js
2235
- function startOfWeek(date, options) {
2236
- const defaultOptions2 = getDefaultOptions();
2237
- const weekStartsOn = options?.weekStartsOn ?? options?.locale?.options?.weekStartsOn ?? defaultOptions2.weekStartsOn ?? defaultOptions2.locale?.options?.weekStartsOn ?? 0;
2238
- const _date = toDate(date, options?.in);
2239
- const day = _date.getDay();
2240
- const diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
2241
- _date.setDate(_date.getDate() - diff);
2242
- _date.setHours(0, 0, 0, 0);
2243
- return _date;
2244
- }
2245
-
2246
- // ../../node_modules/date-fns/startOfISOWeek.js
2247
- function startOfISOWeek(date, options) {
2248
- return startOfWeek(date, { ...options, weekStartsOn: 1 });
2249
- }
2250
-
2251
- // ../../node_modules/date-fns/getISOWeekYear.js
2252
- function getISOWeekYear(date, options) {
2253
- const _date = toDate(date, options?.in);
2254
- const year = _date.getFullYear();
2255
- const fourthOfJanuaryOfNextYear = constructFrom(_date, 0);
2256
- fourthOfJanuaryOfNextYear.setFullYear(year + 1, 0, 4);
2257
- fourthOfJanuaryOfNextYear.setHours(0, 0, 0, 0);
2258
- const startOfNextYear = startOfISOWeek(fourthOfJanuaryOfNextYear);
2259
- const fourthOfJanuaryOfThisYear = constructFrom(_date, 0);
2260
- fourthOfJanuaryOfThisYear.setFullYear(year, 0, 4);
2261
- fourthOfJanuaryOfThisYear.setHours(0, 0, 0, 0);
2262
- const startOfThisYear = startOfISOWeek(fourthOfJanuaryOfThisYear);
2263
- if (_date.getTime() >= startOfNextYear.getTime()) {
2264
- return year + 1;
2265
- } else if (_date.getTime() >= startOfThisYear.getTime()) {
2266
- return year;
2267
- } else {
2268
- return year - 1;
2269
- }
2270
- }
2271
-
2272
- // ../../node_modules/date-fns/_lib/getTimezoneOffsetInMilliseconds.js
2273
- function getTimezoneOffsetInMilliseconds(date) {
2274
- const _date = toDate(date);
2275
- const utcDate = new Date(
2276
- Date.UTC(
2277
- _date.getFullYear(),
2278
- _date.getMonth(),
2279
- _date.getDate(),
2280
- _date.getHours(),
2281
- _date.getMinutes(),
2282
- _date.getSeconds(),
2283
- _date.getMilliseconds()
2284
- )
2285
- );
2286
- utcDate.setUTCFullYear(_date.getFullYear());
2287
- return +date - +utcDate;
2288
- }
2289
-
2290
- // ../../node_modules/date-fns/_lib/normalizeDates.js
2291
- function normalizeDates(context, ...dates) {
2292
- const normalize = constructFrom.bind(
2293
- null,
2294
- context || dates.find((date) => typeof date === "object")
2295
- );
2296
- return dates.map(normalize);
2297
- }
2298
-
2299
- // ../../node_modules/date-fns/startOfDay.js
2300
- function startOfDay(date, options) {
2301
- const _date = toDate(date, options?.in);
2302
- _date.setHours(0, 0, 0, 0);
2303
- return _date;
2304
- }
2305
-
2306
- // ../../node_modules/date-fns/differenceInCalendarDays.js
2307
- function differenceInCalendarDays(laterDate, earlierDate, options) {
2308
- const [laterDate_, earlierDate_] = normalizeDates(
2309
- options?.in,
2310
- laterDate,
2311
- earlierDate
2312
- );
2313
- const laterStartOfDay = startOfDay(laterDate_);
2314
- const earlierStartOfDay = startOfDay(earlierDate_);
2315
- const laterTimestamp = +laterStartOfDay - getTimezoneOffsetInMilliseconds(laterStartOfDay);
2316
- const earlierTimestamp = +earlierStartOfDay - getTimezoneOffsetInMilliseconds(earlierStartOfDay);
2317
- return Math.round((laterTimestamp - earlierTimestamp) / millisecondsInDay);
2318
- }
2319
-
2320
- // ../../node_modules/date-fns/startOfISOWeekYear.js
2321
- function startOfISOWeekYear(date, options) {
2322
- const year = getISOWeekYear(date, options);
2323
- const fourthOfJanuary = constructFrom(options?.in || date, 0);
2324
- fourthOfJanuary.setFullYear(year, 0, 4);
2325
- fourthOfJanuary.setHours(0, 0, 0, 0);
2326
- return startOfISOWeek(fourthOfJanuary);
2327
- }
2328
-
2329
- // ../../node_modules/date-fns/isDate.js
2330
- function isDate(value) {
2331
- return value instanceof Date || typeof value === "object" && Object.prototype.toString.call(value) === "[object Date]";
2332
- }
2333
-
2334
- // ../../node_modules/date-fns/isValid.js
2335
- function isValid(date) {
2336
- return !(!isDate(date) && typeof date !== "number" || isNaN(+toDate(date)));
2337
- }
2338
-
2339
- // ../../node_modules/date-fns/startOfYear.js
2340
- function startOfYear(date, options) {
2341
- const date_ = toDate(date, options?.in);
2342
- date_.setFullYear(date_.getFullYear(), 0, 1);
2343
- date_.setHours(0, 0, 0, 0);
2344
- return date_;
2345
- }
2346
-
2347
- // ../../node_modules/date-fns/locale/en-US/_lib/formatDistance.js
2348
- var formatDistanceLocale = {
2349
- lessThanXSeconds: {
2350
- one: "less than a second",
2351
- other: "less than {{count}} seconds"
2352
- },
2353
- xSeconds: {
2354
- one: "1 second",
2355
- other: "{{count}} seconds"
2356
- },
2357
- halfAMinute: "half a minute",
2358
- lessThanXMinutes: {
2359
- one: "less than a minute",
2360
- other: "less than {{count}} minutes"
2361
- },
2362
- xMinutes: {
2363
- one: "1 minute",
2364
- other: "{{count}} minutes"
2365
- },
2366
- aboutXHours: {
2367
- one: "about 1 hour",
2368
- other: "about {{count}} hours"
2369
- },
2370
- xHours: {
2371
- one: "1 hour",
2372
- other: "{{count}} hours"
2373
- },
2374
- xDays: {
2375
- one: "1 day",
2376
- other: "{{count}} days"
2377
- },
2378
- aboutXWeeks: {
2379
- one: "about 1 week",
2380
- other: "about {{count}} weeks"
2381
- },
2382
- xWeeks: {
2383
- one: "1 week",
2384
- other: "{{count}} weeks"
2385
- },
2386
- aboutXMonths: {
2387
- one: "about 1 month",
2388
- other: "about {{count}} months"
2389
- },
2390
- xMonths: {
2391
- one: "1 month",
2392
- other: "{{count}} months"
2393
- },
2394
- aboutXYears: {
2395
- one: "about 1 year",
2396
- other: "about {{count}} years"
2397
- },
2398
- xYears: {
2399
- one: "1 year",
2400
- other: "{{count}} years"
2401
- },
2402
- overXYears: {
2403
- one: "over 1 year",
2404
- other: "over {{count}} years"
2405
- },
2406
- almostXYears: {
2407
- one: "almost 1 year",
2408
- other: "almost {{count}} years"
2409
- }
2410
- };
2411
- var formatDistance = (token, count, options) => {
2412
- let result;
2413
- const tokenValue = formatDistanceLocale[token];
2414
- if (typeof tokenValue === "string") {
2415
- result = tokenValue;
2416
- } else if (count === 1) {
2417
- result = tokenValue.one;
2418
- } else {
2419
- result = tokenValue.other.replace("{{count}}", count.toString());
2420
- }
2421
- if (options?.addSuffix) {
2422
- if (options.comparison && options.comparison > 0) {
2423
- return "in " + result;
2424
- } else {
2425
- return result + " ago";
2426
- }
2427
- }
2428
- return result;
2429
- };
2430
-
2431
- // ../../node_modules/date-fns/locale/_lib/buildFormatLongFn.js
2432
- function buildFormatLongFn(args) {
2433
- return (options = {}) => {
2434
- const width = options.width ? String(options.width) : args.defaultWidth;
2435
- const format2 = args.formats[width] || args.formats[args.defaultWidth];
2436
- return format2;
2437
- };
2438
- }
2439
-
2440
- // ../../node_modules/date-fns/locale/en-US/_lib/formatLong.js
2441
- var dateFormats = {
2442
- full: "EEEE, MMMM do, y",
2443
- long: "MMMM do, y",
2444
- medium: "MMM d, y",
2445
- short: "MM/dd/yyyy"
2446
- };
2447
- var timeFormats = {
2448
- full: "h:mm:ss a zzzz",
2449
- long: "h:mm:ss a z",
2450
- medium: "h:mm:ss a",
2451
- short: "h:mm a"
2452
- };
2453
- var dateTimeFormats = {
2454
- full: "{{date}} 'at' {{time}}",
2455
- long: "{{date}} 'at' {{time}}",
2456
- medium: "{{date}}, {{time}}",
2457
- short: "{{date}}, {{time}}"
2458
- };
2459
- var formatLong = {
2460
- date: buildFormatLongFn({
2461
- formats: dateFormats,
2462
- defaultWidth: "full"
2463
- }),
2464
- time: buildFormatLongFn({
2465
- formats: timeFormats,
2466
- defaultWidth: "full"
2467
- }),
2468
- dateTime: buildFormatLongFn({
2469
- formats: dateTimeFormats,
2470
- defaultWidth: "full"
2471
- })
2472
- };
2473
-
2474
- // ../../node_modules/date-fns/locale/en-US/_lib/formatRelative.js
2475
- var formatRelativeLocale = {
2476
- lastWeek: "'last' eeee 'at' p",
2477
- yesterday: "'yesterday at' p",
2478
- today: "'today at' p",
2479
- tomorrow: "'tomorrow at' p",
2480
- nextWeek: "eeee 'at' p",
2481
- other: "P"
2482
- };
2483
- var formatRelative = (token, _date, _baseDate, _options) => formatRelativeLocale[token];
2484
-
2485
- // ../../node_modules/date-fns/locale/_lib/buildLocalizeFn.js
2486
- function buildLocalizeFn(args) {
2487
- return (value, options) => {
2488
- const context = options?.context ? String(options.context) : "standalone";
2489
- let valuesArray;
2490
- if (context === "formatting" && args.formattingValues) {
2491
- const defaultWidth = args.defaultFormattingWidth || args.defaultWidth;
2492
- const width = options?.width ? String(options.width) : defaultWidth;
2493
- valuesArray = args.formattingValues[width] || args.formattingValues[defaultWidth];
2494
- } else {
2495
- const defaultWidth = args.defaultWidth;
2496
- const width = options?.width ? String(options.width) : args.defaultWidth;
2497
- valuesArray = args.values[width] || args.values[defaultWidth];
2498
- }
2499
- const index = args.argumentCallback ? args.argumentCallback(value) : value;
2500
- return valuesArray[index];
2501
- };
2502
- }
2503
-
2504
- // ../../node_modules/date-fns/locale/en-US/_lib/localize.js
2505
- var eraValues = {
2506
- narrow: ["B", "A"],
2507
- abbreviated: ["BC", "AD"],
2508
- wide: ["Before Christ", "Anno Domini"]
2509
- };
2510
- var quarterValues = {
2511
- narrow: ["1", "2", "3", "4"],
2512
- abbreviated: ["Q1", "Q2", "Q3", "Q4"],
2513
- wide: ["1st quarter", "2nd quarter", "3rd quarter", "4th quarter"]
2514
- };
2515
- var monthValues = {
2516
- narrow: ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"],
2517
- abbreviated: [
2518
- "Jan",
2519
- "Feb",
2520
- "Mar",
2521
- "Apr",
2522
- "May",
2523
- "Jun",
2524
- "Jul",
2525
- "Aug",
2526
- "Sep",
2527
- "Oct",
2528
- "Nov",
2529
- "Dec"
2530
- ],
2531
- wide: [
2532
- "January",
2533
- "February",
2534
- "March",
2535
- "April",
2536
- "May",
2537
- "June",
2538
- "July",
2539
- "August",
2540
- "September",
2541
- "October",
2542
- "November",
2543
- "December"
2544
- ]
2545
- };
2546
- var dayValues = {
2547
- narrow: ["S", "M", "T", "W", "T", "F", "S"],
2548
- short: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
2549
- abbreviated: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
2550
- wide: [
2551
- "Sunday",
2552
- "Monday",
2553
- "Tuesday",
2554
- "Wednesday",
2555
- "Thursday",
2556
- "Friday",
2557
- "Saturday"
2558
- ]
2559
- };
2560
- var dayPeriodValues = {
2561
- narrow: {
2562
- am: "a",
2563
- pm: "p",
2564
- midnight: "mi",
2565
- noon: "n",
2566
- morning: "morning",
2567
- afternoon: "afternoon",
2568
- evening: "evening",
2569
- night: "night"
2570
- },
2571
- abbreviated: {
2572
- am: "AM",
2573
- pm: "PM",
2574
- midnight: "midnight",
2575
- noon: "noon",
2576
- morning: "morning",
2577
- afternoon: "afternoon",
2578
- evening: "evening",
2579
- night: "night"
2580
- },
2581
- wide: {
2582
- am: "a.m.",
2583
- pm: "p.m.",
2584
- midnight: "midnight",
2585
- noon: "noon",
2586
- morning: "morning",
2587
- afternoon: "afternoon",
2588
- evening: "evening",
2589
- night: "night"
2590
- }
2591
- };
2592
- var formattingDayPeriodValues = {
2593
- narrow: {
2594
- am: "a",
2595
- pm: "p",
2596
- midnight: "mi",
2597
- noon: "n",
2598
- morning: "in the morning",
2599
- afternoon: "in the afternoon",
2600
- evening: "in the evening",
2601
- night: "at night"
2602
- },
2603
- abbreviated: {
2604
- am: "AM",
2605
- pm: "PM",
2606
- midnight: "midnight",
2607
- noon: "noon",
2608
- morning: "in the morning",
2609
- afternoon: "in the afternoon",
2610
- evening: "in the evening",
2611
- night: "at night"
2612
- },
2613
- wide: {
2614
- am: "a.m.",
2615
- pm: "p.m.",
2616
- midnight: "midnight",
2617
- noon: "noon",
2618
- morning: "in the morning",
2619
- afternoon: "in the afternoon",
2620
- evening: "in the evening",
2621
- night: "at night"
2622
- }
2623
- };
2624
- var ordinalNumber = (dirtyNumber, _options) => {
2625
- const number = Number(dirtyNumber);
2626
- const rem100 = number % 100;
2627
- if (rem100 > 20 || rem100 < 10) {
2628
- switch (rem100 % 10) {
2629
- case 1:
2630
- return number + "st";
2631
- case 2:
2632
- return number + "nd";
2633
- case 3:
2634
- return number + "rd";
2635
- }
2636
- }
2637
- return number + "th";
2638
- };
2639
- var localize = {
2640
- ordinalNumber,
2641
- era: buildLocalizeFn({
2642
- values: eraValues,
2643
- defaultWidth: "wide"
2644
- }),
2645
- quarter: buildLocalizeFn({
2646
- values: quarterValues,
2647
- defaultWidth: "wide",
2648
- argumentCallback: (quarter) => quarter - 1
2649
- }),
2650
- month: buildLocalizeFn({
2651
- values: monthValues,
2652
- defaultWidth: "wide"
2653
- }),
2654
- day: buildLocalizeFn({
2655
- values: dayValues,
2656
- defaultWidth: "wide"
2657
- }),
2658
- dayPeriod: buildLocalizeFn({
2659
- values: dayPeriodValues,
2660
- defaultWidth: "wide",
2661
- formattingValues: formattingDayPeriodValues,
2662
- defaultFormattingWidth: "wide"
2663
- })
2664
- };
2665
-
2666
- // ../../node_modules/date-fns/locale/_lib/buildMatchFn.js
2667
- function buildMatchFn(args) {
2668
- return (string, options = {}) => {
2669
- const width = options.width;
2670
- const matchPattern = width && args.matchPatterns[width] || args.matchPatterns[args.defaultMatchWidth];
2671
- const matchResult = string.match(matchPattern);
2672
- if (!matchResult) {
2673
- return null;
2674
- }
2675
- const matchedString = matchResult[0];
2676
- const parsePatterns = width && args.parsePatterns[width] || args.parsePatterns[args.defaultParseWidth];
2677
- const key = Array.isArray(parsePatterns) ? findIndex(parsePatterns, (pattern) => pattern.test(matchedString)) : (
2678
- // [TODO] -- I challenge you to fix the type
2679
- findKey(parsePatterns, (pattern) => pattern.test(matchedString))
2680
- );
2681
- let value;
2682
- value = args.valueCallback ? args.valueCallback(key) : key;
2683
- value = options.valueCallback ? (
2684
- // [TODO] -- I challenge you to fix the type
2685
- options.valueCallback(value)
2686
- ) : value;
2687
- const rest = string.slice(matchedString.length);
2688
- return { value, rest };
2689
- };
2690
- }
2691
- function findKey(object, predicate) {
2692
- for (const key in object) {
2693
- if (Object.prototype.hasOwnProperty.call(object, key) && predicate(object[key])) {
2694
- return key;
2695
- }
2696
- }
2697
- return void 0;
2698
- }
2699
- function findIndex(array, predicate) {
2700
- for (let key = 0; key < array.length; key++) {
2701
- if (predicate(array[key])) {
2702
- return key;
2703
- }
2704
- }
2705
- return void 0;
2706
- }
2707
-
2708
- // ../../node_modules/date-fns/locale/_lib/buildMatchPatternFn.js
2709
- function buildMatchPatternFn(args) {
2710
- return (string, options = {}) => {
2711
- const matchResult = string.match(args.matchPattern);
2712
- if (!matchResult) return null;
2713
- const matchedString = matchResult[0];
2714
- const parseResult = string.match(args.parsePattern);
2715
- if (!parseResult) return null;
2716
- let value = args.valueCallback ? args.valueCallback(parseResult[0]) : parseResult[0];
2717
- value = options.valueCallback ? options.valueCallback(value) : value;
2718
- const rest = string.slice(matchedString.length);
2719
- return { value, rest };
2720
- };
2721
- }
2722
-
2723
- // ../../node_modules/date-fns/locale/en-US/_lib/match.js
2724
- var matchOrdinalNumberPattern = /^(\d+)(th|st|nd|rd)?/i;
2725
- var parseOrdinalNumberPattern = /\d+/i;
2726
- var matchEraPatterns = {
2727
- narrow: /^(b|a)/i,
2728
- abbreviated: /^(b\.?\s?c\.?|b\.?\s?c\.?\s?e\.?|a\.?\s?d\.?|c\.?\s?e\.?)/i,
2729
- wide: /^(before christ|before common era|anno domini|common era)/i
2730
- };
2731
- var parseEraPatterns = {
2732
- any: [/^b/i, /^(a|c)/i]
2733
- };
2734
- var matchQuarterPatterns = {
2735
- narrow: /^[1234]/i,
2736
- abbreviated: /^q[1234]/i,
2737
- wide: /^[1234](th|st|nd|rd)? quarter/i
2738
- };
2739
- var parseQuarterPatterns = {
2740
- any: [/1/i, /2/i, /3/i, /4/i]
2741
- };
2742
- var matchMonthPatterns = {
2743
- narrow: /^[jfmasond]/i,
2744
- abbreviated: /^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i,
2745
- wide: /^(january|february|march|april|may|june|july|august|september|october|november|december)/i
2746
- };
2747
- var parseMonthPatterns = {
2748
- narrow: [
2749
- /^j/i,
2750
- /^f/i,
2751
- /^m/i,
2752
- /^a/i,
2753
- /^m/i,
2754
- /^j/i,
2755
- /^j/i,
2756
- /^a/i,
2757
- /^s/i,
2758
- /^o/i,
2759
- /^n/i,
2760
- /^d/i
2761
- ],
2762
- any: [
2763
- /^ja/i,
2764
- /^f/i,
2765
- /^mar/i,
2766
- /^ap/i,
2767
- /^may/i,
2768
- /^jun/i,
2769
- /^jul/i,
2770
- /^au/i,
2771
- /^s/i,
2772
- /^o/i,
2773
- /^n/i,
2774
- /^d/i
2775
- ]
2776
- };
2777
- var matchDayPatterns = {
2778
- narrow: /^[smtwf]/i,
2779
- short: /^(su|mo|tu|we|th|fr|sa)/i,
2780
- abbreviated: /^(sun|mon|tue|wed|thu|fri|sat)/i,
2781
- wide: /^(sunday|monday|tuesday|wednesday|thursday|friday|saturday)/i
2782
- };
2783
- var parseDayPatterns = {
2784
- narrow: [/^s/i, /^m/i, /^t/i, /^w/i, /^t/i, /^f/i, /^s/i],
2785
- any: [/^su/i, /^m/i, /^tu/i, /^w/i, /^th/i, /^f/i, /^sa/i]
2786
- };
2787
- var matchDayPeriodPatterns = {
2788
- narrow: /^(a|p|mi|n|(in the|at) (morning|afternoon|evening|night))/i,
2789
- any: /^([ap]\.?\s?m\.?|midnight|noon|(in the|at) (morning|afternoon|evening|night))/i
2790
- };
2791
- var parseDayPeriodPatterns = {
2792
- any: {
2793
- am: /^a/i,
2794
- pm: /^p/i,
2795
- midnight: /^mi/i,
2796
- noon: /^no/i,
2797
- morning: /morning/i,
2798
- afternoon: /afternoon/i,
2799
- evening: /evening/i,
2800
- night: /night/i
2801
- }
2802
- };
2803
- var match = {
2804
- ordinalNumber: buildMatchPatternFn({
2805
- matchPattern: matchOrdinalNumberPattern,
2806
- parsePattern: parseOrdinalNumberPattern,
2807
- valueCallback: (value) => parseInt(value, 10)
2808
- }),
2809
- era: buildMatchFn({
2810
- matchPatterns: matchEraPatterns,
2811
- defaultMatchWidth: "wide",
2812
- parsePatterns: parseEraPatterns,
2813
- defaultParseWidth: "any"
2814
- }),
2815
- quarter: buildMatchFn({
2816
- matchPatterns: matchQuarterPatterns,
2817
- defaultMatchWidth: "wide",
2818
- parsePatterns: parseQuarterPatterns,
2819
- defaultParseWidth: "any",
2820
- valueCallback: (index) => index + 1
2821
- }),
2822
- month: buildMatchFn({
2823
- matchPatterns: matchMonthPatterns,
2824
- defaultMatchWidth: "wide",
2825
- parsePatterns: parseMonthPatterns,
2826
- defaultParseWidth: "any"
2827
- }),
2828
- day: buildMatchFn({
2829
- matchPatterns: matchDayPatterns,
2830
- defaultMatchWidth: "wide",
2831
- parsePatterns: parseDayPatterns,
2832
- defaultParseWidth: "any"
2833
- }),
2834
- dayPeriod: buildMatchFn({
2835
- matchPatterns: matchDayPeriodPatterns,
2836
- defaultMatchWidth: "any",
2837
- parsePatterns: parseDayPeriodPatterns,
2838
- defaultParseWidth: "any"
2839
- })
2840
- };
2841
-
2842
- // ../../node_modules/date-fns/locale/en-US.js
2843
- var enUS = {
2844
- code: "en-US",
2845
- formatDistance,
2846
- formatLong,
2847
- formatRelative,
2848
- localize,
2849
- match,
2850
- options: {
2851
- weekStartsOn: 0,
2852
- firstWeekContainsDate: 1
2853
- }
2854
- };
2855
-
2856
- // ../../node_modules/date-fns/getDayOfYear.js
2857
- function getDayOfYear(date, options) {
2858
- const _date = toDate(date, options?.in);
2859
- const diff = differenceInCalendarDays(_date, startOfYear(_date));
2860
- const dayOfYear = diff + 1;
2861
- return dayOfYear;
2862
- }
2863
-
2864
- // ../../node_modules/date-fns/getISOWeek.js
2865
- function getISOWeek(date, options) {
2866
- const _date = toDate(date, options?.in);
2867
- const diff = +startOfISOWeek(_date) - +startOfISOWeekYear(_date);
2868
- return Math.round(diff / millisecondsInWeek) + 1;
2869
- }
2870
-
2871
- // ../../node_modules/date-fns/getWeekYear.js
2872
- function getWeekYear(date, options) {
2873
- const _date = toDate(date, options?.in);
2874
- const year = _date.getFullYear();
2875
- const defaultOptions2 = getDefaultOptions();
2876
- const firstWeekContainsDate = options?.firstWeekContainsDate ?? options?.locale?.options?.firstWeekContainsDate ?? defaultOptions2.firstWeekContainsDate ?? defaultOptions2.locale?.options?.firstWeekContainsDate ?? 1;
2877
- const firstWeekOfNextYear = constructFrom(options?.in || date, 0);
2878
- firstWeekOfNextYear.setFullYear(year + 1, 0, firstWeekContainsDate);
2879
- firstWeekOfNextYear.setHours(0, 0, 0, 0);
2880
- const startOfNextYear = startOfWeek(firstWeekOfNextYear, options);
2881
- const firstWeekOfThisYear = constructFrom(options?.in || date, 0);
2882
- firstWeekOfThisYear.setFullYear(year, 0, firstWeekContainsDate);
2883
- firstWeekOfThisYear.setHours(0, 0, 0, 0);
2884
- const startOfThisYear = startOfWeek(firstWeekOfThisYear, options);
2885
- if (+_date >= +startOfNextYear) {
2886
- return year + 1;
2887
- } else if (+_date >= +startOfThisYear) {
2888
- return year;
2889
- } else {
2890
- return year - 1;
2891
- }
2892
- }
2893
-
2894
- // ../../node_modules/date-fns/startOfWeekYear.js
2895
- function startOfWeekYear(date, options) {
2896
- const defaultOptions2 = getDefaultOptions();
2897
- const firstWeekContainsDate = options?.firstWeekContainsDate ?? options?.locale?.options?.firstWeekContainsDate ?? defaultOptions2.firstWeekContainsDate ?? defaultOptions2.locale?.options?.firstWeekContainsDate ?? 1;
2898
- const year = getWeekYear(date, options);
2899
- const firstWeek = constructFrom(options?.in || date, 0);
2900
- firstWeek.setFullYear(year, 0, firstWeekContainsDate);
2901
- firstWeek.setHours(0, 0, 0, 0);
2902
- const _date = startOfWeek(firstWeek, options);
2903
- return _date;
2904
- }
2905
-
2906
- // ../../node_modules/date-fns/getWeek.js
2907
- function getWeek(date, options) {
2908
- const _date = toDate(date, options?.in);
2909
- const diff = +startOfWeek(_date, options) - +startOfWeekYear(_date, options);
2910
- return Math.round(diff / millisecondsInWeek) + 1;
2911
- }
2912
-
2913
- // ../../node_modules/date-fns/_lib/addLeadingZeros.js
2914
- function addLeadingZeros(number, targetLength) {
2915
- const sign = number < 0 ? "-" : "";
2916
- const output = Math.abs(number).toString().padStart(targetLength, "0");
2917
- return sign + output;
2918
- }
2919
-
2920
- // ../../node_modules/date-fns/_lib/format/lightFormatters.js
2921
- var lightFormatters = {
2922
- // Year
2923
- y(date, token) {
2924
- const signedYear = date.getFullYear();
2925
- const year = signedYear > 0 ? signedYear : 1 - signedYear;
2926
- return addLeadingZeros(token === "yy" ? year % 100 : year, token.length);
2927
- },
2928
- // Month
2929
- M(date, token) {
2930
- const month = date.getMonth();
2931
- return token === "M" ? String(month + 1) : addLeadingZeros(month + 1, 2);
2932
- },
2933
- // Day of the month
2934
- d(date, token) {
2935
- return addLeadingZeros(date.getDate(), token.length);
2936
- },
2937
- // AM or PM
2938
- a(date, token) {
2939
- const dayPeriodEnumValue = date.getHours() / 12 >= 1 ? "pm" : "am";
2940
- switch (token) {
2941
- case "a":
2942
- case "aa":
2943
- return dayPeriodEnumValue.toUpperCase();
2944
- case "aaa":
2945
- return dayPeriodEnumValue;
2946
- case "aaaaa":
2947
- return dayPeriodEnumValue[0];
2948
- case "aaaa":
2949
- default:
2950
- return dayPeriodEnumValue === "am" ? "a.m." : "p.m.";
2951
- }
2952
- },
2953
- // Hour [1-12]
2954
- h(date, token) {
2955
- return addLeadingZeros(date.getHours() % 12 || 12, token.length);
2956
- },
2957
- // Hour [0-23]
2958
- H(date, token) {
2959
- return addLeadingZeros(date.getHours(), token.length);
2960
- },
2961
- // Minute
2962
- m(date, token) {
2963
- return addLeadingZeros(date.getMinutes(), token.length);
2964
- },
2965
- // Second
2966
- s(date, token) {
2967
- return addLeadingZeros(date.getSeconds(), token.length);
2968
- },
2969
- // Fraction of second
2970
- S(date, token) {
2971
- const numberOfDigits = token.length;
2972
- const milliseconds = date.getMilliseconds();
2973
- const fractionalSeconds = Math.trunc(
2974
- milliseconds * Math.pow(10, numberOfDigits - 3)
2975
- );
2976
- return addLeadingZeros(fractionalSeconds, token.length);
2977
- }
2978
- };
2979
-
2980
- // ../../node_modules/date-fns/_lib/format/formatters.js
2981
- var dayPeriodEnum = {
2982
- am: "am",
2983
- pm: "pm",
2984
- midnight: "midnight",
2985
- noon: "noon",
2986
- morning: "morning",
2987
- afternoon: "afternoon",
2988
- evening: "evening",
2989
- night: "night"
2990
- };
2991
- var formatters = {
2992
- // Era
2993
- G: function(date, token, localize2) {
2994
- const era = date.getFullYear() > 0 ? 1 : 0;
2995
- switch (token) {
2996
- // AD, BC
2997
- case "G":
2998
- case "GG":
2999
- case "GGG":
3000
- return localize2.era(era, { width: "abbreviated" });
3001
- // A, B
3002
- case "GGGGG":
3003
- return localize2.era(era, { width: "narrow" });
3004
- // Anno Domini, Before Christ
3005
- case "GGGG":
3006
- default:
3007
- return localize2.era(era, { width: "wide" });
3008
- }
3009
- },
3010
- // Year
3011
- y: function(date, token, localize2) {
3012
- if (token === "yo") {
3013
- const signedYear = date.getFullYear();
3014
- const year = signedYear > 0 ? signedYear : 1 - signedYear;
3015
- return localize2.ordinalNumber(year, { unit: "year" });
3016
- }
3017
- return lightFormatters.y(date, token);
3018
- },
3019
- // Local week-numbering year
3020
- Y: function(date, token, localize2, options) {
3021
- const signedWeekYear = getWeekYear(date, options);
3022
- const weekYear = signedWeekYear > 0 ? signedWeekYear : 1 - signedWeekYear;
3023
- if (token === "YY") {
3024
- const twoDigitYear = weekYear % 100;
3025
- return addLeadingZeros(twoDigitYear, 2);
3026
- }
3027
- if (token === "Yo") {
3028
- return localize2.ordinalNumber(weekYear, { unit: "year" });
3029
- }
3030
- return addLeadingZeros(weekYear, token.length);
3031
- },
3032
- // ISO week-numbering year
3033
- R: function(date, token) {
3034
- const isoWeekYear = getISOWeekYear(date);
3035
- return addLeadingZeros(isoWeekYear, token.length);
3036
- },
3037
- // Extended year. This is a single number designating the year of this calendar system.
3038
- // The main difference between `y` and `u` localizers are B.C. years:
3039
- // | Year | `y` | `u` |
3040
- // |------|-----|-----|
3041
- // | AC 1 | 1 | 1 |
3042
- // | BC 1 | 1 | 0 |
3043
- // | BC 2 | 2 | -1 |
3044
- // Also `yy` always returns the last two digits of a year,
3045
- // while `uu` pads single digit years to 2 characters and returns other years unchanged.
3046
- u: function(date, token) {
3047
- const year = date.getFullYear();
3048
- return addLeadingZeros(year, token.length);
3049
- },
3050
- // Quarter
3051
- Q: function(date, token, localize2) {
3052
- const quarter = Math.ceil((date.getMonth() + 1) / 3);
3053
- switch (token) {
3054
- // 1, 2, 3, 4
3055
- case "Q":
3056
- return String(quarter);
3057
- // 01, 02, 03, 04
3058
- case "QQ":
3059
- return addLeadingZeros(quarter, 2);
3060
- // 1st, 2nd, 3rd, 4th
3061
- case "Qo":
3062
- return localize2.ordinalNumber(quarter, { unit: "quarter" });
3063
- // Q1, Q2, Q3, Q4
3064
- case "QQQ":
3065
- return localize2.quarter(quarter, {
3066
- width: "abbreviated",
3067
- context: "formatting"
3068
- });
3069
- // 1, 2, 3, 4 (narrow quarter; could be not numerical)
3070
- case "QQQQQ":
3071
- return localize2.quarter(quarter, {
3072
- width: "narrow",
3073
- context: "formatting"
3074
- });
3075
- // 1st quarter, 2nd quarter, ...
3076
- case "QQQQ":
3077
- default:
3078
- return localize2.quarter(quarter, {
3079
- width: "wide",
3080
- context: "formatting"
3081
- });
3082
- }
3083
- },
3084
- // Stand-alone quarter
3085
- q: function(date, token, localize2) {
3086
- const quarter = Math.ceil((date.getMonth() + 1) / 3);
3087
- switch (token) {
3088
- // 1, 2, 3, 4
3089
- case "q":
3090
- return String(quarter);
3091
- // 01, 02, 03, 04
3092
- case "qq":
3093
- return addLeadingZeros(quarter, 2);
3094
- // 1st, 2nd, 3rd, 4th
3095
- case "qo":
3096
- return localize2.ordinalNumber(quarter, { unit: "quarter" });
3097
- // Q1, Q2, Q3, Q4
3098
- case "qqq":
3099
- return localize2.quarter(quarter, {
3100
- width: "abbreviated",
3101
- context: "standalone"
3102
- });
3103
- // 1, 2, 3, 4 (narrow quarter; could be not numerical)
3104
- case "qqqqq":
3105
- return localize2.quarter(quarter, {
3106
- width: "narrow",
3107
- context: "standalone"
3108
- });
3109
- // 1st quarter, 2nd quarter, ...
3110
- case "qqqq":
3111
- default:
3112
- return localize2.quarter(quarter, {
3113
- width: "wide",
3114
- context: "standalone"
3115
- });
3116
- }
3117
- },
3118
- // Month
3119
- M: function(date, token, localize2) {
3120
- const month = date.getMonth();
3121
- switch (token) {
3122
- case "M":
3123
- case "MM":
3124
- return lightFormatters.M(date, token);
3125
- // 1st, 2nd, ..., 12th
3126
- case "Mo":
3127
- return localize2.ordinalNumber(month + 1, { unit: "month" });
3128
- // Jan, Feb, ..., Dec
3129
- case "MMM":
3130
- return localize2.month(month, {
3131
- width: "abbreviated",
3132
- context: "formatting"
3133
- });
3134
- // J, F, ..., D
3135
- case "MMMMM":
3136
- return localize2.month(month, {
3137
- width: "narrow",
3138
- context: "formatting"
3139
- });
3140
- // January, February, ..., December
3141
- case "MMMM":
3142
- default:
3143
- return localize2.month(month, { width: "wide", context: "formatting" });
3144
- }
3145
- },
3146
- // Stand-alone month
3147
- L: function(date, token, localize2) {
3148
- const month = date.getMonth();
3149
- switch (token) {
3150
- // 1, 2, ..., 12
3151
- case "L":
3152
- return String(month + 1);
3153
- // 01, 02, ..., 12
3154
- case "LL":
3155
- return addLeadingZeros(month + 1, 2);
3156
- // 1st, 2nd, ..., 12th
3157
- case "Lo":
3158
- return localize2.ordinalNumber(month + 1, { unit: "month" });
3159
- // Jan, Feb, ..., Dec
3160
- case "LLL":
3161
- return localize2.month(month, {
3162
- width: "abbreviated",
3163
- context: "standalone"
3164
- });
3165
- // J, F, ..., D
3166
- case "LLLLL":
3167
- return localize2.month(month, {
3168
- width: "narrow",
3169
- context: "standalone"
3170
- });
3171
- // January, February, ..., December
3172
- case "LLLL":
3173
- default:
3174
- return localize2.month(month, { width: "wide", context: "standalone" });
3175
- }
3176
- },
3177
- // Local week of year
3178
- w: function(date, token, localize2, options) {
3179
- const week = getWeek(date, options);
3180
- if (token === "wo") {
3181
- return localize2.ordinalNumber(week, { unit: "week" });
3182
- }
3183
- return addLeadingZeros(week, token.length);
3184
- },
3185
- // ISO week of year
3186
- I: function(date, token, localize2) {
3187
- const isoWeek = getISOWeek(date);
3188
- if (token === "Io") {
3189
- return localize2.ordinalNumber(isoWeek, { unit: "week" });
3190
- }
3191
- return addLeadingZeros(isoWeek, token.length);
3192
- },
3193
- // Day of the month
3194
- d: function(date, token, localize2) {
3195
- if (token === "do") {
3196
- return localize2.ordinalNumber(date.getDate(), { unit: "date" });
3197
- }
3198
- return lightFormatters.d(date, token);
3199
- },
3200
- // Day of year
3201
- D: function(date, token, localize2) {
3202
- const dayOfYear = getDayOfYear(date);
3203
- if (token === "Do") {
3204
- return localize2.ordinalNumber(dayOfYear, { unit: "dayOfYear" });
3205
- }
3206
- return addLeadingZeros(dayOfYear, token.length);
3207
- },
3208
- // Day of week
3209
- E: function(date, token, localize2) {
3210
- const dayOfWeek = date.getDay();
3211
- switch (token) {
3212
- // Tue
3213
- case "E":
3214
- case "EE":
3215
- case "EEE":
3216
- return localize2.day(dayOfWeek, {
3217
- width: "abbreviated",
3218
- context: "formatting"
3219
- });
3220
- // T
3221
- case "EEEEE":
3222
- return localize2.day(dayOfWeek, {
3223
- width: "narrow",
3224
- context: "formatting"
3225
- });
3226
- // Tu
3227
- case "EEEEEE":
3228
- return localize2.day(dayOfWeek, {
3229
- width: "short",
3230
- context: "formatting"
3231
- });
3232
- // Tuesday
3233
- case "EEEE":
3234
- default:
3235
- return localize2.day(dayOfWeek, {
3236
- width: "wide",
3237
- context: "formatting"
3238
- });
3239
- }
3240
- },
3241
- // Local day of week
3242
- e: function(date, token, localize2, options) {
3243
- const dayOfWeek = date.getDay();
3244
- const localDayOfWeek = (dayOfWeek - options.weekStartsOn + 8) % 7 || 7;
3245
- switch (token) {
3246
- // Numerical value (Nth day of week with current locale or weekStartsOn)
3247
- case "e":
3248
- return String(localDayOfWeek);
3249
- // Padded numerical value
3250
- case "ee":
3251
- return addLeadingZeros(localDayOfWeek, 2);
3252
- // 1st, 2nd, ..., 7th
3253
- case "eo":
3254
- return localize2.ordinalNumber(localDayOfWeek, { unit: "day" });
3255
- case "eee":
3256
- return localize2.day(dayOfWeek, {
3257
- width: "abbreviated",
3258
- context: "formatting"
3259
- });
3260
- // T
3261
- case "eeeee":
3262
- return localize2.day(dayOfWeek, {
3263
- width: "narrow",
3264
- context: "formatting"
3265
- });
3266
- // Tu
3267
- case "eeeeee":
3268
- return localize2.day(dayOfWeek, {
3269
- width: "short",
3270
- context: "formatting"
3271
- });
3272
- // Tuesday
3273
- case "eeee":
3274
- default:
3275
- return localize2.day(dayOfWeek, {
3276
- width: "wide",
3277
- context: "formatting"
3278
- });
3279
- }
3280
- },
3281
- // Stand-alone local day of week
3282
- c: function(date, token, localize2, options) {
3283
- const dayOfWeek = date.getDay();
3284
- const localDayOfWeek = (dayOfWeek - options.weekStartsOn + 8) % 7 || 7;
3285
- switch (token) {
3286
- // Numerical value (same as in `e`)
3287
- case "c":
3288
- return String(localDayOfWeek);
3289
- // Padded numerical value
3290
- case "cc":
3291
- return addLeadingZeros(localDayOfWeek, token.length);
3292
- // 1st, 2nd, ..., 7th
3293
- case "co":
3294
- return localize2.ordinalNumber(localDayOfWeek, { unit: "day" });
3295
- case "ccc":
3296
- return localize2.day(dayOfWeek, {
3297
- width: "abbreviated",
3298
- context: "standalone"
3299
- });
3300
- // T
3301
- case "ccccc":
3302
- return localize2.day(dayOfWeek, {
3303
- width: "narrow",
3304
- context: "standalone"
3305
- });
3306
- // Tu
3307
- case "cccccc":
3308
- return localize2.day(dayOfWeek, {
3309
- width: "short",
3310
- context: "standalone"
3311
- });
3312
- // Tuesday
3313
- case "cccc":
3314
- default:
3315
- return localize2.day(dayOfWeek, {
3316
- width: "wide",
3317
- context: "standalone"
3318
- });
3319
- }
3320
- },
3321
- // ISO day of week
3322
- i: function(date, token, localize2) {
3323
- const dayOfWeek = date.getDay();
3324
- const isoDayOfWeek = dayOfWeek === 0 ? 7 : dayOfWeek;
3325
- switch (token) {
3326
- // 2
3327
- case "i":
3328
- return String(isoDayOfWeek);
3329
- // 02
3330
- case "ii":
3331
- return addLeadingZeros(isoDayOfWeek, token.length);
3332
- // 2nd
3333
- case "io":
3334
- return localize2.ordinalNumber(isoDayOfWeek, { unit: "day" });
3335
- // Tue
3336
- case "iii":
3337
- return localize2.day(dayOfWeek, {
3338
- width: "abbreviated",
3339
- context: "formatting"
3340
- });
3341
- // T
3342
- case "iiiii":
3343
- return localize2.day(dayOfWeek, {
3344
- width: "narrow",
3345
- context: "formatting"
3346
- });
3347
- // Tu
3348
- case "iiiiii":
3349
- return localize2.day(dayOfWeek, {
3350
- width: "short",
3351
- context: "formatting"
3352
- });
3353
- // Tuesday
3354
- case "iiii":
3355
- default:
3356
- return localize2.day(dayOfWeek, {
3357
- width: "wide",
3358
- context: "formatting"
3359
- });
3360
- }
3361
- },
3362
- // AM or PM
3363
- a: function(date, token, localize2) {
3364
- const hours = date.getHours();
3365
- const dayPeriodEnumValue = hours / 12 >= 1 ? "pm" : "am";
3366
- switch (token) {
3367
- case "a":
3368
- case "aa":
3369
- return localize2.dayPeriod(dayPeriodEnumValue, {
3370
- width: "abbreviated",
3371
- context: "formatting"
3372
- });
3373
- case "aaa":
3374
- return localize2.dayPeriod(dayPeriodEnumValue, {
3375
- width: "abbreviated",
3376
- context: "formatting"
3377
- }).toLowerCase();
3378
- case "aaaaa":
3379
- return localize2.dayPeriod(dayPeriodEnumValue, {
3380
- width: "narrow",
3381
- context: "formatting"
3382
- });
3383
- case "aaaa":
3384
- default:
3385
- return localize2.dayPeriod(dayPeriodEnumValue, {
3386
- width: "wide",
3387
- context: "formatting"
3388
- });
3389
- }
3390
- },
3391
- // AM, PM, midnight, noon
3392
- b: function(date, token, localize2) {
3393
- const hours = date.getHours();
3394
- let dayPeriodEnumValue;
3395
- if (hours === 12) {
3396
- dayPeriodEnumValue = dayPeriodEnum.noon;
3397
- } else if (hours === 0) {
3398
- dayPeriodEnumValue = dayPeriodEnum.midnight;
3399
- } else {
3400
- dayPeriodEnumValue = hours / 12 >= 1 ? "pm" : "am";
3401
- }
3402
- switch (token) {
3403
- case "b":
3404
- case "bb":
3405
- return localize2.dayPeriod(dayPeriodEnumValue, {
3406
- width: "abbreviated",
3407
- context: "formatting"
3408
- });
3409
- case "bbb":
3410
- return localize2.dayPeriod(dayPeriodEnumValue, {
3411
- width: "abbreviated",
3412
- context: "formatting"
3413
- }).toLowerCase();
3414
- case "bbbbb":
3415
- return localize2.dayPeriod(dayPeriodEnumValue, {
3416
- width: "narrow",
3417
- context: "formatting"
3418
- });
3419
- case "bbbb":
3420
- default:
3421
- return localize2.dayPeriod(dayPeriodEnumValue, {
3422
- width: "wide",
3423
- context: "formatting"
3424
- });
3425
- }
3426
- },
3427
- // in the morning, in the afternoon, in the evening, at night
3428
- B: function(date, token, localize2) {
3429
- const hours = date.getHours();
3430
- let dayPeriodEnumValue;
3431
- if (hours >= 17) {
3432
- dayPeriodEnumValue = dayPeriodEnum.evening;
3433
- } else if (hours >= 12) {
3434
- dayPeriodEnumValue = dayPeriodEnum.afternoon;
3435
- } else if (hours >= 4) {
3436
- dayPeriodEnumValue = dayPeriodEnum.morning;
3437
- } else {
3438
- dayPeriodEnumValue = dayPeriodEnum.night;
3439
- }
3440
- switch (token) {
3441
- case "B":
3442
- case "BB":
3443
- case "BBB":
3444
- return localize2.dayPeriod(dayPeriodEnumValue, {
3445
- width: "abbreviated",
3446
- context: "formatting"
3447
- });
3448
- case "BBBBB":
3449
- return localize2.dayPeriod(dayPeriodEnumValue, {
3450
- width: "narrow",
3451
- context: "formatting"
3452
- });
3453
- case "BBBB":
3454
- default:
3455
- return localize2.dayPeriod(dayPeriodEnumValue, {
3456
- width: "wide",
3457
- context: "formatting"
3458
- });
3459
- }
3460
- },
3461
- // Hour [1-12]
3462
- h: function(date, token, localize2) {
3463
- if (token === "ho") {
3464
- let hours = date.getHours() % 12;
3465
- if (hours === 0) hours = 12;
3466
- return localize2.ordinalNumber(hours, { unit: "hour" });
3467
- }
3468
- return lightFormatters.h(date, token);
3469
- },
3470
- // Hour [0-23]
3471
- H: function(date, token, localize2) {
3472
- if (token === "Ho") {
3473
- return localize2.ordinalNumber(date.getHours(), { unit: "hour" });
3474
- }
3475
- return lightFormatters.H(date, token);
3476
- },
3477
- // Hour [0-11]
3478
- K: function(date, token, localize2) {
3479
- const hours = date.getHours() % 12;
3480
- if (token === "Ko") {
3481
- return localize2.ordinalNumber(hours, { unit: "hour" });
3482
- }
3483
- return addLeadingZeros(hours, token.length);
3484
- },
3485
- // Hour [1-24]
3486
- k: function(date, token, localize2) {
3487
- let hours = date.getHours();
3488
- if (hours === 0) hours = 24;
3489
- if (token === "ko") {
3490
- return localize2.ordinalNumber(hours, { unit: "hour" });
3491
- }
3492
- return addLeadingZeros(hours, token.length);
3493
- },
3494
- // Minute
3495
- m: function(date, token, localize2) {
3496
- if (token === "mo") {
3497
- return localize2.ordinalNumber(date.getMinutes(), { unit: "minute" });
3498
- }
3499
- return lightFormatters.m(date, token);
3500
- },
3501
- // Second
3502
- s: function(date, token, localize2) {
3503
- if (token === "so") {
3504
- return localize2.ordinalNumber(date.getSeconds(), { unit: "second" });
3505
- }
3506
- return lightFormatters.s(date, token);
3507
- },
3508
- // Fraction of second
3509
- S: function(date, token) {
3510
- return lightFormatters.S(date, token);
3511
- },
3512
- // Timezone (ISO-8601. If offset is 0, output is always `'Z'`)
3513
- X: function(date, token, _localize) {
3514
- const timezoneOffset = date.getTimezoneOffset();
3515
- if (timezoneOffset === 0) {
3516
- return "Z";
3517
- }
3518
- switch (token) {
3519
- // Hours and optional minutes
3520
- case "X":
3521
- return formatTimezoneWithOptionalMinutes(timezoneOffset);
3522
- // Hours, minutes and optional seconds without `:` delimiter
3523
- // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets
3524
- // so this token always has the same output as `XX`
3525
- case "XXXX":
3526
- case "XX":
3527
- return formatTimezone(timezoneOffset);
3528
- // Hours, minutes and optional seconds with `:` delimiter
3529
- // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets
3530
- // so this token always has the same output as `XXX`
3531
- case "XXXXX":
3532
- case "XXX":
3533
- // Hours and minutes with `:` delimiter
3534
- default:
3535
- return formatTimezone(timezoneOffset, ":");
3536
- }
3537
- },
3538
- // Timezone (ISO-8601. If offset is 0, output is `'+00:00'` or equivalent)
3539
- x: function(date, token, _localize) {
3540
- const timezoneOffset = date.getTimezoneOffset();
3541
- switch (token) {
3542
- // Hours and optional minutes
3543
- case "x":
3544
- return formatTimezoneWithOptionalMinutes(timezoneOffset);
3545
- // Hours, minutes and optional seconds without `:` delimiter
3546
- // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets
3547
- // so this token always has the same output as `xx`
3548
- case "xxxx":
3549
- case "xx":
3550
- return formatTimezone(timezoneOffset);
3551
- // Hours, minutes and optional seconds with `:` delimiter
3552
- // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets
3553
- // so this token always has the same output as `xxx`
3554
- case "xxxxx":
3555
- case "xxx":
3556
- // Hours and minutes with `:` delimiter
3557
- default:
3558
- return formatTimezone(timezoneOffset, ":");
3559
- }
3560
- },
3561
- // Timezone (GMT)
3562
- O: function(date, token, _localize) {
3563
- const timezoneOffset = date.getTimezoneOffset();
3564
- switch (token) {
3565
- // Short
3566
- case "O":
3567
- case "OO":
3568
- case "OOO":
3569
- return "GMT" + formatTimezoneShort(timezoneOffset, ":");
3570
- // Long
3571
- case "OOOO":
3572
- default:
3573
- return "GMT" + formatTimezone(timezoneOffset, ":");
3574
- }
3575
- },
3576
- // Timezone (specific non-location)
3577
- z: function(date, token, _localize) {
3578
- const timezoneOffset = date.getTimezoneOffset();
3579
- switch (token) {
3580
- // Short
3581
- case "z":
3582
- case "zz":
3583
- case "zzz":
3584
- return "GMT" + formatTimezoneShort(timezoneOffset, ":");
3585
- // Long
3586
- case "zzzz":
3587
- default:
3588
- return "GMT" + formatTimezone(timezoneOffset, ":");
3589
- }
3590
- },
3591
- // Seconds timestamp
3592
- t: function(date, token, _localize) {
3593
- const timestamp = Math.trunc(+date / 1e3);
3594
- return addLeadingZeros(timestamp, token.length);
3595
- },
3596
- // Milliseconds timestamp
3597
- T: function(date, token, _localize) {
3598
- return addLeadingZeros(+date, token.length);
3599
- }
3600
- };
3601
- function formatTimezoneShort(offset, delimiter = "") {
3602
- const sign = offset > 0 ? "-" : "+";
3603
- const absOffset = Math.abs(offset);
3604
- const hours = Math.trunc(absOffset / 60);
3605
- const minutes = absOffset % 60;
3606
- if (minutes === 0) {
3607
- return sign + String(hours);
3608
- }
3609
- return sign + String(hours) + delimiter + addLeadingZeros(minutes, 2);
3610
- }
3611
- function formatTimezoneWithOptionalMinutes(offset, delimiter) {
3612
- if (offset % 60 === 0) {
3613
- const sign = offset > 0 ? "-" : "+";
3614
- return sign + addLeadingZeros(Math.abs(offset) / 60, 2);
3615
- }
3616
- return formatTimezone(offset, delimiter);
3617
- }
3618
- function formatTimezone(offset, delimiter = "") {
3619
- const sign = offset > 0 ? "-" : "+";
3620
- const absOffset = Math.abs(offset);
3621
- const hours = addLeadingZeros(Math.trunc(absOffset / 60), 2);
3622
- const minutes = addLeadingZeros(absOffset % 60, 2);
3623
- return sign + hours + delimiter + minutes;
3624
- }
3625
-
3626
- // ../../node_modules/date-fns/_lib/format/longFormatters.js
3627
- var dateLongFormatter = (pattern, formatLong2) => {
3628
- switch (pattern) {
3629
- case "P":
3630
- return formatLong2.date({ width: "short" });
3631
- case "PP":
3632
- return formatLong2.date({ width: "medium" });
3633
- case "PPP":
3634
- return formatLong2.date({ width: "long" });
3635
- case "PPPP":
3636
- default:
3637
- return formatLong2.date({ width: "full" });
3638
- }
3639
- };
3640
- var timeLongFormatter = (pattern, formatLong2) => {
3641
- switch (pattern) {
3642
- case "p":
3643
- return formatLong2.time({ width: "short" });
3644
- case "pp":
3645
- return formatLong2.time({ width: "medium" });
3646
- case "ppp":
3647
- return formatLong2.time({ width: "long" });
3648
- case "pppp":
3649
- default:
3650
- return formatLong2.time({ width: "full" });
3651
- }
3652
- };
3653
- var dateTimeLongFormatter = (pattern, formatLong2) => {
3654
- const matchResult = pattern.match(/(P+)(p+)?/) || [];
3655
- const datePattern = matchResult[1];
3656
- const timePattern = matchResult[2];
3657
- if (!timePattern) {
3658
- return dateLongFormatter(pattern, formatLong2);
3659
- }
3660
- let dateTimeFormat;
3661
- switch (datePattern) {
3662
- case "P":
3663
- dateTimeFormat = formatLong2.dateTime({ width: "short" });
3664
- break;
3665
- case "PP":
3666
- dateTimeFormat = formatLong2.dateTime({ width: "medium" });
3667
- break;
3668
- case "PPP":
3669
- dateTimeFormat = formatLong2.dateTime({ width: "long" });
3670
- break;
3671
- case "PPPP":
3672
- default:
3673
- dateTimeFormat = formatLong2.dateTime({ width: "full" });
3674
- break;
3675
- }
3676
- return dateTimeFormat.replace("{{date}}", dateLongFormatter(datePattern, formatLong2)).replace("{{time}}", timeLongFormatter(timePattern, formatLong2));
3677
- };
3678
- var longFormatters = {
3679
- p: timeLongFormatter,
3680
- P: dateTimeLongFormatter
3681
- };
3682
-
3683
- // ../../node_modules/date-fns/_lib/protectedTokens.js
3684
- var dayOfYearTokenRE = /^D+$/;
3685
- var weekYearTokenRE = /^Y+$/;
3686
- var throwTokens = ["D", "DD", "YY", "YYYY"];
3687
- function isProtectedDayOfYearToken(token) {
3688
- return dayOfYearTokenRE.test(token);
3689
- }
3690
- function isProtectedWeekYearToken(token) {
3691
- return weekYearTokenRE.test(token);
3692
- }
3693
- function warnOrThrowProtectedError(token, format2, input) {
3694
- const _message = message(token, format2, input);
3695
- console.warn(_message);
3696
- if (throwTokens.includes(token)) throw new RangeError(_message);
3697
- }
3698
- function message(token, format2, input) {
3699
- const subject = token[0] === "Y" ? "years" : "days of the month";
3700
- return `Use \`${token.toLowerCase()}\` instead of \`${token}\` (in \`${format2}\`) for formatting ${subject} to the input \`${input}\`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md`;
3701
- }
3702
-
3703
- // ../../node_modules/date-fns/format.js
3704
- var formattingTokensRegExp = /[yYQqMLwIdDecihHKkms]o|(\w)\1*|''|'(''|[^'])+('|$)|./g;
3705
- var longFormattingTokensRegExp = /P+p+|P+|p+|''|'(''|[^'])+('|$)|./g;
3706
- var escapedStringRegExp = /^'([^]*?)'?$/;
3707
- var doubleQuoteRegExp = /''/g;
3708
- var unescapedLatinCharacterRegExp = /[a-zA-Z]/;
3709
- function format(date, formatStr, options) {
3710
- const defaultOptions2 = getDefaultOptions();
3711
- const locale = options?.locale ?? defaultOptions2.locale ?? enUS;
3712
- const firstWeekContainsDate = options?.firstWeekContainsDate ?? options?.locale?.options?.firstWeekContainsDate ?? defaultOptions2.firstWeekContainsDate ?? defaultOptions2.locale?.options?.firstWeekContainsDate ?? 1;
3713
- const weekStartsOn = options?.weekStartsOn ?? options?.locale?.options?.weekStartsOn ?? defaultOptions2.weekStartsOn ?? defaultOptions2.locale?.options?.weekStartsOn ?? 0;
3714
- const originalDate = toDate(date, options?.in);
3715
- if (!isValid(originalDate)) {
3716
- throw new RangeError("Invalid time value");
3717
- }
3718
- let parts = formatStr.match(longFormattingTokensRegExp).map((substring) => {
3719
- const firstCharacter = substring[0];
3720
- if (firstCharacter === "p" || firstCharacter === "P") {
3721
- const longFormatter = longFormatters[firstCharacter];
3722
- return longFormatter(substring, locale.formatLong);
3723
- }
3724
- return substring;
3725
- }).join("").match(formattingTokensRegExp).map((substring) => {
3726
- if (substring === "''") {
3727
- return { isToken: false, value: "'" };
3728
- }
3729
- const firstCharacter = substring[0];
3730
- if (firstCharacter === "'") {
3731
- return { isToken: false, value: cleanEscapedString(substring) };
3732
- }
3733
- if (formatters[firstCharacter]) {
3734
- return { isToken: true, value: substring };
3735
- }
3736
- if (firstCharacter.match(unescapedLatinCharacterRegExp)) {
3737
- throw new RangeError(
3738
- "Format string contains an unescaped latin alphabet character `" + firstCharacter + "`"
3739
- );
3740
- }
3741
- return { isToken: false, value: substring };
3742
- });
3743
- if (locale.localize.preprocessor) {
3744
- parts = locale.localize.preprocessor(originalDate, parts);
3745
- }
3746
- const formatterOptions = {
3747
- firstWeekContainsDate,
3748
- weekStartsOn,
3749
- locale
3750
- };
3751
- return parts.map((part) => {
3752
- if (!part.isToken) return part.value;
3753
- const token = part.value;
3754
- if (!options?.useAdditionalWeekYearTokens && isProtectedWeekYearToken(token) || !options?.useAdditionalDayOfYearTokens && isProtectedDayOfYearToken(token)) {
3755
- warnOrThrowProtectedError(token, formatStr, String(date));
3756
- }
3757
- const formatter = formatters[token[0]];
3758
- return formatter(originalDate, token, locale.localize, formatterOptions);
3759
- }).join("");
3760
- }
3761
- function cleanEscapedString(input) {
3762
- const matched = input.match(escapedStringRegExp);
3763
- if (!matched) {
3764
- return input;
3765
- }
3766
- return matched[1].replace(doubleQuoteRegExp, "'");
3767
- }
3768
-
3769
- // components/customer/chat-message.tsx
3770
- var import_lucide_react5 = require("lucide-react");
3771
-
3772
- // components/markdown-renderer.tsx
3773
- var import_react_markdown = __toESM(require("react-markdown"));
3774
- var import_remark_gfm = __toESM(require("remark-gfm"));
3775
- var import_jsx_runtime10 = require("react/jsx-runtime");
3776
- function MarkdownRenderer({ content }) {
3777
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3778
- import_react_markdown.default,
3779
- {
3780
- remarkPlugins: [import_remark_gfm.default],
3781
- components: {
3782
- a: ({ node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3783
- "a",
3784
- {
3785
- target: "_blank",
3786
- rel: "noopener noreferrer",
3787
- className: "text-blue-600 hover:underline",
3788
- ...props
3789
- }
3790
- ),
3791
- h1: ({ node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { className: "text-2xl font-bold mt-6 mb-4", ...props }),
3792
- h2: ({ node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { className: "text-xl font-semibold mt-5 mb-3", ...props }),
3793
- h3: ({ node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "text-lg font-semibold mt-4 mb-2", ...props }),
3794
- code: ({ node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3795
- "code",
3796
- {
3797
- className: "block bg-gray-100 p-3 rounded font-mono",
3798
- ...props
3799
- }
3800
- ),
3801
- ul: ({ node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { className: "list-disc pl-6 my-4", ...props }),
3802
- ol: ({ node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ol", { className: "list-decimal pl-6 my-4", ...props }),
3803
- p: ({ node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "my-4", ...props }),
3804
- blockquote: ({ node, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3805
- "blockquote",
3806
- {
3807
- className: "border-l-4 border-gray-200 pl-4 my-4 italic",
3808
- ...props
3809
- }
3810
- )
3811
- },
3812
- children: content
3813
- }
3814
- );
3815
- }
3816
-
3817
- // components/customer/chat-message.tsx
3818
- var import_jsx_runtime11 = require("react/jsx-runtime");
3819
- var Message = ({
3820
- message: message2,
3821
- isConsecutive,
3822
- onRetry
3823
- }) => {
3824
- const renderAttachment = (attachment, index) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "mt-2", children: attachment.type === "image" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3825
- "img",
3826
- {
3827
- src: attachment.url,
3828
- alt: attachment.title,
3829
- className: "max-w-full rounded",
3830
- loading: "lazy"
3831
- }
3832
- ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3833
- "a",
3834
- {
3835
- href: attachment.url,
3836
- className: "flex items-center space-x-2 text-sm hover:underline",
3837
- target: "_blank",
3838
- rel: "noopener noreferrer",
3839
- children: [
3840
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.Paperclip, { className: "w-4 h-4" }),
3841
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: attachment.title })
3842
- ]
3843
- }
3844
- ) }, index);
3845
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3846
- "div",
3847
- {
3848
- className: "flex justify-start gap-2",
3849
- "data-message-id": message2.id,
3850
- role: "article",
3851
- "aria-label": `Message from ${message2.senderId}`,
3852
- children: [
3853
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex pt-10 w-10", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "w-8 h-8 rounded-full flex justify-center", children: [
3854
- message2.role === "user" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.User, {}),
3855
- message2.role === "ai" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.Bot, {}),
3856
- message2.role === "humanAgent" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.UserCog, {})
3857
- ] }) }),
3858
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3859
- "div",
3860
- {
3861
- className: `p-3 rounded-lg max-w-[80%] bg-gray-100 text-primary-900 ${isConsecutive ? "mt-1" : "mt-4"}`,
3862
- children: [
3863
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "break-words", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MarkdownRenderer, { content: message2.content }) }),
3864
- message2.attachments?.map(
3865
- (attachment, i) => renderAttachment(attachment, i)
3866
- ),
3867
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center justify-end space-x-1 mt-1", children: [
3868
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xs opacity-70", children: format(message2.time, "HH:mm") }),
3869
- message2.role === "user" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
3870
- message2.status === "sending" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "w-4 h-4 animate-spin rounded-full border-2 border-gray-300 border-t-white" }),
3871
- message2.status === "sent" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.Check, { className: "w-4 h-4" }),
3872
- message2.status === "delivered" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.CheckCheck, { className: "w-4 h-4" }),
3873
- message2.status === "failed" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3874
- "button",
3875
- {
3876
- onClick: () => onRetry(message2.id),
3877
- className: "text-red-300 hover:text-red-400",
3878
- "aria-label": "Retry sending message",
3879
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.AlertCircle, { className: "w-4 h-4" })
3880
- }
3881
- )
3882
- ] })
3883
- ] })
3884
- ]
3885
- }
3886
- )
3887
- ]
3888
- }
3889
- );
3890
- };
3891
-
3892
- // components/customer/chat-messages.tsx
3893
- var import_jsx_runtime12 = require("react/jsx-runtime");
3894
- var ChatMessages = ({
3895
- onRetry,
3896
- messages
3897
- }) => {
3898
- const messageEndRef = (0, import_react8.useRef)(null);
3899
- const scrollToBottom = () => {
3900
- messageEndRef.current?.scrollIntoView({ behavior: "smooth" });
3901
- };
3902
- (0, import_react8.useEffect)(() => {
3903
- scrollToBottom();
3904
- }, [messages]);
3905
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3906
- "div",
3907
- {
3908
- className: "flex-1 overflow-y-auto p-4 space-y-4 bg-white min-h-[calc(100vh-290px)]",
3909
- role: "log",
3910
- "aria-label": "Chat messages",
3911
- children: [
3912
- messages.filter(
3913
- (msg) => (!msg.toolCalls?.length || msg.toolCalls.length === 0) && !msg.toolCallId
3914
- ).map((msg, index) => {
3915
- const isConsecutive = index > 0 && messages[index - 1].senderId === msg.senderId && msg.time - messages[index - 1].time < 3e5;
3916
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3917
- Message,
3918
- {
3919
- message: msg,
3920
- isConsecutive,
3921
- onRetry
3922
- },
3923
- msg.id
3924
- );
3925
- }),
3926
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { ref: messageEndRef })
3927
- ]
3928
- }
3929
- );
3930
- };
3931
-
3932
- // components/customer/chat-typing-indicator.tsx
3933
- var import_jsx_runtime13 = require("react/jsx-runtime");
3934
- var ChatTypingIndicator = ({
3935
- typingUsers
3936
- }) => {
3937
- if (typingUsers.size === 0) return null;
3938
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "px-4 py-2 text-sm text-gray-500 italic", role: "status", children: [
3939
- Array.from(typingUsers).join(", "),
3940
- " typing..."
3941
- ] });
3942
- };
3943
-
3944
- // components/customer/generic-chat-widget.tsx
3945
- var import_react9 = require("react");
3946
- var import_jsx_runtime14 = require("react/jsx-runtime");
3947
- var Alert = ({ title, description }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "p-4 bg-red-50 border border-red-200 rounded-lg", role: "alert", children: [
3948
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "font-medium text-red-800", children: title }),
3949
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-red-600", children: description })
3950
- ] });
3951
- var GenericChatWidget = ({
3952
- onFileUpload
3953
- }) => {
3954
- const [typingUsers] = (0, import_react9.useState)(/* @__PURE__ */ new Set());
3955
- const { error, messages } = useWebSocketChatCustomerContext();
3956
- const handleRetry = (messageId) => {
3957
- };
3958
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3959
- "div",
3960
- {
3961
- className: "flex flex-col w-full max-w-lg border rounded-lg shadow-lg",
3962
- role: "region",
3963
- "aria-label": "Chat interface",
3964
- children: [
3965
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChatHeader, {}),
3966
- error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Alert, { title: "Error", description: error.message }),
3967
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChatMessages, { onRetry: handleRetry, messages }),
3968
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChatTypingIndicator, { typingUsers }),
3969
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ChatInput, { onFileUpload })
3970
- ]
3971
- }
3972
- );
3973
- };
3974
1078
  // Annotate the CommonJS export names for ESM import in node:
3975
1079
  0 && (module.exports = {
3976
- AdminChatHeader,
3977
- AdminChatInput,
3978
- AdminChatList,
3979
- AdminChatListItem,
3980
1080
  AgentStatusAway,
3981
1081
  AgentStatusBusy,
3982
1082
  AgentStatusOffline,
@@ -3987,6 +1087,7 @@ var GenericChatWidget = ({
3987
1087
  AttachmentTypeAudio,
3988
1088
  AttachmentTypeBullets,
3989
1089
  AttachmentTypeData,
1090
+ AttachmentTypeDataFile,
3990
1091
  AttachmentTypeDocument,
3991
1092
  AttachmentTypeDocumentAnalysis,
3992
1093
  AttachmentTypeDocumentSources,
@@ -3995,6 +1096,7 @@ var GenericChatWidget = ({
3995
1096
  AttachmentTypeLocation,
3996
1097
  AttachmentTypeRecords,
3997
1098
  AttachmentTypeReferences,
1099
+ AttachmentTypeSpreadsheet,
3998
1100
  AttachmentTypeSticker,
3999
1101
  AttachmentTypeSubsections,
4000
1102
  AttachmentTypeVideo,
@@ -4008,6 +1110,10 @@ var GenericChatWidget = ({
4008
1110
  ChatEventTypeAgentSessionEnd,
4009
1111
  ChatEventTypeAgentSessionStart,
4010
1112
  ChatEventTypeAgentStatusChange,
1113
+ ChatEventTypeAttachmentProcessingComplete,
1114
+ ChatEventTypeAttachmentProcessingError,
1115
+ ChatEventTypeAttachmentProcessingProgress,
1116
+ ChatEventTypeAttachmentProcessingStarted,
4011
1117
  ChatEventTypeBlockUser,
4012
1118
  ChatEventTypeCSATRequest,
4013
1119
  ChatEventTypeCSATResponse,
@@ -4059,6 +1165,7 @@ var GenericChatWidget = ({
4059
1165
  ChatEventTypePong,
4060
1166
  ChatEventTypeRead,
4061
1167
  ChatEventTypeReconnected,
1168
+ ChatEventTypeRetryAttachment,
4062
1169
  ChatEventTypeRoomCreated,
4063
1170
  ChatEventTypeRoomDeleted,
4064
1171
  ChatEventTypeRoomUpdated,
@@ -4093,10 +1200,6 @@ var GenericChatWidget = ({
4093
1200
  ChatEventTypeUserSuggestedActions,
4094
1201
  ChatEventTypeWaiting,
4095
1202
  ChatEventTypeWaitingForAgent,
4096
- ChatHeader,
4097
- ChatHumanAgentActions,
4098
- ChatInput,
4099
- ChatMessages,
4100
1203
  ChatRoleAI,
4101
1204
  ChatRoleDataQuery,
4102
1205
  ChatRoleEvent,
@@ -4112,19 +1215,16 @@ var GenericChatWidget = ({
4112
1215
  ChatStatusActive,
4113
1216
  ChatStatusArchived,
4114
1217
  ChatStatusClosed,
4115
- ChatStatusCustomerUI,
4116
1218
  ChatStatusDisconnected,
4117
1219
  ChatTypeCustomerSupport,
4118
1220
  ChatTypeDirect,
4119
1221
  ChatTypeGroup,
4120
1222
  ChatTypePrivateRoom,
4121
1223
  ChatTypePublicRoom,
4122
- ChatTypingIndicator,
4123
1224
  CompleteChatByAgentSubject,
4124
1225
  CreateAgentQueueSubject,
4125
1226
  DeleteAgentQueueSubject,
4126
1227
  EndAgentSessionSubject,
4127
- GenericChatWidget,
4128
1228
  GetActiveChatCountSubject,
4129
1229
  GetActiveChatsSubject,
4130
1230
  GetAgentQueuesSubject,
@@ -4160,14 +1260,6 @@ var GenericChatWidget = ({
4160
1260
  UserStatusBusy,
4161
1261
  UserStatusOffline,
4162
1262
  UserStatusOnline,
4163
- WebSocketChatAdminContext,
4164
- WebSocketChatAdminProvider,
4165
- WebSocketChatCustomerContext,
4166
- WebSocketChatCustomerProvider,
4167
- useWebSocketChatAdmin,
4168
- useWebSocketChatAdminContext,
4169
- useWebSocketChatBase,
4170
- useWebSocketChatCustomer,
4171
- useWebSocketChatCustomerContext
1263
+ useChat
4172
1264
  });
4173
1265
  //# sourceMappingURL=index.js.map