@elqnt/chat 3.0.1 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/api/index.d.mts +39 -1
- package/dist/api/index.d.ts +39 -1
- package/dist/api/index.js +40 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/index.mjs +35 -0
- package/dist/api/index.mjs.map +1 -1
- package/dist/hooks/index.d.mts +101 -2
- package/dist/hooks/index.d.ts +101 -2
- package/dist/hooks/index.js +619 -8
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +613 -7
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +625 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +617 -7
- package/dist/index.mjs.map +1 -1
- package/dist/models/index.d.mts +37 -21
- package/dist/models/index.d.ts +37 -21
- package/dist/models/index.js +6 -0
- package/dist/models/index.js.map +1 -1
- package/dist/models/index.mjs +4 -0
- package/dist/models/index.mjs.map +1 -1
- package/dist/transport/index.d.mts +2 -0
- package/dist/transport/index.d.ts +2 -0
- package/package.json +5 -3
package/dist/index.mjs
CHANGED
|
@@ -372,8 +372,394 @@ function createSSETransport(options = {}) {
|
|
|
372
372
|
return transport;
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
+
// transport/sse-fetch.ts
|
|
376
|
+
function createFetchSSETransport(options = {}) {
|
|
377
|
+
const {
|
|
378
|
+
retryConfig = DEFAULT_RETRY_CONFIG,
|
|
379
|
+
debug = false,
|
|
380
|
+
logger = createLogger(debug),
|
|
381
|
+
customFetch = fetch
|
|
382
|
+
} = options;
|
|
383
|
+
let abortController;
|
|
384
|
+
let config;
|
|
385
|
+
let state = "disconnected";
|
|
386
|
+
let error;
|
|
387
|
+
let retryCount = 0;
|
|
388
|
+
let reconnectTimeout;
|
|
389
|
+
let intentionalDisconnect = false;
|
|
390
|
+
const metrics = {
|
|
391
|
+
latency: 0,
|
|
392
|
+
messagesSent: 0,
|
|
393
|
+
messagesReceived: 0,
|
|
394
|
+
messagesQueued: 0,
|
|
395
|
+
reconnectCount: 0,
|
|
396
|
+
transportType: "sse-fetch"
|
|
397
|
+
};
|
|
398
|
+
const globalHandlers = /* @__PURE__ */ new Set();
|
|
399
|
+
const typeHandlers = /* @__PURE__ */ new Map();
|
|
400
|
+
function emit(event) {
|
|
401
|
+
metrics.messagesReceived++;
|
|
402
|
+
metrics.lastMessageAt = Date.now();
|
|
403
|
+
globalHandlers.forEach((handler) => {
|
|
404
|
+
try {
|
|
405
|
+
handler(event);
|
|
406
|
+
} catch (err) {
|
|
407
|
+
logger.error("Error in message handler:", err);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
const handlers = typeHandlers.get(event.type);
|
|
411
|
+
if (handlers) {
|
|
412
|
+
handlers.forEach((handler) => {
|
|
413
|
+
try {
|
|
414
|
+
handler(event);
|
|
415
|
+
} catch (err) {
|
|
416
|
+
logger.error(`Error in ${event.type} handler:`, err);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
async function sendRest(endpoint, body) {
|
|
422
|
+
if (!config) {
|
|
423
|
+
throw new Error("Transport not connected");
|
|
424
|
+
}
|
|
425
|
+
const url = `${config.baseUrl}/${endpoint}`;
|
|
426
|
+
logger.debug(`POST ${endpoint}`, body);
|
|
427
|
+
const response = await customFetch(url, {
|
|
428
|
+
method: "POST",
|
|
429
|
+
headers: { "Content-Type": "application/json" },
|
|
430
|
+
body: JSON.stringify(body)
|
|
431
|
+
});
|
|
432
|
+
if (!response.ok) {
|
|
433
|
+
const errorText = await response.text();
|
|
434
|
+
throw new Error(`API error: ${response.status} - ${errorText}`);
|
|
435
|
+
}
|
|
436
|
+
const json = await response.json();
|
|
437
|
+
if (json && typeof json === "object" && "data" in json) {
|
|
438
|
+
return json.data;
|
|
439
|
+
}
|
|
440
|
+
return json;
|
|
441
|
+
}
|
|
442
|
+
function parseSSEChunk(chunk) {
|
|
443
|
+
const events = [];
|
|
444
|
+
const lines = chunk.split("\n");
|
|
445
|
+
let eventType = "message";
|
|
446
|
+
let data = "";
|
|
447
|
+
for (const line of lines) {
|
|
448
|
+
if (line.startsWith("event:")) {
|
|
449
|
+
eventType = line.slice(6).trim();
|
|
450
|
+
} else if (line.startsWith("data:")) {
|
|
451
|
+
data = line.slice(5).trim();
|
|
452
|
+
} else if (line === "" && data) {
|
|
453
|
+
try {
|
|
454
|
+
const parsed = JSON.parse(data);
|
|
455
|
+
events.push(parsed);
|
|
456
|
+
} catch {
|
|
457
|
+
logger.warn("Failed to parse SSE data:", data);
|
|
458
|
+
}
|
|
459
|
+
eventType = "message";
|
|
460
|
+
data = "";
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return events;
|
|
464
|
+
}
|
|
465
|
+
async function startStream(cfg) {
|
|
466
|
+
const url = `${cfg.baseUrl}/stream?orgId=${cfg.orgId}&userId=${cfg.userId}&clientType=${cfg.clientType}${cfg.chatKey ? `&chatId=${cfg.chatKey}` : ""}`;
|
|
467
|
+
logger.debug("Connecting to:", url);
|
|
468
|
+
abortController = new AbortController();
|
|
469
|
+
const response = await customFetch(url, {
|
|
470
|
+
method: "GET",
|
|
471
|
+
headers: {
|
|
472
|
+
Accept: "text/event-stream",
|
|
473
|
+
"Cache-Control": "no-cache"
|
|
474
|
+
},
|
|
475
|
+
signal: abortController.signal
|
|
476
|
+
});
|
|
477
|
+
if (!response.ok) {
|
|
478
|
+
throw new Error(`Stream connection failed: ${response.status}`);
|
|
479
|
+
}
|
|
480
|
+
if (!response.body) {
|
|
481
|
+
throw new Error("Response body is null - ReadableStream not supported");
|
|
482
|
+
}
|
|
483
|
+
const reader = response.body.getReader();
|
|
484
|
+
const decoder = new TextDecoder();
|
|
485
|
+
let buffer = "";
|
|
486
|
+
const readStream = async () => {
|
|
487
|
+
try {
|
|
488
|
+
while (true) {
|
|
489
|
+
const { done, value } = await reader.read();
|
|
490
|
+
if (done) {
|
|
491
|
+
logger.info("Stream ended");
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
buffer += decoder.decode(value, { stream: true });
|
|
495
|
+
const lastNewline = buffer.lastIndexOf("\n\n");
|
|
496
|
+
if (lastNewline !== -1) {
|
|
497
|
+
const complete = buffer.slice(0, lastNewline + 2);
|
|
498
|
+
buffer = buffer.slice(lastNewline + 2);
|
|
499
|
+
const events = parseSSEChunk(complete);
|
|
500
|
+
events.forEach(emit);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
} catch (err) {
|
|
504
|
+
if (err.name === "AbortError") {
|
|
505
|
+
logger.debug("Stream aborted");
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
logger.error("Stream error:", err);
|
|
509
|
+
throw err;
|
|
510
|
+
}
|
|
511
|
+
if (!intentionalDisconnect) {
|
|
512
|
+
state = "disconnected";
|
|
513
|
+
scheduleReconnect();
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
readStream().catch((err) => {
|
|
517
|
+
if (!intentionalDisconnect) {
|
|
518
|
+
error = {
|
|
519
|
+
code: "CONNECTION_FAILED",
|
|
520
|
+
message: err.message,
|
|
521
|
+
retryable: true,
|
|
522
|
+
timestamp: Date.now(),
|
|
523
|
+
originalError: err
|
|
524
|
+
};
|
|
525
|
+
metrics.lastError = error;
|
|
526
|
+
state = "disconnected";
|
|
527
|
+
scheduleReconnect();
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
function scheduleReconnect() {
|
|
532
|
+
if (intentionalDisconnect || !config) return;
|
|
533
|
+
const maxRetries = retryConfig.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries;
|
|
534
|
+
if (retryCount >= maxRetries) {
|
|
535
|
+
logger.error(`Max retries (${maxRetries}) exceeded`);
|
|
536
|
+
error = {
|
|
537
|
+
code: "CONNECTION_FAILED",
|
|
538
|
+
message: `Max retries (${maxRetries}) exceeded`,
|
|
539
|
+
retryable: false,
|
|
540
|
+
timestamp: Date.now()
|
|
541
|
+
};
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
const interval = calculateRetryInterval(retryCount, retryConfig);
|
|
545
|
+
retryCount++;
|
|
546
|
+
metrics.reconnectCount++;
|
|
547
|
+
logger.info(`Reconnecting in ${interval}ms (attempt ${retryCount})`);
|
|
548
|
+
state = "reconnecting";
|
|
549
|
+
reconnectTimeout = setTimeout(() => {
|
|
550
|
+
if (config) {
|
|
551
|
+
transport.connect(config).catch((err) => {
|
|
552
|
+
logger.error("Reconnect failed:", err);
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
}, interval);
|
|
556
|
+
}
|
|
557
|
+
const transport = {
|
|
558
|
+
async connect(cfg) {
|
|
559
|
+
config = cfg;
|
|
560
|
+
intentionalDisconnect = false;
|
|
561
|
+
if (abortController) {
|
|
562
|
+
abortController.abort();
|
|
563
|
+
abortController = void 0;
|
|
564
|
+
}
|
|
565
|
+
if (reconnectTimeout) {
|
|
566
|
+
clearTimeout(reconnectTimeout);
|
|
567
|
+
reconnectTimeout = void 0;
|
|
568
|
+
}
|
|
569
|
+
state = retryCount > 0 ? "reconnecting" : "connecting";
|
|
570
|
+
const connectionStart = Date.now();
|
|
571
|
+
try {
|
|
572
|
+
await startStream(cfg);
|
|
573
|
+
const connectionTime = Date.now() - connectionStart;
|
|
574
|
+
logger.info(`Connected in ${connectionTime}ms`);
|
|
575
|
+
state = "connected";
|
|
576
|
+
error = void 0;
|
|
577
|
+
retryCount = 0;
|
|
578
|
+
metrics.connectedAt = Date.now();
|
|
579
|
+
metrics.latency = connectionTime;
|
|
580
|
+
} catch (err) {
|
|
581
|
+
const connectError = {
|
|
582
|
+
code: "CONNECTION_FAILED",
|
|
583
|
+
message: err.message,
|
|
584
|
+
retryable: true,
|
|
585
|
+
timestamp: Date.now(),
|
|
586
|
+
originalError: err
|
|
587
|
+
};
|
|
588
|
+
error = connectError;
|
|
589
|
+
metrics.lastError = connectError;
|
|
590
|
+
state = "disconnected";
|
|
591
|
+
if (!intentionalDisconnect) {
|
|
592
|
+
scheduleReconnect();
|
|
593
|
+
}
|
|
594
|
+
throw connectError;
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
disconnect(intentional = true) {
|
|
598
|
+
logger.info("Disconnecting", { intentional });
|
|
599
|
+
intentionalDisconnect = intentional;
|
|
600
|
+
if (reconnectTimeout) {
|
|
601
|
+
clearTimeout(reconnectTimeout);
|
|
602
|
+
reconnectTimeout = void 0;
|
|
603
|
+
}
|
|
604
|
+
if (abortController) {
|
|
605
|
+
abortController.abort();
|
|
606
|
+
abortController = void 0;
|
|
607
|
+
}
|
|
608
|
+
state = "disconnected";
|
|
609
|
+
retryCount = 0;
|
|
610
|
+
},
|
|
611
|
+
async send(event) {
|
|
612
|
+
if (!config) {
|
|
613
|
+
throw new Error("Transport not connected");
|
|
614
|
+
}
|
|
615
|
+
switch (event.type) {
|
|
616
|
+
case "message":
|
|
617
|
+
await sendRest("send", {
|
|
618
|
+
orgId: event.orgId,
|
|
619
|
+
chatKey: event.chatKey,
|
|
620
|
+
userId: event.userId,
|
|
621
|
+
message: event.message
|
|
622
|
+
});
|
|
623
|
+
break;
|
|
624
|
+
case "typing":
|
|
625
|
+
await sendRest("typing", {
|
|
626
|
+
orgId: event.orgId,
|
|
627
|
+
chatKey: event.chatKey,
|
|
628
|
+
userId: event.userId,
|
|
629
|
+
typing: true
|
|
630
|
+
});
|
|
631
|
+
break;
|
|
632
|
+
case "stopped_typing":
|
|
633
|
+
await sendRest("typing", {
|
|
634
|
+
orgId: event.orgId,
|
|
635
|
+
chatKey: event.chatKey,
|
|
636
|
+
userId: event.userId,
|
|
637
|
+
typing: false
|
|
638
|
+
});
|
|
639
|
+
break;
|
|
640
|
+
case "load_chat":
|
|
641
|
+
await sendRest("load", {
|
|
642
|
+
orgId: event.orgId,
|
|
643
|
+
chatKey: event.chatKey,
|
|
644
|
+
userId: event.userId
|
|
645
|
+
});
|
|
646
|
+
break;
|
|
647
|
+
case "new_chat":
|
|
648
|
+
await sendRest("create", {
|
|
649
|
+
orgId: event.orgId,
|
|
650
|
+
userId: event.userId,
|
|
651
|
+
metadata: event.data
|
|
652
|
+
});
|
|
653
|
+
break;
|
|
654
|
+
case "end_chat":
|
|
655
|
+
await sendRest("end", {
|
|
656
|
+
orgId: event.orgId,
|
|
657
|
+
chatKey: event.chatKey,
|
|
658
|
+
userId: event.userId,
|
|
659
|
+
data: event.data
|
|
660
|
+
});
|
|
661
|
+
break;
|
|
662
|
+
default:
|
|
663
|
+
await sendRest("event", {
|
|
664
|
+
type: event.type,
|
|
665
|
+
orgId: event.orgId,
|
|
666
|
+
chatKey: event.chatKey,
|
|
667
|
+
userId: event.userId,
|
|
668
|
+
data: event.data
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
metrics.messagesSent++;
|
|
672
|
+
},
|
|
673
|
+
async sendMessage(message) {
|
|
674
|
+
if (!config) {
|
|
675
|
+
throw new Error("Transport not connected");
|
|
676
|
+
}
|
|
677
|
+
await sendRest("send", {
|
|
678
|
+
orgId: config.orgId,
|
|
679
|
+
chatKey: config.chatKey,
|
|
680
|
+
userId: config.userId,
|
|
681
|
+
message
|
|
682
|
+
});
|
|
683
|
+
metrics.messagesSent++;
|
|
684
|
+
},
|
|
685
|
+
async createChat(options2) {
|
|
686
|
+
if (!config) {
|
|
687
|
+
throw new Error("Transport not connected");
|
|
688
|
+
}
|
|
689
|
+
const response = await sendRest("create", {
|
|
690
|
+
orgId: options2.orgId,
|
|
691
|
+
userId: options2.userId,
|
|
692
|
+
metadata: options2.metadata
|
|
693
|
+
});
|
|
694
|
+
if (!response?.chatKey) {
|
|
695
|
+
throw new Error("Failed to create chat: no chatKey returned");
|
|
696
|
+
}
|
|
697
|
+
return { chatKey: response.chatKey };
|
|
698
|
+
},
|
|
699
|
+
async loadChatData(options2) {
|
|
700
|
+
if (!config) {
|
|
701
|
+
throw new Error("Transport not connected");
|
|
702
|
+
}
|
|
703
|
+
const response = await sendRest("load", {
|
|
704
|
+
orgId: options2.orgId,
|
|
705
|
+
chatKey: options2.chatKey,
|
|
706
|
+
userId: options2.userId
|
|
707
|
+
});
|
|
708
|
+
if (!response?.chat) {
|
|
709
|
+
throw new Error("Failed to load chat: no chat data returned");
|
|
710
|
+
}
|
|
711
|
+
return {
|
|
712
|
+
chat: response.chat,
|
|
713
|
+
agentId: response.agentId
|
|
714
|
+
};
|
|
715
|
+
},
|
|
716
|
+
onMessage(handler) {
|
|
717
|
+
globalHandlers.add(handler);
|
|
718
|
+
return () => globalHandlers.delete(handler);
|
|
719
|
+
},
|
|
720
|
+
on(eventType, handler) {
|
|
721
|
+
if (!typeHandlers.has(eventType)) {
|
|
722
|
+
typeHandlers.set(eventType, /* @__PURE__ */ new Set());
|
|
723
|
+
}
|
|
724
|
+
typeHandlers.get(eventType).add(handler);
|
|
725
|
+
return () => {
|
|
726
|
+
const handlers = typeHandlers.get(eventType);
|
|
727
|
+
if (handlers) {
|
|
728
|
+
handlers.delete(handler);
|
|
729
|
+
if (handlers.size === 0) {
|
|
730
|
+
typeHandlers.delete(eventType);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
},
|
|
735
|
+
getState() {
|
|
736
|
+
return state;
|
|
737
|
+
},
|
|
738
|
+
getMetrics() {
|
|
739
|
+
return { ...metrics };
|
|
740
|
+
},
|
|
741
|
+
getError() {
|
|
742
|
+
return error;
|
|
743
|
+
},
|
|
744
|
+
clearError() {
|
|
745
|
+
error = void 0;
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
return transport;
|
|
749
|
+
}
|
|
750
|
+
|
|
375
751
|
// hooks/use-chat.ts
|
|
376
752
|
function getDefaultTransport(type, debug) {
|
|
753
|
+
if (type === "sse-fetch") {
|
|
754
|
+
return createFetchSSETransport({ debug });
|
|
755
|
+
}
|
|
756
|
+
if (type === "sse") {
|
|
757
|
+
return createSSETransport({ debug });
|
|
758
|
+
}
|
|
759
|
+
const isReactNative = typeof navigator !== "undefined" && navigator.product === "ReactNative";
|
|
760
|
+
if (isReactNative || typeof EventSource === "undefined") {
|
|
761
|
+
return createFetchSSETransport({ debug });
|
|
762
|
+
}
|
|
377
763
|
return createSSETransport({ debug });
|
|
378
764
|
}
|
|
379
765
|
function useChat(options) {
|
|
@@ -484,6 +870,7 @@ function useChat(options) {
|
|
|
484
870
|
throw err;
|
|
485
871
|
}
|
|
486
872
|
setConnectionState("connecting");
|
|
873
|
+
onConnectionChange?.("connecting");
|
|
487
874
|
try {
|
|
488
875
|
const unsubscribe = transport.onMessage(handleEvent);
|
|
489
876
|
await transport.connect({
|
|
@@ -502,6 +889,7 @@ function useChat(options) {
|
|
|
502
889
|
} catch (err) {
|
|
503
890
|
const transportError = err;
|
|
504
891
|
setConnectionState("disconnected");
|
|
892
|
+
onConnectionChange?.("disconnected");
|
|
505
893
|
setError(transportError);
|
|
506
894
|
onErrorRef.current?.(transportError);
|
|
507
895
|
throw err;
|
|
@@ -531,7 +919,7 @@ function useChat(options) {
|
|
|
531
919
|
},
|
|
532
920
|
[orgId, userId]
|
|
533
921
|
);
|
|
534
|
-
const
|
|
922
|
+
const loadChat2 = useCallback(
|
|
535
923
|
async (key) => {
|
|
536
924
|
const transport = transportRef.current;
|
|
537
925
|
if (!transport) {
|
|
@@ -584,7 +972,7 @@ function useChat(options) {
|
|
|
584
972
|
},
|
|
585
973
|
[orgId, chatKey, userId]
|
|
586
974
|
);
|
|
587
|
-
const
|
|
975
|
+
const endChat2 = useCallback(
|
|
588
976
|
async (reason) => {
|
|
589
977
|
const transport = transportRef.current;
|
|
590
978
|
if (!transport) {
|
|
@@ -606,7 +994,7 @@ function useChat(options) {
|
|
|
606
994
|
},
|
|
607
995
|
[orgId, chatKey, userId]
|
|
608
996
|
);
|
|
609
|
-
const
|
|
997
|
+
const sendEvent2 = useCallback(
|
|
610
998
|
async (event) => {
|
|
611
999
|
const transport = transportRef.current;
|
|
612
1000
|
if (!transport) {
|
|
@@ -691,10 +1079,10 @@ function useChat(options) {
|
|
|
691
1079
|
isConnected,
|
|
692
1080
|
// Chat operations
|
|
693
1081
|
startChat,
|
|
694
|
-
loadChat,
|
|
1082
|
+
loadChat: loadChat2,
|
|
695
1083
|
sendMessage,
|
|
696
|
-
sendEvent,
|
|
697
|
-
endChat,
|
|
1084
|
+
sendEvent: sendEvent2,
|
|
1085
|
+
endChat: endChat2,
|
|
698
1086
|
// Typing
|
|
699
1087
|
startTyping,
|
|
700
1088
|
stopTyping,
|
|
@@ -710,12 +1098,226 @@ function useChat(options) {
|
|
|
710
1098
|
};
|
|
711
1099
|
}
|
|
712
1100
|
|
|
1101
|
+
// hooks/use-chat-history.ts
|
|
1102
|
+
import { useMemo } from "react";
|
|
1103
|
+
|
|
1104
|
+
// api/index.ts
|
|
1105
|
+
import { browserApiRequest } from "@elqnt/api-client/browser";
|
|
1106
|
+
async function getChatHistoryApi(options) {
|
|
1107
|
+
return browserApiRequest("/api/v1/chats", {
|
|
1108
|
+
method: "POST",
|
|
1109
|
+
body: {
|
|
1110
|
+
limit: options.limit || 15,
|
|
1111
|
+
offset: options.offset || 0,
|
|
1112
|
+
...options.skipCache ? { skipCache: true } : {}
|
|
1113
|
+
},
|
|
1114
|
+
...options
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
async function getChatApi(chatKey, options) {
|
|
1118
|
+
return browserApiRequest(`/api/v1/chats/${chatKey}`, {
|
|
1119
|
+
method: "GET",
|
|
1120
|
+
...options
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
async function updateChatApi(chatKey, updates, options) {
|
|
1124
|
+
return browserApiRequest(`/api/v1/chats/${chatKey}`, {
|
|
1125
|
+
method: "PATCH",
|
|
1126
|
+
body: updates,
|
|
1127
|
+
...options
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
async function deleteChatApi(chatKey, options) {
|
|
1131
|
+
return browserApiRequest(`/api/v1/chats/${chatKey}`, {
|
|
1132
|
+
method: "DELETE",
|
|
1133
|
+
...options
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
async function getActiveChatsCountApi(options) {
|
|
1137
|
+
return browserApiRequest("/api/v1/chats/active/count", {
|
|
1138
|
+
method: "GET",
|
|
1139
|
+
...options
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
async function getActiveChatsApi(options) {
|
|
1143
|
+
const params = new URLSearchParams();
|
|
1144
|
+
if (options.pastHours) params.set("pastHours", String(options.pastHours));
|
|
1145
|
+
const queryString = params.toString();
|
|
1146
|
+
return browserApiRequest(`/api/v1/chats/active${queryString ? `?${queryString}` : ""}`, {
|
|
1147
|
+
method: "GET",
|
|
1148
|
+
...options
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
async function getWaitingChatsCountApi(options) {
|
|
1152
|
+
return browserApiRequest("/api/v1/chats/waiting/count", {
|
|
1153
|
+
method: "GET",
|
|
1154
|
+
...options
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
async function getChatsByUserApi(userEmail, options) {
|
|
1158
|
+
return browserApiRequest(`/api/v1/chats/user/${encodeURIComponent(userEmail)}`, {
|
|
1159
|
+
method: "GET",
|
|
1160
|
+
...options
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
async function listQueuesApi(options) {
|
|
1164
|
+
return browserApiRequest("/api/v1/queues", {
|
|
1165
|
+
method: "GET",
|
|
1166
|
+
...options
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
async function getOnlineSessionsApi(options) {
|
|
1170
|
+
return browserApiRequest("/api/v1/agents/sessions/online", {
|
|
1171
|
+
method: "GET",
|
|
1172
|
+
...options
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
async function getAgentSessionApi(agentId, options) {
|
|
1176
|
+
return browserApiRequest(`/api/v1/agents/sessions/${agentId}`, {
|
|
1177
|
+
method: "GET",
|
|
1178
|
+
...options
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// hooks/use-chat-history.ts
|
|
1183
|
+
import { useApiAsync } from "@elqnt/api-client/hooks";
|
|
1184
|
+
|
|
1185
|
+
// hooks/use-options-ref.ts
|
|
1186
|
+
import { useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
1187
|
+
function useOptionsRef(options) {
|
|
1188
|
+
const optionsRef = useRef2(options);
|
|
1189
|
+
useEffect2(() => {
|
|
1190
|
+
optionsRef.current = options;
|
|
1191
|
+
}, [options]);
|
|
1192
|
+
return optionsRef;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
// hooks/use-chat-history.ts
|
|
1196
|
+
function useChatHistory(options) {
|
|
1197
|
+
const optionsRef = useOptionsRef(options);
|
|
1198
|
+
const { execute: getChatHistory, loading: listLoading, error: listError } = useApiAsync(
|
|
1199
|
+
(params) => getChatHistoryApi({ ...optionsRef.current, ...params }),
|
|
1200
|
+
(data) => ({
|
|
1201
|
+
chats: data.chats,
|
|
1202
|
+
total: data.total,
|
|
1203
|
+
hasMore: data.hasMore
|
|
1204
|
+
}),
|
|
1205
|
+
{ chats: [], total: 0, hasMore: false }
|
|
1206
|
+
);
|
|
1207
|
+
const { execute: getChat, loading: getLoading, error: getError } = useApiAsync(
|
|
1208
|
+
(chatKey) => getChatApi(chatKey, optionsRef.current),
|
|
1209
|
+
(data) => data.chat || null,
|
|
1210
|
+
null
|
|
1211
|
+
);
|
|
1212
|
+
const { execute: updateChat, loading: updateLoading, error: updateError } = useApiAsync(
|
|
1213
|
+
(chatKey, updates) => updateChatApi(chatKey, updates, optionsRef.current),
|
|
1214
|
+
(data) => !!data.chatKey,
|
|
1215
|
+
false
|
|
1216
|
+
);
|
|
1217
|
+
const { execute: deleteChat, loading: deleteLoading, error: deleteError } = useApiAsync(
|
|
1218
|
+
(chatKey) => deleteChatApi(chatKey, optionsRef.current),
|
|
1219
|
+
(data) => data.success,
|
|
1220
|
+
false
|
|
1221
|
+
);
|
|
1222
|
+
const { execute: getChatsByUser, loading: userChatsLoading, error: userChatsError } = useApiAsync(
|
|
1223
|
+
(userEmail) => getChatsByUserApi(userEmail, optionsRef.current),
|
|
1224
|
+
(data) => data.chats,
|
|
1225
|
+
[]
|
|
1226
|
+
);
|
|
1227
|
+
const loading = listLoading || getLoading || updateLoading || deleteLoading || userChatsLoading;
|
|
1228
|
+
const error = listError || getError || updateError || deleteError || userChatsError;
|
|
1229
|
+
return useMemo(
|
|
1230
|
+
() => ({
|
|
1231
|
+
loading,
|
|
1232
|
+
error,
|
|
1233
|
+
getChatHistory,
|
|
1234
|
+
getChat,
|
|
1235
|
+
updateChat,
|
|
1236
|
+
deleteChat,
|
|
1237
|
+
getChatsByUser
|
|
1238
|
+
}),
|
|
1239
|
+
[loading, error, getChatHistory, getChat, updateChat, deleteChat, getChatsByUser]
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
// hooks/use-chat-monitoring.ts
|
|
1244
|
+
import { useMemo as useMemo2 } from "react";
|
|
1245
|
+
import { useApiAsync as useApiAsync2 } from "@elqnt/api-client/hooks";
|
|
1246
|
+
function useChatMonitoring(options) {
|
|
1247
|
+
const optionsRef = useOptionsRef(options);
|
|
1248
|
+
const { execute: getActiveChats, loading: activeLoading, error: activeError } = useApiAsync2(
|
|
1249
|
+
(pastHours) => getActiveChatsApi({ ...optionsRef.current, pastHours }),
|
|
1250
|
+
(data) => data.chats,
|
|
1251
|
+
[]
|
|
1252
|
+
);
|
|
1253
|
+
const { execute: getActiveChatsCount, loading: activeCountLoading, error: activeCountError } = useApiAsync2(
|
|
1254
|
+
() => getActiveChatsCountApi(optionsRef.current),
|
|
1255
|
+
(data) => data.count,
|
|
1256
|
+
0
|
|
1257
|
+
);
|
|
1258
|
+
const { execute: getWaitingChatsCount, loading: waitingCountLoading, error: waitingCountError } = useApiAsync2(
|
|
1259
|
+
() => getWaitingChatsCountApi(optionsRef.current),
|
|
1260
|
+
(data) => data.count,
|
|
1261
|
+
0
|
|
1262
|
+
);
|
|
1263
|
+
const { execute: listQueues, loading: queuesLoading, error: queuesError } = useApiAsync2(
|
|
1264
|
+
() => listQueuesApi(optionsRef.current),
|
|
1265
|
+
(data) => data.queues,
|
|
1266
|
+
[]
|
|
1267
|
+
);
|
|
1268
|
+
const loading = activeLoading || activeCountLoading || waitingCountLoading || queuesLoading;
|
|
1269
|
+
const error = activeError || activeCountError || waitingCountError || queuesError;
|
|
1270
|
+
return useMemo2(
|
|
1271
|
+
() => ({
|
|
1272
|
+
loading,
|
|
1273
|
+
error,
|
|
1274
|
+
getActiveChats,
|
|
1275
|
+
getActiveChatsCount,
|
|
1276
|
+
getWaitingChatsCount,
|
|
1277
|
+
listQueues
|
|
1278
|
+
}),
|
|
1279
|
+
[loading, error, getActiveChats, getActiveChatsCount, getWaitingChatsCount, listQueues]
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
// hooks/use-human-agent-sessions.ts
|
|
1284
|
+
import { useMemo as useMemo3 } from "react";
|
|
1285
|
+
import { useApiAsync as useApiAsync3 } from "@elqnt/api-client/hooks";
|
|
1286
|
+
function useHumanAgentSessions(options) {
|
|
1287
|
+
const optionsRef = useOptionsRef(options);
|
|
1288
|
+
const { execute: getOnlineSessions, loading: onlineLoading, error: onlineError } = useApiAsync3(
|
|
1289
|
+
() => getOnlineSessionsApi(optionsRef.current),
|
|
1290
|
+
(data) => data.sessions,
|
|
1291
|
+
[]
|
|
1292
|
+
);
|
|
1293
|
+
const { execute: getAgentSession, loading: sessionLoading, error: sessionError } = useApiAsync3(
|
|
1294
|
+
(agentId) => getAgentSessionApi(agentId, optionsRef.current),
|
|
1295
|
+
(data) => data.session || null,
|
|
1296
|
+
null
|
|
1297
|
+
);
|
|
1298
|
+
const loading = onlineLoading || sessionLoading;
|
|
1299
|
+
const error = onlineError || sessionError;
|
|
1300
|
+
return useMemo3(
|
|
1301
|
+
() => ({
|
|
1302
|
+
loading,
|
|
1303
|
+
error,
|
|
1304
|
+
getOnlineSessions,
|
|
1305
|
+
getAgentSession
|
|
1306
|
+
}),
|
|
1307
|
+
[loading, error, getOnlineSessions, getAgentSession]
|
|
1308
|
+
);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
// hooks/index.ts
|
|
1312
|
+
import { useApiAsync as useApiAsync4 } from "@elqnt/api-client/hooks";
|
|
1313
|
+
|
|
713
1314
|
// models/chat-models.ts
|
|
714
1315
|
var ChatStatusActive = "active";
|
|
715
1316
|
var ChatStatusDisconnected = "disconnected";
|
|
716
1317
|
var ChatStatusAbandoned = "abandoned";
|
|
717
1318
|
var ChatStatusClosed = "closed";
|
|
718
1319
|
var ChatStatusArchived = "archived";
|
|
1320
|
+
var ChatStatusCompleted = "completed";
|
|
719
1321
|
var ChatTypeCustomerSupport = "customer_support";
|
|
720
1322
|
var ChatTypePublicRoom = "public_room";
|
|
721
1323
|
var ChatTypePrivateRoom = "private_room";
|
|
@@ -899,6 +1501,7 @@ var UpdateUserStatusSubject = "chat.user.status.update";
|
|
|
899
1501
|
var GetOnlineUsersSubject = "chat.users.online.get";
|
|
900
1502
|
var TriggerAnalyticsScanSubject = "chat.analytics.trigger-scan";
|
|
901
1503
|
var SetupOrgSubject = "chat.org.setup";
|
|
1504
|
+
var GetAgentContextSubject = "chat.agent-context.get";
|
|
902
1505
|
export {
|
|
903
1506
|
AgentStatusAway,
|
|
904
1507
|
AgentStatusBusy,
|
|
@@ -1038,6 +1641,7 @@ export {
|
|
|
1038
1641
|
ChatStatusActive,
|
|
1039
1642
|
ChatStatusArchived,
|
|
1040
1643
|
ChatStatusClosed,
|
|
1644
|
+
ChatStatusCompleted,
|
|
1041
1645
|
ChatStatusDisconnected,
|
|
1042
1646
|
ChatTypeCustomerSupport,
|
|
1043
1647
|
ChatTypeDirect,
|
|
@@ -1050,6 +1654,7 @@ export {
|
|
|
1050
1654
|
EndAgentSessionSubject,
|
|
1051
1655
|
GetActiveChatCountSubject,
|
|
1052
1656
|
GetActiveChatsSubject,
|
|
1657
|
+
GetAgentContextSubject,
|
|
1053
1658
|
GetAgentQueuesSubject,
|
|
1054
1659
|
GetAgentSessionSubject,
|
|
1055
1660
|
GetChatSubject,
|
|
@@ -1083,6 +1688,11 @@ export {
|
|
|
1083
1688
|
UserStatusBusy,
|
|
1084
1689
|
UserStatusOffline,
|
|
1085
1690
|
UserStatusOnline,
|
|
1086
|
-
|
|
1691
|
+
useApiAsync4 as useApiAsync,
|
|
1692
|
+
useChat,
|
|
1693
|
+
useChatHistory,
|
|
1694
|
+
useChatMonitoring,
|
|
1695
|
+
useHumanAgentSessions,
|
|
1696
|
+
useOptionsRef
|
|
1087
1697
|
};
|
|
1088
1698
|
//# sourceMappingURL=index.mjs.map
|