@origonai/web-chat-sdk 0.1.5 → 0.1.6
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 +169 -192
- package/dist/origon-chat-sdk.js.map +1 -1
- package/package.json +1 -1
- package/src/chat.js +1 -12
- package/src/http.js +15 -1
package/dist/origon-chat-sdk.js
CHANGED
|
@@ -2,7 +2,7 @@ import { fetchEventSource as ne } from "@microsoft/fetch-event-source";
|
|
|
2
2
|
function J() {
|
|
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 o = [...t].map((
|
|
5
|
+
const o = [...t].map((r) => r.toString(16).padStart(2, "0")).join("");
|
|
6
6
|
return `${o.slice(0, 8)}-${o.slice(8, 12)}-${o.slice(12, 16)}-${o.slice(
|
|
7
7
|
16,
|
|
8
8
|
20
|
|
@@ -23,27 +23,24 @@ function se(e) {
|
|
|
23
23
|
const o = new URL(e);
|
|
24
24
|
t = `https://${o.hostname}${o.pathname}/sse`;
|
|
25
25
|
} catch (o) {
|
|
26
|
-
console.error("SSE Invalid base URL: ", e);
|
|
27
26
|
}
|
|
28
27
|
return t;
|
|
29
28
|
}
|
|
30
|
-
function
|
|
29
|
+
function ae(e) {
|
|
31
30
|
let t;
|
|
32
31
|
try {
|
|
33
32
|
const o = new URL(e);
|
|
34
33
|
t = `wss://${o.hostname}${o.pathname}/wss`;
|
|
35
34
|
} catch (o) {
|
|
36
|
-
console.error("Socket Invalid base URL: ", e);
|
|
37
35
|
}
|
|
38
36
|
return t;
|
|
39
37
|
}
|
|
40
|
-
function
|
|
38
|
+
function re(e) {
|
|
41
39
|
let t;
|
|
42
40
|
try {
|
|
43
41
|
const o = new URL(e);
|
|
44
42
|
t = `wss://${o.hostname}${o.pathname}/audio`;
|
|
45
43
|
} catch (o) {
|
|
46
|
-
console.error("getCallServerEndpoint: Invalid base URL: ", e);
|
|
47
44
|
}
|
|
48
45
|
return t;
|
|
49
46
|
}
|
|
@@ -56,13 +53,13 @@ const T = {
|
|
|
56
53
|
// this is human agent (dock side)
|
|
57
54
|
SYSTEM: "system"
|
|
58
55
|
// this is system message, for ex "Agent joined" / "Agent left"
|
|
59
|
-
}, W = 1e4,
|
|
56
|
+
}, W = 1e4, ce = 5e3, E = {
|
|
60
57
|
MESSAGE: "message",
|
|
61
58
|
TYPING: "typing",
|
|
62
59
|
TYPING_STOP: "typingOff",
|
|
63
60
|
END: "end"
|
|
64
61
|
};
|
|
65
|
-
function
|
|
62
|
+
function ie() {
|
|
66
63
|
return {
|
|
67
64
|
socket: null,
|
|
68
65
|
previouslyConnected: !1,
|
|
@@ -72,37 +69,36 @@ function re() {
|
|
|
72
69
|
socketConnectionTimeout: null
|
|
73
70
|
};
|
|
74
71
|
}
|
|
75
|
-
let
|
|
76
|
-
function
|
|
77
|
-
|
|
72
|
+
let a = ie();
|
|
73
|
+
function A() {
|
|
74
|
+
a.pingInterval && (clearInterval(a.pingInterval), a.pingInterval = null);
|
|
78
75
|
}
|
|
79
76
|
function le() {
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
A(), a.pingInterval = setInterval(() => {
|
|
78
|
+
a.socket && a.socket.readyState === WebSocket.OPEN ? U({ type: "ping" }) : A();
|
|
82
79
|
}, W);
|
|
83
80
|
}
|
|
84
81
|
function _() {
|
|
85
|
-
|
|
82
|
+
A(), a.socketDisconnectedTimeout && (clearTimeout(a.socketDisconnectedTimeout), a.socketDisconnectedTimeout = null), a.socketConnectionTimeout && (clearTimeout(a.socketConnectionTimeout), a.socketConnectionTimeout = null);
|
|
86
83
|
}
|
|
87
84
|
function K() {
|
|
88
|
-
|
|
85
|
+
a.socketDisconnected = !1, P("socket");
|
|
89
86
|
}
|
|
90
87
|
function B() {
|
|
91
|
-
|
|
88
|
+
a.socketDisconnected = !0, P("sse");
|
|
92
89
|
}
|
|
93
90
|
function de(e) {
|
|
94
91
|
return new Promise((t, o) => {
|
|
95
|
-
if (
|
|
96
|
-
|
|
92
|
+
if (a.socket && (a.socket.readyState === WebSocket.CONNECTING || a.socket.readyState === WebSocket.OPEN)) {
|
|
93
|
+
t(a.socket.readyState === WebSocket.OPEN);
|
|
97
94
|
return;
|
|
98
95
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (!a || !a.endpoint) {
|
|
96
|
+
const r = N();
|
|
97
|
+
if (!r || !r.endpoint) {
|
|
102
98
|
o(new Error("SDK not initialized. Please initialize SDK first."));
|
|
103
99
|
return;
|
|
104
100
|
}
|
|
105
|
-
const d =
|
|
101
|
+
const d = ae(r.endpoint);
|
|
106
102
|
if (!d) {
|
|
107
103
|
o(
|
|
108
104
|
new Error(
|
|
@@ -111,53 +107,53 @@ function de(e) {
|
|
|
111
107
|
);
|
|
112
108
|
return;
|
|
113
109
|
}
|
|
114
|
-
const u = $(),
|
|
110
|
+
const u = $(), c = new URLSearchParams({
|
|
115
111
|
externalId: u
|
|
116
112
|
});
|
|
117
|
-
e.sessionId &&
|
|
118
|
-
const f = `${d}?${
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
},
|
|
122
|
-
const p = JSON.parse(
|
|
113
|
+
e.sessionId && c.set("sessionId", e.sessionId), e.requestId && c.set("requestId", e.requestId), r.token && c.set("token", r.token);
|
|
114
|
+
const f = `${d}?${c.toString()}`;
|
|
115
|
+
a.socket = new WebSocket(f), a.socket.onopen = () => {
|
|
116
|
+
a.previouslyConnected = !0, K(), U({ type: "ping" }), clearTimeout(a.socketConnectionTimeout), le(), t(!0);
|
|
117
|
+
}, a.socket.onmessage = (l) => {
|
|
118
|
+
const p = JSON.parse(l.data);
|
|
123
119
|
ue(p);
|
|
124
|
-
},
|
|
125
|
-
|
|
126
|
-
},
|
|
127
|
-
|
|
120
|
+
}, a.socket.onerror = (l) => {
|
|
121
|
+
P("sse"), o(l);
|
|
122
|
+
}, a.socket.onclose = (l) => {
|
|
123
|
+
l.target === a.socket && (l.code === 1006 && (a.previouslyConnected ? B() : h({
|
|
128
124
|
errorText: "Unable to establish connection",
|
|
129
125
|
done: !0,
|
|
130
126
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
131
|
-
}), clearTimeout(
|
|
132
|
-
},
|
|
133
|
-
|
|
127
|
+
}), clearTimeout(a.socketConnectionTimeout)), a.socket = null, _());
|
|
128
|
+
}, a.previouslyConnected || (a.socketConnectionTimeout = setTimeout(() => {
|
|
129
|
+
h({
|
|
134
130
|
errorText: "Unable to establish connection",
|
|
135
131
|
done: !0,
|
|
136
132
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
137
133
|
}), o(new Error("Socket connection timed out"));
|
|
138
|
-
},
|
|
134
|
+
}, ce));
|
|
139
135
|
});
|
|
140
136
|
}
|
|
141
|
-
function
|
|
142
|
-
|
|
137
|
+
function U(e) {
|
|
138
|
+
a.socketDisconnected || !a.socket || a.socket.send(JSON.stringify({ ...e, eventId: e.eventId || J() }));
|
|
143
139
|
}
|
|
144
140
|
function ue(e) {
|
|
145
|
-
switch (
|
|
141
|
+
switch (e.type) {
|
|
146
142
|
case "pong": {
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
a.socketDisconnected && K(), a.socketDisconnectedTimeout && clearTimeout(a.socketDisconnectedTimeout), a.socketDisconnectedTimeout = setTimeout(() => {
|
|
144
|
+
B();
|
|
149
145
|
}, W + 1e3);
|
|
150
146
|
break;
|
|
151
147
|
}
|
|
152
|
-
case
|
|
148
|
+
case E.TYPING: {
|
|
153
149
|
F(!0);
|
|
154
150
|
break;
|
|
155
151
|
}
|
|
156
|
-
case
|
|
152
|
+
case E.TYPING_STOP: {
|
|
157
153
|
F(!1);
|
|
158
154
|
break;
|
|
159
155
|
}
|
|
160
|
-
case
|
|
156
|
+
case E.MESSAGE: {
|
|
161
157
|
const { eventId: t, data: o } = e;
|
|
162
158
|
t || h({
|
|
163
159
|
...o,
|
|
@@ -166,17 +162,17 @@ function ue(e) {
|
|
|
166
162
|
});
|
|
167
163
|
break;
|
|
168
164
|
}
|
|
169
|
-
case
|
|
165
|
+
case E.END: {
|
|
170
166
|
H();
|
|
171
167
|
break;
|
|
172
168
|
}
|
|
173
169
|
}
|
|
174
170
|
}
|
|
175
171
|
function H() {
|
|
176
|
-
|
|
172
|
+
a.socket && a.socket.close(1e3), a.previouslyConnected = !1, _(), a.socket = null, P("sse");
|
|
177
173
|
}
|
|
178
174
|
function ge() {
|
|
179
|
-
return
|
|
175
|
+
return a.socket !== null && a.socket.readyState === WebSocket.OPEN && !a.socketDisconnected;
|
|
180
176
|
}
|
|
181
177
|
function Y(e = {}) {
|
|
182
178
|
return {
|
|
@@ -198,53 +194,40 @@ function Pe(e) {
|
|
|
198
194
|
s.callbacks = { ...s.callbacks, ...e };
|
|
199
195
|
}
|
|
200
196
|
function Oe(e) {
|
|
201
|
-
|
|
197
|
+
s.credentials = e, e.token && (s.authenticated = !0);
|
|
202
198
|
}
|
|
203
|
-
function
|
|
199
|
+
function N() {
|
|
204
200
|
return s.credentials;
|
|
205
201
|
}
|
|
206
202
|
function fe(e) {
|
|
207
203
|
var t, o;
|
|
208
204
|
e && e !== s.sessionId && (s.sessionId = e, (o = (t = s.callbacks).onSessionUpdate) == null || o.call(t, e));
|
|
209
205
|
}
|
|
210
|
-
async function
|
|
211
|
-
var t;
|
|
206
|
+
async function Re(e = {}) {
|
|
212
207
|
try {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
a = ((t = u == null ? void 0 : u.sessionHistory) != null ? t : []).map((i) => ({
|
|
220
|
-
id: i.id,
|
|
221
|
-
text: i.text,
|
|
222
|
-
role: i.youtubeVideo ? T.BOT : i.role,
|
|
223
|
-
timestamp: i.timestamp,
|
|
224
|
-
video: i.youtubeVideo,
|
|
225
|
-
channel: i.channel,
|
|
226
|
-
done: !0
|
|
227
|
-
}));
|
|
228
|
-
}
|
|
229
|
-
const d = new URLSearchParams();
|
|
230
|
-
return s.credentials.token || d.set("externalId", $()), s.sseUrl = `${se(
|
|
208
|
+
let t = null;
|
|
209
|
+
s.authenticated ? t = s.configData : (t = await ke(s.credentials), s.authenticated = !0, s.configData = t);
|
|
210
|
+
let o = [];
|
|
211
|
+
e.sessionId && (o = await Se(e.sessionId));
|
|
212
|
+
const r = new URLSearchParams();
|
|
213
|
+
return s.credentials.token || r.set("externalId", $()), s.sseUrl = `${se(
|
|
231
214
|
s.credentials.endpoint
|
|
232
|
-
)}?${
|
|
215
|
+
)}?${r.toString()}`, s.sessionId = e.sessionId, s.messages = o, {
|
|
233
216
|
sessionId: s.sessionId,
|
|
234
|
-
messages:
|
|
235
|
-
configData:
|
|
217
|
+
messages: o,
|
|
218
|
+
configData: t
|
|
236
219
|
};
|
|
237
|
-
} catch (
|
|
238
|
-
throw
|
|
220
|
+
} catch (t) {
|
|
221
|
+
throw V(), t;
|
|
239
222
|
}
|
|
240
223
|
}
|
|
241
|
-
function
|
|
224
|
+
function Ae() {
|
|
242
225
|
V();
|
|
243
226
|
}
|
|
244
227
|
function V() {
|
|
245
228
|
s.abortController && s.abortController.abort(), H();
|
|
246
229
|
const { callbacks: e, credentials: t } = s;
|
|
247
|
-
s = Y(e), s.credentials = t
|
|
230
|
+
s = Y(e), s.credentials = t;
|
|
248
231
|
}
|
|
249
232
|
function $() {
|
|
250
233
|
var e;
|
|
@@ -260,27 +243,27 @@ function F(e) {
|
|
|
260
243
|
}
|
|
261
244
|
function P(e) {
|
|
262
245
|
var t, o;
|
|
263
|
-
|
|
246
|
+
s.transport = e, (o = (t = s.callbacks).onTransportUpdate) == null || o.call(t, e);
|
|
264
247
|
}
|
|
265
|
-
function
|
|
266
|
-
return new Promise((
|
|
248
|
+
function Ue({ text: e, html: t, context: o }) {
|
|
249
|
+
return new Promise((r, d) => {
|
|
267
250
|
(async () => {
|
|
268
|
-
var u,
|
|
251
|
+
var u, c, f;
|
|
269
252
|
try {
|
|
270
|
-
const
|
|
253
|
+
const l = {
|
|
271
254
|
role: T.USER,
|
|
272
255
|
text: e,
|
|
273
256
|
html: t,
|
|
274
257
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
275
258
|
};
|
|
276
|
-
if (h(
|
|
277
|
-
|
|
259
|
+
if (h(l), await oe(200), s.transport === "socket" && ge()) {
|
|
260
|
+
U({
|
|
278
261
|
type: "message",
|
|
279
262
|
data: {
|
|
280
263
|
text: e,
|
|
281
264
|
html: t
|
|
282
265
|
}
|
|
283
|
-
}),
|
|
266
|
+
}), r(s.sessionId);
|
|
284
267
|
return;
|
|
285
268
|
}
|
|
286
269
|
const p = {
|
|
@@ -305,33 +288,33 @@ function Ne({ text: e, html: t, context: o }) {
|
|
|
305
288
|
signal: s.abortController.signal,
|
|
306
289
|
onopen: async (g) => {
|
|
307
290
|
if (!g.ok)
|
|
308
|
-
throw
|
|
291
|
+
throw new Error("Failed to send message");
|
|
309
292
|
},
|
|
310
293
|
onmessage: (g) => {
|
|
311
|
-
var
|
|
312
|
-
const
|
|
294
|
+
var b, M, x, q, L, G, z;
|
|
295
|
+
const i = JSON.parse(g.data);
|
|
313
296
|
if (g.event === "connected")
|
|
314
|
-
s.sessionId =
|
|
297
|
+
s.sessionId = i.sessionId, s.requestId = i.requestId;
|
|
315
298
|
else if (g.event === "upgrade_to_websocket")
|
|
316
|
-
|
|
299
|
+
de({
|
|
317
300
|
sessionId: s.sessionId,
|
|
318
|
-
requestId:
|
|
301
|
+
requestId: i.requestId
|
|
319
302
|
});
|
|
320
|
-
else if (
|
|
321
|
-
const I =
|
|
303
|
+
else if (i.error) {
|
|
304
|
+
const I = i.error && typeof i.error == "string" ? i.error : "Failed to connect to the system", k = s.messages.length - 1, C = {
|
|
322
305
|
...s.messages[k],
|
|
323
306
|
loading: !1,
|
|
324
307
|
errorText: I
|
|
325
308
|
};
|
|
326
309
|
s.messages = s.messages.map(
|
|
327
|
-
(
|
|
328
|
-
), (M = (
|
|
329
|
-
} else if (
|
|
330
|
-
if (
|
|
310
|
+
(R, ee) => ee === k ? C : R
|
|
311
|
+
), (M = (b = s.callbacks).onMessageUpdate) == null || M.call(b, k, C), d(new Error(I));
|
|
312
|
+
} else if (i.message !== void 0) {
|
|
313
|
+
if (i.streamId !== void 0) {
|
|
331
314
|
if (s.lastStreamId === void 0)
|
|
332
|
-
s.lastStreamId =
|
|
333
|
-
else if (
|
|
334
|
-
s.lastStreamId =
|
|
315
|
+
s.lastStreamId = i.streamId;
|
|
316
|
+
else if (i.streamId !== s.lastStreamId) {
|
|
317
|
+
s.lastStreamId = i.streamId;
|
|
335
318
|
const C = {
|
|
336
319
|
role: T.BOT,
|
|
337
320
|
text: "",
|
|
@@ -343,13 +326,13 @@ function Ne({ text: e, html: t, context: o }) {
|
|
|
343
326
|
const I = s.messages.length - 1, k = s.messages[I], O = {
|
|
344
327
|
...k,
|
|
345
328
|
loading: !1,
|
|
346
|
-
text: (k.text || "") +
|
|
347
|
-
sources:
|
|
348
|
-
done: (x =
|
|
329
|
+
text: (k.text || "") + i.message,
|
|
330
|
+
sources: i.sources,
|
|
331
|
+
done: (x = i.done) != null ? x : k.done
|
|
349
332
|
};
|
|
350
333
|
s.messages = s.messages.map(
|
|
351
|
-
(C,
|
|
352
|
-
), (L = (q = s.callbacks).onMessageUpdate) == null || L.call(q, I, O),
|
|
334
|
+
(C, R) => R === I ? O : C
|
|
335
|
+
), (L = (q = s.callbacks).onMessageUpdate) == null || L.call(q, I, O), i.done && r(s.sessionId), s.sessionId = (G = i.session_id) != null ? G : s.sessionId, s.requestId = (z = i.requestId) != null ? z : s.requestId;
|
|
353
336
|
}
|
|
354
337
|
},
|
|
355
338
|
onerror: (g) => {
|
|
@@ -357,36 +340,35 @@ function Ne({ text: e, html: t, context: o }) {
|
|
|
357
340
|
},
|
|
358
341
|
openWhenHidden: !0
|
|
359
342
|
});
|
|
360
|
-
} catch (
|
|
361
|
-
console.error("Failed to send message: ", r);
|
|
343
|
+
} catch (l) {
|
|
362
344
|
const p = "Failed to connect to the system", m = s.messages.length - 1, y = s.messages[m], g = {
|
|
363
345
|
...y,
|
|
364
346
|
loading: !1,
|
|
365
|
-
errorText: y.done ? void 0 :
|
|
347
|
+
errorText: y.done ? void 0 : l.message || p,
|
|
366
348
|
done: !0
|
|
367
349
|
};
|
|
368
350
|
s.messages = s.messages.map(
|
|
369
|
-
(
|
|
370
|
-
), (f = (
|
|
351
|
+
(i, b) => b === m ? g : i
|
|
352
|
+
), (f = (c = s.callbacks).onMessageUpdate) == null || f.call(c, m, g), d(l);
|
|
371
353
|
}
|
|
372
354
|
})();
|
|
373
355
|
});
|
|
374
356
|
}
|
|
375
357
|
const pe = "Something went wrong initializing the chat", me = "Chat SDK not initialized";
|
|
376
358
|
async function ke(e) {
|
|
377
|
-
const { endpoint: t } = e, o = `${t}/config`,
|
|
359
|
+
const { endpoint: t } = e, o = `${t}/config`, r = await fetch(o, {
|
|
378
360
|
method: "GET",
|
|
379
361
|
headers: {
|
|
380
362
|
"Content-Type": "application/json"
|
|
381
363
|
}
|
|
382
364
|
});
|
|
383
|
-
if (!
|
|
384
|
-
const
|
|
385
|
-
throw new Error((
|
|
365
|
+
if (!r.ok) {
|
|
366
|
+
const c = await r.json();
|
|
367
|
+
throw new Error((c == null ? void 0 : c.error) || pe);
|
|
386
368
|
}
|
|
387
|
-
return (await
|
|
369
|
+
return (await r.json()).data;
|
|
388
370
|
}
|
|
389
|
-
async function
|
|
371
|
+
async function Ne() {
|
|
390
372
|
const e = new URLSearchParams({
|
|
391
373
|
externalId: $()
|
|
392
374
|
}), t = await Q(`/sessions?${e.toString()}`, "GET");
|
|
@@ -395,21 +377,31 @@ async function Ue() {
|
|
|
395
377
|
return t.json();
|
|
396
378
|
}
|
|
397
379
|
async function Se(e) {
|
|
380
|
+
var u;
|
|
398
381
|
const t = new URLSearchParams({
|
|
399
382
|
sessionId: e
|
|
400
383
|
}), o = await Q(`/session?${t.toString()}`, "GET");
|
|
401
384
|
if (!o.ok)
|
|
402
385
|
throw new Error("Unable to load messages, please try again later");
|
|
403
|
-
|
|
386
|
+
const r = await o.json();
|
|
387
|
+
return ((u = r == null ? void 0 : r.sessionHistory) != null ? u : []).map((c) => ({
|
|
388
|
+
id: c.id,
|
|
389
|
+
text: c.text,
|
|
390
|
+
role: c.youtubeVideo ? T.BOT : c.role,
|
|
391
|
+
timestamp: c.timestamp,
|
|
392
|
+
video: c.youtubeVideo,
|
|
393
|
+
channel: c.channel,
|
|
394
|
+
done: !0
|
|
395
|
+
}));
|
|
404
396
|
}
|
|
405
397
|
async function Q(e, t = "GET", o = null) {
|
|
406
|
-
const
|
|
398
|
+
const r = N(), { endpoint: d, token: u } = r || {};
|
|
407
399
|
if (!d)
|
|
408
400
|
throw new Error(me);
|
|
409
|
-
const
|
|
401
|
+
const c = `${d}${e}`, f = {
|
|
410
402
|
"Content-Type": "application/json"
|
|
411
403
|
};
|
|
412
|
-
return u && (f.Authorization = `Bearer ${u}`), fetch(
|
|
404
|
+
return u && (f.Authorization = `Bearer ${u}`), fetch(c, {
|
|
413
405
|
headers: f,
|
|
414
406
|
method: t,
|
|
415
407
|
body: o ? JSON.stringify(o) : null
|
|
@@ -443,7 +435,7 @@ function Me(e) {
|
|
|
443
435
|
function j() {
|
|
444
436
|
n.peerConnection && (n.peerConnection.close(), n.peerConnection = null), n.localStream && (n.localStream.getTracks().forEach((t) => t.stop()), n.localStream = null), n.remoteStream && (n.remoteStream = null), n.remoteAudio && (n.remoteAudio.srcObject = null, n.remoteAudio.parentNode && n.remoteAudio.parentNode.removeChild(n.remoteAudio), n.remoteAudio = null), n.socket && (n.socket.close(), n.socket = null), D();
|
|
445
437
|
const e = n.callbacks;
|
|
446
|
-
n = Z(e)
|
|
438
|
+
n = Z(e);
|
|
447
439
|
}
|
|
448
440
|
function S(e) {
|
|
449
441
|
var t, o;
|
|
@@ -465,68 +457,60 @@ function Ce() {
|
|
|
465
457
|
timestamp: Date.now(),
|
|
466
458
|
count: n.pingCount
|
|
467
459
|
};
|
|
468
|
-
w(e)
|
|
460
|
+
w(e);
|
|
469
461
|
} else
|
|
470
|
-
|
|
462
|
+
D();
|
|
471
463
|
}, 1e4);
|
|
472
464
|
}
|
|
473
465
|
function he() {
|
|
474
|
-
n.lastPongTime = Date.now()
|
|
466
|
+
n.lastPongTime = Date.now();
|
|
475
467
|
}
|
|
476
468
|
function w(e) {
|
|
477
|
-
|
|
478
|
-
console.error("Failed to send event: no socket instance");
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
if (n.socket.readyState !== WebSocket.OPEN) {
|
|
482
|
-
console.error("Failed to send event: socket state not open ", e);
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
n.socket.send(JSON.stringify(e));
|
|
469
|
+
n.socket && n.socket.readyState === WebSocket.OPEN && n.socket.send(JSON.stringify(e));
|
|
486
470
|
}
|
|
487
471
|
async function we() {
|
|
488
472
|
try {
|
|
489
473
|
n.localStream = await navigator.mediaDevices.getUserMedia({
|
|
490
474
|
audio: !0,
|
|
491
475
|
video: !1
|
|
492
|
-
})
|
|
476
|
+
});
|
|
493
477
|
} catch (e) {
|
|
494
|
-
throw
|
|
478
|
+
throw e;
|
|
495
479
|
}
|
|
496
480
|
}
|
|
497
481
|
function ye() {
|
|
498
482
|
n.peerConnection = new RTCPeerConnection(Ie), n.peerConnection.onicecandidate = (e) => {
|
|
499
483
|
if (e.candidate) {
|
|
500
484
|
const t = JSON.stringify(e.candidate);
|
|
501
|
-
n.peerConnection && n.peerConnection.remoteDescription ?
|
|
485
|
+
n.peerConnection && n.peerConnection.remoteDescription ? w({
|
|
502
486
|
type: "ice",
|
|
503
487
|
data: {
|
|
504
488
|
candidate: t
|
|
505
489
|
}
|
|
506
|
-
})
|
|
490
|
+
}) : n.localIceCandidates.push(t);
|
|
507
491
|
}
|
|
508
492
|
}, n.peerConnection.ontrack = (e) => {
|
|
509
|
-
|
|
493
|
+
n.remoteStream = e.streams[0], n.remoteAudio || (n.remoteAudio = document.createElement("audio"), n.remoteAudio.autoplay = !0, n.remoteAudio.controls = !1, document.body.appendChild(n.remoteAudio)), n.remoteAudio.srcObject = n.remoteStream, n.remoteAudio.play().then(() => {
|
|
494
|
+
}).catch((t) => {
|
|
495
|
+
});
|
|
510
496
|
}, n.peerConnection.onconnectionstatechange = () => {
|
|
511
497
|
const e = n.peerConnection.connectionState;
|
|
512
|
-
|
|
498
|
+
e === "connected" ? S("connected") : (e === "disconnected" || e === "closed") && (S("disconnected"), X());
|
|
513
499
|
}, n.peerConnection.oniceconnectionstatechange = () => {
|
|
514
|
-
console.log(`ICE connection state: ${n.peerConnection.iceConnectionState}`);
|
|
515
500
|
};
|
|
516
501
|
}
|
|
517
|
-
function
|
|
502
|
+
function be(e) {
|
|
518
503
|
return new Promise((t, o) => {
|
|
519
504
|
if (n.socket && (n.socket.readyState === WebSocket.CONNECTING || n.socket.readyState === WebSocket.OPEN)) {
|
|
520
|
-
|
|
505
|
+
t(n.socket.readyState === WebSocket.OPEN);
|
|
521
506
|
return;
|
|
522
507
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
if (!a || !a.endpoint) {
|
|
508
|
+
const r = N();
|
|
509
|
+
if (!r || !r.endpoint) {
|
|
526
510
|
o(new Error("SDK not initialized. Please initialize SDK first."));
|
|
527
511
|
return;
|
|
528
512
|
}
|
|
529
|
-
const d =
|
|
513
|
+
const d = re(r.endpoint);
|
|
530
514
|
if (!d) {
|
|
531
515
|
o(
|
|
532
516
|
new Error(
|
|
@@ -535,25 +519,25 @@ function Ee(e) {
|
|
|
535
519
|
);
|
|
536
520
|
return;
|
|
537
521
|
}
|
|
538
|
-
const u = $(),
|
|
522
|
+
const u = $(), c = new URLSearchParams({
|
|
539
523
|
externalId: u
|
|
540
524
|
});
|
|
541
|
-
e.sessionId &&
|
|
542
|
-
const f = `${d}?${
|
|
543
|
-
n.socket = new WebSocket(f), n.socket.onopen = (
|
|
544
|
-
|
|
545
|
-
}, n.socket.onmessage = (
|
|
546
|
-
const p = JSON.parse(
|
|
547
|
-
|
|
548
|
-
}, n.socket.onerror = (
|
|
549
|
-
|
|
550
|
-
}, n.socket.onclose = (
|
|
551
|
-
|
|
525
|
+
e.sessionId && c.set("sessionId", e.sessionId), r.token && c.set("token", r.token);
|
|
526
|
+
const f = `${d}?${c.toString()}`;
|
|
527
|
+
n.socket = new WebSocket(f), n.socket.onopen = (l) => {
|
|
528
|
+
Ce(), t(!0);
|
|
529
|
+
}, n.socket.onmessage = (l) => {
|
|
530
|
+
const p = JSON.parse(l.data);
|
|
531
|
+
Ee(p);
|
|
532
|
+
}, n.socket.onerror = (l) => {
|
|
533
|
+
S("error"), v(l.message || "Unable to connect voice"), o(l);
|
|
534
|
+
}, n.socket.onclose = (l) => {
|
|
535
|
+
D();
|
|
552
536
|
};
|
|
553
537
|
});
|
|
554
538
|
}
|
|
555
|
-
function
|
|
556
|
-
switch (
|
|
539
|
+
function Ee(e) {
|
|
540
|
+
switch (e.type) {
|
|
557
541
|
case "pong":
|
|
558
542
|
he();
|
|
559
543
|
break;
|
|
@@ -573,61 +557,57 @@ function be(e) {
|
|
|
573
557
|
S("error"), v(e.error || "Unable to connect voice");
|
|
574
558
|
break;
|
|
575
559
|
default:
|
|
576
|
-
console.log("Unknown call event type: ", e.type);
|
|
577
560
|
break;
|
|
578
561
|
}
|
|
579
562
|
}
|
|
580
563
|
async function Te(e) {
|
|
581
564
|
try {
|
|
582
|
-
if (
|
|
565
|
+
if (n.sessionId = e.sessionId, fe(e.sessionId), n.peerConnection) {
|
|
583
566
|
const t = new RTCSessionDescription({
|
|
584
567
|
type: "answer",
|
|
585
568
|
sdp: e.sdp
|
|
586
569
|
});
|
|
587
|
-
|
|
570
|
+
await n.peerConnection.setRemoteDescription(t);
|
|
588
571
|
for (const o of n.localIceCandidates)
|
|
589
572
|
w({
|
|
590
573
|
type: "ice",
|
|
591
574
|
data: {
|
|
592
575
|
candidate: o
|
|
593
576
|
}
|
|
594
|
-
})
|
|
577
|
+
});
|
|
595
578
|
n.localIceCandidates = [];
|
|
596
579
|
for (const o of n.pendingRemoteIceCandidates)
|
|
597
580
|
try {
|
|
598
|
-
const
|
|
599
|
-
await n.peerConnection.addIceCandidate(
|
|
600
|
-
} catch (
|
|
601
|
-
console.error(`Failed to add pending ICE candidate: ${a.message}`);
|
|
581
|
+
const r = new RTCIceCandidate(JSON.parse(o));
|
|
582
|
+
await n.peerConnection.addIceCandidate(r);
|
|
583
|
+
} catch (r) {
|
|
602
584
|
}
|
|
603
585
|
n.pendingRemoteIceCandidates = [];
|
|
604
586
|
}
|
|
605
587
|
} catch (t) {
|
|
606
|
-
console.error(`Failed to handle answer: ${t.message}`);
|
|
607
588
|
}
|
|
608
589
|
}
|
|
609
590
|
async function ve(e) {
|
|
610
591
|
try {
|
|
611
592
|
if (n.peerConnection) {
|
|
612
593
|
if (!n.peerConnection.remoteDescription) {
|
|
613
|
-
n.pendingRemoteIceCandidates.push(e.candidate)
|
|
594
|
+
n.pendingRemoteIceCandidates.push(e.candidate);
|
|
614
595
|
return;
|
|
615
596
|
}
|
|
616
597
|
const t = new RTCIceCandidate(JSON.parse(e.candidate));
|
|
617
|
-
await n.peerConnection.addIceCandidate(t)
|
|
598
|
+
await n.peerConnection.addIceCandidate(t);
|
|
618
599
|
}
|
|
619
600
|
} catch (t) {
|
|
620
|
-
console.error(`Failed to add ICE candidate: ${t.message}`);
|
|
621
601
|
}
|
|
622
602
|
}
|
|
623
603
|
async function De(e) {
|
|
624
604
|
try {
|
|
625
|
-
if (
|
|
605
|
+
if (n.peerConnection) {
|
|
626
606
|
const t = new RTCSessionDescription({
|
|
627
607
|
type: "offer",
|
|
628
608
|
sdp: e.sdp
|
|
629
609
|
});
|
|
630
|
-
|
|
610
|
+
await n.peerConnection.setRemoteDescription(t);
|
|
631
611
|
const o = await n.peerConnection.createAnswer();
|
|
632
612
|
await n.peerConnection.setLocalDescription(o), w({
|
|
633
613
|
type: "renegotiationAnswer",
|
|
@@ -637,27 +617,24 @@ async function De(e) {
|
|
|
637
617
|
});
|
|
638
618
|
}
|
|
639
619
|
} catch (t) {
|
|
640
|
-
console.error(`Failed to handle renegotiation offer: ${t.message}`);
|
|
641
620
|
}
|
|
642
621
|
}
|
|
643
622
|
async function xe(e = {}) {
|
|
644
623
|
try {
|
|
645
|
-
if (n.callStatus === "connecting" || n.callStatus === "connected")
|
|
646
|
-
console.log(`Call already in ${n.callStatus} state`);
|
|
624
|
+
if (n.callStatus === "connecting" || n.callStatus === "connected")
|
|
647
625
|
return;
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}), await Ee(e);
|
|
626
|
+
S("connecting"), v(null), n.sessionId = e.sessionId, await we(), ye(), n.localStream.getTracks().forEach((o) => {
|
|
627
|
+
n.peerConnection.addTrack(o, n.localStream);
|
|
628
|
+
}), await be(e);
|
|
652
629
|
const t = await n.peerConnection.createOffer();
|
|
653
630
|
await n.peerConnection.setLocalDescription(t), w({
|
|
654
631
|
type: "offer",
|
|
655
632
|
data: {
|
|
656
633
|
sdp: t.sdp
|
|
657
634
|
}
|
|
658
|
-
})
|
|
635
|
+
});
|
|
659
636
|
} catch (t) {
|
|
660
|
-
|
|
637
|
+
S("error"), v(t.message || "Unable to connect voice"), j();
|
|
661
638
|
}
|
|
662
639
|
}
|
|
663
640
|
function X() {
|
|
@@ -669,7 +646,7 @@ function qe() {
|
|
|
669
646
|
if (n.localStream) {
|
|
670
647
|
const e = n.localStream.getAudioTracks()[0];
|
|
671
648
|
if (e)
|
|
672
|
-
return e.enabled = !e.enabled, n.isMuted = !e.enabled,
|
|
649
|
+
return e.enabled = !e.enabled, n.isMuted = !e.enabled, n.isMuted;
|
|
673
650
|
}
|
|
674
651
|
return !1;
|
|
675
652
|
}
|
|
@@ -683,8 +660,8 @@ function Ge() {
|
|
|
683
660
|
return;
|
|
684
661
|
}
|
|
685
662
|
n.peerConnection.getStats().then((o) => {
|
|
686
|
-
o.forEach((
|
|
687
|
-
|
|
663
|
+
o.forEach((r) => {
|
|
664
|
+
r.type == "inbound-rtp" && e(r.totalAudioEnergy);
|
|
688
665
|
}), t(new Error("no inbound-rtp stats found"));
|
|
689
666
|
}).catch((o) => {
|
|
690
667
|
t(o);
|
|
@@ -698,8 +675,8 @@ function ze() {
|
|
|
698
675
|
return;
|
|
699
676
|
}
|
|
700
677
|
n.peerConnection.getStats().then((o) => {
|
|
701
|
-
o.forEach((
|
|
702
|
-
|
|
678
|
+
o.forEach((r) => {
|
|
679
|
+
r.type == "outbound-rtp" && e(r.totalAudioEnergy);
|
|
703
680
|
}), t(new Error("no outbound-rtp stats found"));
|
|
704
681
|
}).catch((o) => {
|
|
705
682
|
t(o);
|
|
@@ -709,19 +686,19 @@ function ze() {
|
|
|
709
686
|
export {
|
|
710
687
|
T as MESSAGE_ROLES,
|
|
711
688
|
ke as authenticate,
|
|
712
|
-
|
|
689
|
+
Ae as disconnect,
|
|
713
690
|
X as disconnectCall,
|
|
714
|
-
|
|
691
|
+
Ne as getHistory,
|
|
715
692
|
Ge as getInboundAudioEnergy,
|
|
716
693
|
Le as getLocalStream,
|
|
717
694
|
Se as getMessages,
|
|
718
695
|
ze as getOutboundAudioEnergy,
|
|
719
696
|
Oe as initialize,
|
|
720
|
-
|
|
697
|
+
Ue as sendMessage,
|
|
721
698
|
Me as setCallCallbacks,
|
|
722
699
|
Pe as setCallbacks,
|
|
723
700
|
xe as startCall,
|
|
724
|
-
|
|
701
|
+
Re as startChat,
|
|
725
702
|
qe as toggleMute
|
|
726
703
|
};
|
|
727
704
|
//# 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 BOT: 'assistant', // this can be automated or LLM AI Agent response\n USER: 'user', // this is widget user\n AGENT: 'agent', // this is human agent (dock side)\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 { getMessages, 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 */\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 }\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\n if (payload.sessionId) {\n const messagesRes = await getMessages(payload.sessionId)\n messages = (messagesRes?.sessionHistory ?? []).map((msg) => ({\n id: msg.id,\n text: msg.text,\n role: msg.youtubeVideo\n ? MESSAGE_ROLES.BOT // 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\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\n console.log('Chat initiated successfully')\n\n return {\n sessionId: currentSession.sessionId,\n messages,\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 // Add user message\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 // 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 const loadingMessage = {\n role: MESSAGE_ROLES.BOT,\n text: '',\n loading: true\n }\n addMessage(loadingMessage)\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: JSON.stringify({\n message: text,\n html,\n context\n }),\n signal: currentSession.abortController.signal,\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 } 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 (data.error) {\n const errorMessage =\n data.error && typeof data.error === 'string'\n ? data.error\n : 'Failed to connect to the system'\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n errorText: errorMessage\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n reject(new Error(errorMessage))\n } else if (data.message !== undefined) {\n // If 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.BOT,\n text: '',\n loading: true\n }\n addMessage(newBotMessage)\n }\n }\n\n // Update the last message with new content\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n text: (lastMsg.text || '') + data.message,\n sources: data.sources,\n done: data.done ?? lastMsg.done\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n\n if (data.done) {\n resolve(currentSession.sessionId)\n }\n\n // Store session info for reuse\n currentSession.sessionId = data.session_id ?? currentSession.sessionId\n currentSession.requestId = data.requestId ?? currentSession.requestId\n }\n },\n onerror: (error) => {\n throw error // Rethrow to stop retries\n },\n openWhenHidden: true\n })\n } catch (error) {\n console.error('Failed to send message: ', error)\n const errorMessage = 'Failed to connect to the system'\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n errorText: lastMsg.done ? undefined : error.message || errorMessage,\n done: true\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n reject(error)\n }\n })()\n })\n}\n","/**\n * API Service for Chat SDK\n * Handles all HTTP requests without depending on external state\n */\n\nimport { getCredentials, getExternalId } from './chat.js'\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 messages for a specific session\n * @param {string} sessionId\n * @returns {Promise<{ sessionHistory: Array }>}\n */\nexport async function getMessages(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 return response.json()\n}\n\n/**\n * Internal fetch request helper\n * @param {string} pathname\n * @param {string} method\n * @param {object|null} body\n * @returns {Promise<Response>}\n */\nasync function fetchRequest(pathname, method = 'GET', body = null) {\n const credentials = getCredentials()\n\n const { endpoint, token } = credentials || {}\n if (!endpoint) {\n throw new Error(INITIALIZATION_ERROR)\n }\n\n const url = `${endpoint}${pathname}`\n\n const headers = {\n 'Content-Type': 'application/json'\n }\n if (token) {\n headers.Authorization = `Bearer ${token}`\n }\n\n return fetch(url, {\n headers,\n method,\n body: body ? JSON.stringify(body) : null\n })\n}\n","/**\n * Socket Service for Call SDK\n * Handles WebRTC call functionality without depending on external state\n * Uses callbacks to communicate state changes to the consumer\n */\n\nimport { getCallServerEndpoint } from './utils.js'\nimport { getCredentials, getExternalId, updateSessionId } from './chat.js'\n\n/**\n * @typedef {Object} CallCallbacks\n * @property {(status: string) => void} [onCallStatus] - Called when call status changes\n * @property {(error: string | null) => void} [onCallError] - Called when call error occurs\n */\n\n/**\n * @typedef {Object} CallSession\n * @property {string} [sessionId]\n * @property {WebSocket} [socket]\n * @property {RTCPeerConnection} [peerConnection]\n * @property {MediaStream} [localStream]\n * @property {MediaStream} [remoteStream]\n * @property {HTMLAudioElement} [remoteAudio]\n * @property {boolean} isMuted\n * @property {string} callStatus\n * @property {NodeJS.Timeout} [pingInterval]\n * @property {number} pingCount\n * @property {number | null} lastPongTime\n * @property {CallCallbacks} callbacks\n * @property {string[]} localIceCandidates - Queued local ICE candidates to send after remote description is set\n * @property {string[]} pendingRemoteIceCandidates - Queued remote ICE candidates to add after remote description is set\n */\n\n/**\n * Create a new call session\n * @param {CallCallbacks} [callbacks={}]\n * @returns {CallSession}\n */\nfunction createSession(callbacks = {}) {\n return {\n sessionId: undefined,\n socket: null,\n peerConnection: null,\n localStream: null,\n remoteStream: null,\n remoteAudio: null,\n isMuted: false,\n callStatus: 'disconnected',\n pingInterval: null,\n pingCount: 0,\n lastPongTime: null,\n callbacks,\n localIceCandidates: [],\n pendingRemoteIceCandidates: []\n }\n}\n\n/** @type {CallSession} */\nlet currentSession = createSession()\n\nconst rtcConfig = {\n iceServers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun1.l.google.com:19302' }]\n}\n\n/**\n * Set callbacks for the current session\n * @param {CallCallbacks} callbacks\n */\nexport function setCallCallbacks(callbacks) {\n currentSession.callbacks = { ...currentSession.callbacks, ...callbacks }\n}\n\n/**\n * Clean up the current session\n */\nfunction cleanup() {\n if (currentSession.peerConnection) {\n currentSession.peerConnection.close()\n currentSession.peerConnection = null\n }\n\n if (currentSession.localStream) {\n currentSession.localStream.getTracks().forEach((track) => track.stop())\n currentSession.localStream = null\n }\n\n if (currentSession.remoteStream) {\n currentSession.remoteStream = null\n }\n\n if (currentSession.remoteAudio) {\n currentSession.remoteAudio.srcObject = null\n if (currentSession.remoteAudio.parentNode) {\n currentSession.remoteAudio.parentNode.removeChild(currentSession.remoteAudio)\n }\n currentSession.remoteAudio = null\n }\n\n if (currentSession.socket) {\n currentSession.socket.close()\n currentSession.socket = null\n }\n\n stopPingInterval()\n\n const callbacks = currentSession.callbacks\n currentSession = createSession(callbacks)\n\n console.log('Call session cleaned up')\n}\n\n/**\n * Update call status and notify callback\n * @param {string} status\n */\nfunction setCallStatus(status) {\n currentSession.callStatus = status\n currentSession.callbacks.onCallStatus?.(status)\n}\n\n/**\n * Update call error and notify callback\n * @param {string | null} error\n */\nfunction setCallError(error) {\n currentSession.callbacks.onCallError?.(error)\n}\n\n/**\n * Stop ping interval\n */\nfunction stopPingInterval() {\n if (currentSession.pingInterval) {\n clearInterval(currentSession.pingInterval)\n currentSession.pingInterval = null\n }\n}\n\n/**\n * Start ping interval\n */\nfunction startPingInterval() {\n stopPingInterval()\n\n currentSession.pingInterval = setInterval(() => {\n if (currentSession.socket && currentSession.socket.readyState === WebSocket.OPEN) {\n currentSession.pingCount++\n const pingMessage = {\n type: 'ping',\n timestamp: Date.now(),\n count: currentSession.pingCount\n }\n sendEvent(pingMessage)\n console.log(`Sending keep-alive ping #${currentSession.pingCount}`)\n } else {\n console.log('Socket not open, stopping ping interval')\n stopPingInterval()\n }\n }, 10000)\n}\n\n/**\n * Handle pong response\n */\nfunction handlePong() {\n currentSession.lastPongTime = Date.now()\n console.log(`Received pong #${currentSession.pingCount}`)\n}\n\n/**\n * Send event through socket\n * @param {Object} payload\n */\nfunction sendEvent(payload) {\n if (!currentSession.socket) {\n console.error('Failed to send event: no socket instance')\n return\n }\n if (currentSession.socket.readyState !== WebSocket.OPEN) {\n console.error('Failed to send event: socket state not open ', payload)\n return\n }\n\n currentSession.socket.send(JSON.stringify(payload))\n}\n\n/**\n * Get user media\n */\nasync function getUserMedia() {\n try {\n currentSession.localStream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n video: false\n })\n console.log('Got audio media')\n } catch (error) {\n console.error(`Failed to get audio media: ${error.message}`)\n throw error\n }\n}\n\n/**\n * Create peer connection\n */\nfunction createPeerConnection() {\n currentSession.peerConnection = new RTCPeerConnection(rtcConfig)\n\n currentSession.peerConnection.onicecandidate = (event) => {\n if (event.candidate) {\n const candidateJson = JSON.stringify(event.candidate)\n // Queue local ICE candidates until remote description is set\n if (currentSession.peerConnection && currentSession.peerConnection.remoteDescription) {\n sendEvent({\n type: 'ice',\n data: {\n candidate: candidateJson\n }\n })\n console.log('Sent ICE candidate immediately')\n } else {\n currentSession.localIceCandidates.push(candidateJson)\n console.log('Queued local ICE candidate')\n }\n }\n }\n\n currentSession.peerConnection.ontrack = (event) => {\n console.log('Received remote audio stream')\n currentSession.remoteStream = event.streams[0]\n\n if (!currentSession.remoteAudio) {\n currentSession.remoteAudio = document.createElement('audio')\n currentSession.remoteAudio.autoplay = true\n currentSession.remoteAudio.controls = false\n document.body.appendChild(currentSession.remoteAudio)\n }\n currentSession.remoteAudio.srcObject = currentSession.remoteStream\n // explicitly kick off playback and catch any policy/gesture errors\n currentSession.remoteAudio\n .play()\n .then(() => console.log('🔊 remote audio playing'))\n .catch((err) => console.error('❌ playback error:', err))\n }\n\n currentSession.peerConnection.onconnectionstatechange = () => {\n const newState = currentSession.peerConnection.connectionState\n console.log(`Connection state: ${newState}`)\n\n if (newState === 'connected') {\n setCallStatus('connected')\n } else if (newState === 'disconnected' || newState === 'closed') {\n setCallStatus('disconnected')\n disconnectCall()\n }\n }\n\n currentSession.peerConnection.oniceconnectionstatechange = () => {\n console.log(`ICE connection state: ${currentSession.peerConnection.iceConnectionState}`)\n }\n}\n\n/**\n * Connect socket\n * @param {{ sessionId?: string }} payload\n */\nfunction connectSocket(payload) {\n return new Promise((fulfill, reject) => {\n if (\n currentSession.socket &&\n (currentSession.socket.readyState === WebSocket.CONNECTING ||\n currentSession.socket.readyState === WebSocket.OPEN)\n ) {\n console.log('Socket in connecting/open state, returning.')\n fulfill(currentSession.socket.readyState === WebSocket.OPEN)\n return\n }\n\n console.log('Initializing socket connection..')\n const credentials = getCredentials()\n if (!credentials || !credentials.endpoint) {\n reject(new Error('SDK not initialized. Please initialize SDK first.'))\n return\n }\n\n // Extract hostname from endpoint\n const socketEndpoint = getCallServerEndpoint(credentials.endpoint)\n if (!socketEndpoint) {\n reject(\n new Error(\n 'Invalid endpoint while initializing SDK. Please check the endpoint and try again.'\n )\n )\n return\n }\n\n const externalId = getExternalId()\n const queryParams = new URLSearchParams({\n externalId\n })\n if (payload.sessionId) {\n queryParams.set('sessionId', payload.sessionId)\n }\n if (credentials.token) {\n queryParams.set('token', credentials.token)\n }\n\n const socketUrl = `${socketEndpoint}?${queryParams.toString()}`\n currentSession.socket = new WebSocket(socketUrl)\n\n currentSession.socket.onopen = (event) => {\n console.log('Socket connection established: ', event)\n startPingInterval()\n fulfill(true)\n }\n\n currentSession.socket.onmessage = (event) => {\n const data = JSON.parse(event.data)\n handleCallServerEvent(data)\n }\n\n currentSession.socket.onerror = (error) => {\n console.error('Socket error: ', error)\n setCallStatus('error')\n setCallError(error.message || 'Unable to connect voice')\n reject(error)\n }\n\n currentSession.socket.onclose = (event) => {\n console.log('Socket connection closed: ', event)\n stopPingInterval()\n }\n })\n}\n\n/**\n * Handle call server event\n * @param {Object} action\n */\nfunction handleCallServerEvent(action) {\n console.log('Handling socket server event: ', action)\n\n switch (action.type) {\n case 'pong':\n handlePong()\n break\n\n case 'answer':\n handleAnswer(action.data)\n break\n\n case 'ice':\n handleIceCandidate(action.data)\n break\n\n case 'renegotiationOffer':\n handleRenegotiationOffer(action.data)\n break\n case 'end':\n disconnectCall()\n break\n case 'error':\n setCallStatus('error')\n setCallError(action.error || 'Unable to connect voice')\n break\n\n default:\n console.log('Unknown call event type: ', action.type)\n break\n }\n}\n\n/**\n * Handle answer\n * @param {Object} data\n */\nasync function handleAnswer(data) {\n try {\n console.log('Received answer')\n\n currentSession.sessionId = data.sessionId\n // Update chat session with the new sessionId and notify controller\n updateSessionId(data.sessionId)\n\n if (currentSession.peerConnection) {\n const answer = new RTCSessionDescription({\n type: 'answer',\n sdp: data.sdp\n })\n console.log('Setting remote description answer: ', answer)\n await currentSession.peerConnection.setRemoteDescription(answer)\n console.log('Remote description set')\n\n // Send all queued local ICE candidates\n for (const candidateJson of currentSession.localIceCandidates) {\n sendEvent({\n type: 'ice',\n data: {\n candidate: candidateJson\n }\n })\n console.log('Sent queued local ICE candidate')\n }\n currentSession.localIceCandidates = []\n\n // Process any pending remote ICE candidates\n for (const candidateJson of currentSession.pendingRemoteIceCandidates) {\n try {\n const candidate = new RTCIceCandidate(JSON.parse(candidateJson))\n await currentSession.peerConnection.addIceCandidate(candidate)\n console.log('Added pending remote ICE candidate')\n } catch (err) {\n console.error(`Failed to add pending ICE candidate: ${err.message}`)\n }\n }\n currentSession.pendingRemoteIceCandidates = []\n }\n } catch (error) {\n console.error(`Failed to handle answer: ${error.message}`)\n }\n}\n\n/**\n * Handle ICE candidate\n * @param {Object} data\n */\nasync function handleIceCandidate(data) {\n try {\n if (currentSession.peerConnection) {\n // Check if remote description is set\n if (!currentSession.peerConnection.remoteDescription) {\n // Queue the candidate until remote description is set\n currentSession.pendingRemoteIceCandidates.push(data.candidate)\n console.log('Queued remote ICE candidate - remote description not set')\n return\n }\n const candidate = new RTCIceCandidate(JSON.parse(data.candidate))\n await currentSession.peerConnection.addIceCandidate(candidate)\n console.log('Added ICE candidate')\n }\n } catch (error) {\n console.error(`Failed to add ICE candidate: ${error.message}`)\n }\n}\n\n/**\n * Handle renegotiation offer\n * @param {Object} data\n */\nasync function handleRenegotiationOffer(data) {\n try {\n console.log('Received renegotiation offer')\n\n if (currentSession.peerConnection) {\n const offer = new RTCSessionDescription({\n type: 'offer',\n sdp: data.sdp\n })\n console.log('Setting remote description offer: ', offer)\n await currentSession.peerConnection.setRemoteDescription(offer)\n console.log('Remote description set')\n\n const answer = await currentSession.peerConnection.createAnswer()\n await currentSession.peerConnection.setLocalDescription(answer)\n\n sendEvent({\n type: 'renegotiationAnswer',\n data: {\n sdp: answer.sdp\n }\n })\n }\n } catch (error) {\n console.error(`Failed to handle renegotiation offer: ${error.message}`)\n }\n}\n\n/**\n * Start a call\n * @param {{ sessionId?: string }} payload\n */\nexport async function startCall(payload = {}) {\n try {\n if (currentSession.callStatus === 'connecting' || currentSession.callStatus === 'connected') {\n console.log(`Call already in ${currentSession.callStatus} state`)\n return\n }\n\n console.log('Starting audio call...')\n setCallStatus('connecting')\n setCallError(null)\n\n currentSession.sessionId = payload.sessionId\n\n await getUserMedia()\n\n createPeerConnection()\n\n currentSession.localStream.getTracks().forEach((track) => {\n currentSession.peerConnection.addTrack(track, currentSession.localStream)\n console.log(`Added ${track.kind} track`)\n })\n await connectSocket(payload)\n const offer = await currentSession.peerConnection.createOffer()\n await currentSession.peerConnection.setLocalDescription(offer)\n\n sendEvent({\n type: 'offer',\n data: {\n sdp: offer.sdp\n }\n })\n\n console.log('Call initiated successfully')\n } catch (error) {\n console.log('error: ', error)\n console.error(`Failed to start call: ${error.message}`)\n setCallStatus('error')\n setCallError(error.message || 'Unable to connect voice')\n cleanup()\n }\n}\n\n/**\n * Disconnect call\n */\nexport function disconnectCall() {\n sendEvent({\n type: 'end'\n })\n if (currentSession.socket) {\n currentSession.socket.close()\n currentSession.socket = null\n }\n setCallStatus('disconnected')\n if (currentSession.peerConnection) {\n currentSession.peerConnection.close()\n currentSession.peerConnection = null\n }\n if (currentSession.localStream) {\n currentSession.localStream.getTracks().forEach((track) => track.stop())\n currentSession.localStream = null\n }\n cleanup()\n}\n\n/**\n * Toggle mute\n * @returns {boolean}\n */\nexport function toggleMute() {\n if (currentSession.localStream) {\n const audioTrack = currentSession.localStream.getAudioTracks()[0]\n if (audioTrack) {\n audioTrack.enabled = !audioTrack.enabled\n currentSession.isMuted = !audioTrack.enabled\n console.log(`Audio ${currentSession.isMuted ? 'muted' : 'unmuted'}`)\n return currentSession.isMuted\n }\n }\n return false\n}\n\n/**\n * Get local stream\n * @returns {MediaStream | null}\n */\nexport function getLocalStream() {\n return currentSession.localStream\n}\n\n/**\n * Get inbound audio energy\n * @returns {Promise<number>}\n */\nexport function getInboundAudioEnergy() {\n return new Promise((resolve, reject) => {\n if (!currentSession.peerConnection) {\n reject(new Error('no peer connection'))\n return\n }\n currentSession.peerConnection\n .getStats()\n .then((stats) => {\n stats.forEach((report) => {\n if (report.type == 'inbound-rtp') {\n resolve(report.totalAudioEnergy)\n }\n })\n reject(new Error('no inbound-rtp stats found'))\n })\n .catch((err) => {\n reject(err)\n })\n })\n}\n\n/**\n * Get outbound audio energy (not implemented in original, but may be needed)\n * @returns {Promise<number>}\n */\nexport function getOutboundAudioEnergy() {\n return new Promise((resolve, reject) => {\n if (!currentSession.peerConnection) {\n reject(new Error('no peer connection'))\n return\n }\n currentSession.peerConnection\n .getStats()\n .then((stats) => {\n stats.forEach((report) => {\n if (report.type == 'outbound-rtp') {\n resolve(report.totalAudioEnergy)\n }\n })\n reject(new Error('no outbound-rtp stats found'))\n })\n .catch((err) => {\n reject(err)\n })\n })\n}\n"],"names":["uuidv7","timestamp","bytes","hex","b","getDeviceId","deviceId","sleep","ms","resolve","getSseEndpoint","baseUrl","sseEndpoint","url","e","getSocketEndpoint","socketEndpoint","getCallServerEndpoint","MESSAGE_ROLES","PING_INTERVAL","SOCKET_TIMEOUT","SocketEvents","createSession","currentSession","stopPingInterval","startPingInterval","send","clearAllTimeouts","handleSocketConnected","setTransport","handleSocketDisconnected","connectSocket","payload","fulfill","reject","credentials","getCredentials","externalId","getExternalId","queryParams","socketUrl","event","message","handleSocketEvent","error","ws","addMessage","data","toggleTypingStatus","eventId","disconnect","isConnected","callbacks","setCallbacks","initialize","updateSessionId","sessionId","startChat","configData","authenticate","messages","messagesRes","getMessages","_a","msg","searchParams","cleanup","disconnectSocket","isTyping","transport","sendMessage","text","html","context","userMessage","isSocketConnected","socketSend","loadingMessage","headers","fetchEventSource","response","errorMessage","lastIndex","updatedMsg","index","newBotMessage","lastMsg","_c","_f","_g","AUTHENTICATION_ERROR","INITIALIZATION_ERROR","endpoint","errorPayload","getHistory","fetchRequest","pathname","method","body","token","rtcConfig","setCallCallbacks","track","setCallStatus","status","_b","setCallError","pingMessage","sendEvent","handlePong","getUserMedia","createPeerConnection","candidateJson","err","newState","disconnectCall","handleCallServerEvent","action","handleAnswer","handleIceCandidate","handleRenegotiationOffer","answer","candidate","offer","startCall","toggleMute","audioTrack","getLocalStream","getInboundAudioEnergy","stats","report","getOutboundAudioEnergy"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"origon-chat-sdk.js","sources":["../src/utils.js","../src/constants.js","../src/socket.js","../src/chat.js","../src/http.js","../src/call.js"],"sourcesContent":["/**\n * Utility functions for the Chat SDK\n */\n\nexport function uuidv7() {\n const timestamp = Date.now()\n const bytes = new Uint8Array(16)\n crypto.getRandomValues(bytes)\n\n // Set timestamp (48 bits)\n bytes[0] = (timestamp >> 40) & 0xff\n bytes[1] = (timestamp >> 32) & 0xff\n bytes[2] = (timestamp >> 24) & 0xff\n bytes[3] = (timestamp >> 16) & 0xff\n bytes[4] = (timestamp >> 8) & 0xff\n bytes[5] = timestamp & 0xff\n\n // Set version 7 (0111)\n bytes[6] = (bytes[6] & 0x0f) | 0x70\n\n // Set variant (10xx)\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n\n const hex = [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('')\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(\n 16,\n 20\n )}-${hex.slice(20)}`\n}\n\nexport function getDeviceId() {\n if (localStorage.getItem('chatDeviceId')) {\n return localStorage.getItem('chatDeviceId')\n }\n\n const deviceId = uuidv7()\n localStorage.setItem('chatDeviceId', deviceId)\n return deviceId\n}\n\nexport function parseJwt(token) {\n try {\n const base64Url = token.split('.')[1]\n const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')\n const jsonPayload = decodeURIComponent(\n atob(base64)\n .split('')\n .map(function (c) {\n return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\n })\n .join('')\n )\n\n return JSON.parse(jsonPayload)\n } catch {\n return null\n }\n}\n\nexport async function sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport function getSseEndpoint(baseUrl) {\n let sseEndpoint\n try {\n const url = new URL(baseUrl)\n sseEndpoint = `https://${url.hostname}${url.pathname}/sse`\n } catch {\n console.error('SSE Invalid base URL: ', baseUrl)\n }\n return sseEndpoint\n}\n\nexport function getSocketEndpoint(baseUrl) {\n let socketEndpoint\n try {\n const url = new URL(baseUrl)\n socketEndpoint = `wss://${url.hostname}${url.pathname}/wss`\n } catch {\n console.error('Socket Invalid base URL: ', baseUrl)\n }\n return socketEndpoint\n}\n\nexport function getCallServerEndpoint(baseUrl) {\n let socketEndpoint\n try {\n const url = new URL(baseUrl)\n socketEndpoint = `wss://${url.hostname}${url.pathname}/audio`\n } catch {\n console.error('getCallServerEndpoint: Invalid base URL: ', baseUrl)\n }\n return socketEndpoint\n}\n","/**\n * Constants for the Chat SDK\n */\n\nexport const MESSAGE_ROLES = {\n BOT: 'assistant', // this can be automated or LLM AI Agent response\n USER: 'user', // this is widget user\n AGENT: 'agent', // this is human agent (dock side)\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 { getMessages, 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 */\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 }\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\n if (payload.sessionId) {\n messages = await getMessages(payload.sessionId)\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\n console.log('Chat initiated successfully')\n\n return {\n sessionId: currentSession.sessionId,\n messages,\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 // Add user message\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 // 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 const loadingMessage = {\n role: MESSAGE_ROLES.BOT,\n text: '',\n loading: true\n }\n addMessage(loadingMessage)\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: JSON.stringify({\n message: text,\n html,\n context\n }),\n signal: currentSession.abortController.signal,\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 } 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 (data.error) {\n const errorMessage =\n data.error && typeof data.error === 'string'\n ? data.error\n : 'Failed to connect to the system'\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n errorText: errorMessage\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n reject(new Error(errorMessage))\n } else if (data.message !== undefined) {\n // If 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.BOT,\n text: '',\n loading: true\n }\n addMessage(newBotMessage)\n }\n }\n\n // Update the last message with new content\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n text: (lastMsg.text || '') + data.message,\n sources: data.sources,\n done: data.done ?? lastMsg.done\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n\n if (data.done) {\n resolve(currentSession.sessionId)\n }\n\n // Store session info for reuse\n currentSession.sessionId = data.session_id ?? currentSession.sessionId\n currentSession.requestId = data.requestId ?? currentSession.requestId\n }\n },\n onerror: (error) => {\n throw error // Rethrow to stop retries\n },\n openWhenHidden: true\n })\n } catch (error) {\n console.error('Failed to send message: ', error)\n const errorMessage = 'Failed to connect to the system'\n const lastIndex = currentSession.messages.length - 1\n const lastMsg = currentSession.messages[lastIndex]\n const updatedMsg = {\n ...lastMsg,\n loading: false,\n errorText: lastMsg.done ? undefined : error.message || errorMessage,\n done: true\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n reject(error)\n }\n })()\n })\n}\n","/**\n * API Service for Chat SDK\n * Handles all HTTP requests without depending on external state\n */\n\nimport { getCredentials, getExternalId } from './chat.js'\nimport { MESSAGE_ROLES } from './constants.js'\n\nconst AUTHENTICATION_ERROR = 'Something went wrong initializing the chat'\nconst INITIALIZATION_ERROR = 'Chat SDK not initialized'\n\n/**\n * Authenticate with the chat service\n * @param {{ endpoint: string }} credentials\n * @returns {Promise<object>} Authentication response data\n */\nexport async function authenticate(payload) {\n const { endpoint } = payload\n const url = `${endpoint}/config`\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json'\n }\n })\n\n if (!response.ok) {\n const errorPayload = await response.json()\n throw new Error(errorPayload?.error || AUTHENTICATION_ERROR)\n }\n\n const res = await response.json()\n const data = res.data\n\n return data\n}\n\n/**\n * Get chat history for the current device\n * @returns {Promise<{ sessions: Array }>}\n */\nexport async function getHistory() {\n const queryParams = new URLSearchParams({\n externalId: getExternalId()\n })\n const response = await fetchRequest(`/sessions?${queryParams.toString()}`, 'GET')\n\n if (!response.ok) {\n throw new Error('Unable to load history, please try again later')\n }\n\n return response.json()\n}\n\n/**\n * Get messages for a specific session\n * @param {string} sessionId\n * @returns {Promise<{ sessionHistory: Array }>}\n */\nexport async function getMessages(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 messages = (data?.sessionHistory ?? []).map((msg) => ({\n id: msg.id,\n text: msg.text,\n role: msg.youtubeVideo\n ? MESSAGE_ROLES.BOT // 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 messages\n}\n\n/**\n * Internal fetch request helper\n * @param {string} pathname\n * @param {string} method\n * @param {object|null} body\n * @returns {Promise<Response>}\n */\nasync function fetchRequest(pathname, method = 'GET', body = null) {\n const credentials = getCredentials()\n\n const { endpoint, token } = credentials || {}\n if (!endpoint) {\n throw new Error(INITIALIZATION_ERROR)\n }\n\n const url = `${endpoint}${pathname}`\n\n const headers = {\n 'Content-Type': 'application/json'\n }\n if (token) {\n headers.Authorization = `Bearer ${token}`\n }\n\n return fetch(url, {\n headers,\n method,\n body: body ? JSON.stringify(body) : null\n })\n}\n","/**\n * Socket Service for Call SDK\n * Handles WebRTC call functionality without depending on external state\n * Uses callbacks to communicate state changes to the consumer\n */\n\nimport { getCallServerEndpoint } from './utils.js'\nimport { getCredentials, getExternalId, updateSessionId } from './chat.js'\n\n/**\n * @typedef {Object} CallCallbacks\n * @property {(status: string) => void} [onCallStatus] - Called when call status changes\n * @property {(error: string | null) => void} [onCallError] - Called when call error occurs\n */\n\n/**\n * @typedef {Object} CallSession\n * @property {string} [sessionId]\n * @property {WebSocket} [socket]\n * @property {RTCPeerConnection} [peerConnection]\n * @property {MediaStream} [localStream]\n * @property {MediaStream} [remoteStream]\n * @property {HTMLAudioElement} [remoteAudio]\n * @property {boolean} isMuted\n * @property {string} callStatus\n * @property {NodeJS.Timeout} [pingInterval]\n * @property {number} pingCount\n * @property {number | null} lastPongTime\n * @property {CallCallbacks} callbacks\n * @property {string[]} localIceCandidates - Queued local ICE candidates to send after remote description is set\n * @property {string[]} pendingRemoteIceCandidates - Queued remote ICE candidates to add after remote description is set\n */\n\n/**\n * Create a new call session\n * @param {CallCallbacks} [callbacks={}]\n * @returns {CallSession}\n */\nfunction createSession(callbacks = {}) {\n return {\n sessionId: undefined,\n socket: null,\n peerConnection: null,\n localStream: null,\n remoteStream: null,\n remoteAudio: null,\n isMuted: false,\n callStatus: 'disconnected',\n pingInterval: null,\n pingCount: 0,\n lastPongTime: null,\n callbacks,\n localIceCandidates: [],\n pendingRemoteIceCandidates: []\n }\n}\n\n/** @type {CallSession} */\nlet currentSession = createSession()\n\nconst rtcConfig = {\n iceServers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun1.l.google.com:19302' }]\n}\n\n/**\n * Set callbacks for the current session\n * @param {CallCallbacks} callbacks\n */\nexport function setCallCallbacks(callbacks) {\n currentSession.callbacks = { ...currentSession.callbacks, ...callbacks }\n}\n\n/**\n * Clean up the current session\n */\nfunction cleanup() {\n if (currentSession.peerConnection) {\n currentSession.peerConnection.close()\n currentSession.peerConnection = null\n }\n\n if (currentSession.localStream) {\n currentSession.localStream.getTracks().forEach((track) => track.stop())\n currentSession.localStream = null\n }\n\n if (currentSession.remoteStream) {\n currentSession.remoteStream = null\n }\n\n if (currentSession.remoteAudio) {\n currentSession.remoteAudio.srcObject = null\n if (currentSession.remoteAudio.parentNode) {\n currentSession.remoteAudio.parentNode.removeChild(currentSession.remoteAudio)\n }\n currentSession.remoteAudio = null\n }\n\n if (currentSession.socket) {\n currentSession.socket.close()\n currentSession.socket = null\n }\n\n stopPingInterval()\n\n const callbacks = currentSession.callbacks\n currentSession = createSession(callbacks)\n\n console.log('Call session cleaned up')\n}\n\n/**\n * Update call status and notify callback\n * @param {string} status\n */\nfunction setCallStatus(status) {\n currentSession.callStatus = status\n currentSession.callbacks.onCallStatus?.(status)\n}\n\n/**\n * Update call error and notify callback\n * @param {string | null} error\n */\nfunction setCallError(error) {\n currentSession.callbacks.onCallError?.(error)\n}\n\n/**\n * Stop ping interval\n */\nfunction stopPingInterval() {\n if (currentSession.pingInterval) {\n clearInterval(currentSession.pingInterval)\n currentSession.pingInterval = null\n }\n}\n\n/**\n * Start ping interval\n */\nfunction startPingInterval() {\n stopPingInterval()\n\n currentSession.pingInterval = setInterval(() => {\n if (currentSession.socket && currentSession.socket.readyState === WebSocket.OPEN) {\n currentSession.pingCount++\n const pingMessage = {\n type: 'ping',\n timestamp: Date.now(),\n count: currentSession.pingCount\n }\n sendEvent(pingMessage)\n console.log(`Sending keep-alive ping #${currentSession.pingCount}`)\n } else {\n console.log('Socket not open, stopping ping interval')\n stopPingInterval()\n }\n }, 10000)\n}\n\n/**\n * Handle pong response\n */\nfunction handlePong() {\n currentSession.lastPongTime = Date.now()\n console.log(`Received pong #${currentSession.pingCount}`)\n}\n\n/**\n * Send event through socket\n * @param {Object} payload\n */\nfunction sendEvent(payload) {\n if (!currentSession.socket) {\n console.error('Failed to send event: no socket instance')\n return\n }\n if (currentSession.socket.readyState !== WebSocket.OPEN) {\n console.error('Failed to send event: socket state not open ', payload)\n return\n }\n\n currentSession.socket.send(JSON.stringify(payload))\n}\n\n/**\n * Get user media\n */\nasync function getUserMedia() {\n try {\n currentSession.localStream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n video: false\n })\n console.log('Got audio media')\n } catch (error) {\n console.error(`Failed to get audio media: ${error.message}`)\n throw error\n }\n}\n\n/**\n * Create peer connection\n */\nfunction createPeerConnection() {\n currentSession.peerConnection = new RTCPeerConnection(rtcConfig)\n\n currentSession.peerConnection.onicecandidate = (event) => {\n if (event.candidate) {\n const candidateJson = JSON.stringify(event.candidate)\n // Queue local ICE candidates until remote description is set\n if (currentSession.peerConnection && currentSession.peerConnection.remoteDescription) {\n sendEvent({\n type: 'ice',\n data: {\n candidate: candidateJson\n }\n })\n console.log('Sent ICE candidate immediately')\n } else {\n currentSession.localIceCandidates.push(candidateJson)\n console.log('Queued local ICE candidate')\n }\n }\n }\n\n currentSession.peerConnection.ontrack = (event) => {\n console.log('Received remote audio stream')\n currentSession.remoteStream = event.streams[0]\n\n if (!currentSession.remoteAudio) {\n currentSession.remoteAudio = document.createElement('audio')\n currentSession.remoteAudio.autoplay = true\n currentSession.remoteAudio.controls = false\n document.body.appendChild(currentSession.remoteAudio)\n }\n currentSession.remoteAudio.srcObject = currentSession.remoteStream\n // explicitly kick off playback and catch any policy/gesture errors\n currentSession.remoteAudio\n .play()\n .then(() => console.log('🔊 remote audio playing'))\n .catch((err) => console.error('❌ playback error:', err))\n }\n\n currentSession.peerConnection.onconnectionstatechange = () => {\n const newState = currentSession.peerConnection.connectionState\n console.log(`Connection state: ${newState}`)\n\n if (newState === 'connected') {\n setCallStatus('connected')\n } else if (newState === 'disconnected' || newState === 'closed') {\n setCallStatus('disconnected')\n disconnectCall()\n }\n }\n\n currentSession.peerConnection.oniceconnectionstatechange = () => {\n console.log(`ICE connection state: ${currentSession.peerConnection.iceConnectionState}`)\n }\n}\n\n/**\n * Connect socket\n * @param {{ sessionId?: string }} payload\n */\nfunction connectSocket(payload) {\n return new Promise((fulfill, reject) => {\n if (\n currentSession.socket &&\n (currentSession.socket.readyState === WebSocket.CONNECTING ||\n currentSession.socket.readyState === WebSocket.OPEN)\n ) {\n console.log('Socket in connecting/open state, returning.')\n fulfill(currentSession.socket.readyState === WebSocket.OPEN)\n return\n }\n\n console.log('Initializing socket connection..')\n const credentials = getCredentials()\n if (!credentials || !credentials.endpoint) {\n reject(new Error('SDK not initialized. Please initialize SDK first.'))\n return\n }\n\n // Extract hostname from endpoint\n const socketEndpoint = getCallServerEndpoint(credentials.endpoint)\n if (!socketEndpoint) {\n reject(\n new Error(\n 'Invalid endpoint while initializing SDK. Please check the endpoint and try again.'\n )\n )\n return\n }\n\n const externalId = getExternalId()\n const queryParams = new URLSearchParams({\n externalId\n })\n if (payload.sessionId) {\n queryParams.set('sessionId', payload.sessionId)\n }\n if (credentials.token) {\n queryParams.set('token', credentials.token)\n }\n\n const socketUrl = `${socketEndpoint}?${queryParams.toString()}`\n currentSession.socket = new WebSocket(socketUrl)\n\n currentSession.socket.onopen = (event) => {\n console.log('Socket connection established: ', event)\n startPingInterval()\n fulfill(true)\n }\n\n currentSession.socket.onmessage = (event) => {\n const data = JSON.parse(event.data)\n handleCallServerEvent(data)\n }\n\n currentSession.socket.onerror = (error) => {\n console.error('Socket error: ', error)\n setCallStatus('error')\n setCallError(error.message || 'Unable to connect voice')\n reject(error)\n }\n\n currentSession.socket.onclose = (event) => {\n console.log('Socket connection closed: ', event)\n stopPingInterval()\n }\n })\n}\n\n/**\n * Handle call server event\n * @param {Object} action\n */\nfunction handleCallServerEvent(action) {\n console.log('Handling socket server event: ', action)\n\n switch (action.type) {\n case 'pong':\n handlePong()\n break\n\n case 'answer':\n handleAnswer(action.data)\n break\n\n case 'ice':\n handleIceCandidate(action.data)\n break\n\n case 'renegotiationOffer':\n handleRenegotiationOffer(action.data)\n break\n case 'end':\n disconnectCall()\n break\n case 'error':\n setCallStatus('error')\n setCallError(action.error || 'Unable to connect voice')\n break\n\n default:\n console.log('Unknown call event type: ', action.type)\n break\n }\n}\n\n/**\n * Handle answer\n * @param {Object} data\n */\nasync function handleAnswer(data) {\n try {\n console.log('Received answer')\n\n currentSession.sessionId = data.sessionId\n // Update chat session with the new sessionId and notify controller\n updateSessionId(data.sessionId)\n\n if (currentSession.peerConnection) {\n const answer = new RTCSessionDescription({\n type: 'answer',\n sdp: data.sdp\n })\n console.log('Setting remote description answer: ', answer)\n await currentSession.peerConnection.setRemoteDescription(answer)\n console.log('Remote description set')\n\n // Send all queued local ICE candidates\n for (const candidateJson of currentSession.localIceCandidates) {\n sendEvent({\n type: 'ice',\n data: {\n candidate: candidateJson\n }\n })\n console.log('Sent queued local ICE candidate')\n }\n currentSession.localIceCandidates = []\n\n // Process any pending remote ICE candidates\n for (const candidateJson of currentSession.pendingRemoteIceCandidates) {\n try {\n const candidate = new RTCIceCandidate(JSON.parse(candidateJson))\n await currentSession.peerConnection.addIceCandidate(candidate)\n console.log('Added pending remote ICE candidate')\n } catch (err) {\n console.error(`Failed to add pending ICE candidate: ${err.message}`)\n }\n }\n currentSession.pendingRemoteIceCandidates = []\n }\n } catch (error) {\n console.error(`Failed to handle answer: ${error.message}`)\n }\n}\n\n/**\n * Handle ICE candidate\n * @param {Object} data\n */\nasync function handleIceCandidate(data) {\n try {\n if (currentSession.peerConnection) {\n // Check if remote description is set\n if (!currentSession.peerConnection.remoteDescription) {\n // Queue the candidate until remote description is set\n currentSession.pendingRemoteIceCandidates.push(data.candidate)\n console.log('Queued remote ICE candidate - remote description not set')\n return\n }\n const candidate = new RTCIceCandidate(JSON.parse(data.candidate))\n await currentSession.peerConnection.addIceCandidate(candidate)\n console.log('Added ICE candidate')\n }\n } catch (error) {\n console.error(`Failed to add ICE candidate: ${error.message}`)\n }\n}\n\n/**\n * Handle renegotiation offer\n * @param {Object} data\n */\nasync function handleRenegotiationOffer(data) {\n try {\n console.log('Received renegotiation offer')\n\n if (currentSession.peerConnection) {\n const offer = new RTCSessionDescription({\n type: 'offer',\n sdp: data.sdp\n })\n console.log('Setting remote description offer: ', offer)\n await currentSession.peerConnection.setRemoteDescription(offer)\n console.log('Remote description set')\n\n const answer = await currentSession.peerConnection.createAnswer()\n await currentSession.peerConnection.setLocalDescription(answer)\n\n sendEvent({\n type: 'renegotiationAnswer',\n data: {\n sdp: answer.sdp\n }\n })\n }\n } catch (error) {\n console.error(`Failed to handle renegotiation offer: ${error.message}`)\n }\n}\n\n/**\n * Start a call\n * @param {{ sessionId?: string }} payload\n */\nexport async function startCall(payload = {}) {\n try {\n if (currentSession.callStatus === 'connecting' || currentSession.callStatus === 'connected') {\n console.log(`Call already in ${currentSession.callStatus} state`)\n return\n }\n\n console.log('Starting audio call...')\n setCallStatus('connecting')\n setCallError(null)\n\n currentSession.sessionId = payload.sessionId\n\n await getUserMedia()\n\n createPeerConnection()\n\n currentSession.localStream.getTracks().forEach((track) => {\n currentSession.peerConnection.addTrack(track, currentSession.localStream)\n console.log(`Added ${track.kind} track`)\n })\n await connectSocket(payload)\n const offer = await currentSession.peerConnection.createOffer()\n await currentSession.peerConnection.setLocalDescription(offer)\n\n sendEvent({\n type: 'offer',\n data: {\n sdp: offer.sdp\n }\n })\n\n console.log('Call initiated successfully')\n } catch (error) {\n console.log('error: ', error)\n console.error(`Failed to start call: ${error.message}`)\n setCallStatus('error')\n setCallError(error.message || 'Unable to connect voice')\n cleanup()\n }\n}\n\n/**\n * Disconnect call\n */\nexport function disconnectCall() {\n sendEvent({\n type: 'end'\n })\n if (currentSession.socket) {\n currentSession.socket.close()\n currentSession.socket = null\n }\n setCallStatus('disconnected')\n if (currentSession.peerConnection) {\n currentSession.peerConnection.close()\n currentSession.peerConnection = null\n }\n if (currentSession.localStream) {\n currentSession.localStream.getTracks().forEach((track) => track.stop())\n currentSession.localStream = null\n }\n cleanup()\n}\n\n/**\n * Toggle mute\n * @returns {boolean}\n */\nexport function toggleMute() {\n if (currentSession.localStream) {\n const audioTrack = currentSession.localStream.getAudioTracks()[0]\n if (audioTrack) {\n audioTrack.enabled = !audioTrack.enabled\n currentSession.isMuted = !audioTrack.enabled\n console.log(`Audio ${currentSession.isMuted ? 'muted' : 'unmuted'}`)\n return currentSession.isMuted\n }\n }\n return false\n}\n\n/**\n * Get local stream\n * @returns {MediaStream | null}\n */\nexport function getLocalStream() {\n return currentSession.localStream\n}\n\n/**\n * Get inbound audio energy\n * @returns {Promise<number>}\n */\nexport function getInboundAudioEnergy() {\n return new Promise((resolve, reject) => {\n if (!currentSession.peerConnection) {\n reject(new Error('no peer connection'))\n return\n }\n currentSession.peerConnection\n .getStats()\n .then((stats) => {\n stats.forEach((report) => {\n if (report.type == 'inbound-rtp') {\n resolve(report.totalAudioEnergy)\n }\n })\n reject(new Error('no inbound-rtp stats found'))\n })\n .catch((err) => {\n reject(err)\n })\n })\n}\n\n/**\n * Get outbound audio energy (not implemented in original, but may be needed)\n * @returns {Promise<number>}\n */\nexport function getOutboundAudioEnergy() {\n return new Promise((resolve, reject) => {\n if (!currentSession.peerConnection) {\n reject(new Error('no peer connection'))\n return\n }\n currentSession.peerConnection\n .getStats()\n .then((stats) => {\n stats.forEach((report) => {\n if (report.type == 'outbound-rtp') {\n resolve(report.totalAudioEnergy)\n }\n })\n reject(new Error('no outbound-rtp stats found'))\n })\n .catch((err) => {\n reject(err)\n })\n })\n}\n"],"names":["uuidv7","timestamp","bytes","hex","b","getDeviceId","deviceId","sleep","ms","resolve","getSseEndpoint","baseUrl","sseEndpoint","url","e","getSocketEndpoint","socketEndpoint","getCallServerEndpoint","MESSAGE_ROLES","PING_INTERVAL","SOCKET_TIMEOUT","SocketEvents","createSession","currentSession","stopPingInterval","startPingInterval","send","clearAllTimeouts","handleSocketConnected","setTransport","handleSocketDisconnected","connectSocket","payload","fulfill","reject","credentials","getCredentials","externalId","getExternalId","queryParams","socketUrl","event","message","handleSocketEvent","error","ws","addMessage","data","toggleTypingStatus","eventId","disconnect","isConnected","callbacks","setCallbacks","initialize","updateSessionId","sessionId","startChat","configData","authenticate","messages","getMessages","searchParams","cleanup","disconnectSocket","isTyping","transport","sendMessage","text","html","context","userMessage","isSocketConnected","socketSend","loadingMessage","headers","fetchEventSource","response","errorMessage","lastIndex","updatedMsg","msg","index","newBotMessage","lastMsg","_c","_f","_g","AUTHENTICATION_ERROR","INITIALIZATION_ERROR","endpoint","errorPayload","getHistory","fetchRequest","_a","pathname","method","body","token","rtcConfig","setCallCallbacks","track","setCallStatus","status","_b","setCallError","pingMessage","sendEvent","handlePong","getUserMedia","createPeerConnection","candidateJson","err","newState","disconnectCall","handleCallServerEvent","action","handleAnswer","handleIceCandidate","handleRenegotiationOffer","answer","candidate","offer","startCall","toggleMute","audioTrack","getLocalStream","getInboundAudioEnergy","stats","report","getOutboundAudioEnergy"],"mappings":"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"}
|
package/package.json
CHANGED
package/src/chat.js
CHANGED
|
@@ -125,18 +125,7 @@ export async function startChat(payload = {}) {
|
|
|
125
125
|
let messages = []
|
|
126
126
|
|
|
127
127
|
if (payload.sessionId) {
|
|
128
|
-
|
|
129
|
-
messages = (messagesRes?.sessionHistory ?? []).map((msg) => ({
|
|
130
|
-
id: msg.id,
|
|
131
|
-
text: msg.text,
|
|
132
|
-
role: msg.youtubeVideo
|
|
133
|
-
? MESSAGE_ROLES.BOT // for youtube video messages, role is "system" from backend, we need to make it "assistant"
|
|
134
|
-
: msg.role,
|
|
135
|
-
timestamp: msg.timestamp,
|
|
136
|
-
video: msg.youtubeVideo,
|
|
137
|
-
channel: msg.channel,
|
|
138
|
-
done: true
|
|
139
|
-
}))
|
|
128
|
+
messages = await getMessages(payload.sessionId)
|
|
140
129
|
}
|
|
141
130
|
|
|
142
131
|
const searchParams = new URLSearchParams()
|
package/src/http.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { getCredentials, getExternalId } from './chat.js'
|
|
7
|
+
import { MESSAGE_ROLES } from './constants.js'
|
|
7
8
|
|
|
8
9
|
const AUTHENTICATION_ERROR = 'Something went wrong initializing the chat'
|
|
9
10
|
const INITIALIZATION_ERROR = 'Chat SDK not initialized'
|
|
@@ -67,7 +68,20 @@ export async function getMessages(sessionId) {
|
|
|
67
68
|
throw new Error('Unable to load messages, please try again later')
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
const data = await response.json()
|
|
72
|
+
const messages = (data?.sessionHistory ?? []).map((msg) => ({
|
|
73
|
+
id: msg.id,
|
|
74
|
+
text: msg.text,
|
|
75
|
+
role: msg.youtubeVideo
|
|
76
|
+
? MESSAGE_ROLES.BOT // for youtube video messages, role is "system" from backend, we need to make it "assistant"
|
|
77
|
+
: msg.role,
|
|
78
|
+
timestamp: msg.timestamp,
|
|
79
|
+
video: msg.youtubeVideo,
|
|
80
|
+
channel: msg.channel,
|
|
81
|
+
done: true
|
|
82
|
+
}))
|
|
83
|
+
|
|
84
|
+
return messages
|
|
71
85
|
}
|
|
72
86
|
|
|
73
87
|
/**
|