@origonai/web-chat-sdk 1.0.1 → 1.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 +0 -4
- package/dist/origon-chat-sdk.js +65 -68
- package/dist/origon-chat-sdk.js.map +1 -1
- package/package.json +1 -1
- package/src/chat.js +4 -3
- package/src/constants.js +1 -7
package/README.md
CHANGED
|
@@ -286,10 +286,6 @@ MESSAGE_ROLES.ASSISTANT // 'assistant' - AI/bot or LLM AI Agent responses
|
|
|
286
286
|
MESSAGE_ROLES.USER // 'user' - Widget user messages
|
|
287
287
|
MESSAGE_ROLES.SUPERVISOR // 'supervisor' - Human supervisor messages
|
|
288
288
|
MESSAGE_ROLES.SYSTEM // 'system' - System notifications (e.g., "Agent joined" / "Agent left")
|
|
289
|
-
|
|
290
|
-
// Deprecated (will be removed in v1.0):
|
|
291
|
-
MESSAGE_ROLES.BOT // use ASSISTANT instead
|
|
292
|
-
MESSAGE_ROLES.AGENT // use SUPERVISOR instead
|
|
293
289
|
```
|
|
294
290
|
|
|
295
291
|
---
|
package/dist/origon-chat-sdk.js
CHANGED
|
@@ -51,14 +51,9 @@ const w = {
|
|
|
51
51
|
// this is widget user
|
|
52
52
|
SUPERVISOR: "supervisor",
|
|
53
53
|
// this is human supervisor (ex. Samespace Dock agent, or Resolve human agent)
|
|
54
|
-
SYSTEM: "system"
|
|
54
|
+
SYSTEM: "system"
|
|
55
55
|
// this is system message, for ex "Agent joined" / "Agent left"
|
|
56
|
-
|
|
57
|
-
/** @deprecated Use ASSISTANT instead */
|
|
58
|
-
BOT: "assistant",
|
|
59
|
-
/** @deprecated Use SUPERVISOR instead */
|
|
60
|
-
AGENT: "supervisor"
|
|
61
|
-
}, Y = 1e4, ge = 5e3, T = {
|
|
56
|
+
}, Y = 1e4, ge = 5e3, v = {
|
|
62
57
|
MESSAGE: "message",
|
|
63
58
|
TYPING: "typing",
|
|
64
59
|
TYPING_STOP: "typingOff",
|
|
@@ -87,10 +82,10 @@ function B() {
|
|
|
87
82
|
U(), r.socketDisconnectedTimeout && (clearTimeout(r.socketDisconnectedTimeout), r.socketDisconnectedTimeout = null), r.socketConnectionTimeout && (clearTimeout(r.socketConnectionTimeout), r.socketConnectionTimeout = null);
|
|
88
83
|
}
|
|
89
84
|
function Q() {
|
|
90
|
-
r.socketDisconnected = !1,
|
|
85
|
+
r.socketDisconnected = !1, A("socket");
|
|
91
86
|
}
|
|
92
87
|
function Z() {
|
|
93
|
-
r.socketDisconnected = !0,
|
|
88
|
+
r.socketDisconnected = !0, A("sse");
|
|
94
89
|
}
|
|
95
90
|
function me(e) {
|
|
96
91
|
return new Promise((t, s) => {
|
|
@@ -112,8 +107,8 @@ function me(e) {
|
|
|
112
107
|
);
|
|
113
108
|
return;
|
|
114
109
|
}
|
|
115
|
-
const
|
|
116
|
-
externalId:
|
|
110
|
+
const f = P(), i = new URLSearchParams({
|
|
111
|
+
externalId: f
|
|
117
112
|
});
|
|
118
113
|
e.sessionId && i.set("sessionId", e.sessionId), e.requestId && i.set("requestId", e.requestId), c.token && i.set("token", c.token);
|
|
119
114
|
const u = `${d}?${i.toString()}`;
|
|
@@ -123,7 +118,7 @@ function me(e) {
|
|
|
123
118
|
const p = JSON.parse(l.data);
|
|
124
119
|
Se(p);
|
|
125
120
|
}, r.socket.onerror = (l) => {
|
|
126
|
-
|
|
121
|
+
A("sse"), s(l);
|
|
127
122
|
}, r.socket.onclose = (l) => {
|
|
128
123
|
l.target === r.socket && (l.code === 1006 && (r.previouslyConnected ? Z() : k({
|
|
129
124
|
errorText: "Unable to establish connection",
|
|
@@ -150,15 +145,15 @@ function Se(e) {
|
|
|
150
145
|
}, Y + 1e3);
|
|
151
146
|
break;
|
|
152
147
|
}
|
|
153
|
-
case
|
|
148
|
+
case v.TYPING: {
|
|
154
149
|
V(!0);
|
|
155
150
|
break;
|
|
156
151
|
}
|
|
157
|
-
case
|
|
152
|
+
case v.TYPING_STOP: {
|
|
158
153
|
V(!1);
|
|
159
154
|
break;
|
|
160
155
|
}
|
|
161
|
-
case
|
|
156
|
+
case v.MESSAGE: {
|
|
162
157
|
const { eventId: t, data: s } = e;
|
|
163
158
|
t || k({
|
|
164
159
|
...s,
|
|
@@ -167,14 +162,14 @@ function Se(e) {
|
|
|
167
162
|
});
|
|
168
163
|
break;
|
|
169
164
|
}
|
|
170
|
-
case
|
|
165
|
+
case v.END: {
|
|
171
166
|
j();
|
|
172
167
|
break;
|
|
173
168
|
}
|
|
174
169
|
}
|
|
175
170
|
}
|
|
176
171
|
function j() {
|
|
177
|
-
r.socket && r.socket.close(1e3), r.previouslyConnected = !1, B(), r.socket = null,
|
|
172
|
+
r.socket && r.socket.close(1e3), r.previouslyConnected = !1, B(), r.socket = null, A("sse");
|
|
178
173
|
}
|
|
179
174
|
function ke() {
|
|
180
175
|
return r.socket !== null && r.socket.readyState === WebSocket.OPEN && !r.socketDisconnected;
|
|
@@ -215,11 +210,11 @@ async function qe(e = {}) {
|
|
|
215
210
|
o.authenticated ? t = o.configData : (t = await ye(o.credentials), o.authenticated = !0, o.configData = t);
|
|
216
211
|
let s = [], c = "agent";
|
|
217
212
|
if (e.sessionId) {
|
|
218
|
-
const
|
|
219
|
-
s =
|
|
213
|
+
const f = await Ee(e.sessionId);
|
|
214
|
+
s = f.messages, c = f.control || "agent";
|
|
220
215
|
}
|
|
221
216
|
const d = new URLSearchParams();
|
|
222
|
-
return o.credentials.token || d.set("externalId",
|
|
217
|
+
return o.credentials.token || d.set("externalId", P()), o.sseUrl = `${le(
|
|
223
218
|
o.credentials.endpoint
|
|
224
219
|
)}?${d.toString()}`, o.sessionId = e.sessionId, o.messages = s, o.control = c, c === "human" && Ce({ text: "", html: "" }).catch(() => {
|
|
225
220
|
}), {
|
|
@@ -240,7 +235,7 @@ function ee() {
|
|
|
240
235
|
const { callbacks: e, credentials: t } = o;
|
|
241
236
|
o = X(e), o.credentials = t;
|
|
242
237
|
}
|
|
243
|
-
function
|
|
238
|
+
function P() {
|
|
244
239
|
var e;
|
|
245
240
|
return (e = o.credentials) != null && e.externalId ? o.credentials.externalId : ae();
|
|
246
241
|
}
|
|
@@ -252,24 +247,24 @@ function V(e) {
|
|
|
252
247
|
var t, s;
|
|
253
248
|
(s = (t = o.callbacks).onTyping) == null || s.call(t, e);
|
|
254
249
|
}
|
|
255
|
-
function
|
|
250
|
+
function A(e) {
|
|
256
251
|
var t, s;
|
|
257
252
|
o.transport = e, (s = (t = o.callbacks).onTransportUpdate) == null || s.call(t, e);
|
|
258
253
|
}
|
|
259
254
|
function Ce({ text: e, html: t, context: s }) {
|
|
260
255
|
return new Promise((c, d) => {
|
|
261
256
|
(async () => {
|
|
262
|
-
var
|
|
257
|
+
var f, i, u;
|
|
263
258
|
try {
|
|
264
259
|
const l = !e && !t;
|
|
265
260
|
if (!l) {
|
|
266
|
-
const
|
|
261
|
+
const g = {
|
|
267
262
|
role: w.USER,
|
|
268
263
|
text: e,
|
|
269
264
|
html: t,
|
|
270
265
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
271
266
|
};
|
|
272
|
-
k(
|
|
267
|
+
k(g), await ie(200);
|
|
273
268
|
}
|
|
274
269
|
if (o.transport === "socket" && ke()) {
|
|
275
270
|
O({
|
|
@@ -282,19 +277,19 @@ function Ce({ text: e, html: t, context: s }) {
|
|
|
282
277
|
return;
|
|
283
278
|
}
|
|
284
279
|
if (o.control === "agent") {
|
|
285
|
-
const
|
|
280
|
+
const g = {
|
|
286
281
|
role: w.ASSISTANT,
|
|
287
282
|
text: "",
|
|
288
283
|
loading: !0
|
|
289
284
|
};
|
|
290
|
-
k(
|
|
285
|
+
k(g);
|
|
291
286
|
}
|
|
292
287
|
const p = new URL(o.sseUrl);
|
|
293
288
|
o.sessionId && p.searchParams.set("sessionId", o.sessionId), o.requestId && p.searchParams.set("requestId", o.requestId), o.lastStreamId = void 0, o.abortController = new AbortController();
|
|
294
289
|
const C = {
|
|
295
290
|
"Content-Type": "application/json"
|
|
296
291
|
};
|
|
297
|
-
(
|
|
292
|
+
(f = o.credentials) != null && f.token && (C.Authorization = `Bearer ${o.credentials.token}`), await ce(p.toString(), {
|
|
298
293
|
method: "POST",
|
|
299
294
|
headers: C,
|
|
300
295
|
body: l ? void 0 : JSON.stringify({
|
|
@@ -304,21 +299,21 @@ function Ce({ text: e, html: t, context: s }) {
|
|
|
304
299
|
}),
|
|
305
300
|
signal: o.abortController.signal,
|
|
306
301
|
openWhenHidden: !0,
|
|
307
|
-
onopen: async (
|
|
308
|
-
if (!
|
|
302
|
+
onopen: async (g) => {
|
|
303
|
+
if (!g.ok)
|
|
309
304
|
throw new Error("Failed to send message");
|
|
310
305
|
},
|
|
311
|
-
onmessage: (
|
|
306
|
+
onmessage: (g) => {
|
|
312
307
|
var E, b, M, x, q, L, G, z, F, W, J, _, K;
|
|
313
|
-
const a = JSON.parse(
|
|
314
|
-
if (
|
|
308
|
+
const a = JSON.parse(g.data);
|
|
309
|
+
if (g.event === "connected")
|
|
315
310
|
o.sessionId = a.sessionId, o.requestId = a.requestId, a.control && (o.control = a.control, (b = (E = o.callbacks).onControlUpdate) == null || b.call(E, a.control));
|
|
316
|
-
else if (
|
|
311
|
+
else if (g.event === "upgrade_to_websocket")
|
|
317
312
|
me({
|
|
318
313
|
sessionId: o.sessionId,
|
|
319
314
|
requestId: a.requestId
|
|
320
315
|
});
|
|
321
|
-
else if (
|
|
316
|
+
else if (g.event === "update")
|
|
322
317
|
a.control && (o.control = a.control, (x = (M = o.callbacks).onControlUpdate) == null || x.call(M, a.control));
|
|
323
318
|
else if (a.error) {
|
|
324
319
|
const h = a.error && typeof a.error == "string" ? a.error : "Failed to connect to the system", S = o.messages.length - 1, m = {
|
|
@@ -329,7 +324,9 @@ function Ce({ text: e, html: t, context: s }) {
|
|
|
329
324
|
o.messages = o.messages.map(
|
|
330
325
|
($, re) => re === S ? m : $
|
|
331
326
|
), (L = (q = o.callbacks).onMessageUpdate) == null || L.call(q, S, m), d(new Error(h));
|
|
332
|
-
} else if (
|
|
327
|
+
} else if (g.event === "done")
|
|
328
|
+
c(o.sessionId);
|
|
329
|
+
else if (a.message !== void 0) {
|
|
333
330
|
if (a.role === w.SUPERVISOR) {
|
|
334
331
|
const m = {
|
|
335
332
|
role: w.SUPERVISOR,
|
|
@@ -337,7 +334,7 @@ function Ce({ text: e, html: t, context: s }) {
|
|
|
337
334
|
sources: a.sources,
|
|
338
335
|
done: !0
|
|
339
336
|
};
|
|
340
|
-
k(m), c(o.sessionId), o.sessionId = (G = a.
|
|
337
|
+
k(m), c(o.sessionId), o.sessionId = (G = a.sessionId) != null ? G : o.sessionId, o.requestId = (z = a.requestId) != null ? z : o.requestId;
|
|
341
338
|
return;
|
|
342
339
|
}
|
|
343
340
|
if (a.streamId !== void 0) {
|
|
@@ -362,19 +359,19 @@ function Ce({ text: e, html: t, context: s }) {
|
|
|
362
359
|
};
|
|
363
360
|
o.messages = o.messages.map(
|
|
364
361
|
(m, $) => $ === h ? R : m
|
|
365
|
-
), (J = (W = o.callbacks).onMessageUpdate) == null || J.call(W, h, R), a.done
|
|
362
|
+
), (J = (W = o.callbacks).onMessageUpdate) == null || J.call(W, h, R), a.done, o.sessionId = (_ = a.sessionId) != null ? _ : o.sessionId, o.requestId = (K = a.requestId) != null ? K : o.requestId;
|
|
366
363
|
}
|
|
367
364
|
},
|
|
368
|
-
onerror: (
|
|
369
|
-
throw
|
|
365
|
+
onerror: (g) => {
|
|
366
|
+
throw g;
|
|
370
367
|
},
|
|
371
368
|
openWhenHidden: !0
|
|
372
369
|
});
|
|
373
370
|
} catch (l) {
|
|
374
|
-
const p = "Failed to connect to the system", C = o.messages.length - 1,
|
|
375
|
-
...
|
|
371
|
+
const p = "Failed to connect to the system", C = o.messages.length - 1, g = o.messages[C], a = {
|
|
372
|
+
...g,
|
|
376
373
|
loading: !1,
|
|
377
|
-
errorText:
|
|
374
|
+
errorText: g.done ? void 0 : l.message || p,
|
|
378
375
|
done: !0
|
|
379
376
|
};
|
|
380
377
|
o.messages = o.messages.map(
|
|
@@ -400,7 +397,7 @@ async function ye(e) {
|
|
|
400
397
|
}
|
|
401
398
|
async function Ge() {
|
|
402
399
|
const e = new URLSearchParams({
|
|
403
|
-
externalId:
|
|
400
|
+
externalId: P()
|
|
404
401
|
}), t = await ne(`/sessions?${e.toString()}`, "GET");
|
|
405
402
|
if (!t.ok)
|
|
406
403
|
throw new Error("Unable to load history, please try again later");
|
|
@@ -413,7 +410,7 @@ async function Ee(e) {
|
|
|
413
410
|
}), s = await ne(`/session?${t.toString()}`, "GET");
|
|
414
411
|
if (!s.ok)
|
|
415
412
|
throw new Error("Unable to load messages, please try again later");
|
|
416
|
-
const c = await s.json(), d = c == null ? void 0 : c.control,
|
|
413
|
+
const c = await s.json(), d = c == null ? void 0 : c.control, f = ((i = c == null ? void 0 : c.history) != null ? i : []).map((u) => ({
|
|
417
414
|
id: u.id,
|
|
418
415
|
text: u.text,
|
|
419
416
|
role: u.youtubeVideo ? w.ASSISTANT : u.role,
|
|
@@ -422,16 +419,16 @@ async function Ee(e) {
|
|
|
422
419
|
channel: u.channel,
|
|
423
420
|
done: !0
|
|
424
421
|
}));
|
|
425
|
-
return { control: d, messages:
|
|
422
|
+
return { control: d, messages: f };
|
|
426
423
|
}
|
|
427
424
|
async function ne(e, t = "GET", s = null) {
|
|
428
|
-
const c = N(), { endpoint: d, token:
|
|
425
|
+
const c = N(), { endpoint: d, token: f } = c || {};
|
|
429
426
|
if (!d)
|
|
430
427
|
throw new Error(we);
|
|
431
428
|
const i = `${d}${e}`, u = {
|
|
432
429
|
"Content-Type": "application/json"
|
|
433
430
|
};
|
|
434
|
-
return
|
|
431
|
+
return f && (u.Authorization = `Bearer ${f}`), fetch(i, {
|
|
435
432
|
headers: u,
|
|
436
433
|
method: t,
|
|
437
434
|
body: s ? JSON.stringify(s) : null
|
|
@@ -463,7 +460,7 @@ function ze(e) {
|
|
|
463
460
|
n.callbacks = { ...n.callbacks, ...e };
|
|
464
461
|
}
|
|
465
462
|
function oe() {
|
|
466
|
-
n.peerConnection && (n.peerConnection.close(), n.peerConnection = null), n.localStream && (n.localStream.getTracks().forEach((t) => t.stop()), n.localStream = null), n.remoteStream && (n.remoteStream = null), n.remoteAudio && (n.remoteAudio.srcObject = null, n.remoteAudio.parentNode && n.remoteAudio.parentNode.removeChild(n.remoteAudio), n.remoteAudio = null), n.socket && (n.socket.close(), n.socket = null),
|
|
463
|
+
n.peerConnection && (n.peerConnection.close(), n.peerConnection = null), n.localStream && (n.localStream.getTracks().forEach((t) => t.stop()), n.localStream = null), n.remoteStream && (n.remoteStream = null), n.remoteAudio && (n.remoteAudio.srcObject = null, n.remoteAudio.parentNode && n.remoteAudio.parentNode.removeChild(n.remoteAudio), n.remoteAudio = null), n.socket && (n.socket.close(), n.socket = null), D();
|
|
467
464
|
const e = n.callbacks;
|
|
468
465
|
n = te(e);
|
|
469
466
|
}
|
|
@@ -471,15 +468,15 @@ function I(e) {
|
|
|
471
468
|
var t, s;
|
|
472
469
|
n.callStatus = e, (s = (t = n.callbacks).onCallStatus) == null || s.call(t, e);
|
|
473
470
|
}
|
|
474
|
-
function
|
|
471
|
+
function T(e) {
|
|
475
472
|
var t, s;
|
|
476
473
|
(s = (t = n.callbacks).onCallError) == null || s.call(t, e);
|
|
477
474
|
}
|
|
478
|
-
function
|
|
475
|
+
function D() {
|
|
479
476
|
n.pingInterval && (clearInterval(n.pingInterval), n.pingInterval = null);
|
|
480
477
|
}
|
|
481
|
-
function
|
|
482
|
-
|
|
478
|
+
function ve() {
|
|
479
|
+
D(), n.pingInterval = setInterval(() => {
|
|
483
480
|
if (n.socket && n.socket.readyState === WebSocket.OPEN) {
|
|
484
481
|
n.pingCount++;
|
|
485
482
|
const e = {
|
|
@@ -489,16 +486,16 @@ function Te() {
|
|
|
489
486
|
};
|
|
490
487
|
y(e);
|
|
491
488
|
} else
|
|
492
|
-
|
|
489
|
+
D();
|
|
493
490
|
}, 1e4);
|
|
494
491
|
}
|
|
495
|
-
function
|
|
492
|
+
function Te() {
|
|
496
493
|
n.lastPongTime = Date.now();
|
|
497
494
|
}
|
|
498
495
|
function y(e) {
|
|
499
496
|
n.socket && n.socket.readyState === WebSocket.OPEN && n.socket.send(JSON.stringify(e));
|
|
500
497
|
}
|
|
501
|
-
async function
|
|
498
|
+
async function De() {
|
|
502
499
|
try {
|
|
503
500
|
n.localStream = await navigator.mediaDevices.getUserMedia({
|
|
504
501
|
audio: !0,
|
|
@@ -508,7 +505,7 @@ async function Ae() {
|
|
|
508
505
|
throw e;
|
|
509
506
|
}
|
|
510
507
|
}
|
|
511
|
-
function
|
|
508
|
+
function Pe() {
|
|
512
509
|
n.peerConnection = new RTCPeerConnection(be), n.peerConnection.onicecandidate = (e) => {
|
|
513
510
|
if (e.candidate) {
|
|
514
511
|
const t = JSON.stringify(e.candidate);
|
|
@@ -529,7 +526,7 @@ function De() {
|
|
|
529
526
|
}, n.peerConnection.oniceconnectionstatechange = () => {
|
|
530
527
|
};
|
|
531
528
|
}
|
|
532
|
-
function
|
|
529
|
+
function Ae(e) {
|
|
533
530
|
return new Promise((t, s) => {
|
|
534
531
|
if (n.socket && (n.socket.readyState === WebSocket.CONNECTING || n.socket.readyState === WebSocket.OPEN)) {
|
|
535
532
|
t(n.socket.readyState === WebSocket.OPEN);
|
|
@@ -549,27 +546,27 @@ function Pe(e) {
|
|
|
549
546
|
);
|
|
550
547
|
return;
|
|
551
548
|
}
|
|
552
|
-
const
|
|
553
|
-
externalId:
|
|
549
|
+
const f = P(), i = new URLSearchParams({
|
|
550
|
+
externalId: f
|
|
554
551
|
});
|
|
555
552
|
e.sessionId && i.set("sessionId", e.sessionId), c.token && i.set("token", c.token);
|
|
556
553
|
const u = `${d}?${i.toString()}`;
|
|
557
554
|
n.socket = new WebSocket(u), n.socket.onopen = (l) => {
|
|
558
|
-
|
|
555
|
+
ve(), t(!0);
|
|
559
556
|
}, n.socket.onmessage = (l) => {
|
|
560
557
|
const p = JSON.parse(l.data);
|
|
561
558
|
Re(p);
|
|
562
559
|
}, n.socket.onerror = (l) => {
|
|
563
|
-
I("error"),
|
|
560
|
+
I("error"), T(l.message || "Unable to connect voice"), s(l);
|
|
564
561
|
}, n.socket.onclose = (l) => {
|
|
565
|
-
|
|
562
|
+
D();
|
|
566
563
|
};
|
|
567
564
|
});
|
|
568
565
|
}
|
|
569
566
|
function Re(e) {
|
|
570
567
|
switch (e.type) {
|
|
571
568
|
case "pong":
|
|
572
|
-
|
|
569
|
+
Te();
|
|
573
570
|
break;
|
|
574
571
|
case "answer":
|
|
575
572
|
$e(e.data);
|
|
@@ -584,7 +581,7 @@ function Re(e) {
|
|
|
584
581
|
se();
|
|
585
582
|
break;
|
|
586
583
|
case "error":
|
|
587
|
-
I("error"),
|
|
584
|
+
I("error"), T(e.error || "Unable to connect voice");
|
|
588
585
|
break;
|
|
589
586
|
default:
|
|
590
587
|
break;
|
|
@@ -653,9 +650,9 @@ async function Fe(e = {}) {
|
|
|
653
650
|
try {
|
|
654
651
|
if (n.callStatus === "connecting" || n.callStatus === "connected")
|
|
655
652
|
return;
|
|
656
|
-
I("connecting"),
|
|
653
|
+
I("connecting"), T(null), n.sessionId = e.sessionId, await De(), Pe(), n.localStream.getTracks().forEach((s) => {
|
|
657
654
|
n.peerConnection.addTrack(s, n.localStream);
|
|
658
|
-
}), await
|
|
655
|
+
}), await Ae(e);
|
|
659
656
|
const t = await n.peerConnection.createOffer();
|
|
660
657
|
await n.peerConnection.setLocalDescription(t), y({
|
|
661
658
|
type: "offer",
|
|
@@ -664,7 +661,7 @@ async function Fe(e = {}) {
|
|
|
664
661
|
}
|
|
665
662
|
});
|
|
666
663
|
} catch (t) {
|
|
667
|
-
I("error"),
|
|
664
|
+
I("error"), T(t.message || "Unable to connect voice"), oe();
|
|
668
665
|
}
|
|
669
666
|
}
|
|
670
667
|
function se() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"origon-chat-sdk.js","sources":["../src/utils.js","../src/constants.js","../src/socket.js","../src/chat.js","../src/http.js","../src/call.js"],"sourcesContent":["/**\n * Utility functions for the Chat SDK\n */\n\nexport function uuidv7() {\n const timestamp = Date.now()\n const bytes = new Uint8Array(16)\n crypto.getRandomValues(bytes)\n\n // Set timestamp (48 bits)\n bytes[0] = (timestamp >> 40) & 0xff\n bytes[1] = (timestamp >> 32) & 0xff\n bytes[2] = (timestamp >> 24) & 0xff\n bytes[3] = (timestamp >> 16) & 0xff\n bytes[4] = (timestamp >> 8) & 0xff\n bytes[5] = timestamp & 0xff\n\n // Set version 7 (0111)\n bytes[6] = (bytes[6] & 0x0f) | 0x70\n\n // Set variant (10xx)\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n\n const hex = [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(\n 16,\n 20\n )}-${hex.slice(20)}`\n}\n\nexport function getDeviceId() {\n if (localStorage.getItem('chatDeviceId')) {\n return localStorage.getItem('chatDeviceId')\n }\n\n const deviceId = uuidv7()\n localStorage.setItem('chatDeviceId', deviceId)\n return deviceId\n}\n\nexport function parseJwt(token) {\n try {\n const base64Url = token.split('.')[1]\n const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split('')\n .map(function (c) {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join('')\n )\n\n return JSON.parse(jsonPayload)\n } catch {\n return null\n }\n}\n\nexport async function sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport function getSseEndpoint(baseUrl) {\n let sseEndpoint\n try {\n const url = new URL(baseUrl)\n sseEndpoint = `https://${url.hostname}${url.pathname}/sse`\n } catch {\n console.error('SSE Invalid base URL: ', baseUrl)\n }\n return sseEndpoint\n}\n\nexport function getSocketEndpoint(baseUrl) {\n let socketEndpoint\n try {\n const url = new URL(baseUrl)\n socketEndpoint = `wss://${url.hostname}${url.pathname}/wss`\n } catch {\n console.error('Socket Invalid base URL: ', baseUrl)\n }\n return socketEndpoint\n}\n\nexport function getCallServerEndpoint(baseUrl) {\n let socketEndpoint\n try {\n const url = new URL(baseUrl)\n socketEndpoint = `wss://${url.hostname}${url.pathname}/audio`\n } catch {\n console.error('getCallServerEndpoint: Invalid base URL: ', baseUrl)\n }\n return socketEndpoint\n}\n","/**\n * Constants for the Chat SDK\n */\n\nexport const MESSAGE_ROLES = {\n ASSISTANT: 'assistant', // this can be automated or LLM AI Agent response\n USER: 'user', // this is widget user\n SUPERVISOR: 'supervisor', // this is human supervisor (ex. Samespace Dock agent, or Resolve human agent)\n SYSTEM: 'system', // this is system message, for ex \"Agent joined\" / \"Agent left\"\n\n // Deprecated aliases for backwards compatibility (will be removed in v1.0)\n /** @deprecated Use ASSISTANT instead */\n BOT: 'assistant',\n /** @deprecated Use SUPERVISOR instead */\n AGENT: 'supervisor'\n}\n","/**\n * Socket Service for Chat SDK\n * Handles WebSocket connection for real-time chat functionality\n */\n\nimport { getSocketEndpoint, uuidv7 } from './utils.js'\nimport {\n getCredentials,\n getExternalId,\n addMessage,\n toggleTypingStatus,\n setTransport\n} from './chat.js'\n\nconst PING_INTERVAL = 10000\nconst SOCKET_TIMEOUT = 5000\n\n/**\n * @typedef {Object} SocketSession\n * @property {WebSocket} [socket]\n * @property {boolean} previouslyConnected\n * @property {boolean} socketDisconnected\n * @property {NodeJS.Timeout} [pingInterval]\n * @property {NodeJS.Timeout} [socketDisconnectedTimeout]\n * @property {NodeJS.Timeout} [socketConnectionTimeout]\n */\n\n/**\n * Socket Events\n */\nexport const SocketEvents = {\n MESSAGE: 'message',\n TYPING: 'typing',\n TYPING_STOP: 'typingOff',\n END: 'end'\n}\n\n/**\n * Create a new socket session\n * @returns {SocketSession}\n */\nfunction createSession() {\n return {\n socket: null,\n previouslyConnected: false,\n socketDisconnected: false,\n pingInterval: null,\n socketDisconnectedTimeout: null,\n socketConnectionTimeout: null\n }\n}\n\n/** @type {SocketSession} */\nlet currentSession = createSession()\n\n/**\n * Stop ping interval\n */\nfunction stopPingInterval() {\n if (currentSession.pingInterval) {\n clearInterval(currentSession.pingInterval)\n currentSession.pingInterval = null\n }\n}\n\n/**\n * Start ping interval\n */\nfunction startPingInterval() {\n stopPingInterval()\n\n currentSession.pingInterval = setInterval(() => {\n if (currentSession.socket && currentSession.socket.readyState === WebSocket.OPEN) {\n send({ type: 'ping' })\n console.log('Sending keep-alive ping')\n } else {\n console.log('Socket not open, stopping ping interval')\n stopPingInterval()\n }\n }, PING_INTERVAL)\n}\n\n/**\n * Clear all timeouts\n */\nfunction clearAllTimeouts() {\n stopPingInterval()\n if (currentSession.socketDisconnectedTimeout) {\n clearTimeout(currentSession.socketDisconnectedTimeout)\n currentSession.socketDisconnectedTimeout = null\n }\n if (currentSession.socketConnectionTimeout) {\n clearTimeout(currentSession.socketConnectionTimeout)\n currentSession.socketConnectionTimeout = null\n }\n}\n\n/**\n * Handle socket connected state\n */\nfunction handleSocketConnected() {\n console.log('handleSocketConnected')\n currentSession.socketDisconnected = false\n setTransport('socket')\n}\n\n/**\n * Handle socket disconnected state\n */\nfunction handleSocketDisconnected() {\n console.log('handleSocketDisconnected')\n currentSession.socketDisconnected = true\n setTransport('sse')\n}\n\n/**\n * Connect to socket\n * @param {{ token: string, sessionId?: string }} payload\n * @returns {Promise<boolean>}\n */\nexport function connectSocket(payload) {\n return new Promise((fulfill, reject) => {\n if (\n currentSession.socket &&\n (currentSession.socket.readyState === WebSocket.CONNECTING ||\n currentSession.socket.readyState === WebSocket.OPEN)\n ) {\n console.log('Socket in connecting/open state, returning.')\n fulfill(currentSession.socket.readyState === WebSocket.OPEN)\n return\n }\n\n console.log('Initializing socket connection..')\n const credentials = getCredentials()\n if (!credentials || !credentials.endpoint) {\n reject(new Error('SDK not initialized. Please initialize SDK first.'))\n return\n }\n\n const socketEndpoint = getSocketEndpoint(credentials.endpoint)\n if (!socketEndpoint) {\n reject(\n new Error(\n 'Invalid endpoint while initializing SDK. Please check the endpoint and try again.'\n )\n )\n return\n }\n\n const externalId = getExternalId()\n const queryParams = new URLSearchParams({\n externalId\n })\n\n if (payload.sessionId) {\n queryParams.set('sessionId', payload.sessionId)\n }\n if (payload.requestId) {\n queryParams.set('requestId', payload.requestId)\n }\n if (credentials.token) {\n queryParams.set('token', credentials.token)\n }\n\n const socketUrl = `${socketEndpoint}?${queryParams.toString()}`\n currentSession.socket = new WebSocket(socketUrl)\n\n currentSession.socket.onopen = () => {\n console.log('-------- socket connected --------')\n currentSession.previouslyConnected = true\n handleSocketConnected()\n send({ type: 'ping' })\n clearTimeout(currentSession.socketConnectionTimeout)\n startPingInterval()\n fulfill(true)\n }\n\n currentSession.socket.onmessage = (event) => {\n const message = JSON.parse(event.data)\n handleSocketEvent(message)\n }\n\n currentSession.socket.onerror = (error) => {\n console.error('Socket error:', error)\n setTransport('sse')\n reject(error)\n }\n\n currentSession.socket.onclose = (ws) => {\n console.log('-------- socket disconnected --------: ', ws.code, ws.reason)\n\n if (ws.target === currentSession.socket) {\n if (ws.code === 1006) {\n // abnormal closure\n if (currentSession.previouslyConnected) {\n handleSocketDisconnected()\n } else {\n addMessage({\n errorText: 'Unable to establish connection',\n done: true,\n timestamp: new Date().toISOString()\n })\n }\n clearTimeout(currentSession.socketConnectionTimeout)\n }\n\n currentSession.socket = null\n clearAllTimeouts()\n }\n }\n\n if (!currentSession.previouslyConnected) {\n currentSession.socketConnectionTimeout = setTimeout(() => {\n console.error('Socket connection timed out')\n addMessage({\n errorText: 'Unable to establish connection',\n done: true,\n timestamp: new Date().toISOString()\n })\n reject(new Error('Socket connection timed out'))\n }, SOCKET_TIMEOUT)\n }\n })\n}\n\n/**\n * Send data through socket\n * @param {Object} data\n */\nexport function send(data) {\n console.log('sending socket event: ', data.type)\n if (currentSession.socketDisconnected || !currentSession.socket) {\n return\n }\n currentSession.socket.send(JSON.stringify({ ...data, eventId: data.eventId || uuidv7() }))\n}\n\n/**\n * Send data through socket and wait for acknowledgment\n * @param {Object} data\n * @returns {Promise<Object>}\n */\nexport function sendWithAck(data) {\n return new Promise((resolve, reject) => {\n if (!currentSession.socket) {\n console.error('sendWithAck: socket instance not found or not connected')\n reject(new Error('Socket instance not found or not connected'))\n return\n }\n\n const autoRejectTimeout = setTimeout(() => {\n reject(new Error('Timeout'))\n }, 5000)\n\n const eventId = data.eventId || uuidv7()\n\n const onMessage = (event) => {\n const eventData = JSON.parse(event.data)\n if (eventData.eventId === eventId) {\n clearTimeout(autoRejectTimeout)\n currentSession.socket.removeEventListener('message', onMessage)\n if (eventData.data) {\n resolve(eventData.data)\n } else {\n reject(new Error(eventData.error?.message ?? 'Unknown error'))\n }\n }\n }\n currentSession.socket.addEventListener('message', onMessage)\n currentSession.socket.send(JSON.stringify({ ...data, eventId }))\n })\n}\n\n/**\n * Handle socket event\n * @param {Object} event\n */\nfunction handleSocketEvent(event) {\n console.log('received socket event: ', event.type)\n\n switch (event.type) {\n case 'pong': {\n if (currentSession.socketDisconnected) {\n handleSocketConnected()\n }\n if (currentSession.socketDisconnectedTimeout) {\n clearTimeout(currentSession.socketDisconnectedTimeout)\n }\n currentSession.socketDisconnectedTimeout = setTimeout(() => {\n console.log('---- socket ping timeout ----')\n handleSocketDisconnected()\n }, PING_INTERVAL + 1000)\n break\n }\n case SocketEvents.TYPING: {\n toggleTypingStatus(true)\n break\n }\n case SocketEvents.TYPING_STOP: {\n toggleTypingStatus(false)\n break\n }\n case SocketEvents.MESSAGE: {\n const { eventId, data } = event\n if (!eventId) {\n addMessage({\n ...data,\n done: true,\n timestamp: new Date().toISOString()\n })\n }\n break\n }\n case SocketEvents.END: {\n disconnect()\n break\n }\n default:\n break\n }\n}\n\n/**\n * Reconnect to socket\n */\nexport function reconnect() {\n if (currentSession.socket) {\n send({ type: 'ping' })\n }\n}\n\n/**\n * Disconnect socket\n */\nexport function disconnect() {\n console.log('Disconnecting socket')\n if (currentSession.socket) {\n currentSession.socket.close(1000)\n }\n currentSession.previouslyConnected = false\n clearAllTimeouts()\n currentSession.socket = null\n setTransport('sse')\n}\n\n/**\n * Check if socket is connected\n * @returns {boolean}\n */\nexport function isConnected() {\n return (\n currentSession.socket !== null &&\n currentSession.socket.readyState === WebSocket.OPEN &&\n !currentSession.socketDisconnected\n )\n}\n\n/**\n * Check if socket is disconnected\n * @returns {boolean}\n */\nexport function isDisconnected() {\n return currentSession.socketDisconnected\n}\n","/**\n * Chat Service for Chat SDK\n * Handles real-time chat functionality without depending on external state\n * Uses callbacks to communicate state changes to the consumer\n */\n\nimport { fetchEventSource } from '@microsoft/fetch-event-source'\nimport { getSession, authenticate } from './http.js'\nimport { getDeviceId, getSseEndpoint, sleep } from './utils.js'\nimport { MESSAGE_ROLES } from './constants.js'\nimport {\n connectSocket,\n send as socketSend,\n disconnect as disconnectSocket,\n isConnected as isSocketConnected\n} from './socket.js'\n\n/**\n * @typedef {Object} ChatCallbacks\n * @property {(message: Object) => void} [onMessageAdd] - Called when a new message is added\n * @property {(index: number, updatedMsg: Object) => void} [onMessageUpdate] - Called when an existing message is updated\n * @property {(sessionId: string) => void} [onSessionUpdate] - Called when session ID is updated\n * @property {(transport: TransportType) => void} [onTransportUpdate] - Called when transport type changes\n * @property {(control: 'agent' | 'human') => void} [onControlUpdate] - Called when control changes between agent and human\n */\n\n/**\n * @typedef {'sse' | 'socket'} TransportType\n */\n\n/**\n * @typedef {Object} ChatSession\n * @property {string} sessionId\n * @property {string} sseUrl\n * @property {string} [requestId]\n * @property {AbortController} [abortController]\n * @property {string} [lastStreamId]\n * @property {Array} messages\n * @property {ChatCallbacks} callbacks\n * @property {TransportType} transport\n */\n\n/**\n * Create a new chat session\n * @param {ChatCallbacks} [callbacks={}]\n * @returns {ChatSession}\n */\nfunction createSession(callbacks = {}) {\n return {\n credentials: undefined,\n authenticated: false,\n configData: undefined,\n sessionId: undefined,\n requestId: undefined,\n sseUrl: undefined,\n abortController: undefined,\n lastStreamId: undefined,\n messages: [],\n callbacks,\n transport: 'sse',\n control: 'agent'\n }\n}\n\n/** @type {ChatSession} */\nlet currentSession = createSession()\n\n/**\n * Set callbacks for the current session\n * @param {ChatCallbacks} callbacks\n */\nexport function setCallbacks(callbacks) {\n currentSession.callbacks = { ...currentSession.callbacks, ...callbacks }\n}\n\n/**\n * Initialize the chat session\n * @param {Object} credentials - Credentials for the chat\n */\nexport function initialize(credentials) {\n console.log('Initializing chat...', credentials)\n currentSession.credentials = credentials\n if (credentials.token) {\n currentSession.authenticated = true\n }\n}\n\n/**\n * Get current chat session credentials\n * @returns {{ endpoint: string, apiKey: string } | undefined}\n */\nexport function getCredentials() {\n return currentSession.credentials\n}\n\n/**\n * Update the session ID and notify via callback\n * @param {string} sessionId - The new session ID\n */\nexport function updateSessionId(sessionId) {\n if (sessionId && sessionId !== currentSession.sessionId) {\n currentSession.sessionId = sessionId\n currentSession.callbacks.onSessionUpdate?.(sessionId)\n }\n}\n\n/**\n * Initiate a new chat session or resume an existing one\n * @param {Object} credentials - Credentials for the chat\n * @param {Object} payload - Payload for the chat. It contains sessionId (optional)\n * @param {string} [payload.sessionId] - Optional session ID to resume\n * @returns {Promise<{ sessionId: string, messages: Array }>}\n */\nexport async function startChat(payload = {}) {\n try {\n console.log('startChat: ', payload, currentSession)\n\n let configData = null\n if (!currentSession.authenticated) {\n configData = await authenticate(currentSession.credentials)\n currentSession.authenticated = true\n currentSession.configData = configData\n } else {\n configData = currentSession.configData\n }\n\n let messages = []\n let control = 'agent'\n\n if (payload.sessionId) {\n const session = await getSession(payload.sessionId)\n messages = session.messages\n control = session.control || 'agent'\n }\n\n const searchParams = new URLSearchParams()\n if (!currentSession.credentials.token) {\n searchParams.set('externalId', getExternalId()) // externalId is needed only for public urls, not for internal chat (where token is provided)\n }\n currentSession.sseUrl = `${getSseEndpoint(\n currentSession.credentials.endpoint\n )}?${searchParams.toString()}`\n currentSession.sessionId = payload.sessionId\n currentSession.messages = messages\n currentSession.control = control\n\n if (control === 'human') {\n // Connect to SSE for incoming messages when control is human\n sendMessage({ text: '', html: '' }).catch(() => {})\n }\n\n console.log('Chat initiated successfully')\n\n return {\n sessionId: currentSession.sessionId,\n messages,\n control,\n configData\n }\n } catch (error) {\n console.error(`Failed to start chat: ${error.message}`)\n cleanup()\n throw error\n }\n}\n\n/**\n * Disconnect from the current chat session\n */\nexport function disconnect() {\n cleanup()\n}\n\n/**\n * Clean up the current session\n */\nfunction cleanup() {\n if (currentSession.abortController) {\n currentSession.abortController.abort()\n }\n disconnectSocket()\n\n const { callbacks, credentials } = currentSession\n currentSession = createSession(callbacks)\n currentSession.credentials = credentials\n\n console.log('Chat session cleaned up')\n}\n\nexport function getExternalId() {\n if (currentSession.credentials?.externalId) {\n return currentSession.credentials.externalId\n }\n return getDeviceId()\n}\n\n/**\n * Add a message to the chat\n * @param {Object} message - The message object to add\n */\nexport function addMessage(message) {\n currentSession.messages = [...currentSession.messages, message]\n currentSession.callbacks.onMessageAdd?.(message)\n}\n\nexport function toggleTypingStatus(isTyping) {\n currentSession.callbacks.onTyping?.(isTyping)\n}\n\n/**\n * Set the transport type\n * @param {TransportType} transport\n */\nexport function setTransport(transport) {\n console.log('Setting transport to:', transport)\n currentSession.transport = transport\n currentSession.callbacks.onTransportUpdate?.(transport)\n}\n\n/**\n * Get current transport type\n * @returns {TransportType}\n */\nexport function getTransport() {\n return currentSession.transport\n}\n\n/**\n * Send a message in the current chat session\n * @param {{ text: string, html?: string }} message\n * @returns {Promise<string>}\n */\nexport function sendMessage({ text, html, context }) {\n return new Promise((resolve, reject) => {\n ;(async () => {\n try {\n const isEmpty = !text && !html\n\n // Add user message only if there's content\n if (!isEmpty) {\n const userMessage = {\n role: MESSAGE_ROLES.USER,\n text,\n html,\n timestamp: new Date().toISOString()\n }\n addMessage(userMessage)\n await sleep(200)\n }\n\n // If transport is socket and socket is connected, use socket\n if (currentSession.transport === 'socket' && isSocketConnected()) {\n socketSend({\n type: 'message',\n data: {\n text,\n html\n }\n })\n resolve(currentSession.sessionId)\n return\n }\n\n if (currentSession.control === 'agent') {\n const loadingMessage = {\n role: MESSAGE_ROLES.ASSISTANT,\n text: '',\n loading: true\n }\n addMessage(loadingMessage)\n }\n\n const url = new URL(currentSession.sseUrl)\n if (currentSession.sessionId) {\n url.searchParams.set('sessionId', currentSession.sessionId)\n }\n if (currentSession.requestId) {\n url.searchParams.set('requestId', currentSession.requestId)\n }\n\n currentSession.lastStreamId = undefined\n\n // Create a new abort controller for this request\n currentSession.abortController = new AbortController()\n\n const headers = {\n 'Content-Type': 'application/json'\n }\n if (currentSession.credentials?.token) {\n headers.Authorization = `Bearer ${currentSession.credentials.token}`\n }\n\n await fetchEventSource(url.toString(), {\n method: 'POST',\n headers,\n body: isEmpty\n ? undefined\n : JSON.stringify({\n message: text,\n html,\n context\n }),\n signal: currentSession.abortController.signal,\n openWhenHidden: true,\n onopen: async (response) => {\n if (!response.ok) {\n console.error('Failed to send message bad response: ', response)\n throw new Error('Failed to send message')\n }\n },\n onmessage: (response) => {\n console.log('Event: ', response)\n const data = JSON.parse(response.data)\n\n if (response.event === 'connected') {\n currentSession.sessionId = data.sessionId\n currentSession.requestId = data.requestId\n console.log('Connected: ', data)\n if (data.control) {\n currentSession.control = data.control\n currentSession.callbacks.onControlUpdate?.(data.control)\n }\n } else if (response.event === 'upgrade_to_websocket') {\n console.log('Upgrade to websocket: ', data)\n connectSocket({\n sessionId: currentSession.sessionId,\n requestId: data.requestId\n })\n } else if (response.event === 'update') {\n if (data.control) {\n currentSession.control = data.control\n currentSession.callbacks.onControlUpdate?.(data.control)\n }\n } else if (data.error) {\n const errorMessage =\n data.error && typeof data.error === 'string'\n ? data.error\n : 'Failed to connect to the system'\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n errorText: errorMessage\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n reject(new Error(errorMessage))\n } else if (data.message !== undefined) {\n // If role is supervisor, treat it as a new message\n if (data.role === MESSAGE_ROLES.SUPERVISOR) {\n const supervisorMessage = {\n role: MESSAGE_ROLES.SUPERVISOR,\n text: data.message,\n sources: data.sources,\n done: true\n }\n addMessage(supervisorMessage)\n resolve(currentSession.sessionId)\n\n // Store session info for reuse\n currentSession.sessionId = data.session_id ?? currentSession.sessionId\n currentSession.requestId = data.requestId ?? currentSession.requestId\n return\n }\n\n // If streamId changes, start a new assistant message\n if (data.streamId !== undefined) {\n if (currentSession.lastStreamId === undefined) {\n currentSession.lastStreamId = data.streamId\n } else if (data.streamId !== currentSession.lastStreamId) {\n currentSession.lastStreamId = data.streamId\n const newBotMessage = {\n role: MESSAGE_ROLES.ASSISTANT,\n text: '',\n loading: true\n }\n addMessage(newBotMessage)\n }\n }\n\n // Update the last message with new content\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n text: (lastMsg.text || '') + data.message,\n sources: data.sources,\n done: data.done ?? lastMsg.done\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n\n if (data.done) {\n resolve(currentSession.sessionId)\n }\n\n // Store session info for reuse\n currentSession.sessionId = data.session_id ?? currentSession.sessionId\n currentSession.requestId = data.requestId ?? currentSession.requestId\n }\n },\n onerror: (error) => {\n throw error // Rethrow to stop retries\n },\n openWhenHidden: true\n })\n } catch (error) {\n console.error('Failed to send message: ', error)\n const errorMessage = 'Failed to connect to the system'\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n errorText: lastMsg.done ? undefined : error.message || errorMessage,\n done: true\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n reject(error)\n }\n })()\n })\n}\n","/**\n * API Service for Chat SDK\n * Handles all HTTP requests without depending on external state\n */\n\nimport { getCredentials, getExternalId } from './chat.js'\nimport { MESSAGE_ROLES } from './constants.js'\n\nconst AUTHENTICATION_ERROR = 'Something went wrong initializing the chat'\nconst INITIALIZATION_ERROR = 'Chat SDK not initialized'\n\n/**\n * Authenticate with the chat service\n * @param {{ endpoint: string }} credentials\n * @returns {Promise<object>} Authentication response data\n */\nexport async function authenticate(payload) {\n const { endpoint } = payload\n const url = `${endpoint}/config`\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json'\n }\n })\n\n if (!response.ok) {\n const errorPayload = await response.json()\n throw new Error(errorPayload?.error || AUTHENTICATION_ERROR)\n }\n\n const res = await response.json()\n const data = res.data\n\n return data\n}\n\n/**\n * Get chat history for the current device\n * @returns {Promise<{ sessions: Array }>}\n */\nexport async function getHistory() {\n const queryParams = new URLSearchParams({\n externalId: getExternalId()\n })\n const response = await fetchRequest(`/sessions?${queryParams.toString()}`, 'GET')\n\n if (!response.ok) {\n throw new Error('Unable to load history, please try again later')\n }\n\n return response.json()\n}\n\n/**\n * Get session data (control and history) for a specific session\n * @param {string} sessionId\n * @returns {Promise<{ control: string, messages: Array }>}\n */\nexport async function getSession(sessionId) {\n const queryParams = new URLSearchParams({\n sessionId\n })\n const response = await fetchRequest(`/session?${queryParams.toString()}`, 'GET')\n\n if (!response.ok) {\n throw new Error('Unable to load messages, please try again later')\n }\n\n const data = await response.json()\n const control = data?.control\n const messages = (data?.history ?? []).map((msg) => ({\n id: msg.id,\n text: msg.text,\n role: msg.youtubeVideo\n ? MESSAGE_ROLES.ASSISTANT // for youtube video messages, role is \"system\" from backend, we need to make it \"assistant\"\n : msg.role,\n timestamp: msg.timestamp,\n video: msg.youtubeVideo,\n channel: msg.channel,\n done: true\n }))\n\n return { control, messages }\n}\n\n/**\n * Internal fetch request helper\n * @param {string} pathname\n * @param {string} method\n * @param {object|null} body\n * @returns {Promise<Response>}\n */\nasync function fetchRequest(pathname, method = 'GET', body = null) {\n const credentials = getCredentials()\n\n const { endpoint, token } = credentials || {}\n if (!endpoint) {\n throw new Error(INITIALIZATION_ERROR)\n }\n\n const url = `${endpoint}${pathname}`\n\n const headers = {\n 'Content-Type': 'application/json'\n }\n if (token) {\n headers.Authorization = `Bearer ${token}`\n }\n\n return fetch(url, {\n headers,\n method,\n body: body ? JSON.stringify(body) : null\n })\n}\n","/**\n * Socket Service for Call SDK\n * Handles WebRTC call functionality without depending on external state\n * Uses callbacks to communicate state changes to the consumer\n */\n\nimport { getCallServerEndpoint } from './utils.js'\nimport { getCredentials, getExternalId, updateSessionId } from './chat.js'\n\n/**\n * @typedef {Object} CallCallbacks\n * @property {(status: string) => void} [onCallStatus] - Called when call status changes\n * @property {(error: string | null) => void} [onCallError] - Called when call error occurs\n */\n\n/**\n * @typedef {Object} CallSession\n * @property {string} [sessionId]\n * @property {WebSocket} [socket]\n * @property {RTCPeerConnection} [peerConnection]\n * @property {MediaStream} [localStream]\n * @property {MediaStream} [remoteStream]\n * @property {HTMLAudioElement} [remoteAudio]\n * @property {boolean} isMuted\n * @property {string} callStatus\n * @property {NodeJS.Timeout} [pingInterval]\n * @property {number} pingCount\n * @property {number | null} lastPongTime\n * @property {CallCallbacks} callbacks\n * @property {string[]} localIceCandidates - Queued local ICE candidates to send after remote description is set\n * @property {string[]} pendingRemoteIceCandidates - Queued remote ICE candidates to add after remote description is set\n */\n\n/**\n * Create a new call session\n * @param {CallCallbacks} [callbacks={}]\n * @returns {CallSession}\n */\nfunction createSession(callbacks = {}) {\n return {\n sessionId: undefined,\n socket: null,\n peerConnection: null,\n localStream: null,\n remoteStream: null,\n remoteAudio: null,\n isMuted: false,\n callStatus: 'disconnected',\n pingInterval: null,\n pingCount: 0,\n lastPongTime: null,\n callbacks,\n localIceCandidates: [],\n pendingRemoteIceCandidates: []\n }\n}\n\n/** @type {CallSession} */\nlet currentSession = createSession()\n\nconst rtcConfig = {\n iceServers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun1.l.google.com:19302' }]\n}\n\n/**\n * Set callbacks for the current session\n * @param {CallCallbacks} callbacks\n */\nexport function setCallCallbacks(callbacks) {\n currentSession.callbacks = { ...currentSession.callbacks, ...callbacks }\n}\n\n/**\n * Clean up the current session\n */\nfunction cleanup() {\n if (currentSession.peerConnection) {\n currentSession.peerConnection.close()\n currentSession.peerConnection = null\n }\n\n if (currentSession.localStream) {\n currentSession.localStream.getTracks().forEach((track) => track.stop())\n currentSession.localStream = null\n }\n\n if (currentSession.remoteStream) {\n currentSession.remoteStream = null\n }\n\n if (currentSession.remoteAudio) {\n currentSession.remoteAudio.srcObject = null\n if (currentSession.remoteAudio.parentNode) {\n currentSession.remoteAudio.parentNode.removeChild(currentSession.remoteAudio)\n }\n currentSession.remoteAudio = null\n }\n\n if (currentSession.socket) {\n currentSession.socket.close()\n currentSession.socket = null\n }\n\n stopPingInterval()\n\n const callbacks = currentSession.callbacks\n currentSession = createSession(callbacks)\n\n console.log('Call session cleaned up')\n}\n\n/**\n * Update call status and notify callback\n * @param {string} status\n */\nfunction setCallStatus(status) {\n currentSession.callStatus = status\n currentSession.callbacks.onCallStatus?.(status)\n}\n\n/**\n * Update call error and notify callback\n * @param {string | null} error\n */\nfunction setCallError(error) {\n currentSession.callbacks.onCallError?.(error)\n}\n\n/**\n * Stop ping interval\n */\nfunction stopPingInterval() {\n if (currentSession.pingInterval) {\n clearInterval(currentSession.pingInterval)\n currentSession.pingInterval = null\n }\n}\n\n/**\n * Start ping interval\n */\nfunction startPingInterval() {\n stopPingInterval()\n\n currentSession.pingInterval = setInterval(() => {\n if (currentSession.socket && currentSession.socket.readyState === WebSocket.OPEN) {\n currentSession.pingCount++\n const pingMessage = {\n type: 'ping',\n timestamp: Date.now(),\n count: currentSession.pingCount\n }\n sendEvent(pingMessage)\n console.log(`Sending keep-alive ping #${currentSession.pingCount}`)\n } else {\n console.log('Socket not open, stopping ping interval')\n stopPingInterval()\n }\n }, 10000)\n}\n\n/**\n * Handle pong response\n */\nfunction handlePong() {\n currentSession.lastPongTime = Date.now()\n console.log(`Received pong #${currentSession.pingCount}`)\n}\n\n/**\n * Send event through socket\n * @param {Object} payload\n */\nfunction sendEvent(payload) {\n if (!currentSession.socket) {\n console.error('Failed to send event: no socket instance')\n return\n }\n if (currentSession.socket.readyState !== WebSocket.OPEN) {\n console.error('Failed to send event: socket state not open ', payload)\n return\n }\n\n currentSession.socket.send(JSON.stringify(payload))\n}\n\n/**\n * Get user media\n */\nasync function getUserMedia() {\n try {\n currentSession.localStream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n video: false\n })\n console.log('Got audio media')\n } catch (error) {\n console.error(`Failed to get audio media: ${error.message}`)\n throw error\n }\n}\n\n/**\n * Create peer connection\n */\nfunction createPeerConnection() {\n currentSession.peerConnection = new RTCPeerConnection(rtcConfig)\n\n currentSession.peerConnection.onicecandidate = (event) => {\n if (event.candidate) {\n const candidateJson = JSON.stringify(event.candidate)\n // Queue local ICE candidates until remote description is set\n if (currentSession.peerConnection && currentSession.peerConnection.remoteDescription) {\n sendEvent({\n type: 'ice',\n data: {\n candidate: candidateJson\n }\n })\n console.log('Sent ICE candidate immediately')\n } else {\n currentSession.localIceCandidates.push(candidateJson)\n console.log('Queued local ICE candidate')\n }\n }\n }\n\n currentSession.peerConnection.ontrack = (event) => {\n console.log('Received remote audio stream')\n currentSession.remoteStream = event.streams[0]\n\n if (!currentSession.remoteAudio) {\n currentSession.remoteAudio = document.createElement('audio')\n currentSession.remoteAudio.autoplay = true\n currentSession.remoteAudio.controls = false\n document.body.appendChild(currentSession.remoteAudio)\n }\n currentSession.remoteAudio.srcObject = currentSession.remoteStream\n // explicitly kick off playback and catch any policy/gesture errors\n currentSession.remoteAudio\n .play()\n .then(() => console.log('🔊 remote audio playing'))\n .catch((err) => console.error('❌ playback error:', err))\n }\n\n currentSession.peerConnection.onconnectionstatechange = () => {\n const newState = currentSession.peerConnection.connectionState\n console.log(`Connection state: ${newState}`)\n\n if (newState === 'connected') {\n setCallStatus('connected')\n } else if (newState === 'disconnected' || newState === 'closed') {\n setCallStatus('disconnected')\n disconnectCall()\n }\n }\n\n currentSession.peerConnection.oniceconnectionstatechange = () => {\n console.log(`ICE connection state: ${currentSession.peerConnection.iceConnectionState}`)\n }\n}\n\n/**\n * Connect socket\n * @param {{ sessionId?: string }} payload\n */\nfunction connectSocket(payload) {\n return new Promise((fulfill, reject) => {\n if (\n currentSession.socket &&\n (currentSession.socket.readyState === WebSocket.CONNECTING ||\n currentSession.socket.readyState === WebSocket.OPEN)\n ) {\n console.log('Socket in connecting/open state, returning.')\n fulfill(currentSession.socket.readyState === WebSocket.OPEN)\n return\n }\n\n console.log('Initializing socket connection..')\n const credentials = getCredentials()\n if (!credentials || !credentials.endpoint) {\n reject(new Error('SDK not initialized. Please initialize SDK first.'))\n return\n }\n\n // Extract hostname from endpoint\n const socketEndpoint = getCallServerEndpoint(credentials.endpoint)\n if (!socketEndpoint) {\n reject(\n new Error(\n 'Invalid endpoint while initializing SDK. Please check the endpoint and try again.'\n )\n )\n return\n }\n\n const externalId = getExternalId()\n const queryParams = new URLSearchParams({\n externalId\n })\n if (payload.sessionId) {\n queryParams.set('sessionId', payload.sessionId)\n }\n if (credentials.token) {\n queryParams.set('token', credentials.token)\n }\n\n const socketUrl = `${socketEndpoint}?${queryParams.toString()}`\n currentSession.socket = new WebSocket(socketUrl)\n\n currentSession.socket.onopen = (event) => {\n console.log('Socket connection established: ', event)\n startPingInterval()\n fulfill(true)\n }\n\n currentSession.socket.onmessage = (event) => {\n const data = JSON.parse(event.data)\n handleCallServerEvent(data)\n }\n\n currentSession.socket.onerror = (error) => {\n console.error('Socket error: ', error)\n setCallStatus('error')\n setCallError(error.message || 'Unable to connect voice')\n reject(error)\n }\n\n currentSession.socket.onclose = (event) => {\n console.log('Socket connection closed: ', event)\n stopPingInterval()\n }\n })\n}\n\n/**\n * Handle call server event\n * @param {Object} action\n */\nfunction handleCallServerEvent(action) {\n console.log('Handling socket server event: ', action)\n\n switch (action.type) {\n case 'pong':\n handlePong()\n break\n\n case 'answer':\n handleAnswer(action.data)\n break\n\n case 'ice':\n handleIceCandidate(action.data)\n break\n\n case 'renegotiationOffer':\n handleRenegotiationOffer(action.data)\n break\n case 'end':\n disconnectCall()\n break\n case 'error':\n setCallStatus('error')\n setCallError(action.error || 'Unable to connect voice')\n break\n\n default:\n console.log('Unknown call event type: ', action.type)\n break\n }\n}\n\n/**\n * Handle answer\n * @param {Object} data\n */\nasync function handleAnswer(data) {\n try {\n console.log('Received answer')\n\n currentSession.sessionId = data.sessionId\n // Update chat session with the new sessionId and notify controller\n updateSessionId(data.sessionId)\n\n if (currentSession.peerConnection) {\n const answer = new RTCSessionDescription({\n type: 'answer',\n sdp: data.sdp\n })\n console.log('Setting remote description answer: ', answer)\n await currentSession.peerConnection.setRemoteDescription(answer)\n console.log('Remote description set')\n\n // Send all queued local ICE candidates\n for (const candidateJson of currentSession.localIceCandidates) {\n sendEvent({\n type: 'ice',\n data: {\n candidate: candidateJson\n }\n })\n console.log('Sent queued local ICE candidate')\n }\n currentSession.localIceCandidates = []\n\n // Process any pending remote ICE candidates\n for (const candidateJson of currentSession.pendingRemoteIceCandidates) {\n try {\n const candidate = new RTCIceCandidate(JSON.parse(candidateJson))\n await currentSession.peerConnection.addIceCandidate(candidate)\n console.log('Added pending remote ICE candidate')\n } catch (err) {\n console.error(`Failed to add pending ICE candidate: ${err.message}`)\n }\n }\n currentSession.pendingRemoteIceCandidates = []\n }\n } catch (error) {\n console.error(`Failed to handle answer: ${error.message}`)\n }\n}\n\n/**\n * Handle ICE candidate\n * @param {Object} data\n */\nasync function handleIceCandidate(data) {\n try {\n if (currentSession.peerConnection) {\n // Check if remote description is set\n if (!currentSession.peerConnection.remoteDescription) {\n // Queue the candidate until remote description is set\n currentSession.pendingRemoteIceCandidates.push(data.candidate)\n console.log('Queued remote ICE candidate - remote description not set')\n return\n }\n const candidate = new RTCIceCandidate(JSON.parse(data.candidate))\n await currentSession.peerConnection.addIceCandidate(candidate)\n console.log('Added ICE candidate')\n }\n } catch (error) {\n console.error(`Failed to add ICE candidate: ${error.message}`)\n }\n}\n\n/**\n * Handle renegotiation offer\n * @param {Object} data\n */\nasync function handleRenegotiationOffer(data) {\n try {\n console.log('Received renegotiation offer')\n\n if (currentSession.peerConnection) {\n const offer = new RTCSessionDescription({\n type: 'offer',\n sdp: data.sdp\n })\n console.log('Setting remote description offer: ', offer)\n await currentSession.peerConnection.setRemoteDescription(offer)\n console.log('Remote description set')\n\n const answer = await currentSession.peerConnection.createAnswer()\n await currentSession.peerConnection.setLocalDescription(answer)\n\n sendEvent({\n type: 'renegotiationAnswer',\n data: {\n sdp: answer.sdp\n }\n })\n }\n } catch (error) {\n console.error(`Failed to handle renegotiation offer: ${error.message}`)\n }\n}\n\n/**\n * Start a call\n * @param {{ sessionId?: string }} payload\n */\nexport async function startCall(payload = {}) {\n try {\n if (currentSession.callStatus === 'connecting' || currentSession.callStatus === 'connected') {\n console.log(`Call already in ${currentSession.callStatus} state`)\n return\n }\n\n console.log('Starting audio call...')\n setCallStatus('connecting')\n setCallError(null)\n\n currentSession.sessionId = payload.sessionId\n\n await getUserMedia()\n\n createPeerConnection()\n\n currentSession.localStream.getTracks().forEach((track) => {\n currentSession.peerConnection.addTrack(track, currentSession.localStream)\n console.log(`Added ${track.kind} track`)\n })\n await connectSocket(payload)\n const offer = await currentSession.peerConnection.createOffer()\n await currentSession.peerConnection.setLocalDescription(offer)\n\n sendEvent({\n type: 'offer',\n data: {\n sdp: offer.sdp\n }\n })\n\n console.log('Call initiated successfully')\n } catch (error) {\n console.log('error: ', error)\n console.error(`Failed to start call: ${error.message}`)\n setCallStatus('error')\n setCallError(error.message || 'Unable to connect voice')\n cleanup()\n }\n}\n\n/**\n * Disconnect call\n */\nexport function disconnectCall() {\n sendEvent({\n type: 'end'\n })\n if (currentSession.socket) {\n currentSession.socket.close()\n currentSession.socket = null\n }\n setCallStatus('disconnected')\n if (currentSession.peerConnection) {\n currentSession.peerConnection.close()\n currentSession.peerConnection = null\n }\n if (currentSession.localStream) {\n currentSession.localStream.getTracks().forEach((track) => track.stop())\n currentSession.localStream = null\n }\n cleanup()\n}\n\n/**\n * Toggle mute\n * @returns {boolean}\n */\nexport function toggleMute() {\n if (currentSession.localStream) {\n const audioTrack = currentSession.localStream.getAudioTracks()[0]\n if (audioTrack) {\n audioTrack.enabled = !audioTrack.enabled\n currentSession.isMuted = !audioTrack.enabled\n console.log(`Audio ${currentSession.isMuted ? 'muted' : 'unmuted'}`)\n return currentSession.isMuted\n }\n }\n return false\n}\n\n/**\n * Get local stream\n * @returns {MediaStream | null}\n */\nexport function getLocalStream() {\n return currentSession.localStream\n}\n\n/**\n * Get inbound audio energy\n * @returns {Promise<number>}\n */\nexport function getInboundAudioEnergy() {\n return new Promise((resolve, reject) => {\n if (!currentSession.peerConnection) {\n reject(new Error('no peer connection'))\n return\n }\n currentSession.peerConnection\n .getStats()\n .then((stats) => {\n stats.forEach((report) => {\n if (report.type == 'inbound-rtp') {\n resolve(report.totalAudioEnergy)\n }\n })\n reject(new Error('no inbound-rtp stats found'))\n })\n .catch((err) => {\n reject(err)\n })\n })\n}\n\n/**\n * Get outbound audio energy (not implemented in original, but may be needed)\n * @returns {Promise<number>}\n */\nexport function getOutboundAudioEnergy() {\n return new Promise((resolve, reject) => {\n if (!currentSession.peerConnection) {\n reject(new Error('no peer connection'))\n return\n }\n currentSession.peerConnection\n .getStats()\n .then((stats) => {\n stats.forEach((report) => {\n if (report.type == 'outbound-rtp') {\n resolve(report.totalAudioEnergy)\n }\n })\n reject(new Error('no outbound-rtp stats found'))\n })\n .catch((err) => {\n reject(err)\n })\n })\n}\n"],"names":["uuidv7","timestamp","bytes","hex","b","getDeviceId","deviceId","sleep","ms","resolve","getSseEndpoint","baseUrl","sseEndpoint","url","e","getSocketEndpoint","socketEndpoint","getCallServerEndpoint","MESSAGE_ROLES","PING_INTERVAL","SOCKET_TIMEOUT","SocketEvents","createSession","currentSession","stopPingInterval","startPingInterval","send","clearAllTimeouts","handleSocketConnected","setTransport","handleSocketDisconnected","connectSocket","payload","fulfill","reject","credentials","getCredentials","externalId","getExternalId","queryParams","socketUrl","event","message","handleSocketEvent","error","ws","addMessage","data","toggleTypingStatus","eventId","disconnect","isConnected","callbacks","setCallbacks","initialize","updateSessionId","sessionId","startChat","configData","authenticate","messages","control","session","getSession","searchParams","sendMessage","cleanup","disconnectSocket","isTyping","transport","text","html","context","isEmpty","userMessage","isSocketConnected","socketSend","loadingMessage","headers","fetchEventSource","response","errorMessage","lastIndex","updatedMsg","msg","index","supervisorMessage","_g","_h","newBotMessage","lastMsg","_i","_l","_m","AUTHENTICATION_ERROR","INITIALIZATION_ERROR","endpoint","errorPayload","getHistory","fetchRequest","_a","pathname","method","body","token","rtcConfig","setCallCallbacks","track","setCallStatus","status","_b","setCallError","pingMessage","sendEvent","handlePong","getUserMedia","createPeerConnection","candidateJson","err","newState","disconnectCall","handleCallServerEvent","action","handleAnswer","handleIceCandidate","handleRenegotiationOffer","answer","candidate","offer","startCall","toggleMute","audioTrack","getLocalStream","getInboundAudioEnergy","stats","report","getOutboundAudioEnergy"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"origon-chat-sdk.js","sources":["../src/utils.js","../src/constants.js","../src/socket.js","../src/chat.js","../src/http.js","../src/call.js"],"sourcesContent":["/**\n * Utility functions for the Chat SDK\n */\n\nexport function uuidv7() {\n const timestamp = Date.now()\n const bytes = new Uint8Array(16)\n crypto.getRandomValues(bytes)\n\n // Set timestamp (48 bits)\n bytes[0] = (timestamp >> 40) & 0xff\n bytes[1] = (timestamp >> 32) & 0xff\n bytes[2] = (timestamp >> 24) & 0xff\n bytes[3] = (timestamp >> 16) & 0xff\n bytes[4] = (timestamp >> 8) & 0xff\n bytes[5] = timestamp & 0xff\n\n // Set version 7 (0111)\n bytes[6] = (bytes[6] & 0x0f) | 0x70\n\n // Set variant (10xx)\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n\n const hex = [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(\n 16,\n 20\n )}-${hex.slice(20)}`\n}\n\nexport function getDeviceId() {\n if (localStorage.getItem('chatDeviceId')) {\n return localStorage.getItem('chatDeviceId')\n }\n\n const deviceId = uuidv7()\n localStorage.setItem('chatDeviceId', deviceId)\n return deviceId\n}\n\nexport function parseJwt(token) {\n try {\n const base64Url = token.split('.')[1]\n const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split('')\n .map(function (c) {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join('')\n )\n\n return JSON.parse(jsonPayload)\n } catch {\n return null\n }\n}\n\nexport async function sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport function getSseEndpoint(baseUrl) {\n let sseEndpoint\n try {\n const url = new URL(baseUrl)\n sseEndpoint = `https://${url.hostname}${url.pathname}/sse`\n } catch {\n console.error('SSE Invalid base URL: ', baseUrl)\n }\n return sseEndpoint\n}\n\nexport function getSocketEndpoint(baseUrl) {\n let socketEndpoint\n try {\n const url = new URL(baseUrl)\n socketEndpoint = `wss://${url.hostname}${url.pathname}/wss`\n } catch {\n console.error('Socket Invalid base URL: ', baseUrl)\n }\n return socketEndpoint\n}\n\nexport function getCallServerEndpoint(baseUrl) {\n let socketEndpoint\n try {\n const url = new URL(baseUrl)\n socketEndpoint = `wss://${url.hostname}${url.pathname}/audio`\n } catch {\n console.error('getCallServerEndpoint: Invalid base URL: ', baseUrl)\n }\n return socketEndpoint\n}\n","/**\n * Constants for the Chat SDK\n */\n\nexport const MESSAGE_ROLES = {\n ASSISTANT: 'assistant', // this can be automated or LLM AI Agent response\n USER: 'user', // this is widget user\n SUPERVISOR: 'supervisor', // this is human supervisor (ex. Samespace Dock agent, or Resolve human agent)\n SYSTEM: 'system' // this is system message, for ex \"Agent joined\" / \"Agent left\"\n}\n","/**\n * Socket Service for Chat SDK\n * Handles WebSocket connection for real-time chat functionality\n */\n\nimport { getSocketEndpoint, uuidv7 } from './utils.js'\nimport {\n getCredentials,\n getExternalId,\n addMessage,\n toggleTypingStatus,\n setTransport\n} from './chat.js'\n\nconst PING_INTERVAL = 10000\nconst SOCKET_TIMEOUT = 5000\n\n/**\n * @typedef {Object} SocketSession\n * @property {WebSocket} [socket]\n * @property {boolean} previouslyConnected\n * @property {boolean} socketDisconnected\n * @property {NodeJS.Timeout} [pingInterval]\n * @property {NodeJS.Timeout} [socketDisconnectedTimeout]\n * @property {NodeJS.Timeout} [socketConnectionTimeout]\n */\n\n/**\n * Socket Events\n */\nexport const SocketEvents = {\n MESSAGE: 'message',\n TYPING: 'typing',\n TYPING_STOP: 'typingOff',\n END: 'end'\n}\n\n/**\n * Create a new socket session\n * @returns {SocketSession}\n */\nfunction createSession() {\n return {\n socket: null,\n previouslyConnected: false,\n socketDisconnected: false,\n pingInterval: null,\n socketDisconnectedTimeout: null,\n socketConnectionTimeout: null\n }\n}\n\n/** @type {SocketSession} */\nlet currentSession = createSession()\n\n/**\n * Stop ping interval\n */\nfunction stopPingInterval() {\n if (currentSession.pingInterval) {\n clearInterval(currentSession.pingInterval)\n currentSession.pingInterval = null\n }\n}\n\n/**\n * Start ping interval\n */\nfunction startPingInterval() {\n stopPingInterval()\n\n currentSession.pingInterval = setInterval(() => {\n if (currentSession.socket && currentSession.socket.readyState === WebSocket.OPEN) {\n send({ type: 'ping' })\n console.log('Sending keep-alive ping')\n } else {\n console.log('Socket not open, stopping ping interval')\n stopPingInterval()\n }\n }, PING_INTERVAL)\n}\n\n/**\n * Clear all timeouts\n */\nfunction clearAllTimeouts() {\n stopPingInterval()\n if (currentSession.socketDisconnectedTimeout) {\n clearTimeout(currentSession.socketDisconnectedTimeout)\n currentSession.socketDisconnectedTimeout = null\n }\n if (currentSession.socketConnectionTimeout) {\n clearTimeout(currentSession.socketConnectionTimeout)\n currentSession.socketConnectionTimeout = null\n }\n}\n\n/**\n * Handle socket connected state\n */\nfunction handleSocketConnected() {\n console.log('handleSocketConnected')\n currentSession.socketDisconnected = false\n setTransport('socket')\n}\n\n/**\n * Handle socket disconnected state\n */\nfunction handleSocketDisconnected() {\n console.log('handleSocketDisconnected')\n currentSession.socketDisconnected = true\n setTransport('sse')\n}\n\n/**\n * Connect to socket\n * @param {{ token: string, sessionId?: string }} payload\n * @returns {Promise<boolean>}\n */\nexport function connectSocket(payload) {\n return new Promise((fulfill, reject) => {\n if (\n currentSession.socket &&\n (currentSession.socket.readyState === WebSocket.CONNECTING ||\n currentSession.socket.readyState === WebSocket.OPEN)\n ) {\n console.log('Socket in connecting/open state, returning.')\n fulfill(currentSession.socket.readyState === WebSocket.OPEN)\n return\n }\n\n console.log('Initializing socket connection..')\n const credentials = getCredentials()\n if (!credentials || !credentials.endpoint) {\n reject(new Error('SDK not initialized. Please initialize SDK first.'))\n return\n }\n\n const socketEndpoint = getSocketEndpoint(credentials.endpoint)\n if (!socketEndpoint) {\n reject(\n new Error(\n 'Invalid endpoint while initializing SDK. Please check the endpoint and try again.'\n )\n )\n return\n }\n\n const externalId = getExternalId()\n const queryParams = new URLSearchParams({\n externalId\n })\n\n if (payload.sessionId) {\n queryParams.set('sessionId', payload.sessionId)\n }\n if (payload.requestId) {\n queryParams.set('requestId', payload.requestId)\n }\n if (credentials.token) {\n queryParams.set('token', credentials.token)\n }\n\n const socketUrl = `${socketEndpoint}?${queryParams.toString()}`\n currentSession.socket = new WebSocket(socketUrl)\n\n currentSession.socket.onopen = () => {\n console.log('-------- socket connected --------')\n currentSession.previouslyConnected = true\n handleSocketConnected()\n send({ type: 'ping' })\n clearTimeout(currentSession.socketConnectionTimeout)\n startPingInterval()\n fulfill(true)\n }\n\n currentSession.socket.onmessage = (event) => {\n const message = JSON.parse(event.data)\n handleSocketEvent(message)\n }\n\n currentSession.socket.onerror = (error) => {\n console.error('Socket error:', error)\n setTransport('sse')\n reject(error)\n }\n\n currentSession.socket.onclose = (ws) => {\n console.log('-------- socket disconnected --------: ', ws.code, ws.reason)\n\n if (ws.target === currentSession.socket) {\n if (ws.code === 1006) {\n // abnormal closure\n if (currentSession.previouslyConnected) {\n handleSocketDisconnected()\n } else {\n addMessage({\n errorText: 'Unable to establish connection',\n done: true,\n timestamp: new Date().toISOString()\n })\n }\n clearTimeout(currentSession.socketConnectionTimeout)\n }\n\n currentSession.socket = null\n clearAllTimeouts()\n }\n }\n\n if (!currentSession.previouslyConnected) {\n currentSession.socketConnectionTimeout = setTimeout(() => {\n console.error('Socket connection timed out')\n addMessage({\n errorText: 'Unable to establish connection',\n done: true,\n timestamp: new Date().toISOString()\n })\n reject(new Error('Socket connection timed out'))\n }, SOCKET_TIMEOUT)\n }\n })\n}\n\n/**\n * Send data through socket\n * @param {Object} data\n */\nexport function send(data) {\n console.log('sending socket event: ', data.type)\n if (currentSession.socketDisconnected || !currentSession.socket) {\n return\n }\n currentSession.socket.send(JSON.stringify({ ...data, eventId: data.eventId || uuidv7() }))\n}\n\n/**\n * Send data through socket and wait for acknowledgment\n * @param {Object} data\n * @returns {Promise<Object>}\n */\nexport function sendWithAck(data) {\n return new Promise((resolve, reject) => {\n if (!currentSession.socket) {\n console.error('sendWithAck: socket instance not found or not connected')\n reject(new Error('Socket instance not found or not connected'))\n return\n }\n\n const autoRejectTimeout = setTimeout(() => {\n reject(new Error('Timeout'))\n }, 5000)\n\n const eventId = data.eventId || uuidv7()\n\n const onMessage = (event) => {\n const eventData = JSON.parse(event.data)\n if (eventData.eventId === eventId) {\n clearTimeout(autoRejectTimeout)\n currentSession.socket.removeEventListener('message', onMessage)\n if (eventData.data) {\n resolve(eventData.data)\n } else {\n reject(new Error(eventData.error?.message ?? 'Unknown error'))\n }\n }\n }\n currentSession.socket.addEventListener('message', onMessage)\n currentSession.socket.send(JSON.stringify({ ...data, eventId }))\n })\n}\n\n/**\n * Handle socket event\n * @param {Object} event\n */\nfunction handleSocketEvent(event) {\n console.log('received socket event: ', event.type)\n\n switch (event.type) {\n case 'pong': {\n if (currentSession.socketDisconnected) {\n handleSocketConnected()\n }\n if (currentSession.socketDisconnectedTimeout) {\n clearTimeout(currentSession.socketDisconnectedTimeout)\n }\n currentSession.socketDisconnectedTimeout = setTimeout(() => {\n console.log('---- socket ping timeout ----')\n handleSocketDisconnected()\n }, PING_INTERVAL + 1000)\n break\n }\n case SocketEvents.TYPING: {\n toggleTypingStatus(true)\n break\n }\n case SocketEvents.TYPING_STOP: {\n toggleTypingStatus(false)\n break\n }\n case SocketEvents.MESSAGE: {\n const { eventId, data } = event\n if (!eventId) {\n addMessage({\n ...data,\n done: true,\n timestamp: new Date().toISOString()\n })\n }\n break\n }\n case SocketEvents.END: {\n disconnect()\n break\n }\n default:\n break\n }\n}\n\n/**\n * Reconnect to socket\n */\nexport function reconnect() {\n if (currentSession.socket) {\n send({ type: 'ping' })\n }\n}\n\n/**\n * Disconnect socket\n */\nexport function disconnect() {\n console.log('Disconnecting socket')\n if (currentSession.socket) {\n currentSession.socket.close(1000)\n }\n currentSession.previouslyConnected = false\n clearAllTimeouts()\n currentSession.socket = null\n setTransport('sse')\n}\n\n/**\n * Check if socket is connected\n * @returns {boolean}\n */\nexport function isConnected() {\n return (\n currentSession.socket !== null &&\n currentSession.socket.readyState === WebSocket.OPEN &&\n !currentSession.socketDisconnected\n )\n}\n\n/**\n * Check if socket is disconnected\n * @returns {boolean}\n */\nexport function isDisconnected() {\n return currentSession.socketDisconnected\n}\n","/**\n * Chat Service for Chat SDK\n * Handles real-time chat functionality without depending on external state\n * Uses callbacks to communicate state changes to the consumer\n */\n\nimport { fetchEventSource } from '@microsoft/fetch-event-source'\nimport { getSession, authenticate } from './http.js'\nimport { getDeviceId, getSseEndpoint, sleep } from './utils.js'\nimport { MESSAGE_ROLES } from './constants.js'\nimport {\n connectSocket,\n send as socketSend,\n disconnect as disconnectSocket,\n isConnected as isSocketConnected\n} from './socket.js'\n\n/**\n * @typedef {Object} ChatCallbacks\n * @property {(message: Object) => void} [onMessageAdd] - Called when a new message is added\n * @property {(index: number, updatedMsg: Object) => void} [onMessageUpdate] - Called when an existing message is updated\n * @property {(sessionId: string) => void} [onSessionUpdate] - Called when session ID is updated\n * @property {(transport: TransportType) => void} [onTransportUpdate] - Called when transport type changes\n * @property {(control: 'agent' | 'human') => void} [onControlUpdate] - Called when control changes between agent and human\n */\n\n/**\n * @typedef {'sse' | 'socket'} TransportType\n */\n\n/**\n * @typedef {Object} ChatSession\n * @property {string} sessionId\n * @property {string} sseUrl\n * @property {string} [requestId]\n * @property {AbortController} [abortController]\n * @property {string} [lastStreamId]\n * @property {Array} messages\n * @property {ChatCallbacks} callbacks\n * @property {TransportType} transport\n */\n\n/**\n * Create a new chat session\n * @param {ChatCallbacks} [callbacks={}]\n * @returns {ChatSession}\n */\nfunction createSession(callbacks = {}) {\n return {\n credentials: undefined,\n authenticated: false,\n configData: undefined,\n sessionId: undefined,\n requestId: undefined,\n sseUrl: undefined,\n abortController: undefined,\n lastStreamId: undefined,\n messages: [],\n callbacks,\n transport: 'sse',\n control: 'agent'\n }\n}\n\n/** @type {ChatSession} */\nlet currentSession = createSession()\n\n/**\n * Set callbacks for the current session\n * @param {ChatCallbacks} callbacks\n */\nexport function setCallbacks(callbacks) {\n currentSession.callbacks = { ...currentSession.callbacks, ...callbacks }\n}\n\n/**\n * Initialize the chat session\n * @param {Object} credentials - Credentials for the chat\n */\nexport function initialize(credentials) {\n console.log('Initializing chat...', credentials)\n currentSession.credentials = credentials\n if (credentials.token) {\n currentSession.authenticated = true\n }\n}\n\n/**\n * Get current chat session credentials\n * @returns {{ endpoint: string, apiKey: string } | undefined}\n */\nexport function getCredentials() {\n return currentSession.credentials\n}\n\n/**\n * Update the session ID and notify via callback\n * @param {string} sessionId - The new session ID\n */\nexport function updateSessionId(sessionId) {\n if (sessionId && sessionId !== currentSession.sessionId) {\n currentSession.sessionId = sessionId\n currentSession.callbacks.onSessionUpdate?.(sessionId)\n }\n}\n\n/**\n * Initiate a new chat session or resume an existing one\n * @param {Object} credentials - Credentials for the chat\n * @param {Object} payload - Payload for the chat. It contains sessionId (optional)\n * @param {string} [payload.sessionId] - Optional session ID to resume\n * @returns {Promise<{ sessionId: string, messages: Array }>}\n */\nexport async function startChat(payload = {}) {\n try {\n console.log('startChat: ', payload, currentSession)\n\n let configData = null\n if (!currentSession.authenticated) {\n configData = await authenticate(currentSession.credentials)\n currentSession.authenticated = true\n currentSession.configData = configData\n } else {\n configData = currentSession.configData\n }\n\n let messages = []\n let control = 'agent'\n\n if (payload.sessionId) {\n const session = await getSession(payload.sessionId)\n messages = session.messages\n control = session.control || 'agent'\n }\n\n const searchParams = new URLSearchParams()\n if (!currentSession.credentials.token) {\n searchParams.set('externalId', getExternalId()) // externalId is needed only for public urls, not for internal chat (where token is provided)\n }\n currentSession.sseUrl = `${getSseEndpoint(\n currentSession.credentials.endpoint\n )}?${searchParams.toString()}`\n currentSession.sessionId = payload.sessionId\n currentSession.messages = messages\n currentSession.control = control\n\n if (control === 'human') {\n // Connect to SSE for incoming messages when control is human\n sendMessage({ text: '', html: '' }).catch(() => {})\n }\n\n console.log('Chat initiated successfully')\n\n return {\n sessionId: currentSession.sessionId,\n messages,\n control,\n configData\n }\n } catch (error) {\n console.error(`Failed to start chat: ${error.message}`)\n cleanup()\n throw error\n }\n}\n\n/**\n * Disconnect from the current chat session\n */\nexport function disconnect() {\n cleanup()\n}\n\n/**\n * Clean up the current session\n */\nfunction cleanup() {\n if (currentSession.abortController) {\n currentSession.abortController.abort()\n }\n disconnectSocket()\n\n const { callbacks, credentials } = currentSession\n currentSession = createSession(callbacks)\n currentSession.credentials = credentials\n\n console.log('Chat session cleaned up')\n}\n\nexport function getExternalId() {\n if (currentSession.credentials?.externalId) {\n return currentSession.credentials.externalId\n }\n return getDeviceId()\n}\n\n/**\n * Add a message to the chat\n * @param {Object} message - The message object to add\n */\nexport function addMessage(message) {\n currentSession.messages = [...currentSession.messages, message]\n currentSession.callbacks.onMessageAdd?.(message)\n}\n\nexport function toggleTypingStatus(isTyping) {\n currentSession.callbacks.onTyping?.(isTyping)\n}\n\n/**\n * Set the transport type\n * @param {TransportType} transport\n */\nexport function setTransport(transport) {\n console.log('Setting transport to:', transport)\n currentSession.transport = transport\n currentSession.callbacks.onTransportUpdate?.(transport)\n}\n\n/**\n * Get current transport type\n * @returns {TransportType}\n */\nexport function getTransport() {\n return currentSession.transport\n}\n\n/**\n * Send a message in the current chat session\n * @param {{ text: string, html?: string }} message\n * @returns {Promise<string>}\n */\nexport function sendMessage({ text, html, context }) {\n return new Promise((resolve, reject) => {\n ;(async () => {\n try {\n const isEmpty = !text && !html\n\n // Add user message only if there's content\n if (!isEmpty) {\n const userMessage = {\n role: MESSAGE_ROLES.USER,\n text,\n html,\n timestamp: new Date().toISOString()\n }\n addMessage(userMessage)\n await sleep(200)\n }\n\n // If transport is socket and socket is connected, use socket\n if (currentSession.transport === 'socket' && isSocketConnected()) {\n socketSend({\n type: 'message',\n data: {\n text,\n html\n }\n })\n resolve(currentSession.sessionId)\n return\n }\n\n if (currentSession.control === 'agent') {\n const loadingMessage = {\n role: MESSAGE_ROLES.ASSISTANT,\n text: '',\n loading: true\n }\n addMessage(loadingMessage)\n }\n\n const url = new URL(currentSession.sseUrl)\n if (currentSession.sessionId) {\n url.searchParams.set('sessionId', currentSession.sessionId)\n }\n if (currentSession.requestId) {\n url.searchParams.set('requestId', currentSession.requestId)\n }\n\n currentSession.lastStreamId = undefined\n\n // Create a new abort controller for this request\n currentSession.abortController = new AbortController()\n\n const headers = {\n 'Content-Type': 'application/json'\n }\n if (currentSession.credentials?.token) {\n headers.Authorization = `Bearer ${currentSession.credentials.token}`\n }\n\n await fetchEventSource(url.toString(), {\n method: 'POST',\n headers,\n body: isEmpty\n ? undefined\n : JSON.stringify({\n message: text,\n html,\n context\n }),\n signal: currentSession.abortController.signal,\n openWhenHidden: true,\n onopen: async (response) => {\n if (!response.ok) {\n console.error('Failed to send message bad response: ', response)\n throw new Error('Failed to send message')\n }\n },\n onmessage: (response) => {\n console.log('Event: ', response)\n const data = JSON.parse(response.data)\n\n if (response.event === 'connected') {\n currentSession.sessionId = data.sessionId\n currentSession.requestId = data.requestId\n console.log('Connected: ', data)\n if (data.control) {\n currentSession.control = data.control\n currentSession.callbacks.onControlUpdate?.(data.control)\n }\n } else if (response.event === 'upgrade_to_websocket') {\n console.log('Upgrade to websocket: ', data)\n connectSocket({\n sessionId: currentSession.sessionId,\n requestId: data.requestId\n })\n } else if (response.event === 'update') {\n if (data.control) {\n currentSession.control = data.control\n currentSession.callbacks.onControlUpdate?.(data.control)\n }\n } else if (data.error) {\n const errorMessage =\n data.error && typeof data.error === 'string'\n ? data.error\n : 'Failed to connect to the system'\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n errorText: errorMessage\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n reject(new Error(errorMessage))\n } else if (response.event === 'done') {\n resolve(currentSession.sessionId)\n } else if (data.message !== undefined) {\n // If role is supervisor, treat it as a new message\n if (data.role === MESSAGE_ROLES.SUPERVISOR) {\n const supervisorMessage = {\n role: MESSAGE_ROLES.SUPERVISOR,\n text: data.message,\n sources: data.sources,\n done: true\n }\n addMessage(supervisorMessage)\n resolve(currentSession.sessionId)\n\n // Store session info for reuse\n currentSession.sessionId = data.sessionId ?? currentSession.sessionId\n currentSession.requestId = data.requestId ?? currentSession.requestId\n return\n }\n\n // If streamId changes, start a new assistant message\n if (data.streamId !== undefined) {\n if (currentSession.lastStreamId === undefined) {\n currentSession.lastStreamId = data.streamId\n } else if (data.streamId !== currentSession.lastStreamId) {\n currentSession.lastStreamId = data.streamId\n const newBotMessage = {\n role: MESSAGE_ROLES.ASSISTANT,\n text: '',\n loading: true\n }\n addMessage(newBotMessage)\n }\n }\n\n // Update the last message with new content\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n text: (lastMsg.text || '') + data.message,\n sources: data.sources,\n done: data.done ?? lastMsg.done\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n\n if (data.done) {\n }\n\n // Store session info for reuse\n currentSession.sessionId = data.sessionId ?? currentSession.sessionId\n currentSession.requestId = data.requestId ?? currentSession.requestId\n }\n },\n onerror: (error) => {\n throw error // Rethrow to stop retries\n },\n openWhenHidden: true\n })\n } catch (error) {\n console.error('Failed to send message: ', error)\n const errorMessage = 'Failed to connect to the system'\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n errorText: lastMsg.done ? undefined : error.message || errorMessage,\n done: true\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n reject(error)\n }\n })()\n })\n}\n","/**\n * API Service for Chat SDK\n * Handles all HTTP requests without depending on external state\n */\n\nimport { getCredentials, getExternalId } from './chat.js'\nimport { MESSAGE_ROLES } from './constants.js'\n\nconst AUTHENTICATION_ERROR = 'Something went wrong initializing the chat'\nconst INITIALIZATION_ERROR = 'Chat SDK not initialized'\n\n/**\n * Authenticate with the chat service\n * @param {{ endpoint: string }} credentials\n * @returns {Promise<object>} Authentication response data\n */\nexport async function authenticate(payload) {\n const { endpoint } = payload\n const url = `${endpoint}/config`\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json'\n }\n })\n\n if (!response.ok) {\n const errorPayload = await response.json()\n throw new Error(errorPayload?.error || AUTHENTICATION_ERROR)\n }\n\n const res = await response.json()\n const data = res.data\n\n return data\n}\n\n/**\n * Get chat history for the current device\n * @returns {Promise<{ sessions: Array }>}\n */\nexport async function getHistory() {\n const queryParams = new URLSearchParams({\n externalId: getExternalId()\n })\n const response = await fetchRequest(`/sessions?${queryParams.toString()}`, 'GET')\n\n if (!response.ok) {\n throw new Error('Unable to load history, please try again later')\n }\n\n return response.json()\n}\n\n/**\n * Get session data (control and history) for a specific session\n * @param {string} sessionId\n * @returns {Promise<{ control: string, messages: Array }>}\n */\nexport async function getSession(sessionId) {\n const queryParams = new URLSearchParams({\n sessionId\n })\n const response = await fetchRequest(`/session?${queryParams.toString()}`, 'GET')\n\n if (!response.ok) {\n throw new Error('Unable to load messages, please try again later')\n }\n\n const data = await response.json()\n const control = data?.control\n const messages = (data?.history ?? []).map((msg) => ({\n id: msg.id,\n text: msg.text,\n role: msg.youtubeVideo\n ? MESSAGE_ROLES.ASSISTANT // for youtube video messages, role is \"system\" from backend, we need to make it \"assistant\"\n : msg.role,\n timestamp: msg.timestamp,\n video: msg.youtubeVideo,\n channel: msg.channel,\n done: true\n }))\n\n return { control, messages }\n}\n\n/**\n * Internal fetch request helper\n * @param {string} pathname\n * @param {string} method\n * @param {object|null} body\n * @returns {Promise<Response>}\n */\nasync function fetchRequest(pathname, method = 'GET', body = null) {\n const credentials = getCredentials()\n\n const { endpoint, token } = credentials || {}\n if (!endpoint) {\n throw new Error(INITIALIZATION_ERROR)\n }\n\n const url = `${endpoint}${pathname}`\n\n const headers = {\n 'Content-Type': 'application/json'\n }\n if (token) {\n headers.Authorization = `Bearer ${token}`\n }\n\n return fetch(url, {\n headers,\n method,\n body: body ? JSON.stringify(body) : null\n })\n}\n","/**\n * Socket Service for Call SDK\n * Handles WebRTC call functionality without depending on external state\n * Uses callbacks to communicate state changes to the consumer\n */\n\nimport { getCallServerEndpoint } from './utils.js'\nimport { getCredentials, getExternalId, updateSessionId } from './chat.js'\n\n/**\n * @typedef {Object} CallCallbacks\n * @property {(status: string) => void} [onCallStatus] - Called when call status changes\n * @property {(error: string | null) => void} [onCallError] - Called when call error occurs\n */\n\n/**\n * @typedef {Object} CallSession\n * @property {string} [sessionId]\n * @property {WebSocket} [socket]\n * @property {RTCPeerConnection} [peerConnection]\n * @property {MediaStream} [localStream]\n * @property {MediaStream} [remoteStream]\n * @property {HTMLAudioElement} [remoteAudio]\n * @property {boolean} isMuted\n * @property {string} callStatus\n * @property {NodeJS.Timeout} [pingInterval]\n * @property {number} pingCount\n * @property {number | null} lastPongTime\n * @property {CallCallbacks} callbacks\n * @property {string[]} localIceCandidates - Queued local ICE candidates to send after remote description is set\n * @property {string[]} pendingRemoteIceCandidates - Queued remote ICE candidates to add after remote description is set\n */\n\n/**\n * Create a new call session\n * @param {CallCallbacks} [callbacks={}]\n * @returns {CallSession}\n */\nfunction createSession(callbacks = {}) {\n return {\n sessionId: undefined,\n socket: null,\n peerConnection: null,\n localStream: null,\n remoteStream: null,\n remoteAudio: null,\n isMuted: false,\n callStatus: 'disconnected',\n pingInterval: null,\n pingCount: 0,\n lastPongTime: null,\n callbacks,\n localIceCandidates: [],\n pendingRemoteIceCandidates: []\n }\n}\n\n/** @type {CallSession} */\nlet currentSession = createSession()\n\nconst rtcConfig = {\n iceServers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun1.l.google.com:19302' }]\n}\n\n/**\n * Set callbacks for the current session\n * @param {CallCallbacks} callbacks\n */\nexport function setCallCallbacks(callbacks) {\n currentSession.callbacks = { ...currentSession.callbacks, ...callbacks }\n}\n\n/**\n * Clean up the current session\n */\nfunction cleanup() {\n if (currentSession.peerConnection) {\n currentSession.peerConnection.close()\n currentSession.peerConnection = null\n }\n\n if (currentSession.localStream) {\n currentSession.localStream.getTracks().forEach((track) => track.stop())\n currentSession.localStream = null\n }\n\n if (currentSession.remoteStream) {\n currentSession.remoteStream = null\n }\n\n if (currentSession.remoteAudio) {\n currentSession.remoteAudio.srcObject = null\n if (currentSession.remoteAudio.parentNode) {\n currentSession.remoteAudio.parentNode.removeChild(currentSession.remoteAudio)\n }\n currentSession.remoteAudio = null\n }\n\n if (currentSession.socket) {\n currentSession.socket.close()\n currentSession.socket = null\n }\n\n stopPingInterval()\n\n const callbacks = currentSession.callbacks\n currentSession = createSession(callbacks)\n\n console.log('Call session cleaned up')\n}\n\n/**\n * Update call status and notify callback\n * @param {string} status\n */\nfunction setCallStatus(status) {\n currentSession.callStatus = status\n currentSession.callbacks.onCallStatus?.(status)\n}\n\n/**\n * Update call error and notify callback\n * @param {string | null} error\n */\nfunction setCallError(error) {\n currentSession.callbacks.onCallError?.(error)\n}\n\n/**\n * Stop ping interval\n */\nfunction stopPingInterval() {\n if (currentSession.pingInterval) {\n clearInterval(currentSession.pingInterval)\n currentSession.pingInterval = null\n }\n}\n\n/**\n * Start ping interval\n */\nfunction startPingInterval() {\n stopPingInterval()\n\n currentSession.pingInterval = setInterval(() => {\n if (currentSession.socket && currentSession.socket.readyState === WebSocket.OPEN) {\n currentSession.pingCount++\n const pingMessage = {\n type: 'ping',\n timestamp: Date.now(),\n count: currentSession.pingCount\n }\n sendEvent(pingMessage)\n console.log(`Sending keep-alive ping #${currentSession.pingCount}`)\n } else {\n console.log('Socket not open, stopping ping interval')\n stopPingInterval()\n }\n }, 10000)\n}\n\n/**\n * Handle pong response\n */\nfunction handlePong() {\n currentSession.lastPongTime = Date.now()\n console.log(`Received pong #${currentSession.pingCount}`)\n}\n\n/**\n * Send event through socket\n * @param {Object} payload\n */\nfunction sendEvent(payload) {\n if (!currentSession.socket) {\n console.error('Failed to send event: no socket instance')\n return\n }\n if (currentSession.socket.readyState !== WebSocket.OPEN) {\n console.error('Failed to send event: socket state not open ', payload)\n return\n }\n\n currentSession.socket.send(JSON.stringify(payload))\n}\n\n/**\n * Get user media\n */\nasync function getUserMedia() {\n try {\n currentSession.localStream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n video: false\n })\n console.log('Got audio media')\n } catch (error) {\n console.error(`Failed to get audio media: ${error.message}`)\n throw error\n }\n}\n\n/**\n * Create peer connection\n */\nfunction createPeerConnection() {\n currentSession.peerConnection = new RTCPeerConnection(rtcConfig)\n\n currentSession.peerConnection.onicecandidate = (event) => {\n if (event.candidate) {\n const candidateJson = JSON.stringify(event.candidate)\n // Queue local ICE candidates until remote description is set\n if (currentSession.peerConnection && currentSession.peerConnection.remoteDescription) {\n sendEvent({\n type: 'ice',\n data: {\n candidate: candidateJson\n }\n })\n console.log('Sent ICE candidate immediately')\n } else {\n currentSession.localIceCandidates.push(candidateJson)\n console.log('Queued local ICE candidate')\n }\n }\n }\n\n currentSession.peerConnection.ontrack = (event) => {\n console.log('Received remote audio stream')\n currentSession.remoteStream = event.streams[0]\n\n if (!currentSession.remoteAudio) {\n currentSession.remoteAudio = document.createElement('audio')\n currentSession.remoteAudio.autoplay = true\n currentSession.remoteAudio.controls = false\n document.body.appendChild(currentSession.remoteAudio)\n }\n currentSession.remoteAudio.srcObject = currentSession.remoteStream\n // explicitly kick off playback and catch any policy/gesture errors\n currentSession.remoteAudio\n .play()\n .then(() => console.log('🔊 remote audio playing'))\n .catch((err) => console.error('❌ playback error:', err))\n }\n\n currentSession.peerConnection.onconnectionstatechange = () => {\n const newState = currentSession.peerConnection.connectionState\n console.log(`Connection state: ${newState}`)\n\n if (newState === 'connected') {\n setCallStatus('connected')\n } else if (newState === 'disconnected' || newState === 'closed') {\n setCallStatus('disconnected')\n disconnectCall()\n }\n }\n\n currentSession.peerConnection.oniceconnectionstatechange = () => {\n console.log(`ICE connection state: ${currentSession.peerConnection.iceConnectionState}`)\n }\n}\n\n/**\n * Connect socket\n * @param {{ sessionId?: string }} payload\n */\nfunction connectSocket(payload) {\n return new Promise((fulfill, reject) => {\n if (\n currentSession.socket &&\n (currentSession.socket.readyState === WebSocket.CONNECTING ||\n currentSession.socket.readyState === WebSocket.OPEN)\n ) {\n console.log('Socket in connecting/open state, returning.')\n fulfill(currentSession.socket.readyState === WebSocket.OPEN)\n return\n }\n\n console.log('Initializing socket connection..')\n const credentials = getCredentials()\n if (!credentials || !credentials.endpoint) {\n reject(new Error('SDK not initialized. Please initialize SDK first.'))\n return\n }\n\n // Extract hostname from endpoint\n const socketEndpoint = getCallServerEndpoint(credentials.endpoint)\n if (!socketEndpoint) {\n reject(\n new Error(\n 'Invalid endpoint while initializing SDK. Please check the endpoint and try again.'\n )\n )\n return\n }\n\n const externalId = getExternalId()\n const queryParams = new URLSearchParams({\n externalId\n })\n if (payload.sessionId) {\n queryParams.set('sessionId', payload.sessionId)\n }\n if (credentials.token) {\n queryParams.set('token', credentials.token)\n }\n\n const socketUrl = `${socketEndpoint}?${queryParams.toString()}`\n currentSession.socket = new WebSocket(socketUrl)\n\n currentSession.socket.onopen = (event) => {\n console.log('Socket connection established: ', event)\n startPingInterval()\n fulfill(true)\n }\n\n currentSession.socket.onmessage = (event) => {\n const data = JSON.parse(event.data)\n handleCallServerEvent(data)\n }\n\n currentSession.socket.onerror = (error) => {\n console.error('Socket error: ', error)\n setCallStatus('error')\n setCallError(error.message || 'Unable to connect voice')\n reject(error)\n }\n\n currentSession.socket.onclose = (event) => {\n console.log('Socket connection closed: ', event)\n stopPingInterval()\n }\n })\n}\n\n/**\n * Handle call server event\n * @param {Object} action\n */\nfunction handleCallServerEvent(action) {\n console.log('Handling socket server event: ', action)\n\n switch (action.type) {\n case 'pong':\n handlePong()\n break\n\n case 'answer':\n handleAnswer(action.data)\n break\n\n case 'ice':\n handleIceCandidate(action.data)\n break\n\n case 'renegotiationOffer':\n handleRenegotiationOffer(action.data)\n break\n case 'end':\n disconnectCall()\n break\n case 'error':\n setCallStatus('error')\n setCallError(action.error || 'Unable to connect voice')\n break\n\n default:\n console.log('Unknown call event type: ', action.type)\n break\n }\n}\n\n/**\n * Handle answer\n * @param {Object} data\n */\nasync function handleAnswer(data) {\n try {\n console.log('Received answer')\n\n currentSession.sessionId = data.sessionId\n // Update chat session with the new sessionId and notify controller\n updateSessionId(data.sessionId)\n\n if (currentSession.peerConnection) {\n const answer = new RTCSessionDescription({\n type: 'answer',\n sdp: data.sdp\n })\n console.log('Setting remote description answer: ', answer)\n await currentSession.peerConnection.setRemoteDescription(answer)\n console.log('Remote description set')\n\n // Send all queued local ICE candidates\n for (const candidateJson of currentSession.localIceCandidates) {\n sendEvent({\n type: 'ice',\n data: {\n candidate: candidateJson\n }\n })\n console.log('Sent queued local ICE candidate')\n }\n currentSession.localIceCandidates = []\n\n // Process any pending remote ICE candidates\n for (const candidateJson of currentSession.pendingRemoteIceCandidates) {\n try {\n const candidate = new RTCIceCandidate(JSON.parse(candidateJson))\n await currentSession.peerConnection.addIceCandidate(candidate)\n console.log('Added pending remote ICE candidate')\n } catch (err) {\n console.error(`Failed to add pending ICE candidate: ${err.message}`)\n }\n }\n currentSession.pendingRemoteIceCandidates = []\n }\n } catch (error) {\n console.error(`Failed to handle answer: ${error.message}`)\n }\n}\n\n/**\n * Handle ICE candidate\n * @param {Object} data\n */\nasync function handleIceCandidate(data) {\n try {\n if (currentSession.peerConnection) {\n // Check if remote description is set\n if (!currentSession.peerConnection.remoteDescription) {\n // Queue the candidate until remote description is set\n currentSession.pendingRemoteIceCandidates.push(data.candidate)\n console.log('Queued remote ICE candidate - remote description not set')\n return\n }\n const candidate = new RTCIceCandidate(JSON.parse(data.candidate))\n await currentSession.peerConnection.addIceCandidate(candidate)\n console.log('Added ICE candidate')\n }\n } catch (error) {\n console.error(`Failed to add ICE candidate: ${error.message}`)\n }\n}\n\n/**\n * Handle renegotiation offer\n * @param {Object} data\n */\nasync function handleRenegotiationOffer(data) {\n try {\n console.log('Received renegotiation offer')\n\n if (currentSession.peerConnection) {\n const offer = new RTCSessionDescription({\n type: 'offer',\n sdp: data.sdp\n })\n console.log('Setting remote description offer: ', offer)\n await currentSession.peerConnection.setRemoteDescription(offer)\n console.log('Remote description set')\n\n const answer = await currentSession.peerConnection.createAnswer()\n await currentSession.peerConnection.setLocalDescription(answer)\n\n sendEvent({\n type: 'renegotiationAnswer',\n data: {\n sdp: answer.sdp\n }\n })\n }\n } catch (error) {\n console.error(`Failed to handle renegotiation offer: ${error.message}`)\n }\n}\n\n/**\n * Start a call\n * @param {{ sessionId?: string }} payload\n */\nexport async function startCall(payload = {}) {\n try {\n if (currentSession.callStatus === 'connecting' || currentSession.callStatus === 'connected') {\n console.log(`Call already in ${currentSession.callStatus} state`)\n return\n }\n\n console.log('Starting audio call...')\n setCallStatus('connecting')\n setCallError(null)\n\n currentSession.sessionId = payload.sessionId\n\n await getUserMedia()\n\n createPeerConnection()\n\n currentSession.localStream.getTracks().forEach((track) => {\n currentSession.peerConnection.addTrack(track, currentSession.localStream)\n console.log(`Added ${track.kind} track`)\n })\n await connectSocket(payload)\n const offer = await currentSession.peerConnection.createOffer()\n await currentSession.peerConnection.setLocalDescription(offer)\n\n sendEvent({\n type: 'offer',\n data: {\n sdp: offer.sdp\n }\n })\n\n console.log('Call initiated successfully')\n } catch (error) {\n console.log('error: ', error)\n console.error(`Failed to start call: ${error.message}`)\n setCallStatus('error')\n setCallError(error.message || 'Unable to connect voice')\n cleanup()\n }\n}\n\n/**\n * Disconnect call\n */\nexport function disconnectCall() {\n sendEvent({\n type: 'end'\n })\n if (currentSession.socket) {\n currentSession.socket.close()\n currentSession.socket = null\n }\n setCallStatus('disconnected')\n if (currentSession.peerConnection) {\n currentSession.peerConnection.close()\n currentSession.peerConnection = null\n }\n if (currentSession.localStream) {\n currentSession.localStream.getTracks().forEach((track) => track.stop())\n currentSession.localStream = null\n }\n cleanup()\n}\n\n/**\n * Toggle mute\n * @returns {boolean}\n */\nexport function toggleMute() {\n if (currentSession.localStream) {\n const audioTrack = currentSession.localStream.getAudioTracks()[0]\n if (audioTrack) {\n audioTrack.enabled = !audioTrack.enabled\n currentSession.isMuted = !audioTrack.enabled\n console.log(`Audio ${currentSession.isMuted ? 'muted' : 'unmuted'}`)\n return currentSession.isMuted\n }\n }\n return false\n}\n\n/**\n * Get local stream\n * @returns {MediaStream | null}\n */\nexport function getLocalStream() {\n return currentSession.localStream\n}\n\n/**\n * Get inbound audio energy\n * @returns {Promise<number>}\n */\nexport function getInboundAudioEnergy() {\n return new Promise((resolve, reject) => {\n if (!currentSession.peerConnection) {\n reject(new Error('no peer connection'))\n return\n }\n currentSession.peerConnection\n .getStats()\n .then((stats) => {\n stats.forEach((report) => {\n if (report.type == 'inbound-rtp') {\n resolve(report.totalAudioEnergy)\n }\n })\n reject(new Error('no inbound-rtp stats found'))\n })\n .catch((err) => {\n reject(err)\n })\n })\n}\n\n/**\n * Get outbound audio energy (not implemented in original, but may be needed)\n * @returns {Promise<number>}\n */\nexport function getOutboundAudioEnergy() {\n return new Promise((resolve, reject) => {\n if (!currentSession.peerConnection) {\n reject(new Error('no peer connection'))\n return\n }\n currentSession.peerConnection\n .getStats()\n .then((stats) => {\n stats.forEach((report) => {\n if (report.type == 'outbound-rtp') {\n resolve(report.totalAudioEnergy)\n }\n })\n reject(new Error('no outbound-rtp stats found'))\n })\n .catch((err) => {\n reject(err)\n })\n })\n}\n"],"names":["uuidv7","timestamp","bytes","hex","b","getDeviceId","deviceId","sleep","ms","resolve","getSseEndpoint","baseUrl","sseEndpoint","url","e","getSocketEndpoint","socketEndpoint","getCallServerEndpoint","MESSAGE_ROLES","PING_INTERVAL","SOCKET_TIMEOUT","SocketEvents","createSession","currentSession","stopPingInterval","startPingInterval","send","clearAllTimeouts","handleSocketConnected","setTransport","handleSocketDisconnected","connectSocket","payload","fulfill","reject","credentials","getCredentials","externalId","getExternalId","queryParams","socketUrl","event","message","handleSocketEvent","error","ws","addMessage","data","toggleTypingStatus","eventId","disconnect","isConnected","callbacks","setCallbacks","initialize","updateSessionId","sessionId","startChat","configData","authenticate","messages","control","session","getSession","searchParams","sendMessage","cleanup","disconnectSocket","isTyping","transport","text","html","context","isEmpty","userMessage","isSocketConnected","socketSend","loadingMessage","headers","fetchEventSource","response","errorMessage","lastIndex","updatedMsg","msg","index","supervisorMessage","_g","_h","newBotMessage","lastMsg","_i","_l","_m","AUTHENTICATION_ERROR","INITIALIZATION_ERROR","endpoint","errorPayload","getHistory","fetchRequest","_a","pathname","method","body","token","rtcConfig","setCallCallbacks","track","setCallStatus","status","_b","setCallError","pingMessage","sendEvent","handlePong","getUserMedia","createPeerConnection","candidateJson","err","newState","disconnectCall","handleCallServerEvent","action","handleAnswer","handleIceCandidate","handleRenegotiationOffer","answer","candidate","offer","startCall","toggleMute","audioTrack","getLocalStream","getInboundAudioEnergy","stats","report","getOutboundAudioEnergy"],"mappings":";AAIO,SAASA,IAAS;AACvB,QAAMC,IAAY,KAAK,IAAG,GACpBC,IAAQ,IAAI,WAAW,EAAE;AAC/B,SAAO,gBAAgBA,CAAK,GAG5BA,EAAM,CAAC,IAAKD,KAAa,KAAM,KAC/BC,EAAM,CAAC,IAAKD,KAAa,KAAM,KAC/BC,EAAM,CAAC,IAAKD,KAAa,KAAM,KAC/BC,EAAM,CAAC,IAAKD,KAAa,KAAM,KAC/BC,EAAM,CAAC,IAAKD,KAAa,IAAK,KAC9BC,EAAM,CAAC,IAAID,IAAY,KAGvBC,EAAM,CAAC,IAAKA,EAAM,CAAC,IAAI,KAAQ,KAG/BA,EAAM,CAAC,IAAKA,EAAM,CAAC,IAAI,KAAQ;AAE/B,QAAMC,IAAM,CAAC,GAAGD,CAAK,EAAE,IAAI,CAACE,MAAMA,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AAC1E,SAAO,GAAGD,EAAI,MAAM,GAAG,CAAC,CAAC,IAAIA,EAAI,MAAM,GAAG,EAAE,CAAC,IAAIA,EAAI,MAAM,IAAI,EAAE,CAAC,IAAIA,EAAI;AAAA,IACxE;AAAA,IACA;AAAA,EACJ,CAAG,IAAIA,EAAI,MAAM,EAAE,CAAC;AACpB;AAEO,SAASE,KAAc;AAC5B,MAAI,aAAa,QAAQ,cAAc;AACrC,WAAO,aAAa,QAAQ,cAAc;AAG5C,QAAMC,IAAWN,EAAM;AACvB,sBAAa,QAAQ,gBAAgBM,CAAQ,GACtCA;AACT;AAqBO,eAAeC,GAAMC,GAAI;AAC9B,SAAO,IAAI,QAAQ,CAACC,MAAY,WAAWA,GAASD,CAAE,CAAC;AACzD;AAEO,SAASE,GAAeC,GAAS;AACtC,MAAIC;AACJ,MAAI;AACF,UAAMC,IAAM,IAAI,IAAIF,CAAO;AAC3B,IAAAC,IAAc,WAAWC,EAAI,QAAQ,GAAGA,EAAI,QAAQ;AAAA,EACtD,SAAQC,GAAA;AAAA,EAER;AACA,SAAOF;AACT;AAEO,SAASG,GAAkBJ,GAAS;AACzC,MAAIK;AACJ,MAAI;AACF,UAAMH,IAAM,IAAI,IAAIF,CAAO;AAC3B,IAAAK,IAAiB,SAASH,EAAI,QAAQ,GAAGA,EAAI,QAAQ;AAAA,EACvD,SAAQC,GAAA;AAAA,EAER;AACA,SAAOE;AACT;AAEO,SAASC,GAAsBN,GAAS;AAC7C,MAAIK;AACJ,MAAI;AACF,UAAMH,IAAM,IAAI,IAAIF,CAAO;AAC3B,IAAAK,IAAiB,SAASH,EAAI,QAAQ,GAAGA,EAAI,QAAQ;AAAA,EACvD,SAAQC,GAAA;AAAA,EAER;AACA,SAAOE;AACT;AC1FY,MAACE,IAAgB;AAAA,EAC3B,WAAW;AAAA;AAAA,EACX,MAAM;AAAA;AAAA,EACN,YAAY;AAAA;AAAA,EACZ,QAAQ;AAAA;AACV,GCKMC,IAAgB,KAChBC,KAAiB,KAeVC,IAAe;AAAA,EAC1B,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,KAAK;AACP;AAMA,SAASC,KAAgB;AACvB,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,qBAAqB;AAAA,IACrB,oBAAoB;AAAA,IACpB,cAAc;AAAA,IACd,2BAA2B;AAAA,IAC3B,yBAAyB;AAAA,EAC7B;AACA;AAGA,IAAIC,IAAiBD,GAAa;AAKlC,SAASE,IAAmB;AAC1B,EAAID,EAAe,iBACjB,cAAcA,EAAe,YAAY,GACzCA,EAAe,eAAe;AAElC;AAKA,SAASE,KAAoB;AAC3BD,EAAAA,EAAgB,GAEhBD,EAAe,eAAe,YAAY,MAAM;AAC9C,IAAIA,EAAe,UAAUA,EAAe,OAAO,eAAe,UAAU,OAC1EG,EAAK,EAAE,MAAM,OAAM,CAAE,IAIrBF,EAAgB;AAAA,EAEpB,GAAGL,CAAa;AAClB;AAKA,SAASQ,IAAmB;AAC1BH,EAAAA,EAAgB,GACZD,EAAe,8BACjB,aAAaA,EAAe,yBAAyB,GACrDA,EAAe,4BAA4B,OAEzCA,EAAe,4BACjB,aAAaA,EAAe,uBAAuB,GACnDA,EAAe,0BAA0B;AAE7C;AAKA,SAASK,IAAwB;AAE/BL,EAAAA,EAAe,qBAAqB,IACpCM,EAAa,QAAQ;AACvB;AAKA,SAASC,IAA2B;AAElCP,EAAAA,EAAe,qBAAqB,IACpCM,EAAa,KAAK;AACpB;AAOO,SAASE,GAAcC,GAAS;AACrC,SAAO,IAAI,QAAQ,CAACC,GAASC,MAAW;AACtC,QACEX,EAAe,WACdA,EAAe,OAAO,eAAe,UAAU,cAC9CA,EAAe,OAAO,eAAe,UAAU,OACjD;AAEA,MAAAU,EAAQV,EAAe,OAAO,eAAe,UAAU,IAAI;AAC3D;AAAA,IACF;AAGA,UAAMY,IAAcC,EAAc;AAClC,QAAI,CAACD,KAAe,CAACA,EAAY,UAAU;AACzC,MAAAD,EAAO,IAAI,MAAM,mDAAmD,CAAC;AACrE;AAAA,IACF;AAEA,UAAMlB,IAAiBD,GAAkBoB,EAAY,QAAQ;AAC7D,QAAI,CAACnB,GAAgB;AACnB,MAAAkB;AAAA,QACE,IAAI;AAAA,UACF;AAAA,QACV;AAAA,MACA;AACM;AAAA,IACF;AAEA,UAAMG,IAAaC,EAAa,GAC1BC,IAAc,IAAI,gBAAgB;AAAA,MACtC,YAAAF;AAAA,IACN,CAAK;AAED,IAAIL,EAAQ,aACVO,EAAY,IAAI,aAAaP,EAAQ,SAAS,GAE5CA,EAAQ,aACVO,EAAY,IAAI,aAAaP,EAAQ,SAAS,GAE5CG,EAAY,SACdI,EAAY,IAAI,SAASJ,EAAY,KAAK;AAG5C,UAAMK,IAAY,GAAGxB,CAAc,IAAIuB,EAAY,UAAU;AAC7DhB,IAAAA,EAAe,SAAS,IAAI,UAAUiB,CAAS,GAE/CjB,EAAe,OAAO,SAAS,MAAM;AAEnCA,MAAAA,EAAe,sBAAsB,IACrCK,EAAqB,GACrBF,EAAK,EAAE,MAAM,OAAM,CAAE,GACrB,aAAaH,EAAe,uBAAuB,GACnDE,GAAiB,GACjBQ,EAAQ,EAAI;AAAA,IACd,GAEAV,EAAe,OAAO,YAAY,CAACkB,MAAU;AAC3C,YAAMC,IAAU,KAAK,MAAMD,EAAM,IAAI;AACrC,MAAAE,GAAkBD,CAAO;AAAA,IAC3B,GAEAnB,EAAe,OAAO,UAAU,CAACqB,MAAU;AAEzC,MAAAf,EAAa,KAAK,GAClBK,EAAOU,CAAK;AAAA,IACd,GAEArB,EAAe,OAAO,UAAU,CAACsB,MAAO;AAGtC,MAAIA,EAAG,WAAWtB,EAAe,WAC3BsB,EAAG,SAAS,SAEVtB,EAAe,sBACjBO,EAAwB,IAExBgB,EAAW;AAAA,QACT,WAAW;AAAA,QACX,MAAM;AAAA,QACN,YAAW,oBAAI,KAAI,GAAG,YAAW;AAAA,MAC/C,CAAa,GAEH,aAAavB,EAAe,uBAAuB,IAGrDA,EAAe,SAAS,MACxBI,EAAgB;AAAA,IAEpB,GAEKJ,EAAe,wBAClBA,EAAe,0BAA0B,WAAW,MAAM;AAExD,MAAAuB,EAAW;AAAA,QACT,WAAW;AAAA,QACX,MAAM;AAAA,QACN,YAAW,oBAAI,KAAI,GAAG,YAAW;AAAA,MAC3C,CAAS,GACDZ,EAAO,IAAI,MAAM,6BAA6B,CAAC;AAAA,IACjD,GAAGd,EAAc;AAAA,EAErB,CAAC;AACH;AAMO,SAASM,EAAKqB,GAAM;AAEzB,EAAIxB,EAAe,sBAAsB,CAACA,EAAe,UAGzDA,EAAe,OAAO,KAAK,KAAK,UAAU,EAAE,GAAGwB,GAAM,SAASA,EAAK,WAAW/C,EAAM,EAAE,CAAE,CAAC;AAC3F;AA0CA,SAAS2C,GAAkBF,GAAO;AAGhC,UAAQA,EAAM,MAAI;AAAA,IAChB,KAAK,QAAQ;AACX,MAAIlB,EAAe,sBACjBK,EAAqB,GAEnBL,EAAe,6BACjB,aAAaA,EAAe,yBAAyB,GAEvDA,EAAe,4BAA4B,WAAW,MAAM;AAE1D,QAAAO,EAAwB;AAAA,MAC1B,GAAGX,IAAgB,GAAI;AACvB;AAAA,IACF;AAAA,IACA,KAAKE,EAAa,QAAQ;AACxB,MAAA2B,EAAmB,EAAI;AACvB;AAAA,IACF;AAAA,IACA,KAAK3B,EAAa,aAAa;AAC7B,MAAA2B,EAAmB,EAAK;AACxB;AAAA,IACF;AAAA,IACA,KAAK3B,EAAa,SAAS;AACzB,YAAM,EAAE,SAAA4B,GAAS,MAAAF,MAASN;AAC1B,MAAKQ,KACHH,EAAW;AAAA,QACT,GAAGC;AAAA,QACH,MAAM;AAAA,QACN,YAAW,oBAAI,KAAI,GAAG,YAAW;AAAA,MAC3C,CAAS;AAEH;AAAA,IACF;AAAA,IACA,KAAK1B,EAAa,KAAK;AACrB6B,MAAAA,EAAU;AACV;AAAA,IACF;AAAA,EAGJ;AACA;AAcO,SAASA,IAAa;AAE3B,EAAI3B,EAAe,UACjBA,EAAe,OAAO,MAAM,GAAI,GAElCA,EAAe,sBAAsB,IACrCI,EAAgB,GAChBJ,EAAe,SAAS,MACxBM,EAAa,KAAK;AACpB;AAMO,SAASsB,KAAc;AAC5B,SACE5B,EAAe,WAAW,QAC1BA,EAAe,OAAO,eAAe,UAAU,QAC/C,CAACA,EAAe;AAEpB;ACpTA,SAASD,EAAc8B,IAAY,IAAI;AACrC,SAAO;AAAA,IACL,aAAa;AAAA,IACb,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,UAAU,CAAA;AAAA,IACV,WAAAA;AAAA,IACA,WAAW;AAAA,IACX,SAAS;AAAA,EACb;AACA;AAGA,IAAI7B,IAAiBD,EAAa;AAM3B,SAAS+B,GAAaD,GAAW;AACtC7B,EAAAA,EAAe,YAAY,EAAE,GAAGA,EAAe,WAAW,GAAG6B,EAAS;AACxE;AAMO,SAASE,GAAWnB,GAAa;AAEtCZ,EAAAA,EAAe,cAAcY,GACzBA,EAAY,UACdZ,EAAe,gBAAgB;AAEnC;AAMO,SAASa,IAAiB;AAC/B,SAAOb,EAAe;AACxB;AAMO,SAASgC,GAAgBC,GAAW;;AACzC,EAAIA,KAAaA,MAAcjC,EAAe,cAC5CA,EAAe,YAAYiC,IAC3BjC,KAAAA,IAAAA,EAAe,WAAU,oBAAzBA,QAAAA,EAAAA,KAAAA,GAA2CiC;AAE/C;AASO,eAAeC,GAAUzB,IAAU,IAAI;AAC5C,MAAI;AAGF,QAAI0B,IAAa;AACjB,IAAKnC,EAAe,gBAKlBmC,IAAanC,EAAe,cAJ5BmC,IAAa,MAAMC,GAAapC,EAAe,WAAW,GAC1DA,EAAe,gBAAgB,IAC/BA,EAAe,aAAamC;AAK9B,QAAIE,IAAW,CAAA,GACXC,IAAU;AAEd,QAAI7B,EAAQ,WAAW;AACrB,YAAM8B,IAAU,MAAMC,GAAW/B,EAAQ,SAAS;AAClD,MAAA4B,IAAWE,EAAQ,UACnBD,IAAUC,EAAQ,WAAW;AAAA,IAC/B;AAEA,UAAME,IAAe,IAAI,gBAAe;AACxC,WAAKzC,EAAe,YAAY,SAC9ByC,EAAa,IAAI,cAAc1B,GAAe,GAEhDf,EAAe,SAAS,GAAGb;AAAA,MACzBa,EAAe,YAAY;AAAA,IACjC,CAAK,IAAIyC,EAAa,UAAU,IAC5BzC,EAAe,YAAYS,EAAQ,WACnCT,EAAe,WAAWqC,GAC1BrC,EAAe,UAAUsC,GAErBA,MAAY,WAEdI,GAAY,EAAE,MAAM,IAAI,MAAM,IAAI,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC,GAK7C;AAAA,MACL,WAAW1C,EAAe;AAAA,MAC1B,UAAAqC;AAAA,MACA,SAAAC;AAAA,MACA,YAAAH;AAAA,IACN;AAAA,EACE,SAASd,GAAO;AAEdsB,UAAAA,GAAO,GACDtB;AAAA,EACR;AACF;AAKO,SAASM,KAAa;AAC3BgB,EAAAA,GAAO;AACT;AAKA,SAASA,KAAU;AACjB,EAAI3C,EAAe,mBACjBA,EAAe,gBAAgB,MAAK,GAEtC4C,EAAgB;AAEhB,QAAM,EAAE,WAAAf,GAAW,aAAAjB,MAAgBZ;AACnCA,EAAAA,IAAiBD,EAAc8B,CAAS,GACxC7B,EAAe,cAAcY;AAG/B;AAEO,SAASG,IAAgB;;AAC9B,UAAIf,IAAAA,EAAe,gBAAfA,QAAAA,EAA4B,aACvBA,EAAe,YAAY,aAE7BlB,GAAW;AACpB;AAMO,SAASyC,EAAWJ,GAAS;;AAClCnB,EAAAA,EAAe,WAAW,CAAC,GAAGA,EAAe,UAAUmB,CAAO,IAC9DnB,KAAAA,IAAAA,EAAe,WAAU,iBAAzBA,QAAAA,EAAAA,KAAAA,GAAwCmB;AAC1C;AAEO,SAASM,EAAmBoB,GAAU;;AAC3C7C,GAAAA,KAAAA,IAAAA,EAAe,WAAU,aAAzBA,QAAAA,EAAAA,KAAAA,GAAoC6C;AACtC;AAMO,SAASvC,EAAawC,GAAW;;AAEtC9C,EAAAA,EAAe,YAAY8C,IAC3B9C,KAAAA,IAAAA,EAAe,WAAU,sBAAzBA,QAAAA,EAAAA,KAAAA,GAA6C8C;AAC/C;AAeO,SAASJ,GAAY,EAAE,MAAAK,GAAM,MAAAC,GAAM,SAAAC,EAAO,GAAI;AACnD,SAAO,IAAI,QAAQ,CAAC/D,GAASyB,MAAW;AACrC,KAAC,YAAY;;AACZ,UAAI;AACF,cAAMuC,IAAU,CAACH,KAAQ,CAACC;AAG1B,YAAI,CAACE,GAAS;AACZ,gBAAMC,IAAc;AAAA,YAClB,MAAMxD,EAAc;AAAA,YACpB,MAAAoD;AAAA,YACA,MAAAC;AAAA,YACA,YAAW,oBAAI,KAAI,GAAG,YAAW;AAAA,UAC7C;AACU,UAAAzB,EAAW4B,CAAW,GACtB,MAAMnE,GAAM,GAAG;AAAA,QACjB;AAGA,YAAIgB,EAAe,cAAc,YAAYoD,GAAiB,GAAI;AAChEC,UAAAA,EAAW;AAAA,YACT,MAAM;AAAA,YACN,MAAM;AAAA,cACJ,MAAAN;AAAA,cACA,MAAAC;AAAA,YACd;AAAA,UACA,CAAW,GACD9D,EAAQc,EAAe,SAAS;AAChC;AAAA,QACF;AAEA,YAAIA,EAAe,YAAY,SAAS;AACtC,gBAAMsD,IAAiB;AAAA,YACrB,MAAM3D,EAAc;AAAA,YACpB,MAAM;AAAA,YACN,SAAS;AAAA,UACrB;AACU,UAAA4B,EAAW+B,CAAc;AAAA,QAC3B;AAEA,cAAMhE,IAAM,IAAI,IAAIU,EAAe,MAAM;AACzC,QAAIA,EAAe,aACjBV,EAAI,aAAa,IAAI,aAAaU,EAAe,SAAS,GAExDA,EAAe,aACjBV,EAAI,aAAa,IAAI,aAAaU,EAAe,SAAS,GAG5DA,EAAe,eAAe,QAG9BA,EAAe,kBAAkB,IAAI,gBAAe;AAEpD,cAAMuD,IAAU;AAAA,UACd,gBAAgB;AAAA,QAC1B;AACQ,SAAIvD,IAAAA,EAAe,gBAAfA,QAAAA,EAA4B,UAC9BuD,EAAQ,gBAAgB,UAAUvD,EAAe,YAAY,KAAK,KAGpE,MAAMwD,GAAiBlE,EAAI,YAAY;AAAA,UACrC,QAAQ;AAAA,UACR,SAAAiE;AAAA,UACA,MAAML,IACF,SACA,KAAK,UAAU;AAAA,YACb,SAASH;AAAA,YACT,MAAAC;AAAA,YACA,SAAAC;AAAA,UAChB,CAAe;AAAA,UACL,QAAQjD,EAAe,gBAAgB;AAAA,UACvC,gBAAgB;AAAA,UAChB,QAAQ,OAAOyD,MAAa;AAC1B,gBAAI,CAACA,EAAS;AAEZ,oBAAM,IAAI,MAAM,wBAAwB;AAAA,UAE5C;AAAA,UACA,WAAW,CAACA,MAAa;;AAEvB,kBAAMjC,IAAO,KAAK,MAAMiC,EAAS,IAAI;AAErC,gBAAIA,EAAS,UAAU;AACrBzD,cAAAA,EAAe,YAAYwB,EAAK,WAChCxB,EAAe,YAAYwB,EAAK,WAE5BA,EAAK,YACPxB,EAAe,UAAUwB,EAAK,UAC9BxB,KAAAA,IAAAA,EAAe,WAAU,oBAAzBA,QAAAA,EAAAA,KAAAA,GAA2CwB,EAAK;AAAA,qBAEzCiC,EAAS,UAAU;AAE5BjD,cAAAA,GAAc;AAAA,gBACZ,WAAWR,EAAe;AAAA,gBAC1B,WAAWwB,EAAK;AAAA,cAChC,CAAe;AAAA,qBACQiC,EAAS,UAAU;AAC5B,cAAIjC,EAAK,YACPxB,EAAe,UAAUwB,EAAK,UAC9BxB,KAAAA,IAAAA,EAAe,WAAU,oBAAzBA,QAAAA,EAAAA,KAAAA,GAA2CwB,EAAK;AAAA,qBAEzCA,EAAK,OAAO;AACrB,oBAAMkC,IACJlC,EAAK,SAAS,OAAOA,EAAK,SAAU,WAChCA,EAAK,QACL,mCACAmC,IAAY3D,EAAe,SAAS,SAAS,GAE7C4D,IAAa;AAAA,gBACjB,GAFc5D,EAAe,SAAS2D,CAAS;AAAA,gBAG/C,SAAS;AAAA,gBACT,WAAWD;AAAA,cAC3B;AACc1D,cAAAA,EAAe,WAAWA,EAAe,SAAS;AAAA,gBAAI,CAAC6D,GAAKC,OAC1DA,OAAUH,IAAYC,IAAaC;AAAA,cACnD,IACc7D,KAAAA,IAAAA,EAAe,WAAU,oBAAzBA,QAAAA,EAAAA,KAAAA,GAA2C2D,GAAWC,IACtDjD,EAAO,IAAI,MAAM+C,CAAY,CAAC;AAAA,YAChC,WAAWD,EAAS,UAAU;AAC5B,cAAAvE,EAAQc,EAAe,SAAS;AAAA,qBACvBwB,EAAK,YAAY,QAAW;AAErC,kBAAIA,EAAK,SAAS7B,EAAc,YAAY;AAC1C,sBAAMoE,IAAoB;AAAA,kBACxB,MAAMpE,EAAc;AAAA,kBACpB,MAAM6B,EAAK;AAAA,kBACX,SAASA,EAAK;AAAA,kBACd,MAAM;AAAA,gBACxB;AACgB,gBAAAD,EAAWwC,CAAiB,GAC5B7E,EAAQc,EAAe,SAAS,GAGhCA,EAAe,aAAYgE,IAAAxC,EAAK,cAAL,OAAAwC,IAAkBhE,EAAe,WAC5DA,EAAe,aAAYiE,IAAAzC,EAAK,cAAL,OAAAyC,IAAkBjE,EAAe;AAC5D;AAAA,cACF;AAGA,kBAAIwB,EAAK,aAAa;AACpB,oBAAIxB,EAAe,iBAAiB;AAClCA,kBAAAA,EAAe,eAAewB,EAAK;AAAA,yBAC1BA,EAAK,aAAaxB,EAAe,cAAc;AACxDA,kBAAAA,EAAe,eAAewB,EAAK;AACnC,wBAAM0C,IAAgB;AAAA,oBACpB,MAAMvE,EAAc;AAAA,oBACpB,MAAM;AAAA,oBACN,SAAS;AAAA,kBAC7B;AACkB,kBAAA4B,EAAW2C,CAAa;AAAA,gBAC1B;AAAA;AAIF,oBAAMP,IAAY3D,EAAe,SAAS,SAAS,GAC7CmE,IAAUnE,EAAe,SAAS2D,CAAS,GAC3CC,IAAa;AAAA,gBACjB,GAAGO;AAAA,gBACH,SAAS;AAAA,gBACT,OAAOA,EAAQ,QAAQ,MAAM3C,EAAK;AAAA,gBAClC,SAASA,EAAK;AAAA,gBACd,OAAM4C,IAAA5C,EAAK,SAAL,OAAA4C,IAAaD,EAAQ;AAAA,cAC3C;AACcnE,cAAAA,EAAe,WAAWA,EAAe,SAAS;AAAA,gBAAI,CAAC6D,GAAKC,MAC1DA,MAAUH,IAAYC,IAAaC;AAAA,cACnD,IAEc7D,KAAAA,IAAAA,EAAe,WAAU,oBAAzBA,QAAAA,EAAAA,KAAAA,GAA2C2D,GAAWC,IAElDpC,EAAK,MAITxB,EAAe,aAAYqE,IAAA7C,EAAK,cAAL,OAAA6C,IAAkBrE,EAAe,WAC5DA,EAAe,aAAYsE,IAAA9C,EAAK,cAAL,OAAA8C,IAAkBtE,EAAe;AAAA,YAC9D;AAAA,UACF;AAAA,UACA,SAAS,CAACqB,MAAU;AAClB,kBAAMA;AAAA,UACR;AAAA,UACA,gBAAgB;AAAA,QAC1B,CAAS;AAAA,MACH,SAASA,GAAO;AAEd,cAAMqC,IAAe,mCACfC,IAAY3D,EAAe,SAAS,SAAS,GAC7CmE,IAAUnE,EAAe,SAAS2D,CAAS,GAC3CC,IAAa;AAAA,UACjB,GAAGO;AAAA,UACH,SAAS;AAAA,UACT,WAAWA,EAAQ,OAAO,SAAY9C,EAAM,WAAWqC;AAAA,UACvD,MAAM;AAAA,QAChB;AACQ1D,QAAAA,EAAe,WAAWA,EAAe,SAAS;AAAA,UAAI,CAAC6D,GAAKC,MAC1DA,MAAUH,IAAYC,IAAaC;AAAA,QAC7C,IACQ7D,KAAAA,IAAAA,EAAe,WAAU,oBAAzBA,QAAAA,EAAAA,KAAAA,GAA2C2D,GAAWC,IACtDjD,EAAOU,CAAK;AAAA,MACd;AAAA,IACF,GAAC;AAAA,EACH,CAAC;AACH;ACzaA,MAAMkD,KAAuB,8CACvBC,KAAuB;AAOtB,eAAepC,GAAa3B,GAAS;AAC1C,QAAM,EAAE,UAAAgE,EAAQ,IAAKhE,GACfnB,IAAM,GAAGmF,CAAQ,WAEjBhB,IAAW,MAAM,MAAMnE,GAAK;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,gBAAgB;AAAA,IACtB;AAAA,EACA,CAAG;AAED,MAAI,CAACmE,EAAS,IAAI;AAChB,UAAMiB,IAAe,MAAMjB,EAAS,KAAI;AACxC,UAAM,IAAI,OAAMiB,KAAA,gBAAAA,EAAc,UAASH,EAAoB;AAAA,EAC7D;AAKA,UAHY,MAAMd,EAAS,KAAI,GACd;AAGnB;AAMO,eAAekB,KAAa;AACjC,QAAM3D,IAAc,IAAI,gBAAgB;AAAA,IACtC,YAAYD,EAAa;AAAA,EAC7B,CAAG,GACK0C,IAAW,MAAMmB,GAAa,aAAa5D,EAAY,SAAQ,CAAE,IAAI,KAAK;AAEhF,MAAI,CAACyC,EAAS;AACZ,UAAM,IAAI,MAAM,gDAAgD;AAGlE,SAAOA,EAAS,KAAI;AACtB;AAOO,eAAejB,GAAWP,GAAW;;AAC1C,QAAMjB,IAAc,IAAI,gBAAgB;AAAA,IACtC,WAAAiB;AAAA,EACJ,CAAG,GACKwB,IAAW,MAAMmB,GAAa,YAAY5D,EAAY,SAAQ,CAAE,IAAI,KAAK;AAE/E,MAAI,CAACyC,EAAS;AACZ,UAAM,IAAI,MAAM,iDAAiD;AAGnE,QAAMjC,IAAO,MAAMiC,EAAS,KAAI,GAC1BnB,IAAUd,KAAA,gBAAAA,EAAM,SAChBa,MAAYwC,IAAArD,KAAA,gBAAAA,EAAM,YAAN,OAAAqD,IAAiB,CAAA,GAAI,IAAI,CAAChB,OAAS;AAAA,IACnD,IAAIA,EAAI;AAAA,IACR,MAAMA,EAAI;AAAA,IACV,MAAMA,EAAI,eACNlE,EAAc,YACdkE,EAAI;AAAA,IACR,WAAWA,EAAI;AAAA,IACf,OAAOA,EAAI;AAAA,IACX,SAASA,EAAI;AAAA,IACb,MAAM;AAAA,EACV,EAAI;AAEF,SAAO,EAAE,SAAAvB,GAAS,UAAAD,EAAQ;AAC5B;AASA,eAAeuC,GAAaE,GAAUC,IAAS,OAAOC,IAAO,MAAM;AACjE,QAAMpE,IAAcC,EAAc,GAE5B,EAAE,UAAA4D,GAAU,OAAAQ,EAAK,IAAKrE,KAAe,CAAA;AAC3C,MAAI,CAAC6D;AACH,UAAM,IAAI,MAAMD,EAAoB;AAGtC,QAAMlF,IAAM,GAAGmF,CAAQ,GAAGK,CAAQ,IAE5BvB,IAAU;AAAA,IACd,gBAAgB;AAAA,EACpB;AACE,SAAI0B,MACF1B,EAAQ,gBAAgB,UAAU0B,CAAK,KAGlC,MAAM3F,GAAK;AAAA,IAChB,SAAAiE;AAAA,IACA,QAAAwB;AAAA,IACA,MAAMC,IAAO,KAAK,UAAUA,CAAI,IAAI;AAAA,EACxC,CAAG;AACH;AC9EA,SAASjF,GAAc8B,IAAY,IAAI;AACrC,SAAO;AAAA,IACL,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,aAAa;AAAA,IACb,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAAA;AAAA,IACA,oBAAoB,CAAA;AAAA,IACpB,4BAA4B,CAAA;AAAA,EAChC;AACA;AAGA,IAAI7B,IAAiBD,GAAa;AAElC,MAAMmF,KAAY;AAAA,EAChB,YAAY,CAAC,EAAE,MAAM,+BAA8B,GAAI,EAAE,MAAM,gCAA+B,CAAE;AAClG;AAMO,SAASC,GAAiBtD,GAAW;AAC1C,EAAA7B,EAAe,YAAY,EAAE,GAAGA,EAAe,WAAW,GAAG6B,EAAS;AACxE;AAKA,SAASc,KAAU;AACjB,EAAI3C,EAAe,mBACjBA,EAAe,eAAe,MAAK,GACnCA,EAAe,iBAAiB,OAG9BA,EAAe,gBACjBA,EAAe,YAAY,UAAS,EAAG,QAAQ,CAACoF,MAAUA,EAAM,KAAI,CAAE,GACtEpF,EAAe,cAAc,OAG3BA,EAAe,iBACjBA,EAAe,eAAe,OAG5BA,EAAe,gBACjBA,EAAe,YAAY,YAAY,MACnCA,EAAe,YAAY,cAC7BA,EAAe,YAAY,WAAW,YAAYA,EAAe,WAAW,GAE9EA,EAAe,cAAc,OAG3BA,EAAe,WACjBA,EAAe,OAAO,MAAK,GAC3BA,EAAe,SAAS,OAG1BC,EAAgB;AAEhB,QAAM4B,IAAY7B,EAAe;AACjC,EAAAA,IAAiBD,GAAc8B,CAAS;AAG1C;AAMA,SAASwD,EAAcC,GAAQ;;AAC7B,EAAAtF,EAAe,aAAasF,IAC5BC,KAAAV,IAAA7E,EAAe,WAAU,iBAAzB,QAAAuF,EAAA,KAAAV,GAAwCS;AAC1C;AAMA,SAASE,EAAanE,GAAO;;AAC3B,GAAAkE,KAAAV,IAAA7E,EAAe,WAAU,gBAAzB,QAAAuF,EAAA,KAAAV,GAAuCxD;AACzC;AAKA,SAASpB,IAAmB;AAC1B,EAAID,EAAe,iBACjB,cAAcA,EAAe,YAAY,GACzCA,EAAe,eAAe;AAElC;AAKA,SAASE,KAAoB;AAC3B,EAAAD,EAAgB,GAEhBD,EAAe,eAAe,YAAY,MAAM;AAC9C,QAAIA,EAAe,UAAUA,EAAe,OAAO,eAAe,UAAU,MAAM;AAChF,MAAAA,EAAe;AACf,YAAMyF,IAAc;AAAA,QAClB,MAAM;AAAA,QACN,WAAW,KAAK,IAAG;AAAA,QACnB,OAAOzF,EAAe;AAAA,MAC9B;AACM,MAAA0F,EAAUD,CAAW;AAAA,IAEvB;AAEE,MAAAxF,EAAgB;AAAA,EAEpB,GAAG,GAAK;AACV;AAKA,SAAS0F,KAAa;AACpB,EAAA3F,EAAe,eAAe,KAAK,IAAG;AAExC;AAMA,SAAS0F,EAAUjF,GAAS;AAC1B,EAAKT,EAAe,UAIhBA,EAAe,OAAO,eAAe,UAAU,QAKnDA,EAAe,OAAO,KAAK,KAAK,UAAUS,CAAO,CAAC;AACpD;AAKA,eAAemF,KAAe;AAC5B,MAAI;AACF,IAAA5F,EAAe,cAAc,MAAM,UAAU,aAAa,aAAa;AAAA,MACrE,OAAO;AAAA,MACP,OAAO;AAAA,IACb,CAAK;AAAA,EAEH,SAASqB,GAAO;AAEd,UAAMA;AAAA,EACR;AACF;AAKA,SAASwE,KAAuB;AAC9B,EAAA7F,EAAe,iBAAiB,IAAI,kBAAkBkF,EAAS,GAE/DlF,EAAe,eAAe,iBAAiB,CAACkB,MAAU;AACxD,QAAIA,EAAM,WAAW;AACnB,YAAM4E,IAAgB,KAAK,UAAU5E,EAAM,SAAS;AAEpD,MAAIlB,EAAe,kBAAkBA,EAAe,eAAe,oBACjE0F,EAAU;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,WAAWI;AAAA,QACvB;AAAA,MACA,CAAS,IAGD9F,EAAe,mBAAmB,KAAK8F,CAAa;AAAA,IAGxD;AAAA,EACF,GAEA9F,EAAe,eAAe,UAAU,CAACkB,MAAU;AAEjD,IAAAlB,EAAe,eAAekB,EAAM,QAAQ,CAAC,GAExClB,EAAe,gBAClBA,EAAe,cAAc,SAAS,cAAc,OAAO,GAC3DA,EAAe,YAAY,WAAW,IACtCA,EAAe,YAAY,WAAW,IACtC,SAAS,KAAK,YAAYA,EAAe,WAAW,IAEtDA,EAAe,YAAY,YAAYA,EAAe,cAEtDA,EAAe,YACZ,KAAI,EACJ,KAAK,MAAA;AAAA,KAA4C,EACjD,MAAM,CAAC+F,MAAG;AAAA,KAA4C;AAAA,EAC3D,GAEA/F,EAAe,eAAe,0BAA0B,MAAM;AAC5D,UAAMgG,IAAWhG,EAAe,eAAe;AAG/C,IAAIgG,MAAa,cACfX,EAAc,WAAW,KAChBW,MAAa,kBAAkBA,MAAa,cACrDX,EAAc,cAAc,GAC5BY,GAAc;AAAA,EAElB,GAEAjG,EAAe,eAAe,6BAA6B,MAAM;AAAA,EAEjE;AACF;AAMA,SAASQ,GAAcC,GAAS;AAC9B,SAAO,IAAI,QAAQ,CAACC,GAASC,MAAW;AACtC,QACEX,EAAe,WACdA,EAAe,OAAO,eAAe,UAAU,cAC9CA,EAAe,OAAO,eAAe,UAAU,OACjD;AAEA,MAAAU,EAAQV,EAAe,OAAO,eAAe,UAAU,IAAI;AAC3D;AAAA,IACF;AAGA,UAAMY,IAAcC,EAAc;AAClC,QAAI,CAACD,KAAe,CAACA,EAAY,UAAU;AACzC,MAAAD,EAAO,IAAI,MAAM,mDAAmD,CAAC;AACrE;AAAA,IACF;AAGA,UAAMlB,IAAiBC,GAAsBkB,EAAY,QAAQ;AACjE,QAAI,CAACnB,GAAgB;AACnB,MAAAkB;AAAA,QACE,IAAI;AAAA,UACF;AAAA,QACV;AAAA,MACA;AACM;AAAA,IACF;AAEA,UAAMG,IAAaC,EAAa,GAC1BC,IAAc,IAAI,gBAAgB;AAAA,MACtC,YAAAF;AAAA,IACN,CAAK;AACD,IAAIL,EAAQ,aACVO,EAAY,IAAI,aAAaP,EAAQ,SAAS,GAE5CG,EAAY,SACdI,EAAY,IAAI,SAASJ,EAAY,KAAK;AAG5C,UAAMK,IAAY,GAAGxB,CAAc,IAAIuB,EAAY,UAAU;AAC7D,IAAAhB,EAAe,SAAS,IAAI,UAAUiB,CAAS,GAE/CjB,EAAe,OAAO,SAAS,CAACkB,MAAU;AAExC,MAAAhB,GAAiB,GACjBQ,EAAQ,EAAI;AAAA,IACd,GAEAV,EAAe,OAAO,YAAY,CAACkB,MAAU;AAC3C,YAAMM,IAAO,KAAK,MAAMN,EAAM,IAAI;AAClC,MAAAgF,GAAsB1E,CAAI;AAAA,IAC5B,GAEAxB,EAAe,OAAO,UAAU,CAACqB,MAAU;AAEzC,MAAAgE,EAAc,OAAO,GACrBG,EAAanE,EAAM,WAAW,yBAAyB,GACvDV,EAAOU,CAAK;AAAA,IACd,GAEArB,EAAe,OAAO,UAAU,CAACkB,MAAU;AAEzC,MAAAjB,EAAgB;AAAA,IAClB;AAAA,EACF,CAAC;AACH;AAMA,SAASiG,GAAsBC,GAAQ;AAGrC,UAAQA,EAAO,MAAI;AAAA,IACjB,KAAK;AACH,MAAAR,GAAU;AACV;AAAA,IAEF,KAAK;AACH,MAAAS,GAAaD,EAAO,IAAI;AACxB;AAAA,IAEF,KAAK;AACH,MAAAE,GAAmBF,EAAO,IAAI;AAC9B;AAAA,IAEF,KAAK;AACH,MAAAG,GAAyBH,EAAO,IAAI;AACpC;AAAA,IACF,KAAK;AACH,MAAAF,GAAc;AACd;AAAA,IACF,KAAK;AACH,MAAAZ,EAAc,OAAO,GACrBG,EAAaW,EAAO,SAAS,yBAAyB;AACtD;AAAA,IAEF;AAEE;AAAA,EACN;AACA;AAMA,eAAeC,GAAa5E,GAAM;AAChC,MAAI;AAOF,QAJAxB,EAAe,YAAYwB,EAAK,WAEhCQ,GAAgBR,EAAK,SAAS,GAE1BxB,EAAe,gBAAgB;AACjC,YAAMuG,IAAS,IAAI,sBAAsB;AAAA,QACvC,MAAM;AAAA,QACN,KAAK/E,EAAK;AAAA,MAClB,CAAO;AAED,YAAMxB,EAAe,eAAe,qBAAqBuG,CAAM;AAI/D,iBAAWT,KAAiB9F,EAAe;AACzC,QAAA0F,EAAU;AAAA,UACR,MAAM;AAAA,UACN,MAAM;AAAA,YACJ,WAAWI;AAAA,UACvB;AAAA,QACA,CAAS;AAGH,MAAA9F,EAAe,qBAAqB,CAAA;AAGpC,iBAAW8F,KAAiB9F,EAAe;AACzC,YAAI;AACF,gBAAMwG,IAAY,IAAI,gBAAgB,KAAK,MAAMV,CAAa,CAAC;AAC/D,gBAAM9F,EAAe,eAAe,gBAAgBwG,CAAS;AAAA,QAE/D,SAAST,GAAK;AAAA,QAEd;AAEF,MAAA/F,EAAe,6BAA6B,CAAA;AAAA,IAC9C;AAAA,EACF,SAASqB,GAAO;AAAA,EAEhB;AACF;AAMA,eAAegF,GAAmB7E,GAAM;AACtC,MAAI;AACF,QAAIxB,EAAe,gBAAgB;AAEjC,UAAI,CAACA,EAAe,eAAe,mBAAmB;AAEpD,QAAAA,EAAe,2BAA2B,KAAKwB,EAAK,SAAS;AAE7D;AAAA,MACF;AACA,YAAMgF,IAAY,IAAI,gBAAgB,KAAK,MAAMhF,EAAK,SAAS,CAAC;AAChE,YAAMxB,EAAe,eAAe,gBAAgBwG,CAAS;AAAA,IAE/D;AAAA,EACF,SAASnF,GAAO;AAAA,EAEhB;AACF;AAMA,eAAeiF,GAAyB9E,GAAM;AAC5C,MAAI;AAGF,QAAIxB,EAAe,gBAAgB;AACjC,YAAMyG,IAAQ,IAAI,sBAAsB;AAAA,QACtC,MAAM;AAAA,QACN,KAAKjF,EAAK;AAAA,MAClB,CAAO;AAED,YAAMxB,EAAe,eAAe,qBAAqByG,CAAK;AAG9D,YAAMF,IAAS,MAAMvG,EAAe,eAAe,aAAY;AAC/D,YAAMA,EAAe,eAAe,oBAAoBuG,CAAM,GAE9Db,EAAU;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,KAAKa,EAAO;AAAA,QACtB;AAAA,MACA,CAAO;AAAA,IACH;AAAA,EACF,SAASlF,GAAO;AAAA,EAEhB;AACF;AAMO,eAAeqF,GAAUjG,IAAU,IAAI;AAC5C,MAAI;AACF,QAAIT,EAAe,eAAe,gBAAgBA,EAAe,eAAe;AAE9E;AAIF,IAAAqF,EAAc,YAAY,GAC1BG,EAAa,IAAI,GAEjBxF,EAAe,YAAYS,EAAQ,WAEnC,MAAMmF,GAAY,GAElBC,GAAoB,GAEpB7F,EAAe,YAAY,UAAS,EAAG,QAAQ,CAACoF,MAAU;AACxD,MAAApF,EAAe,eAAe,SAASoF,GAAOpF,EAAe,WAAW;AAAA,IAE1E,CAAC,GACD,MAAMQ,GAAcC,CAAO;AAC3B,UAAMgG,IAAQ,MAAMzG,EAAe,eAAe,YAAW;AAC7D,UAAMA,EAAe,eAAe,oBAAoByG,CAAK,GAE7Df,EAAU;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,KAAKe,EAAM;AAAA,MACnB;AAAA,IACA,CAAK;AAAA,EAGH,SAASpF,GAAO;AAGd,IAAAgE,EAAc,OAAO,GACrBG,EAAanE,EAAM,WAAW,yBAAyB,GACvDsB,GAAO;AAAA,EACT;AACF;AAKO,SAASsD,KAAiB;AAC/B,EAAAP,EAAU;AAAA,IACR,MAAM;AAAA,EACV,CAAG,GACG1F,EAAe,WACjBA,EAAe,OAAO,MAAK,GAC3BA,EAAe,SAAS,OAE1BqF,EAAc,cAAc,GACxBrF,EAAe,mBACjBA,EAAe,eAAe,MAAK,GACnCA,EAAe,iBAAiB,OAE9BA,EAAe,gBACjBA,EAAe,YAAY,UAAS,EAAG,QAAQ,CAACoF,MAAUA,EAAM,KAAI,CAAE,GACtEpF,EAAe,cAAc,OAE/B2C,GAAO;AACT;AAMO,SAASgE,KAAa;AAC3B,MAAI3G,EAAe,aAAa;AAC9B,UAAM4G,IAAa5G,EAAe,YAAY,eAAc,EAAG,CAAC;AAChE,QAAI4G;AACF,aAAAA,EAAW,UAAU,CAACA,EAAW,SACjC5G,EAAe,UAAU,CAAC4G,EAAW,SAE9B5G,EAAe;AAAA,EAE1B;AACA,SAAO;AACT;AAMO,SAAS6G,KAAiB;AAC/B,SAAO7G,EAAe;AACxB;AAMO,SAAS8G,KAAwB;AACtC,SAAO,IAAI,QAAQ,CAAC5H,GAASyB,MAAW;AACtC,QAAI,CAACX,EAAe,gBAAgB;AAClC,MAAAW,EAAO,IAAI,MAAM,oBAAoB,CAAC;AACtC;AAAA,IACF;AACA,IAAAX,EAAe,eACZ,SAAQ,EACR,KAAK,CAAC+G,MAAU;AACf,MAAAA,EAAM,QAAQ,CAACC,MAAW;AACxB,QAAIA,EAAO,QAAQ,iBACjB9H,EAAQ8H,EAAO,gBAAgB;AAAA,MAEnC,CAAC,GACDrG,EAAO,IAAI,MAAM,4BAA4B,CAAC;AAAA,IAChD,CAAC,EACA,MAAM,CAACoF,MAAQ;AACd,MAAApF,EAAOoF,CAAG;AAAA,IACZ,CAAC;AAAA,EACL,CAAC;AACH;AAMO,SAASkB,KAAyB;AACvC,SAAO,IAAI,QAAQ,CAAC/H,GAASyB,MAAW;AACtC,QAAI,CAACX,EAAe,gBAAgB;AAClC,MAAAW,EAAO,IAAI,MAAM,oBAAoB,CAAC;AACtC;AAAA,IACF;AACA,IAAAX,EAAe,eACZ,SAAQ,EACR,KAAK,CAAC+G,MAAU;AACf,MAAAA,EAAM,QAAQ,CAACC,MAAW;AACxB,QAAIA,EAAO,QAAQ,kBACjB9H,EAAQ8H,EAAO,gBAAgB;AAAA,MAEnC,CAAC,GACDrG,EAAO,IAAI,MAAM,6BAA6B,CAAC;AAAA,IACjD,CAAC,EACA,MAAM,CAACoF,MAAQ;AACd,MAAApF,EAAOoF,CAAG;AAAA,IACZ,CAAC;AAAA,EACL,CAAC;AACH;"}
|
package/package.json
CHANGED
package/src/chat.js
CHANGED
|
@@ -348,6 +348,8 @@ export function sendMessage({ text, html, context }) {
|
|
|
348
348
|
)
|
|
349
349
|
currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)
|
|
350
350
|
reject(new Error(errorMessage))
|
|
351
|
+
} else if (response.event === 'done') {
|
|
352
|
+
resolve(currentSession.sessionId)
|
|
351
353
|
} else if (data.message !== undefined) {
|
|
352
354
|
// If role is supervisor, treat it as a new message
|
|
353
355
|
if (data.role === MESSAGE_ROLES.SUPERVISOR) {
|
|
@@ -361,7 +363,7 @@ export function sendMessage({ text, html, context }) {
|
|
|
361
363
|
resolve(currentSession.sessionId)
|
|
362
364
|
|
|
363
365
|
// Store session info for reuse
|
|
364
|
-
currentSession.sessionId = data.
|
|
366
|
+
currentSession.sessionId = data.sessionId ?? currentSession.sessionId
|
|
365
367
|
currentSession.requestId = data.requestId ?? currentSession.requestId
|
|
366
368
|
return
|
|
367
369
|
}
|
|
@@ -398,11 +400,10 @@ export function sendMessage({ text, html, context }) {
|
|
|
398
400
|
currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)
|
|
399
401
|
|
|
400
402
|
if (data.done) {
|
|
401
|
-
resolve(currentSession.sessionId)
|
|
402
403
|
}
|
|
403
404
|
|
|
404
405
|
// Store session info for reuse
|
|
405
|
-
currentSession.sessionId = data.
|
|
406
|
+
currentSession.sessionId = data.sessionId ?? currentSession.sessionId
|
|
406
407
|
currentSession.requestId = data.requestId ?? currentSession.requestId
|
|
407
408
|
}
|
|
408
409
|
},
|
package/src/constants.js
CHANGED
|
@@ -6,11 +6,5 @@ export const MESSAGE_ROLES = {
|
|
|
6
6
|
ASSISTANT: 'assistant', // this can be automated or LLM AI Agent response
|
|
7
7
|
USER: 'user', // this is widget user
|
|
8
8
|
SUPERVISOR: 'supervisor', // this is human supervisor (ex. Samespace Dock agent, or Resolve human agent)
|
|
9
|
-
SYSTEM: 'system'
|
|
10
|
-
|
|
11
|
-
// Deprecated aliases for backwards compatibility (will be removed in v1.0)
|
|
12
|
-
/** @deprecated Use ASSISTANT instead */
|
|
13
|
-
BOT: 'assistant',
|
|
14
|
-
/** @deprecated Use SUPERVISOR instead */
|
|
15
|
-
AGENT: 'supervisor'
|
|
9
|
+
SYSTEM: 'system' // this is system message, for ex "Agent joined" / "Agent left"
|
|
16
10
|
}
|