@origonai/web-chat-sdk 1.0.4 → 1.0.5
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/dist/origon-chat-sdk.js +230 -223
- package/dist/origon-chat-sdk.js.map +1 -1
- package/package.json +1 -1
- package/src/chat.js +11 -0
package/dist/origon-chat-sdk.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { fetchEventSource as
|
|
2
|
-
function
|
|
1
|
+
import { fetchEventSource as ie } from "@microsoft/fetch-event-source";
|
|
2
|
+
function B() {
|
|
3
3
|
const e = Date.now(), t = new Uint8Array(16);
|
|
4
4
|
crypto.getRandomValues(t), t[0] = e >> 40 & 255, t[1] = e >> 32 & 255, t[2] = e >> 24 & 255, t[3] = e >> 16 & 255, t[4] = e >> 8 & 255, t[5] = e & 255, t[6] = t[6] & 15 | 112, t[8] = t[8] & 63 | 128;
|
|
5
|
-
const s = [...t].map((
|
|
5
|
+
const s = [...t].map((a) => a.toString(16).padStart(2, "0")).join("");
|
|
6
6
|
return `${s.slice(0, 8)}-${s.slice(8, 12)}-${s.slice(12, 16)}-${s.slice(
|
|
7
7
|
16,
|
|
8
8
|
20
|
|
9
9
|
)}-${s.slice(20)}`;
|
|
10
10
|
}
|
|
11
|
-
function
|
|
11
|
+
function le() {
|
|
12
12
|
if (localStorage.getItem("chatDeviceId"))
|
|
13
13
|
return localStorage.getItem("chatDeviceId");
|
|
14
|
-
const e =
|
|
14
|
+
const e = B();
|
|
15
15
|
return localStorage.setItem("chatDeviceId", e), e;
|
|
16
16
|
}
|
|
17
|
-
async function
|
|
17
|
+
async function de(e) {
|
|
18
18
|
return new Promise((t) => setTimeout(t, e));
|
|
19
19
|
}
|
|
20
|
-
function
|
|
20
|
+
function ue(e) {
|
|
21
21
|
let t;
|
|
22
22
|
try {
|
|
23
23
|
const s = new URL(e);
|
|
@@ -26,7 +26,7 @@ function le(e) {
|
|
|
26
26
|
}
|
|
27
27
|
return t;
|
|
28
28
|
}
|
|
29
|
-
function
|
|
29
|
+
function ge(e) {
|
|
30
30
|
let t;
|
|
31
31
|
try {
|
|
32
32
|
const s = new URL(e);
|
|
@@ -35,7 +35,7 @@ function de(e) {
|
|
|
35
35
|
}
|
|
36
36
|
return t;
|
|
37
37
|
}
|
|
38
|
-
function
|
|
38
|
+
function fe(e) {
|
|
39
39
|
let t;
|
|
40
40
|
try {
|
|
41
41
|
const s = new URL(e);
|
|
@@ -44,7 +44,7 @@ function ue(e) {
|
|
|
44
44
|
}
|
|
45
45
|
return t;
|
|
46
46
|
}
|
|
47
|
-
const
|
|
47
|
+
const y = {
|
|
48
48
|
ASSISTANT: "assistant",
|
|
49
49
|
// this can be automated or LLM AI Agent response
|
|
50
50
|
USER: "user",
|
|
@@ -53,13 +53,13 @@ const w = {
|
|
|
53
53
|
// this is human supervisor (ex. Samespace Dock agent, or Resolve human agent)
|
|
54
54
|
SYSTEM: "system"
|
|
55
55
|
// this is system message, for ex "Agent joined" / "Agent left"
|
|
56
|
-
},
|
|
56
|
+
}, Q = 1e4, pe = 5e3, D = {
|
|
57
57
|
MESSAGE: "message",
|
|
58
58
|
TYPING: "typing",
|
|
59
59
|
TYPING_STOP: "typingOff",
|
|
60
60
|
END: "end"
|
|
61
61
|
};
|
|
62
|
-
function
|
|
62
|
+
function me() {
|
|
63
63
|
return {
|
|
64
64
|
socket: null,
|
|
65
65
|
previouslyConnected: !1,
|
|
@@ -69,36 +69,36 @@ function fe() {
|
|
|
69
69
|
socketConnectionTimeout: null
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
|
-
let c =
|
|
72
|
+
let c = me();
|
|
73
73
|
function U() {
|
|
74
74
|
c.pingInterval && (clearInterval(c.pingInterval), c.pingInterval = null);
|
|
75
75
|
}
|
|
76
|
-
function
|
|
76
|
+
function Se() {
|
|
77
77
|
U(), c.pingInterval = setInterval(() => {
|
|
78
78
|
c.socket && c.socket.readyState === WebSocket.OPEN ? O({ type: "ping" }) : U();
|
|
79
|
-
},
|
|
79
|
+
}, Q);
|
|
80
80
|
}
|
|
81
|
-
function
|
|
81
|
+
function Z() {
|
|
82
82
|
U(), c.socketDisconnectedTimeout && (clearTimeout(c.socketDisconnectedTimeout), c.socketDisconnectedTimeout = null), c.socketConnectionTimeout && (clearTimeout(c.socketConnectionTimeout), c.socketConnectionTimeout = null);
|
|
83
83
|
}
|
|
84
|
-
function
|
|
85
|
-
c.socketDisconnected = !1,
|
|
84
|
+
function j() {
|
|
85
|
+
c.socketDisconnected = !1, $("socket");
|
|
86
86
|
}
|
|
87
|
-
function
|
|
88
|
-
c.socketDisconnected = !0,
|
|
87
|
+
function X() {
|
|
88
|
+
c.socketDisconnected = !0, $("sse");
|
|
89
89
|
}
|
|
90
|
-
function
|
|
90
|
+
function ke(e) {
|
|
91
91
|
return new Promise((t, s) => {
|
|
92
92
|
if (c.socket && (c.socket.readyState === WebSocket.CONNECTING || c.socket.readyState === WebSocket.OPEN)) {
|
|
93
93
|
t(c.socket.readyState === WebSocket.OPEN);
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
|
-
const
|
|
97
|
-
if (!
|
|
96
|
+
const a = N();
|
|
97
|
+
if (!a || !a.endpoint) {
|
|
98
98
|
s(new Error("SDK not initialized. Please initialize SDK first."));
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
|
-
const d =
|
|
101
|
+
const d = ge(a.endpoint);
|
|
102
102
|
if (!d) {
|
|
103
103
|
s(
|
|
104
104
|
new Error(
|
|
@@ -107,74 +107,74 @@ function me(e) {
|
|
|
107
107
|
);
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
|
-
const f =
|
|
110
|
+
const f = A(), i = new URLSearchParams({
|
|
111
111
|
externalId: f
|
|
112
112
|
});
|
|
113
|
-
e.sessionId && i.set("sessionId", e.sessionId), e.requestId && i.set("requestId", e.requestId),
|
|
113
|
+
e.sessionId && i.set("sessionId", e.sessionId), e.requestId && i.set("requestId", e.requestId), a.token && i.set("token", a.token);
|
|
114
114
|
const u = `${d}?${i.toString()}`;
|
|
115
115
|
c.socket = new WebSocket(u), c.socket.onopen = () => {
|
|
116
|
-
c.previouslyConnected = !0,
|
|
116
|
+
c.previouslyConnected = !0, j(), O({ type: "ping" }), clearTimeout(c.socketConnectionTimeout), Se(), t(!0);
|
|
117
117
|
}, c.socket.onmessage = (l) => {
|
|
118
|
-
const
|
|
119
|
-
|
|
118
|
+
const S = JSON.parse(l.data);
|
|
119
|
+
Ie(S);
|
|
120
120
|
}, c.socket.onerror = (l) => {
|
|
121
|
-
|
|
121
|
+
$("sse"), s(l);
|
|
122
122
|
}, c.socket.onclose = (l) => {
|
|
123
|
-
l.target === c.socket && (l.code === 1006 && (c.previouslyConnected ?
|
|
123
|
+
l.target === c.socket && (l.code === 1006 && (c.previouslyConnected ? X() : I({
|
|
124
124
|
errorText: "Unable to establish connection",
|
|
125
125
|
done: !0,
|
|
126
126
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
127
|
-
}), clearTimeout(c.socketConnectionTimeout)), c.socket = null,
|
|
127
|
+
}), clearTimeout(c.socketConnectionTimeout)), c.socket = null, Z());
|
|
128
128
|
}, c.previouslyConnected || (c.socketConnectionTimeout = setTimeout(() => {
|
|
129
|
-
|
|
129
|
+
I({
|
|
130
130
|
errorText: "Unable to establish connection",
|
|
131
131
|
done: !0,
|
|
132
132
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
133
133
|
}), s(new Error("Socket connection timed out"));
|
|
134
|
-
},
|
|
134
|
+
}, pe));
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
function O(e) {
|
|
138
|
-
c.socketDisconnected || !c.socket || c.socket.send(JSON.stringify({ ...e, eventId: e.eventId ||
|
|
138
|
+
c.socketDisconnected || !c.socket || c.socket.send(JSON.stringify({ ...e, eventId: e.eventId || B() }));
|
|
139
139
|
}
|
|
140
|
-
function
|
|
140
|
+
function Ie(e) {
|
|
141
141
|
switch (e.type) {
|
|
142
142
|
case "pong": {
|
|
143
|
-
c.socketDisconnected &&
|
|
144
|
-
|
|
145
|
-
},
|
|
143
|
+
c.socketDisconnected && j(), c.socketDisconnectedTimeout && clearTimeout(c.socketDisconnectedTimeout), c.socketDisconnectedTimeout = setTimeout(() => {
|
|
144
|
+
X();
|
|
145
|
+
}, Q + 1e3);
|
|
146
146
|
break;
|
|
147
147
|
}
|
|
148
|
-
case
|
|
149
|
-
|
|
148
|
+
case D.TYPING: {
|
|
149
|
+
Y(!0);
|
|
150
150
|
break;
|
|
151
151
|
}
|
|
152
|
-
case
|
|
153
|
-
|
|
152
|
+
case D.TYPING_STOP: {
|
|
153
|
+
Y(!1);
|
|
154
154
|
break;
|
|
155
155
|
}
|
|
156
|
-
case
|
|
156
|
+
case D.MESSAGE: {
|
|
157
157
|
const { eventId: t, data: s } = e;
|
|
158
|
-
t ||
|
|
158
|
+
t || I({
|
|
159
159
|
...s,
|
|
160
160
|
done: !0,
|
|
161
161
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
162
162
|
});
|
|
163
163
|
break;
|
|
164
164
|
}
|
|
165
|
-
case
|
|
166
|
-
|
|
165
|
+
case D.END: {
|
|
166
|
+
ee();
|
|
167
167
|
break;
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
function
|
|
172
|
-
c.socket && c.socket.close(1e3), c.previouslyConnected = !1,
|
|
171
|
+
function ee() {
|
|
172
|
+
c.socket && c.socket.close(1e3), c.previouslyConnected = !1, Z(), c.socket = null, $("sse");
|
|
173
173
|
}
|
|
174
|
-
function
|
|
174
|
+
function Ce() {
|
|
175
175
|
return c.socket !== null && c.socket.readyState === WebSocket.OPEN && !c.socketDisconnected;
|
|
176
176
|
}
|
|
177
|
-
function
|
|
177
|
+
function ne(e = {}) {
|
|
178
178
|
return {
|
|
179
179
|
credentials: void 0,
|
|
180
180
|
authenticated: !1,
|
|
@@ -190,108 +190,108 @@ function X(e = {}) {
|
|
|
190
190
|
control: "agent"
|
|
191
191
|
};
|
|
192
192
|
}
|
|
193
|
-
let o =
|
|
194
|
-
function
|
|
193
|
+
let o = ne();
|
|
194
|
+
function Le(e) {
|
|
195
195
|
o.callbacks = { ...o.callbacks, ...e };
|
|
196
196
|
}
|
|
197
|
-
function
|
|
197
|
+
function Ge(e) {
|
|
198
198
|
o.credentials = e, e.token && (o.authenticated = !0);
|
|
199
199
|
}
|
|
200
200
|
function N() {
|
|
201
201
|
return o.credentials;
|
|
202
202
|
}
|
|
203
|
-
function
|
|
203
|
+
function he(e) {
|
|
204
204
|
var t, s;
|
|
205
205
|
e && e !== o.sessionId && (o.sessionId = e, (s = (t = o.callbacks).onSessionUpdate) == null || s.call(t, e));
|
|
206
206
|
}
|
|
207
|
-
async function
|
|
207
|
+
async function ze(e = {}) {
|
|
208
208
|
try {
|
|
209
209
|
let t = null;
|
|
210
|
-
o.authenticated ? t = o.configData : (t = await
|
|
211
|
-
let s = [],
|
|
210
|
+
o.authenticated ? t = o.configData : (t = await Ee(o.credentials), o.authenticated = !0, o.configData = t);
|
|
211
|
+
let s = [], a = "agent";
|
|
212
212
|
if (e.sessionId) {
|
|
213
|
-
const f = await
|
|
214
|
-
s = f.messages,
|
|
213
|
+
const f = await ve(e.sessionId);
|
|
214
|
+
s = f.messages, a = f.control || "agent";
|
|
215
215
|
}
|
|
216
216
|
const d = new URLSearchParams();
|
|
217
|
-
return o.credentials.token || d.set("externalId",
|
|
217
|
+
return o.credentials.token || d.set("externalId", A()), o.sseUrl = `${ue(
|
|
218
218
|
o.credentials.endpoint
|
|
219
|
-
)}?${d.toString()}`, o.sessionId = e.sessionId, o.messages = s, o.control =
|
|
219
|
+
)}?${d.toString()}`, o.sessionId = e.sessionId, o.messages = s, o.control = a, a === "human" && we({ text: "", html: "" }).catch(() => {
|
|
220
220
|
}), {
|
|
221
221
|
sessionId: o.sessionId,
|
|
222
222
|
messages: s,
|
|
223
|
-
control:
|
|
223
|
+
control: a,
|
|
224
224
|
configData: t
|
|
225
225
|
};
|
|
226
226
|
} catch (t) {
|
|
227
|
-
throw
|
|
227
|
+
throw te(), t;
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
|
-
function
|
|
231
|
-
|
|
230
|
+
function Fe() {
|
|
231
|
+
te();
|
|
232
232
|
}
|
|
233
|
-
function
|
|
234
|
-
o.abortController && o.abortController.abort(),
|
|
233
|
+
function te() {
|
|
234
|
+
o.abortController && o.abortController.abort(), ee();
|
|
235
235
|
const { callbacks: e, credentials: t } = o;
|
|
236
|
-
o =
|
|
236
|
+
o = ne(e), o.credentials = t;
|
|
237
237
|
}
|
|
238
|
-
function
|
|
238
|
+
function A() {
|
|
239
239
|
var e;
|
|
240
|
-
return (e = o.credentials) != null && e.externalId ? o.credentials.externalId :
|
|
240
|
+
return (e = o.credentials) != null && e.externalId ? o.credentials.externalId : le();
|
|
241
241
|
}
|
|
242
|
-
function
|
|
242
|
+
function I(e) {
|
|
243
243
|
var t, s;
|
|
244
244
|
o.messages = [...o.messages, e], (s = (t = o.callbacks).onMessageAdd) == null || s.call(t, e);
|
|
245
245
|
}
|
|
246
|
-
function
|
|
246
|
+
function Y(e) {
|
|
247
247
|
var t, s;
|
|
248
248
|
(s = (t = o.callbacks).onTyping) == null || s.call(t, e);
|
|
249
249
|
}
|
|
250
|
-
function
|
|
250
|
+
function $(e) {
|
|
251
251
|
var t, s;
|
|
252
252
|
o.transport = e, (s = (t = o.callbacks).onTransportUpdate) == null || s.call(t, e);
|
|
253
253
|
}
|
|
254
|
-
function
|
|
255
|
-
return new Promise((
|
|
254
|
+
function we({ text: e, html: t, context: s }) {
|
|
255
|
+
return new Promise((a, d) => {
|
|
256
256
|
(async () => {
|
|
257
257
|
var f, i, u;
|
|
258
258
|
try {
|
|
259
259
|
const l = !e && !t;
|
|
260
260
|
if (!l) {
|
|
261
261
|
const g = {
|
|
262
|
-
role:
|
|
262
|
+
role: y.USER,
|
|
263
263
|
text: e,
|
|
264
264
|
html: t,
|
|
265
265
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
266
266
|
};
|
|
267
|
-
|
|
267
|
+
I(g), await de(200);
|
|
268
268
|
}
|
|
269
|
-
if (o.transport === "socket" &&
|
|
269
|
+
if (o.transport === "socket" && Ce()) {
|
|
270
270
|
O({
|
|
271
271
|
type: "message",
|
|
272
272
|
data: {
|
|
273
273
|
text: e,
|
|
274
274
|
html: t
|
|
275
275
|
}
|
|
276
|
-
}),
|
|
276
|
+
}), a(o.sessionId);
|
|
277
277
|
return;
|
|
278
278
|
}
|
|
279
279
|
if (o.control === "agent") {
|
|
280
280
|
const g = {
|
|
281
|
-
role:
|
|
281
|
+
role: y.ASSISTANT,
|
|
282
282
|
text: "",
|
|
283
283
|
loading: !0
|
|
284
284
|
};
|
|
285
|
-
|
|
285
|
+
I(g);
|
|
286
286
|
}
|
|
287
|
-
const
|
|
288
|
-
o.sessionId &&
|
|
289
|
-
const
|
|
287
|
+
const S = new URL(o.sseUrl);
|
|
288
|
+
o.sessionId && S.searchParams.set("sessionId", o.sessionId), o.requestId && S.searchParams.set("requestId", o.requestId), o.lastStreamId = void 0, o.abortController = new AbortController();
|
|
289
|
+
const h = {
|
|
290
290
|
"Content-Type": "application/json"
|
|
291
291
|
};
|
|
292
|
-
(f = o.credentials) != null && f.token && (
|
|
292
|
+
(f = o.credentials) != null && f.token && (h.Authorization = `Bearer ${o.credentials.token}`), await ie(S.toString(), {
|
|
293
293
|
method: "POST",
|
|
294
|
-
headers:
|
|
294
|
+
headers: h,
|
|
295
295
|
body: l ? void 0 : JSON.stringify({
|
|
296
296
|
message: e,
|
|
297
297
|
html: t,
|
|
@@ -304,62 +304,69 @@ function Ce({ text: e, html: t, context: s }) {
|
|
|
304
304
|
throw new Error("Failed to send message");
|
|
305
305
|
},
|
|
306
306
|
onmessage: (g) => {
|
|
307
|
-
var
|
|
308
|
-
const
|
|
307
|
+
var v, T, M, x, q, L, G, z, F, W, J, _, K, V, H;
|
|
308
|
+
const r = JSON.parse(g.data);
|
|
309
309
|
if (g.event === "connected")
|
|
310
|
-
o.sessionId =
|
|
310
|
+
o.sessionId = r.sessionId, o.requestId = r.requestId, r.control && (o.control = r.control, (T = (v = o.callbacks).onControlUpdate) == null || T.call(v, r.control));
|
|
311
311
|
else if (g.event === "upgrade_to_websocket")
|
|
312
|
-
|
|
312
|
+
ke({
|
|
313
313
|
sessionId: o.sessionId,
|
|
314
|
-
requestId:
|
|
314
|
+
requestId: r.requestId
|
|
315
315
|
});
|
|
316
316
|
else if (g.event === "update")
|
|
317
|
-
|
|
318
|
-
else if (
|
|
319
|
-
const
|
|
320
|
-
...o.messages[
|
|
317
|
+
r.control && (o.control = r.control, (x = (M = o.callbacks).onControlUpdate) == null || x.call(M, r.control));
|
|
318
|
+
else if (r.error) {
|
|
319
|
+
const p = r.error && typeof r.error == "string" ? r.error : "Failed to connect to the system", k = o.messages.length - 1, m = {
|
|
320
|
+
...o.messages[k],
|
|
321
321
|
loading: !1,
|
|
322
|
-
errorText:
|
|
322
|
+
errorText: p
|
|
323
323
|
};
|
|
324
324
|
o.messages = o.messages.map(
|
|
325
|
-
(
|
|
326
|
-
), (L = (q = o.callbacks).onMessageUpdate) == null || L.call(q,
|
|
327
|
-
} else if (g.event === "done")
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
325
|
+
(E, re) => re === k ? m : E
|
|
326
|
+
), (L = (q = o.callbacks).onMessageUpdate) == null || L.call(q, k, m), d(new Error(p));
|
|
327
|
+
} else if (g.event === "done") {
|
|
328
|
+
const p = o.messages.length - 1, w = {
|
|
329
|
+
...o.messages[p],
|
|
330
|
+
loading: !1,
|
|
331
|
+
done: !0
|
|
332
|
+
};
|
|
333
|
+
o.messages = o.messages.map(
|
|
334
|
+
(m, E) => E === p ? w : m
|
|
335
|
+
), (z = (G = o.callbacks).onMessageUpdate) == null || z.call(G, p, w), a(o.sessionId);
|
|
336
|
+
} else if (r.message !== void 0) {
|
|
337
|
+
if (r.role === y.SUPERVISOR) {
|
|
331
338
|
const m = {
|
|
332
|
-
role:
|
|
333
|
-
text:
|
|
334
|
-
sources:
|
|
339
|
+
role: y.SUPERVISOR,
|
|
340
|
+
text: r.message,
|
|
341
|
+
sources: r.sources,
|
|
335
342
|
done: !0
|
|
336
343
|
};
|
|
337
|
-
|
|
344
|
+
I(m), a(o.sessionId), o.sessionId = (F = r.sessionId) != null ? F : o.sessionId, o.requestId = (W = r.requestId) != null ? W : o.requestId;
|
|
338
345
|
return;
|
|
339
346
|
}
|
|
340
|
-
if (
|
|
347
|
+
if (r.streamId !== void 0) {
|
|
341
348
|
if (o.lastStreamId === void 0)
|
|
342
|
-
o.lastStreamId =
|
|
343
|
-
else if (
|
|
344
|
-
o.lastStreamId =
|
|
349
|
+
o.lastStreamId = r.streamId;
|
|
350
|
+
else if (r.streamId !== o.lastStreamId) {
|
|
351
|
+
o.lastStreamId = r.streamId;
|
|
345
352
|
const m = {
|
|
346
|
-
role:
|
|
353
|
+
role: y.ASSISTANT,
|
|
347
354
|
text: "",
|
|
348
355
|
loading: !0
|
|
349
356
|
};
|
|
350
|
-
|
|
357
|
+
I(m);
|
|
351
358
|
}
|
|
352
359
|
}
|
|
353
|
-
const
|
|
354
|
-
...
|
|
360
|
+
const p = o.messages.length - 1, k = o.messages[p], w = {
|
|
361
|
+
...k,
|
|
355
362
|
loading: !1,
|
|
356
|
-
text: (
|
|
357
|
-
sources:
|
|
358
|
-
done: (
|
|
363
|
+
text: (k.text || "") + r.message,
|
|
364
|
+
sources: r.sources,
|
|
365
|
+
done: (J = r.done) != null ? J : k.done
|
|
359
366
|
};
|
|
360
367
|
o.messages = o.messages.map(
|
|
361
|
-
(m,
|
|
362
|
-
), (
|
|
368
|
+
(m, E) => E === p ? w : m
|
|
369
|
+
), (K = (_ = o.callbacks).onMessageUpdate) == null || K.call(_, p, w), r.done, o.sessionId = (V = r.sessionId) != null ? V : o.sessionId, o.requestId = (H = r.requestId) != null ? H : o.requestId;
|
|
363
370
|
}
|
|
364
371
|
},
|
|
365
372
|
onerror: (g) => {
|
|
@@ -368,52 +375,52 @@ function Ce({ text: e, html: t, context: s }) {
|
|
|
368
375
|
openWhenHidden: !0
|
|
369
376
|
});
|
|
370
377
|
} catch (l) {
|
|
371
|
-
const
|
|
378
|
+
const S = "Failed to connect to the system", h = o.messages.length - 1, g = o.messages[h], r = {
|
|
372
379
|
...g,
|
|
373
380
|
loading: !1,
|
|
374
|
-
errorText: g.done ? void 0 : l.message ||
|
|
381
|
+
errorText: g.done ? void 0 : l.message || S,
|
|
375
382
|
done: !0
|
|
376
383
|
};
|
|
377
384
|
o.messages = o.messages.map(
|
|
378
|
-
(
|
|
379
|
-
), (u = (i = o.callbacks).onMessageUpdate) == null || u.call(i,
|
|
385
|
+
(v, T) => T === h ? r : v
|
|
386
|
+
), (u = (i = o.callbacks).onMessageUpdate) == null || u.call(i, h, r), d(l);
|
|
380
387
|
}
|
|
381
388
|
})();
|
|
382
389
|
});
|
|
383
390
|
}
|
|
384
|
-
const
|
|
385
|
-
async function
|
|
386
|
-
const { endpoint: t } = e, s = `${t}/config`,
|
|
391
|
+
const ye = "Something went wrong initializing the chat", be = "Chat SDK not initialized";
|
|
392
|
+
async function Ee(e) {
|
|
393
|
+
const { endpoint: t } = e, s = `${t}/config`, a = await fetch(s, {
|
|
387
394
|
method: "GET",
|
|
388
395
|
headers: {
|
|
389
396
|
"Content-Type": "application/json"
|
|
390
397
|
}
|
|
391
398
|
});
|
|
392
|
-
if (!
|
|
393
|
-
const i = await
|
|
394
|
-
throw new Error((i == null ? void 0 : i.error) ||
|
|
399
|
+
if (!a.ok) {
|
|
400
|
+
const i = await a.json();
|
|
401
|
+
throw new Error((i == null ? void 0 : i.error) || ye);
|
|
395
402
|
}
|
|
396
|
-
return (await
|
|
403
|
+
return (await a.json()).data;
|
|
397
404
|
}
|
|
398
|
-
async function
|
|
405
|
+
async function We() {
|
|
399
406
|
const e = new URLSearchParams({
|
|
400
|
-
externalId:
|
|
401
|
-
}), t = await
|
|
407
|
+
externalId: A()
|
|
408
|
+
}), t = await oe(`/sessions?${e.toString()}`, "GET");
|
|
402
409
|
if (!t.ok)
|
|
403
410
|
throw new Error("Unable to load history, please try again later");
|
|
404
411
|
return t.json();
|
|
405
412
|
}
|
|
406
|
-
async function
|
|
413
|
+
async function ve(e) {
|
|
407
414
|
var i;
|
|
408
415
|
const t = new URLSearchParams({
|
|
409
416
|
sessionId: e
|
|
410
|
-
}), s = await
|
|
417
|
+
}), s = await oe(`/session?${t.toString()}`, "GET");
|
|
411
418
|
if (!s.ok)
|
|
412
419
|
throw new Error("Unable to load messages, please try again later");
|
|
413
|
-
const
|
|
420
|
+
const a = await s.json(), d = a == null ? void 0 : a.control, f = ((i = a == null ? void 0 : a.history) != null ? i : []).map((u) => ({
|
|
414
421
|
id: u.id,
|
|
415
422
|
text: u.text,
|
|
416
|
-
role: u.youtubeVideo ?
|
|
423
|
+
role: u.youtubeVideo ? y.ASSISTANT : u.role,
|
|
417
424
|
timestamp: u.timestamp,
|
|
418
425
|
video: u.youtubeVideo,
|
|
419
426
|
channel: u.channel,
|
|
@@ -421,10 +428,10 @@ async function Ee(e) {
|
|
|
421
428
|
}));
|
|
422
429
|
return { control: d, messages: f };
|
|
423
430
|
}
|
|
424
|
-
async function
|
|
425
|
-
const
|
|
431
|
+
async function oe(e, t = "GET", s = null) {
|
|
432
|
+
const a = N(), { endpoint: d, token: f } = a || {};
|
|
426
433
|
if (!d)
|
|
427
|
-
throw new Error(
|
|
434
|
+
throw new Error(be);
|
|
428
435
|
const i = `${d}${e}`, u = {
|
|
429
436
|
"Content-Type": "application/json"
|
|
430
437
|
};
|
|
@@ -434,7 +441,7 @@ async function ne(e, t = "GET", s = null) {
|
|
|
434
441
|
body: s ? JSON.stringify(s) : null
|
|
435
442
|
});
|
|
436
443
|
}
|
|
437
|
-
function
|
|
444
|
+
function se(e = {}) {
|
|
438
445
|
return {
|
|
439
446
|
sessionId: void 0,
|
|
440
447
|
socket: null,
|
|
@@ -452,31 +459,31 @@ function te(e = {}) {
|
|
|
452
459
|
pendingRemoteIceCandidates: []
|
|
453
460
|
};
|
|
454
461
|
}
|
|
455
|
-
let n =
|
|
456
|
-
const
|
|
462
|
+
let n = se();
|
|
463
|
+
const Te = {
|
|
457
464
|
iceServers: [{ urls: "stun:stun.l.google.com:19302" }, { urls: "stun:stun1.l.google.com:19302" }]
|
|
458
465
|
};
|
|
459
|
-
function
|
|
466
|
+
function Je(e) {
|
|
460
467
|
n.callbacks = { ...n.callbacks, ...e };
|
|
461
468
|
}
|
|
462
|
-
function
|
|
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),
|
|
469
|
+
function ce() {
|
|
470
|
+
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), R();
|
|
464
471
|
const e = n.callbacks;
|
|
465
|
-
n =
|
|
472
|
+
n = se(e);
|
|
466
473
|
}
|
|
467
|
-
function
|
|
474
|
+
function C(e) {
|
|
468
475
|
var t, s;
|
|
469
476
|
n.callStatus = e, (s = (t = n.callbacks).onCallStatus) == null || s.call(t, e);
|
|
470
477
|
}
|
|
471
|
-
function
|
|
478
|
+
function P(e) {
|
|
472
479
|
var t, s;
|
|
473
480
|
(s = (t = n.callbacks).onCallError) == null || s.call(t, e);
|
|
474
481
|
}
|
|
475
|
-
function
|
|
482
|
+
function R() {
|
|
476
483
|
n.pingInterval && (clearInterval(n.pingInterval), n.pingInterval = null);
|
|
477
484
|
}
|
|
478
|
-
function
|
|
479
|
-
|
|
485
|
+
function De() {
|
|
486
|
+
R(), n.pingInterval = setInterval(() => {
|
|
480
487
|
if (n.socket && n.socket.readyState === WebSocket.OPEN) {
|
|
481
488
|
n.pingCount++;
|
|
482
489
|
const e = {
|
|
@@ -484,18 +491,18 @@ function ve() {
|
|
|
484
491
|
timestamp: Date.now(),
|
|
485
492
|
count: n.pingCount
|
|
486
493
|
};
|
|
487
|
-
|
|
494
|
+
b(e);
|
|
488
495
|
} else
|
|
489
|
-
|
|
496
|
+
R();
|
|
490
497
|
}, 1e4);
|
|
491
498
|
}
|
|
492
|
-
function
|
|
499
|
+
function Pe() {
|
|
493
500
|
n.lastPongTime = Date.now();
|
|
494
501
|
}
|
|
495
|
-
function
|
|
502
|
+
function b(e) {
|
|
496
503
|
n.socket && n.socket.readyState === WebSocket.OPEN && n.socket.send(JSON.stringify(e));
|
|
497
504
|
}
|
|
498
|
-
async function
|
|
505
|
+
async function Re() {
|
|
499
506
|
try {
|
|
500
507
|
n.localStream = await navigator.mediaDevices.getUserMedia({
|
|
501
508
|
audio: !0,
|
|
@@ -505,11 +512,11 @@ async function De() {
|
|
|
505
512
|
throw e;
|
|
506
513
|
}
|
|
507
514
|
}
|
|
508
|
-
function
|
|
509
|
-
n.peerConnection = new RTCPeerConnection(
|
|
515
|
+
function Ae() {
|
|
516
|
+
n.peerConnection = new RTCPeerConnection(Te), n.peerConnection.onicecandidate = (e) => {
|
|
510
517
|
if (e.candidate) {
|
|
511
518
|
const t = JSON.stringify(e.candidate);
|
|
512
|
-
n.peerConnection && n.peerConnection.remoteDescription ?
|
|
519
|
+
n.peerConnection && n.peerConnection.remoteDescription ? b({
|
|
513
520
|
type: "ice",
|
|
514
521
|
data: {
|
|
515
522
|
candidate: t
|
|
@@ -522,22 +529,22 @@ function Pe() {
|
|
|
522
529
|
});
|
|
523
530
|
}, n.peerConnection.onconnectionstatechange = () => {
|
|
524
531
|
const e = n.peerConnection.connectionState;
|
|
525
|
-
e === "connected" ?
|
|
532
|
+
e === "connected" ? C("connected") : (e === "disconnected" || e === "closed") && (C("disconnected"), ae());
|
|
526
533
|
}, n.peerConnection.oniceconnectionstatechange = () => {
|
|
527
534
|
};
|
|
528
535
|
}
|
|
529
|
-
function
|
|
536
|
+
function $e(e) {
|
|
530
537
|
return new Promise((t, s) => {
|
|
531
538
|
if (n.socket && (n.socket.readyState === WebSocket.CONNECTING || n.socket.readyState === WebSocket.OPEN)) {
|
|
532
539
|
t(n.socket.readyState === WebSocket.OPEN);
|
|
533
540
|
return;
|
|
534
541
|
}
|
|
535
|
-
const
|
|
536
|
-
if (!
|
|
542
|
+
const a = N();
|
|
543
|
+
if (!a || !a.endpoint) {
|
|
537
544
|
s(new Error("SDK not initialized. Please initialize SDK first."));
|
|
538
545
|
return;
|
|
539
546
|
}
|
|
540
|
-
const d =
|
|
547
|
+
const d = fe(a.endpoint);
|
|
541
548
|
if (!d) {
|
|
542
549
|
s(
|
|
543
550
|
new Error(
|
|
@@ -546,54 +553,54 @@ function Re(e) {
|
|
|
546
553
|
);
|
|
547
554
|
return;
|
|
548
555
|
}
|
|
549
|
-
const f =
|
|
556
|
+
const f = A(), i = new URLSearchParams({
|
|
550
557
|
externalId: f
|
|
551
558
|
});
|
|
552
|
-
e.sessionId && i.set("sessionId", e.sessionId),
|
|
559
|
+
e.sessionId && i.set("sessionId", e.sessionId), a.token && i.set("token", a.token);
|
|
553
560
|
const u = `${d}?${i.toString()}`;
|
|
554
561
|
n.socket = new WebSocket(u), n.socket.onopen = (l) => {
|
|
555
|
-
|
|
562
|
+
De(), t(!0);
|
|
556
563
|
}, n.socket.onmessage = (l) => {
|
|
557
|
-
const
|
|
558
|
-
|
|
564
|
+
const S = JSON.parse(l.data);
|
|
565
|
+
Ue(S);
|
|
559
566
|
}, n.socket.onerror = (l) => {
|
|
560
|
-
|
|
567
|
+
C("error"), P(l.message || "Unable to connect voice"), s(l);
|
|
561
568
|
}, n.socket.onclose = (l) => {
|
|
562
|
-
|
|
569
|
+
R();
|
|
563
570
|
};
|
|
564
571
|
});
|
|
565
572
|
}
|
|
566
|
-
function
|
|
573
|
+
function Ue(e) {
|
|
567
574
|
switch (e.type) {
|
|
568
575
|
case "pong":
|
|
569
|
-
|
|
576
|
+
Pe();
|
|
570
577
|
break;
|
|
571
578
|
case "answer":
|
|
572
|
-
|
|
579
|
+
Ne(e.data);
|
|
573
580
|
break;
|
|
574
581
|
case "connected":
|
|
575
|
-
|
|
582
|
+
Oe(e.data);
|
|
576
583
|
break;
|
|
577
584
|
case "ice":
|
|
578
|
-
|
|
585
|
+
Me(e.data);
|
|
579
586
|
break;
|
|
580
587
|
case "renegotiationOffer":
|
|
581
|
-
|
|
588
|
+
xe(e.data);
|
|
582
589
|
break;
|
|
583
590
|
case "end":
|
|
584
|
-
|
|
591
|
+
ae();
|
|
585
592
|
break;
|
|
586
593
|
case "error":
|
|
587
|
-
|
|
594
|
+
C("error"), P(e.error || "Unable to connect voice");
|
|
588
595
|
break;
|
|
589
596
|
default:
|
|
590
597
|
break;
|
|
591
598
|
}
|
|
592
599
|
}
|
|
593
|
-
function
|
|
594
|
-
n.sessionId = e.sessionId,
|
|
600
|
+
function Oe(e) {
|
|
601
|
+
n.sessionId = e.sessionId, he(e.sessionId);
|
|
595
602
|
}
|
|
596
|
-
async function
|
|
603
|
+
async function Ne(e) {
|
|
597
604
|
try {
|
|
598
605
|
if (n.peerConnection) {
|
|
599
606
|
const t = new RTCSessionDescription({
|
|
@@ -602,7 +609,7 @@ async function Ue(e) {
|
|
|
602
609
|
});
|
|
603
610
|
await n.peerConnection.setRemoteDescription(t);
|
|
604
611
|
for (const s of n.localIceCandidates)
|
|
605
|
-
|
|
612
|
+
b({
|
|
606
613
|
type: "ice",
|
|
607
614
|
data: {
|
|
608
615
|
candidate: s
|
|
@@ -611,16 +618,16 @@ async function Ue(e) {
|
|
|
611
618
|
n.localIceCandidates = [];
|
|
612
619
|
for (const s of n.pendingRemoteIceCandidates)
|
|
613
620
|
try {
|
|
614
|
-
const
|
|
615
|
-
await n.peerConnection.addIceCandidate(
|
|
616
|
-
} catch (
|
|
621
|
+
const a = new RTCIceCandidate(JSON.parse(s));
|
|
622
|
+
await n.peerConnection.addIceCandidate(a);
|
|
623
|
+
} catch (a) {
|
|
617
624
|
}
|
|
618
625
|
n.pendingRemoteIceCandidates = [];
|
|
619
626
|
}
|
|
620
627
|
} catch (t) {
|
|
621
628
|
}
|
|
622
629
|
}
|
|
623
|
-
async function
|
|
630
|
+
async function Me(e) {
|
|
624
631
|
try {
|
|
625
632
|
if (n.peerConnection) {
|
|
626
633
|
if (!n.peerConnection.remoteDescription) {
|
|
@@ -633,7 +640,7 @@ async function Oe(e) {
|
|
|
633
640
|
} catch (t) {
|
|
634
641
|
}
|
|
635
642
|
}
|
|
636
|
-
async function
|
|
643
|
+
async function xe(e) {
|
|
637
644
|
try {
|
|
638
645
|
if (n.peerConnection) {
|
|
639
646
|
const t = new RTCSessionDescription({
|
|
@@ -642,7 +649,7 @@ async function Ne(e) {
|
|
|
642
649
|
});
|
|
643
650
|
await n.peerConnection.setRemoteDescription(t);
|
|
644
651
|
const s = await n.peerConnection.createAnswer();
|
|
645
|
-
await n.peerConnection.setLocalDescription(s),
|
|
652
|
+
await n.peerConnection.setLocalDescription(s), b({
|
|
646
653
|
type: "renegotiationAnswer",
|
|
647
654
|
data: {
|
|
648
655
|
sdp: s.sdp
|
|
@@ -652,30 +659,30 @@ async function Ne(e) {
|
|
|
652
659
|
} catch (t) {
|
|
653
660
|
}
|
|
654
661
|
}
|
|
655
|
-
async function
|
|
662
|
+
async function _e(e = {}) {
|
|
656
663
|
try {
|
|
657
664
|
if (n.callStatus === "connecting" || n.callStatus === "connected")
|
|
658
665
|
return;
|
|
659
|
-
|
|
666
|
+
C("connecting"), P(null), n.sessionId = e.sessionId, await Re(), Ae(), n.localStream.getTracks().forEach((s) => {
|
|
660
667
|
n.peerConnection.addTrack(s, n.localStream);
|
|
661
|
-
}), await
|
|
668
|
+
}), await $e(e);
|
|
662
669
|
const t = await n.peerConnection.createOffer();
|
|
663
|
-
await n.peerConnection.setLocalDescription(t),
|
|
670
|
+
await n.peerConnection.setLocalDescription(t), b({
|
|
664
671
|
type: "offer",
|
|
665
672
|
data: {
|
|
666
673
|
sdp: t.sdp
|
|
667
674
|
}
|
|
668
675
|
});
|
|
669
676
|
} catch (t) {
|
|
670
|
-
|
|
677
|
+
C("error"), P(t.message || "Unable to connect voice"), ce();
|
|
671
678
|
}
|
|
672
679
|
}
|
|
673
|
-
function
|
|
674
|
-
|
|
680
|
+
function ae() {
|
|
681
|
+
b({
|
|
675
682
|
type: "end"
|
|
676
|
-
}), n.socket && (n.socket.close(), n.socket = null),
|
|
683
|
+
}), n.socket && (n.socket.close(), n.socket = null), C("disconnected"), n.peerConnection && (n.peerConnection.close(), n.peerConnection = null), n.localStream && (n.localStream.getTracks().forEach((e) => e.stop()), n.localStream = null), ce();
|
|
677
684
|
}
|
|
678
|
-
function
|
|
685
|
+
function Ke() {
|
|
679
686
|
if (n.localStream) {
|
|
680
687
|
const e = n.localStream.getAudioTracks()[0];
|
|
681
688
|
if (e)
|
|
@@ -683,33 +690,33 @@ function Je() {
|
|
|
683
690
|
}
|
|
684
691
|
return !1;
|
|
685
692
|
}
|
|
686
|
-
function
|
|
693
|
+
function Ve() {
|
|
687
694
|
return n.localStream;
|
|
688
695
|
}
|
|
689
|
-
function
|
|
696
|
+
function He() {
|
|
690
697
|
return new Promise((e, t) => {
|
|
691
698
|
if (!n.peerConnection) {
|
|
692
699
|
t(new Error("no peer connection"));
|
|
693
700
|
return;
|
|
694
701
|
}
|
|
695
702
|
n.peerConnection.getStats().then((s) => {
|
|
696
|
-
s.forEach((
|
|
697
|
-
|
|
703
|
+
s.forEach((a) => {
|
|
704
|
+
a.type == "inbound-rtp" && e(a.totalAudioEnergy);
|
|
698
705
|
}), t(new Error("no inbound-rtp stats found"));
|
|
699
706
|
}).catch((s) => {
|
|
700
707
|
t(s);
|
|
701
708
|
});
|
|
702
709
|
});
|
|
703
710
|
}
|
|
704
|
-
function
|
|
711
|
+
function Ye() {
|
|
705
712
|
return new Promise((e, t) => {
|
|
706
713
|
if (!n.peerConnection) {
|
|
707
714
|
t(new Error("no peer connection"));
|
|
708
715
|
return;
|
|
709
716
|
}
|
|
710
717
|
n.peerConnection.getStats().then((s) => {
|
|
711
|
-
s.forEach((
|
|
712
|
-
|
|
718
|
+
s.forEach((a) => {
|
|
719
|
+
a.type == "outbound-rtp" && e(a.totalAudioEnergy);
|
|
713
720
|
}), t(new Error("no outbound-rtp stats found"));
|
|
714
721
|
}).catch((s) => {
|
|
715
722
|
t(s);
|
|
@@ -717,21 +724,21 @@ function Ve() {
|
|
|
717
724
|
});
|
|
718
725
|
}
|
|
719
726
|
export {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
727
|
+
y as MESSAGE_ROLES,
|
|
728
|
+
Ee as authenticate,
|
|
729
|
+
Fe as disconnect,
|
|
730
|
+
ae as disconnectCall,
|
|
731
|
+
We as getHistory,
|
|
732
|
+
He as getInboundAudioEnergy,
|
|
733
|
+
Ve as getLocalStream,
|
|
734
|
+
Ye as getOutboundAudioEnergy,
|
|
735
|
+
ve as getSession,
|
|
736
|
+
Ge as initialize,
|
|
737
|
+
we as sendMessage,
|
|
738
|
+
Je as setCallCallbacks,
|
|
739
|
+
Le as setCallbacks,
|
|
740
|
+
_e as startCall,
|
|
741
|
+
ze as startChat,
|
|
742
|
+
Ke as toggleMute
|
|
736
743
|
};
|
|
737
744
|
//# sourceMappingURL=origon-chat-sdk.js.map
|
|
@@ -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","/**\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 'connected':\n handleConnected(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 connected event\n * @param {Object} data\n */\nfunction handleConnected(data) {\n console.log('Received connected event')\n currentSession.sessionId = data.sessionId\n // Update chat session with the new sessionId and notify controller\n updateSessionId(data.sessionId)\n}\n\n/**\n * Handle answer\n * @param {Object} data\n */\nasync function handleAnswer(data) {\n try {\n console.log('Received answer')\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","handleConnected","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,GAAgBF,EAAO,IAAI;AAC3B;AAAA,IAEF,KAAK;AACH,MAAAG,GAAmBH,EAAO,IAAI;AAC9B;AAAA,IAEF,KAAK;AACH,MAAAI,GAAyBJ,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,SAASE,GAAgB7E,GAAM;AAE7B,EAAAxB,EAAe,YAAYwB,EAAK,WAEhCQ,GAAgBR,EAAK,SAAS;AAChC;AAMA,eAAe4E,GAAa5E,GAAM;AAChC,MAAI;AAGF,QAAIxB,EAAe,gBAAgB;AACjC,YAAMwG,IAAS,IAAI,sBAAsB;AAAA,QACvC,MAAM;AAAA,QACN,KAAKhF,EAAK;AAAA,MAClB,CAAO;AAED,YAAMxB,EAAe,eAAe,qBAAqBwG,CAAM;AAI/D,iBAAWV,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,gBAAMyG,IAAY,IAAI,gBAAgB,KAAK,MAAMX,CAAa,CAAC;AAC/D,gBAAM9F,EAAe,eAAe,gBAAgByG,CAAS;AAAA,QAE/D,SAASV,GAAK;AAAA,QAEd;AAEF,MAAA/F,EAAe,6BAA6B,CAAA;AAAA,IAC9C;AAAA,EACF,SAASqB,GAAO;AAAA,EAEhB;AACF;AAMA,eAAeiF,GAAmB9E,GAAM;AACtC,MAAI;AACF,QAAIxB,EAAe,gBAAgB;AAEjC,UAAI,CAACA,EAAe,eAAe,mBAAmB;AAEpD,QAAAA,EAAe,2BAA2B,KAAKwB,EAAK,SAAS;AAE7D;AAAA,MACF;AACA,YAAMiF,IAAY,IAAI,gBAAgB,KAAK,MAAMjF,EAAK,SAAS,CAAC;AAChE,YAAMxB,EAAe,eAAe,gBAAgByG,CAAS;AAAA,IAE/D;AAAA,EACF,SAASpF,GAAO;AAAA,EAEhB;AACF;AAMA,eAAekF,GAAyB/E,GAAM;AAC5C,MAAI;AAGF,QAAIxB,EAAe,gBAAgB;AACjC,YAAM0G,IAAQ,IAAI,sBAAsB;AAAA,QACtC,MAAM;AAAA,QACN,KAAKlF,EAAK;AAAA,MAClB,CAAO;AAED,YAAMxB,EAAe,eAAe,qBAAqB0G,CAAK;AAG9D,YAAMF,IAAS,MAAMxG,EAAe,eAAe,aAAY;AAC/D,YAAMA,EAAe,eAAe,oBAAoBwG,CAAM,GAE9Dd,EAAU;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,KAAKc,EAAO;AAAA,QACtB;AAAA,MACA,CAAO;AAAA,IACH;AAAA,EACF,SAASnF,GAAO;AAAA,EAEhB;AACF;AAMO,eAAesF,GAAUlG,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,UAAMiG,IAAQ,MAAM1G,EAAe,eAAe,YAAW;AAC7D,UAAMA,EAAe,eAAe,oBAAoB0G,CAAK,GAE7DhB,EAAU;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,KAAKgB,EAAM;AAAA,MACnB;AAAA,IACA,CAAK;AAAA,EAGH,SAASrF,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,SAASiE,KAAa;AAC3B,MAAI5G,EAAe,aAAa;AAC9B,UAAM6G,IAAa7G,EAAe,YAAY,eAAc,EAAG,CAAC;AAChE,QAAI6G;AACF,aAAAA,EAAW,UAAU,CAACA,EAAW,SACjC7G,EAAe,UAAU,CAAC6G,EAAW,SAE9B7G,EAAe;AAAA,EAE1B;AACA,SAAO;AACT;AAMO,SAAS8G,KAAiB;AAC/B,SAAO9G,EAAe;AACxB;AAMO,SAAS+G,KAAwB;AACtC,SAAO,IAAI,QAAQ,CAAC7H,GAASyB,MAAW;AACtC,QAAI,CAACX,EAAe,gBAAgB;AAClC,MAAAW,EAAO,IAAI,MAAM,oBAAoB,CAAC;AACtC;AAAA,IACF;AACA,IAAAX,EAAe,eACZ,SAAQ,EACR,KAAK,CAACgH,MAAU;AACf,MAAAA,EAAM,QAAQ,CAACC,MAAW;AACxB,QAAIA,EAAO,QAAQ,iBACjB/H,EAAQ+H,EAAO,gBAAgB;AAAA,MAEnC,CAAC,GACDtG,EAAO,IAAI,MAAM,4BAA4B,CAAC;AAAA,IAChD,CAAC,EACA,MAAM,CAACoF,MAAQ;AACd,MAAApF,EAAOoF,CAAG;AAAA,IACZ,CAAC;AAAA,EACL,CAAC;AACH;AAMO,SAASmB,KAAyB;AACvC,SAAO,IAAI,QAAQ,CAAChI,GAASyB,MAAW;AACtC,QAAI,CAACX,EAAe,gBAAgB;AAClC,MAAAW,EAAO,IAAI,MAAM,oBAAoB,CAAC;AACtC;AAAA,IACF;AACA,IAAAX,EAAe,eACZ,SAAQ,EACR,KAAK,CAACgH,MAAU;AACf,MAAAA,EAAM,QAAQ,CAACC,MAAW;AACxB,QAAIA,EAAO,QAAQ,kBACjB/H,EAAQ+H,EAAO,gBAAgB;AAAA,MAEnC,CAAC,GACDtG,EAAO,IAAI,MAAM,6BAA6B,CAAC;AAAA,IACjD,CAAC,EACA,MAAM,CAACoF,MAAQ;AACd,MAAApF,EAAOoF,CAAG;AAAA,IACZ,CAAC;AAAA,EACL,CAAC;AACH;"}
|
|
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 const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\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 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 'connected':\n handleConnected(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 connected event\n * @param {Object} data\n */\nfunction handleConnected(data) {\n console.log('Received connected event')\n currentSession.sessionId = data.sessionId\n // Update chat session with the new sessionId and notify controller\n updateSessionId(data.sessionId)\n}\n\n/**\n * Handle answer\n * @param {Object} data\n */\nasync function handleAnswer(data) {\n try {\n console.log('Received answer')\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","_i","_j","newBotMessage","lastMsg","_k","_n","_o","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","handleConnected","handleIceCandidate","handleRenegotiationOffer","answer","candidate","offer","startCall","toggleMute","audioTrack","getLocalStream","getInboundAudioEnergy","stats","report","getOutboundAudioEnergy"],"mappings":"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"}
|
package/package.json
CHANGED
package/src/chat.js
CHANGED
|
@@ -349,6 +349,17 @@ export function sendMessage({ text, html, context }) {
|
|
|
349
349
|
currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)
|
|
350
350
|
reject(new Error(errorMessage))
|
|
351
351
|
} else if (response.event === 'done') {
|
|
352
|
+
const lastIndex = currentSession.messages.length - 1
|
|
353
|
+
const lastMsg = currentSession.messages[lastIndex]
|
|
354
|
+
const updatedMsg = {
|
|
355
|
+
...lastMsg,
|
|
356
|
+
loading: false,
|
|
357
|
+
done: true
|
|
358
|
+
}
|
|
359
|
+
currentSession.messages = currentSession.messages.map((msg, index) =>
|
|
360
|
+
index === lastIndex ? updatedMsg : msg
|
|
361
|
+
)
|
|
362
|
+
currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)
|
|
352
363
|
resolve(currentSession.sessionId)
|
|
353
364
|
} else if (data.message !== undefined) {
|
|
354
365
|
// If role is supervisor, treat it as a new message
|