@origonai/web-chat-sdk 0.1.0 → 0.1.1

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.
@@ -1,33 +1,33 @@
1
- import { fetchEventSource as X } from "@microsoft/fetch-event-source";
2
- function ee() {
3
- const e = Date.now(), o = new Uint8Array(16);
4
- crypto.getRandomValues(o), o[0] = e >> 40 & 255, o[1] = e >> 32 & 255, o[2] = e >> 24 & 255, o[3] = e >> 16 & 255, o[4] = e >> 8 & 255, o[5] = e & 255, o[6] = o[6] & 15 | 112, o[8] = o[8] & 63 | 128;
5
- const s = [...o].map((a) => a.toString(16).padStart(2, "0")).join("");
1
+ import { fetchEventSource as K } from "@microsoft/fetch-event-source";
2
+ function j() {
3
+ const e = Date.now(), t = new Uint8Array(16);
4
+ crypto.getRandomValues(t), t[0] = e >> 40 & 255, t[1] = e >> 32 & 255, t[2] = e >> 24 & 255, t[3] = e >> 16 & 255, t[4] = e >> 8 & 255, t[5] = e & 255, t[6] = t[6] & 15 | 112, t[8] = t[8] & 63 | 128;
5
+ const s = [...t].map((a) => a.toString(16).padStart(2, "0")).join("");
6
6
  return `${s.slice(0, 8)}-${s.slice(8, 12)}-${s.slice(12, 16)}-${s.slice(
7
7
  16,
8
8
  20
9
9
  )}-${s.slice(20)}`;
10
10
  }
11
- function ne() {
11
+ function V() {
12
12
  if (localStorage.getItem("chatDeviceId"))
13
13
  return localStorage.getItem("chatDeviceId");
14
- const e = ee();
14
+ const e = j();
15
15
  return localStorage.setItem("chatDeviceId", e), e;
16
16
  }
17
- async function te(e) {
18
- return new Promise((o) => setTimeout(o, e));
17
+ async function Q(e) {
18
+ return new Promise((t) => setTimeout(t, e));
19
19
  }
20
- function oe(e) {
21
- let o;
20
+ function Y(e) {
21
+ let t;
22
22
  try {
23
23
  const s = new URL(e);
24
- o = `wss://${s.hostname}${s.pathname}/audio`;
24
+ t = `wss://${s.hostname}${s.pathname}/audio`;
25
25
  } catch (s) {
26
26
  console.error("getCallServerEndpoint: Invalid base URL: ", e);
27
27
  }
28
- return o;
28
+ return t;
29
29
  }
30
- const k = {
30
+ const b = {
31
31
  BOT: "assistant",
32
32
  // this can be automated or LLM AI Agent response
33
33
  USER: "user",
@@ -37,7 +37,7 @@ const k = {
37
37
  SYSTEM: "system"
38
38
  // this is system message, for ex "Agent joined" / "Agent left"
39
39
  };
40
- function _(e = {}) {
40
+ function L(e = {}) {
41
41
  return {
42
42
  credentials: void 0,
43
43
  authenticated: !1,
@@ -46,190 +46,174 @@ function _(e = {}) {
46
46
  requestId: void 0,
47
47
  sseUrl: void 0,
48
48
  abortController: void 0,
49
- liveAgent: !1,
50
49
  lastStreamId: void 0,
51
50
  messages: [],
52
51
  callbacks: e
53
52
  };
54
53
  }
55
- let t = _();
56
- function ye(e) {
57
- t.callbacks = { ...t.callbacks, ...e };
54
+ let o = L();
55
+ function Se(e) {
56
+ o.callbacks = { ...o.callbacks, ...e };
58
57
  }
59
- function be(e) {
60
- console.log("Initializing chat...", e), t.credentials = e, e.token && (t.authenticated = !0);
58
+ function Ce(e) {
59
+ console.log("Initializing chat...", e), o.credentials = e, e.token && (o.authenticated = !0);
61
60
  }
62
- function se() {
63
- return t.credentials;
61
+ function Z() {
62
+ return o.credentials;
64
63
  }
65
- function ae(e) {
66
- var o, s;
67
- e && e !== t.sessionId && (t.sessionId = e, (s = (o = t.callbacks).onSessionUpdate) == null || s.call(o, e));
64
+ function X(e) {
65
+ var t, s;
66
+ e && e !== o.sessionId && (o.sessionId = e, (s = (t = o.callbacks).onSessionUpdate) == null || s.call(t, e));
68
67
  }
69
- async function Ee(e = {}) {
70
- var o;
68
+ async function Ie(e = {}) {
69
+ var t;
71
70
  try {
72
- console.log("startChat: ", e, t);
71
+ console.log("startChat: ", e, o);
73
72
  let s = null;
74
- t.authenticated ? s = t.configData : (s = await le(t.credentials), t.authenticated = !0, t.configData = s);
73
+ o.authenticated ? s = o.configData : (s = await oe(o.credentials), o.authenticated = !0, o.configData = s);
75
74
  let a = [];
76
75
  if (e.sessionId) {
77
- const g = await de(e.sessionId);
78
- a = ((o = g == null ? void 0 : g.sessionHistory) != null ? o : []).map((r) => ({
76
+ const d = await se(e.sessionId);
77
+ a = ((t = d == null ? void 0 : d.sessionHistory) != null ? t : []).map((r) => ({
79
78
  id: r.id,
80
79
  text: r.text,
81
- role: r.youtubeVideo ? k.BOT : r.role,
80
+ role: r.youtubeVideo ? b.BOT : r.role,
82
81
  timestamp: r.timestamp,
83
82
  video: r.youtubeVideo,
84
83
  channel: r.channel,
85
84
  done: !0
86
85
  }));
87
86
  }
88
- const u = new URLSearchParams({
89
- externalId: A()
87
+ const l = new URLSearchParams({
88
+ externalId: $()
90
89
  });
91
- return t.sseUrl = `${t.credentials.endpoint}?${u.toString()}`, t.sessionId = e.sessionId, t.messages = a, console.log("Chat initiated successfully"), {
92
- sessionId: t.sessionId,
90
+ return o.sseUrl = `${o.credentials.endpoint}?${l.toString()}`, o.sessionId = e.sessionId, o.messages = a, console.log("Chat initiated successfully"), {
91
+ sessionId: o.sessionId,
93
92
  messages: a,
94
93
  configData: s
95
94
  };
96
95
  } catch (s) {
97
- throw console.error(`Failed to start chat: ${s.message}`), K(), s;
96
+ throw console.error(`Failed to start chat: ${s.message}`), J(), s;
98
97
  }
99
98
  }
100
- function ve() {
101
- K();
99
+ function he() {
100
+ J();
102
101
  }
103
- function K() {
104
- t.abortController && t.abortController.abort();
105
- const { callbacks: e, credentials: o } = t;
106
- t = _(e), t.credentials = o, console.log("Chat session cleaned up");
102
+ function J() {
103
+ o.abortController && o.abortController.abort();
104
+ const { callbacks: e, credentials: t } = o;
105
+ o = L(e), o.credentials = t, console.log("Chat session cleaned up");
107
106
  }
108
- function A() {
107
+ function $() {
109
108
  var e;
110
- return (e = t.credentials) != null && e.externalId ? t.credentials.externalId : ne();
109
+ return (e = o.credentials) != null && e.externalId ? o.credentials.externalId : V();
111
110
  }
112
- function Ae({ text: e, html: o }) {
111
+ function ke({ text: e, html: t }) {
113
112
  return new Promise((s, a) => {
114
113
  (async () => {
115
- var u, g, r, h, l, w, T;
114
+ var l, d, r, h, i, k, M;
116
115
  try {
117
- const y = {
118
- role: k.USER,
116
+ const I = {
117
+ role: b.USER,
119
118
  text: e,
120
- html: o,
119
+ html: t,
121
120
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
122
121
  };
123
- if (t.messages = [...t.messages, y], (g = (u = t.callbacks).onMessagesUpdate) == null || g.call(u, [...t.messages]), await te(200), t.liveAgent)
124
- s(t.sessionId);
125
- else {
126
- const d = {
127
- role: k.BOT,
128
- text: "",
129
- loading: !0
130
- };
131
- t.messages = [...t.messages, d], (h = (r = t.callbacks).onMessagesUpdate) == null || h.call(r, [...t.messages]);
132
- }
133
- const C = new URL(t.sseUrl);
134
- t.sessionId && C.searchParams.set("sessionId", t.sessionId), t.requestId && C.searchParams.set("requestId", t.requestId), t.lastStreamId = void 0, t.abortController = new AbortController();
135
- const I = {
122
+ o.messages = [...o.messages, I], (d = (l = o.callbacks).onMessageAdd) == null || d.call(l, I), await Q(200);
123
+ const w = {
124
+ role: b.BOT,
125
+ text: "",
126
+ loading: !0
127
+ };
128
+ o.messages = [...o.messages, w], (h = (r = o.callbacks).onMessageAdd) == null || h.call(r, w);
129
+ const g = new URL(o.sseUrl);
130
+ o.sessionId && g.searchParams.set("sessionId", o.sessionId), o.requestId && g.searchParams.set("requestId", o.requestId), o.lastStreamId = void 0, o.abortController = new AbortController();
131
+ const A = {
136
132
  "Content-Type": "application/json"
137
133
  };
138
- (l = t.credentials) != null && l.token && (I.Authorization = `Bearer ${t.credentials.token}`), await X(C.toString(), {
134
+ (i = o.credentials) != null && i.token && (A.Authorization = `Bearer ${o.credentials.token}`), await K(g.toString(), {
139
135
  method: "POST",
140
- headers: I,
136
+ headers: A,
141
137
  body: JSON.stringify({
142
138
  message: e,
143
- html: o
139
+ html: t
144
140
  }),
145
- signal: t.abortController.signal,
146
- onopen: async (d) => {
147
- if (!d.ok)
148
- throw console.error("Failed to send message bad response: ", d), new Error("Failed to send message");
141
+ signal: o.abortController.signal,
142
+ onopen: async (u) => {
143
+ if (!u.ok)
144
+ throw console.error("Failed to send message bad response: ", u), new Error("Failed to send message");
149
145
  },
150
- onmessage: (d) => {
151
- var R, $, O, U, P, x, D, M, N, L, q, F, J, z, G, W, B, H;
152
- console.log("Event: ", d);
153
- const i = JSON.parse(d.data);
154
- if (i.status === "connected")
155
- t.sessionId = i.sessionId, t.requestId = i.requestId, t.liveAgent && s(t.sessionId);
156
- else if (i.agent) {
157
- t.liveAgent = !0;
158
- const { type: f, data: c } = i.agent;
159
- switch (f) {
160
- case "typing":
161
- ($ = (R = t.callbacks).onTyping) == null || $.call(R, !0), (U = (O = t.callbacks).onLiveAgentMode) == null || U.call(O, !0);
162
- break;
163
- case "typingOff":
164
- (x = (P = t.callbacks).onTyping) == null || x.call(P, !1), (M = (D = t.callbacks).onLiveAgentMode) == null || M.call(D, !0);
165
- break;
166
- case "message":
167
- if (c.role !== k.USER) {
168
- t.messages = t.messages.filter((b) => !b.loading), t.messages = [...t.messages, c];
169
- const m = c.action === "ended" || c.action === "left";
170
- m && (t.liveAgent = !1), (L = (N = t.callbacks).onMessagesUpdate) == null || L.call(N, [...t.messages]), (F = (q = t.callbacks).onLiveAgentMode) == null || F.call(q, !m);
171
- }
172
- (c.action === "ended" || c.action === "left") && (t.liveAgent = !1);
173
- break;
174
- default:
175
- break;
146
+ onmessage: (u) => {
147
+ var y, O, x, P, U, D, N, q, F;
148
+ console.log("Event: ", u);
149
+ const c = JSON.parse(u.data);
150
+ if (c.status === "connected")
151
+ o.sessionId = c.sessionId, o.requestId = c.requestId;
152
+ else if (c.message !== void 0) {
153
+ if (c.streamId !== void 0) {
154
+ if (o.lastStreamId === void 0)
155
+ o.lastStreamId = c.streamId;
156
+ else if (c.streamId !== o.lastStreamId) {
157
+ o.lastStreamId = c.streamId;
158
+ const p = {
159
+ role: b.BOT,
160
+ text: "",
161
+ loading: !0
162
+ };
163
+ o.messages = [...o.messages, p], (O = (y = o.callbacks).onMessageAdd) == null || O.call(y, p);
164
+ }
176
165
  }
177
- } else if (i.message !== void 0) {
178
- let f = t.messages;
179
- i.streamId !== void 0 && (t.lastStreamId === void 0 ? t.lastStreamId = i.streamId : i.streamId !== t.lastStreamId && (t.lastStreamId = i.streamId, f = [
166
+ const S = o.messages.length - 1, f = o.messages[S], T = {
180
167
  ...f,
181
- {
182
- role: k.BOT,
183
- text: "",
184
- loading: !0
185
- }
186
- ])), t.messages = f.map((c, m) => {
187
- var b;
188
- return m === f.length - 1 ? {
189
- ...c,
190
- loading: !1,
191
- text: (c.text || "") + i.message,
192
- done: (b = i.done) != null ? b : c.done
193
- } : c;
194
- }), (z = (J = t.callbacks).onMessagesUpdate) == null || z.call(J, [...t.messages]), i.done && s(t.sessionId), t.sessionId = (G = i.session_id) != null ? G : t.sessionId, t.requestId = (W = i.requestId) != null ? W : t.requestId;
195
- } else if (i.error) {
196
- const f = "Failed to connect to the system";
197
- t.messages = t.messages.map((c, m) => m === t.messages.length - 1 ? {
198
- ...c,
199
168
  loading: !1,
200
- errorText: f
201
- } : c), (H = (B = t.callbacks).onMessagesUpdate) == null || H.call(B, [...t.messages]), a(new Error(f));
169
+ text: (f.text || "") + c.message,
170
+ done: (x = c.done) != null ? x : f.done
171
+ };
172
+ o.messages = o.messages.map(
173
+ (p, R) => R === S ? T : p
174
+ ), (U = (P = o.callbacks).onMessageUpdate) == null || U.call(P, S, T), c.done && s(o.sessionId), o.sessionId = (D = c.session_id) != null ? D : o.sessionId, o.requestId = (N = c.requestId) != null ? N : o.requestId;
175
+ } else if (c.error) {
176
+ const S = "Failed to connect to the system", f = o.messages.length - 1, p = {
177
+ ...o.messages[f],
178
+ loading: !1,
179
+ errorText: S
180
+ };
181
+ o.messages = o.messages.map(
182
+ (R, _) => _ === f ? p : R
183
+ ), (F = (q = o.callbacks).onMessageUpdate) == null || F.call(q, f, p), a(new Error(S));
202
184
  }
203
185
  },
204
- onerror: (d) => {
205
- throw d;
186
+ onerror: (u) => {
187
+ throw u;
206
188
  },
207
189
  openWhenHidden: !0
208
190
  });
209
- } catch (y) {
210
- console.error("Failed to send message: ", y);
211
- const C = "Failed to connect to the system";
212
- t.messages = t.messages.map((I, d) => d === t.messages.length - 1 ? {
213
- ...I,
191
+ } catch (I) {
192
+ console.error("Failed to send message: ", I);
193
+ const w = "Failed to connect to the system", g = o.messages.length - 1, u = {
194
+ ...o.messages[g],
214
195
  loading: !1,
215
- errorText: C,
196
+ errorText: w,
216
197
  done: !0
217
- } : I), (T = (w = t.callbacks).onMessagesUpdate) == null || T.call(w, [...t.messages]), a(y);
198
+ };
199
+ o.messages = o.messages.map(
200
+ (c, y) => y === g ? u : c
201
+ ), (M = (k = o.callbacks).onMessageUpdate) == null || M.call(k, g, u), a(I);
218
202
  }
219
203
  })();
220
204
  });
221
205
  }
222
- const re = "Something went wrong initializing the chat", ie = "Chat SDK not initialized";
223
- let j = {
206
+ const ee = "Something went wrong initializing the chat", ne = "Chat SDK not initialized";
207
+ let z = {
224
208
  endpoint: null
225
209
  };
226
- function ce(e) {
227
- j = {
210
+ function te(e) {
211
+ z = {
228
212
  endpoint: e.endpoint
229
213
  };
230
214
  }
231
- async function le(e) {
232
- const { endpoint: o } = e, s = `${o}/config`, a = await fetch(s, {
215
+ async function oe(e) {
216
+ const { endpoint: t } = e, s = `${t}/config`, a = await fetch(s, {
233
217
  method: "GET",
234
218
  headers: {
235
219
  "Content-Type": "application/json"
@@ -237,41 +221,41 @@ async function le(e) {
237
221
  });
238
222
  if (!a.ok) {
239
223
  const r = await a.json();
240
- throw new Error((r == null ? void 0 : r.error) || re);
224
+ throw new Error((r == null ? void 0 : r.error) || ee);
241
225
  }
242
- const g = (await a.json()).data;
243
- return ce({ endpoint: o }), g;
226
+ const d = (await a.json()).data;
227
+ return te({ endpoint: t }), d;
244
228
  }
245
- async function Te() {
229
+ async function we() {
246
230
  const e = new URLSearchParams({
247
- externalId: A()
248
- }), o = await V(`/sessions?${e.toString()}`, "GET");
249
- if (!o.ok)
231
+ externalId: $()
232
+ }), t = await G(`/sessions?${e.toString()}`, "GET");
233
+ if (!t.ok)
250
234
  throw new Error("Unable to load history, please try again later");
251
- return o.json();
235
+ return t.json();
252
236
  }
253
- async function de(e) {
254
- const o = new URLSearchParams({
237
+ async function se(e) {
238
+ const t = new URLSearchParams({
255
239
  sessionId: e
256
- }), s = await V(`/session?${o.toString()}`, "GET");
240
+ }), s = await G(`/session?${t.toString()}`, "GET");
257
241
  if (!s.ok)
258
242
  throw new Error("Unable to load messages, please try again later");
259
243
  return s.json();
260
244
  }
261
- async function V(e, o = "GET", s = null) {
262
- const { endpoint: a } = j;
245
+ async function G(e, t = "GET", s = null) {
246
+ const { endpoint: a } = z;
263
247
  if (!a)
264
- throw new Error(ie);
265
- const u = `${a}${e}`;
266
- return fetch(u, {
248
+ throw new Error(ne);
249
+ const l = `${a}${e}`;
250
+ return fetch(l, {
267
251
  headers: {
268
252
  "Content-Type": "application/json"
269
253
  },
270
- method: o,
254
+ method: t,
271
255
  body: s ? JSON.stringify(s) : null
272
256
  });
273
257
  }
274
- function Q(e = {}) {
258
+ function W(e = {}) {
275
259
  return {
276
260
  sessionId: void 0,
277
261
  socket: null,
@@ -289,30 +273,30 @@ function Q(e = {}) {
289
273
  pendingRemoteIceCandidates: []
290
274
  };
291
275
  }
292
- let n = Q();
293
- const ue = {
276
+ let n = W();
277
+ const ae = {
294
278
  iceServers: [{ urls: "stun:stun.l.google.com:19302" }, { urls: "stun:stun1.l.google.com:19302" }]
295
279
  };
296
- function Re(e) {
280
+ function ye(e) {
297
281
  n.callbacks = { ...n.callbacks, ...e };
298
282
  }
299
- function Y() {
300
- n.peerConnection && (n.peerConnection.close(), n.peerConnection = null), n.localStream && (n.localStream.getTracks().forEach((o) => o.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), v();
283
+ function B() {
284
+ 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), v();
301
285
  const e = n.callbacks;
302
- n = Q(e), console.log("Call session cleaned up");
286
+ n = W(e), console.log("Call session cleaned up");
303
287
  }
304
- function p(e) {
305
- var o, s;
306
- n.callStatus = e, (s = (o = n.callbacks).onCallStatus) == null || s.call(o, e);
288
+ function m(e) {
289
+ var t, s;
290
+ n.callStatus = e, (s = (t = n.callbacks).onCallStatus) == null || s.call(t, e);
307
291
  }
308
292
  function E(e) {
309
- var o, s;
310
- (s = (o = n.callbacks).onCallError) == null || s.call(o, e);
293
+ var t, s;
294
+ (s = (t = n.callbacks).onCallError) == null || s.call(t, e);
311
295
  }
312
296
  function v() {
313
297
  n.pingInterval && (clearInterval(n.pingInterval), n.pingInterval = null);
314
298
  }
315
- function ge() {
299
+ function re() {
316
300
  v(), n.pingInterval = setInterval(() => {
317
301
  if (n.socket && n.socket.readyState === WebSocket.OPEN) {
318
302
  n.pingCount++;
@@ -321,15 +305,15 @@ function ge() {
321
305
  timestamp: Date.now(),
322
306
  count: n.pingCount
323
307
  };
324
- S(e), console.log(`Sending keep-alive ping #${n.pingCount}`);
308
+ C(e), console.log(`Sending keep-alive ping #${n.pingCount}`);
325
309
  } else
326
310
  console.log("Socket not open, stopping ping interval"), v();
327
311
  }, 1e4);
328
312
  }
329
- function fe() {
313
+ function ce() {
330
314
  n.lastPongTime = Date.now(), console.log(`Received pong #${n.pingCount}`);
331
315
  }
332
- function S(e) {
316
+ function C(e) {
333
317
  if (!n.socket) {
334
318
  console.error("Failed to send event: no socket instance");
335
319
  return;
@@ -340,7 +324,7 @@ function S(e) {
340
324
  }
341
325
  n.socket.send(JSON.stringify(e));
342
326
  }
343
- async function pe() {
327
+ async function ie() {
344
328
  try {
345
329
  n.localStream = await navigator.mediaDevices.getUserMedia({
346
330
  audio: !0,
@@ -350,40 +334,40 @@ async function pe() {
350
334
  throw console.error(`Failed to get audio media: ${e.message}`), e;
351
335
  }
352
336
  }
353
- function me() {
354
- n.peerConnection = new RTCPeerConnection(ue), n.peerConnection.onicecandidate = (e) => {
337
+ function le() {
338
+ n.peerConnection = new RTCPeerConnection(ae), n.peerConnection.onicecandidate = (e) => {
355
339
  if (e.candidate) {
356
- const o = JSON.stringify(e.candidate);
357
- n.peerConnection && n.peerConnection.remoteDescription ? (S({
340
+ const t = JSON.stringify(e.candidate);
341
+ n.peerConnection && n.peerConnection.remoteDescription ? (C({
358
342
  type: "ice",
359
343
  data: {
360
- candidate: o
344
+ candidate: t
361
345
  }
362
- }), console.log("Sent ICE candidate immediately")) : (n.localIceCandidates.push(o), console.log("Queued local ICE candidate"));
346
+ }), console.log("Sent ICE candidate immediately")) : (n.localIceCandidates.push(t), console.log("Queued local ICE candidate"));
363
347
  }
364
348
  }, n.peerConnection.ontrack = (e) => {
365
- console.log("Received remote audio stream"), 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(() => console.log("🔊 remote audio playing")).catch((o) => console.error("❌ playback error:", o));
349
+ console.log("Received remote audio stream"), 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(() => console.log("🔊 remote audio playing")).catch((t) => console.error("❌ playback error:", t));
366
350
  }, n.peerConnection.onconnectionstatechange = () => {
367
351
  const e = n.peerConnection.connectionState;
368
- console.log(`Connection state: ${e}`), e === "connected" ? p("connected") : (e === "disconnected" || e === "closed") && (p("disconnected"), Z());
352
+ console.log(`Connection state: ${e}`), e === "connected" ? m("connected") : (e === "disconnected" || e === "closed") && (m("disconnected"), H());
369
353
  }, n.peerConnection.oniceconnectionstatechange = () => {
370
354
  console.log(`ICE connection state: ${n.peerConnection.iceConnectionState}`);
371
355
  };
372
356
  }
373
- function Se(e) {
374
- return new Promise((o, s) => {
357
+ function de(e) {
358
+ return new Promise((t, s) => {
375
359
  if (n.socket && (n.socket.readyState === WebSocket.CONNECTING || n.socket.readyState === WebSocket.OPEN)) {
376
- console.log("Socket in connecting/open state, returning."), o(n.socket.readyState === WebSocket.OPEN);
360
+ console.log("Socket in connecting/open state, returning."), t(n.socket.readyState === WebSocket.OPEN);
377
361
  return;
378
362
  }
379
363
  console.log("Initializing socket connection..");
380
- const a = se();
364
+ const a = Z();
381
365
  if (!a || !a.endpoint) {
382
366
  s(new Error("SDK not initialized. Please initialize SDK first."));
383
367
  return;
384
368
  }
385
- const u = oe(a.endpoint);
386
- if (!u) {
369
+ const l = Y(a.endpoint);
370
+ if (!l) {
387
371
  s(
388
372
  new Error(
389
373
  "Invalid endpoint while initializing SDK. Please check the endpoint and try again."
@@ -391,58 +375,58 @@ function Se(e) {
391
375
  );
392
376
  return;
393
377
  }
394
- const g = A(), r = new URLSearchParams({
395
- externalId: g
378
+ const d = $(), r = new URLSearchParams({
379
+ externalId: d
396
380
  });
397
381
  e.sessionId && r.set("sessionId", e.sessionId), a.token && r.set("token", a.token);
398
- const h = `${u}?${r.toString()}`;
399
- n.socket = new WebSocket(h), n.socket.onopen = (l) => {
400
- console.log("Socket connection established: ", l), ge(), o(!0);
401
- }, n.socket.onmessage = (l) => {
402
- const w = JSON.parse(l.data);
403
- Ce(w);
404
- }, n.socket.onerror = (l) => {
405
- console.error("Socket error: ", l), p("error"), E(l.message || "Unable to connect voice"), s(l);
406
- }, n.socket.onclose = (l) => {
407
- console.log("Socket connection closed: ", l), v();
382
+ const h = `${l}?${r.toString()}`;
383
+ n.socket = new WebSocket(h), n.socket.onopen = (i) => {
384
+ console.log("Socket connection established: ", i), re(), t(!0);
385
+ }, n.socket.onmessage = (i) => {
386
+ const k = JSON.parse(i.data);
387
+ ue(k);
388
+ }, n.socket.onerror = (i) => {
389
+ console.error("Socket error: ", i), m("error"), E(i.message || "Unable to connect voice"), s(i);
390
+ }, n.socket.onclose = (i) => {
391
+ console.log("Socket connection closed: ", i), v();
408
392
  };
409
393
  });
410
394
  }
411
- function Ce(e) {
395
+ function ue(e) {
412
396
  switch (console.log("Handling socket server event: ", e), e.type) {
413
397
  case "pong":
414
- fe();
398
+ ce();
415
399
  break;
416
400
  case "answer":
417
- Ie(e.data);
401
+ ge(e.data);
418
402
  break;
419
403
  case "ice":
420
- ke(e.data);
404
+ fe(e.data);
421
405
  break;
422
406
  case "renegotiationOffer":
423
- he(e.data);
407
+ pe(e.data);
424
408
  break;
425
409
  case "end":
426
- Z();
410
+ H();
427
411
  break;
428
412
  case "error":
429
- p("error"), E(e.error || "Unable to connect voice");
413
+ m("error"), E(e.error || "Unable to connect voice");
430
414
  break;
431
415
  default:
432
416
  console.log("Unknown call event type: ", e.type);
433
417
  break;
434
418
  }
435
419
  }
436
- async function Ie(e) {
420
+ async function ge(e) {
437
421
  try {
438
- if (console.log("Received answer"), n.sessionId = e.sessionId, ae(e.sessionId), n.peerConnection) {
439
- const o = new RTCSessionDescription({
422
+ if (console.log("Received answer"), n.sessionId = e.sessionId, X(e.sessionId), n.peerConnection) {
423
+ const t = new RTCSessionDescription({
440
424
  type: "answer",
441
425
  sdp: e.sdp
442
426
  });
443
- console.log("Setting remote description answer: ", o), await n.peerConnection.setRemoteDescription(o), console.log("Remote description set");
427
+ console.log("Setting remote description answer: ", t), await n.peerConnection.setRemoteDescription(t), console.log("Remote description set");
444
428
  for (const s of n.localIceCandidates)
445
- S({
429
+ C({
446
430
  type: "ice",
447
431
  data: {
448
432
  candidate: s
@@ -458,70 +442,70 @@ async function Ie(e) {
458
442
  }
459
443
  n.pendingRemoteIceCandidates = [];
460
444
  }
461
- } catch (o) {
462
- console.error(`Failed to handle answer: ${o.message}`);
445
+ } catch (t) {
446
+ console.error(`Failed to handle answer: ${t.message}`);
463
447
  }
464
448
  }
465
- async function ke(e) {
449
+ async function fe(e) {
466
450
  try {
467
451
  if (n.peerConnection) {
468
452
  if (!n.peerConnection.remoteDescription) {
469
453
  n.pendingRemoteIceCandidates.push(e.candidate), console.log("Queued remote ICE candidate - remote description not set");
470
454
  return;
471
455
  }
472
- const o = new RTCIceCandidate(JSON.parse(e.candidate));
473
- await n.peerConnection.addIceCandidate(o), console.log("Added ICE candidate");
456
+ const t = new RTCIceCandidate(JSON.parse(e.candidate));
457
+ await n.peerConnection.addIceCandidate(t), console.log("Added ICE candidate");
474
458
  }
475
- } catch (o) {
476
- console.error(`Failed to add ICE candidate: ${o.message}`);
459
+ } catch (t) {
460
+ console.error(`Failed to add ICE candidate: ${t.message}`);
477
461
  }
478
462
  }
479
- async function he(e) {
463
+ async function pe(e) {
480
464
  try {
481
465
  if (console.log("Received renegotiation offer"), n.peerConnection) {
482
- const o = new RTCSessionDescription({
466
+ const t = new RTCSessionDescription({
483
467
  type: "offer",
484
468
  sdp: e.sdp
485
469
  });
486
- console.log("Setting remote description offer: ", o), await n.peerConnection.setRemoteDescription(o), console.log("Remote description set");
470
+ console.log("Setting remote description offer: ", t), await n.peerConnection.setRemoteDescription(t), console.log("Remote description set");
487
471
  const s = await n.peerConnection.createAnswer();
488
- await n.peerConnection.setLocalDescription(s), S({
472
+ await n.peerConnection.setLocalDescription(s), C({
489
473
  type: "renegotiationAnswer",
490
474
  data: {
491
475
  sdp: s.sdp
492
476
  }
493
477
  });
494
478
  }
495
- } catch (o) {
496
- console.error(`Failed to handle renegotiation offer: ${o.message}`);
479
+ } catch (t) {
480
+ console.error(`Failed to handle renegotiation offer: ${t.message}`);
497
481
  }
498
482
  }
499
- async function $e(e = {}) {
483
+ async function be(e = {}) {
500
484
  try {
501
485
  if (n.callStatus === "connecting" || n.callStatus === "connected") {
502
486
  console.log(`Call already in ${n.callStatus} state`);
503
487
  return;
504
488
  }
505
- console.log("Starting audio call..."), p("connecting"), E(null), n.sessionId = e.sessionId, await pe(), me(), n.localStream.getTracks().forEach((s) => {
489
+ console.log("Starting audio call..."), m("connecting"), E(null), n.sessionId = e.sessionId, await ie(), le(), n.localStream.getTracks().forEach((s) => {
506
490
  n.peerConnection.addTrack(s, n.localStream), console.log(`Added ${s.kind} track`);
507
- }), await Se(e);
508
- const o = await n.peerConnection.createOffer();
509
- await n.peerConnection.setLocalDescription(o), S({
491
+ }), await de(e);
492
+ const t = await n.peerConnection.createOffer();
493
+ await n.peerConnection.setLocalDescription(t), C({
510
494
  type: "offer",
511
495
  data: {
512
- sdp: o.sdp
496
+ sdp: t.sdp
513
497
  }
514
498
  }), console.log("Call initiated successfully");
515
- } catch (o) {
516
- console.log("error: ", o), console.error(`Failed to start call: ${o.message}`), p("error"), E(o.message || "Unable to connect voice"), Y();
499
+ } catch (t) {
500
+ console.log("error: ", t), console.error(`Failed to start call: ${t.message}`), m("error"), E(t.message || "Unable to connect voice"), B();
517
501
  }
518
502
  }
519
- function Z() {
520
- S({
503
+ function H() {
504
+ C({
521
505
  type: "end"
522
- }), n.socket && (n.socket.close(), n.socket = null), p("disconnected"), n.peerConnection && (n.peerConnection.close(), n.peerConnection = null), n.localStream && (n.localStream.getTracks().forEach((e) => e.stop()), n.localStream = null), Y();
506
+ }), n.socket && (n.socket.close(), n.socket = null), m("disconnected"), n.peerConnection && (n.peerConnection.close(), n.peerConnection = null), n.localStream && (n.localStream.getTracks().forEach((e) => e.stop()), n.localStream = null), B();
523
507
  }
524
- function Oe() {
508
+ function Ee() {
525
509
  if (n.localStream) {
526
510
  const e = n.localStream.getAudioTracks()[0];
527
511
  if (e)
@@ -529,56 +513,56 @@ function Oe() {
529
513
  }
530
514
  return !1;
531
515
  }
532
- function Ue() {
516
+ function ve() {
533
517
  return n.localStream;
534
518
  }
535
- function Pe() {
536
- return new Promise((e, o) => {
519
+ function Ae() {
520
+ return new Promise((e, t) => {
537
521
  if (!n.peerConnection) {
538
- o(new Error("no peer connection"));
522
+ t(new Error("no peer connection"));
539
523
  return;
540
524
  }
541
525
  n.peerConnection.getStats().then((s) => {
542
526
  s.forEach((a) => {
543
527
  a.type == "inbound-rtp" && e(a.totalAudioEnergy);
544
- }), o(new Error("no inbound-rtp stats found"));
528
+ }), t(new Error("no inbound-rtp stats found"));
545
529
  }).catch((s) => {
546
- o(s);
530
+ t(s);
547
531
  });
548
532
  });
549
533
  }
550
- function xe() {
551
- return new Promise((e, o) => {
534
+ function Te() {
535
+ return new Promise((e, t) => {
552
536
  if (!n.peerConnection) {
553
- o(new Error("no peer connection"));
537
+ t(new Error("no peer connection"));
554
538
  return;
555
539
  }
556
540
  n.peerConnection.getStats().then((s) => {
557
541
  s.forEach((a) => {
558
542
  a.type == "outbound-rtp" && e(a.totalAudioEnergy);
559
- }), o(new Error("no outbound-rtp stats found"));
543
+ }), t(new Error("no outbound-rtp stats found"));
560
544
  }).catch((s) => {
561
- o(s);
545
+ t(s);
562
546
  });
563
547
  });
564
548
  }
565
549
  export {
566
- k as MESSAGE_ROLES,
567
- le as authenticate,
568
- ce as configure,
569
- ve as disconnect,
570
- Z as disconnectCall,
571
- Te as getHistory,
572
- Pe as getInboundAudioEnergy,
573
- Ue as getLocalStream,
574
- de as getMessages,
575
- xe as getOutboundAudioEnergy,
576
- be as initialize,
577
- Ae as sendMessage,
578
- Re as setCallCallbacks,
579
- ye as setCallbacks,
580
- $e as startCall,
581
- Ee as startChat,
582
- Oe as toggleMute
550
+ b as MESSAGE_ROLES,
551
+ oe as authenticate,
552
+ te as configure,
553
+ he as disconnect,
554
+ H as disconnectCall,
555
+ we as getHistory,
556
+ Ae as getInboundAudioEnergy,
557
+ ve as getLocalStream,
558
+ se as getMessages,
559
+ Te as getOutboundAudioEnergy,
560
+ Ce as initialize,
561
+ ke as sendMessage,
562
+ ye as setCallCallbacks,
563
+ Se as setCallbacks,
564
+ be as startCall,
565
+ Ie as startChat,
566
+ Ee as toggleMute
583
567
  };
584
568
  //# sourceMappingURL=origon-chat-sdk.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"origon-chat-sdk.js","sources":["../src/utils.js","../src/constants.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 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('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 * 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, sleep } from './utils.js'\nimport { MESSAGE_ROLES } from './constants.js'\n\n/**\n * @typedef {Object} ChatCallbacks\n * @property {(messages: Array) => void} [onMessagesUpdate] - Called when messages array should be updated\n * @property {(isTyping: boolean) => void} [onTyping] - Called when typing status changes\n * @property {(isLiveAgent: boolean) => void} [onLiveAgentMode] - Called when live agent mode status changes\n * @property {(sessionId: string) => void} [onSessionUpdate] - Called when session ID is updated\n */\n\n/**\n * @typedef {Object} ChatSession\n * @property {string} sessionId\n * @property {string} sseUrl\n * @property {string} [requestId]\n * @property {boolean} liveAgent\n * @property {AbortController} [abortController]\n * @property {string} [lastStreamId]\n * @property {Array} messages\n * @property {ChatCallbacks} callbacks\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 liveAgent: false,\n lastStreamId: undefined,\n messages: [],\n callbacks\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 externalId: getExternalId()\n })\n currentSession.sseUrl = `${currentSession.credentials.endpoint}?${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\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 * 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 }) {\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 currentSession.messages = [...currentSession.messages, userMessage]\n currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])\n\n await sleep(200)\n\n // Add loading message for bot if not in live agent mode\n if (!currentSession.liveAgent) {\n const loadingMessage = {\n role: MESSAGE_ROLES.BOT,\n text: '',\n loading: true\n }\n currentSession.messages = [...currentSession.messages, loadingMessage]\n currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])\n } else {\n resolve(currentSession.sessionId)\n }\n\n const url = new URL(currentSession.sseUrl)\n if (currentSession.sessionId) {\n url.searchParams.set('sessionId', currentSession.sessionId)\n }\n if (currentSession.requestId) {\n url.searchParams.set('requestId', currentSession.requestId)\n }\n\n currentSession.lastStreamId = undefined\n\n // Create a new abort controller for this request\n currentSession.abortController = new AbortController()\n\n const headers = {\n 'Content-Type': 'application/json'\n }\n if (currentSession.credentials?.token) {\n headers.Authorization = `Bearer ${currentSession.credentials.token}`\n }\n\n await fetchEventSource(url.toString(), {\n method: 'POST',\n headers,\n body: JSON.stringify({\n message: text,\n html\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: (event) => {\n console.log('Event: ', event)\n const data = JSON.parse(event.data)\n\n if (data.status === 'connected') {\n currentSession.sessionId = data.sessionId\n currentSession.requestId = data.requestId\n if (currentSession.liveAgent) {\n resolve(currentSession.sessionId)\n }\n } else if (data.agent) {\n currentSession.liveAgent = true\n const { type, data: payload } = data.agent\n\n switch (type) {\n case 'typing':\n currentSession.callbacks.onTyping?.(true)\n currentSession.callbacks.onLiveAgentMode?.(true)\n break\n case 'typingOff':\n currentSession.callbacks.onTyping?.(false)\n currentSession.callbacks.onLiveAgentMode?.(true)\n break\n case 'message':\n if (payload.role !== MESSAGE_ROLES.USER) {\n // Remove loading messages and add new message\n currentSession.messages = currentSession.messages.filter((msg) => !msg.loading)\n currentSession.messages = [...currentSession.messages, payload]\n\n const isEnded = payload.action === 'ended' || payload.action === 'left'\n if (isEnded) {\n currentSession.liveAgent = false\n }\n\n currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])\n currentSession.callbacks.onLiveAgentMode?.(!isEnded)\n }\n if (payload.action === 'ended' || payload.action === 'left') {\n currentSession.liveAgent = false\n }\n break\n default:\n break\n }\n } else if (data.message !== undefined) {\n let messages = currentSession.messages\n\n // If streamId changes, start a new assistant message\n if (data.streamId !== undefined) {\n if (currentSession.lastStreamId === undefined) {\n currentSession.lastStreamId = data.streamId\n } else if (data.streamId !== currentSession.lastStreamId) {\n currentSession.lastStreamId = data.streamId\n messages = [\n ...messages,\n {\n role: MESSAGE_ROLES.BOT,\n text: '',\n loading: true\n }\n ]\n }\n }\n\n // Update the last message with new content\n currentSession.messages = messages.map((msg, index) => {\n if (index === messages.length - 1) {\n return {\n ...msg,\n loading: false,\n text: (msg.text || '') + data.message,\n done: data.done ?? msg.done\n }\n }\n return msg\n })\n\n currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])\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 } else if (data.error) {\n const errorMessage = 'Failed to connect to the system'\n currentSession.messages = currentSession.messages.map((msg, index) => {\n if (index === currentSession.messages.length - 1) {\n return {\n ...msg,\n loading: false,\n errorText: errorMessage\n }\n }\n return msg\n })\n currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])\n reject(new Error(errorMessage))\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 currentSession.messages = currentSession.messages.map((msg, index) => {\n if (index === currentSession.messages.length - 1) {\n return {\n ...msg,\n loading: false,\n errorText: errorMessage,\n done: true\n }\n }\n return msg\n })\n currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])\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 { getExternalId } from './chat.js'\n\nconst AUTHENTICATION_ERROR = 'Something went wrong initializing the chat'\nconst INITIALIZATION_ERROR = 'Chat SDK not initialized'\n\n// Module-level configuration\nlet _config = {\n endpoint: null\n}\n\n/**\n * Configure the API service with endpoint\n * @param {{ endpoint: string }} credentials\n */\nexport function configure(credentials) {\n _config = {\n endpoint: credentials.endpoint\n }\n}\n\n/**\n * Get current configuration\n * @returns {{ endpoint: string | null }}\n */\nexport function getConfig() {\n return { ..._config }\n}\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 // Store endpoint for subsequent requests\n configure({ endpoint })\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 { endpoint } = _config\n\n if (!endpoint) {\n throw new Error(INITIALIZATION_ERROR)\n }\n\n const url = `${endpoint}${pathname}`\n\n return fetch(url, {\n headers: {\n 'Content-Type': 'application/json'\n },\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","getCallServerEndpoint","baseUrl","socketEndpoint","url","e","MESSAGE_ROLES","createSession","callbacks","currentSession","setCallbacks","initialize","credentials","getCredentials","updateSessionId","sessionId","startChat","payload","configData","authenticate","messages","messagesRes","getMessages","_a","msg","searchParams","getExternalId","error","cleanup","disconnect","sendMessage","text","html","reject","userMessage","loadingMessage","headers","fetchEventSource","response","event","data","type","isEnded","index","_o","_p","errorMessage","AUTHENTICATION_ERROR","INITIALIZATION_ERROR","_config","configure","endpoint","errorPayload","getHistory","queryParams","fetchRequest","pathname","method","body","rtcConfig","setCallCallbacks","track","stopPingInterval","setCallStatus","status","_b","setCallError","startPingInterval","pingMessage","sendEvent","handlePong","getUserMedia","createPeerConnection","candidateJson","err","newState","disconnectCall","connectSocket","fulfill","externalId","socketUrl","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/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 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('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 * 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, sleep } from './utils.js'\nimport { MESSAGE_ROLES } from './constants.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 */\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 */\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 }\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 externalId: getExternalId()\n })\n currentSession.sseUrl = `${currentSession.credentials.endpoint}?${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\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 * 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 }) {\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 currentSession.messages = [...currentSession.messages, userMessage]\n currentSession.callbacks.onMessageAdd?.(userMessage)\n\n await sleep(200)\n\n const loadingMessage = {\n role: MESSAGE_ROLES.BOT,\n text: '',\n loading: true\n }\n currentSession.messages = [...currentSession.messages, loadingMessage]\n currentSession.callbacks.onMessageAdd?.(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 }),\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: (event) => {\n console.log('Event: ', event)\n const data = JSON.parse(event.data)\n\n if (data.status === 'connected') {\n currentSession.sessionId = data.sessionId\n currentSession.requestId = data.requestId\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 currentSession.messages = [...currentSession.messages, newBotMessage]\n currentSession.callbacks.onMessageAdd?.(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 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 } else if (data.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: 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 }\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: 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 { getExternalId } from './chat.js'\n\nconst AUTHENTICATION_ERROR = 'Something went wrong initializing the chat'\nconst INITIALIZATION_ERROR = 'Chat SDK not initialized'\n\n// Module-level configuration\nlet _config = {\n endpoint: null\n}\n\n/**\n * Configure the API service with endpoint\n * @param {{ endpoint: string }} credentials\n */\nexport function configure(credentials) {\n _config = {\n endpoint: credentials.endpoint\n }\n}\n\n/**\n * Get current configuration\n * @returns {{ endpoint: string | null }}\n */\nexport function getConfig() {\n return { ..._config }\n}\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 // Store endpoint for subsequent requests\n configure({ endpoint })\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 { endpoint } = _config\n\n if (!endpoint) {\n throw new Error(INITIALIZATION_ERROR)\n }\n\n const url = `${endpoint}${pathname}`\n\n return fetch(url, {\n headers: {\n 'Content-Type': 'application/json'\n },\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","getCallServerEndpoint","baseUrl","socketEndpoint","url","e","MESSAGE_ROLES","createSession","callbacks","currentSession","setCallbacks","initialize","credentials","getCredentials","updateSessionId","sessionId","startChat","payload","configData","authenticate","messages","messagesRes","getMessages","_a","msg","searchParams","getExternalId","error","cleanup","disconnect","sendMessage","text","html","reject","userMessage","loadingMessage","headers","fetchEventSource","response","event","data","newBotMessage","lastIndex","lastMsg","updatedMsg","_c","index","_f","_g","errorMessage","AUTHENTICATION_ERROR","INITIALIZATION_ERROR","_config","configure","endpoint","errorPayload","getHistory","queryParams","fetchRequest","pathname","method","body","rtcConfig","setCallCallbacks","track","stopPingInterval","setCallStatus","status","_b","setCallError","startPingInterval","pingMessage","sendEvent","handlePong","getUserMedia","createPeerConnection","candidateJson","err","newState","disconnectCall","connectSocket","fulfill","externalId","socketUrl","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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@origonai/web-chat-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Origon Web Chat SDK - Core chat functionality without UI dependencies",
5
5
  "type": "module",
6
6
  "main": "./dist/origon-chat-sdk.js",
package/src/chat.js CHANGED
@@ -11,9 +11,8 @@ import { MESSAGE_ROLES } from './constants.js'
11
11
 
12
12
  /**
13
13
  * @typedef {Object} ChatCallbacks
14
- * @property {(messages: Array) => void} [onMessagesUpdate] - Called when messages array should be updated
15
- * @property {(isTyping: boolean) => void} [onTyping] - Called when typing status changes
16
- * @property {(isLiveAgent: boolean) => void} [onLiveAgentMode] - Called when live agent mode status changes
14
+ * @property {(message: Object) => void} [onMessageAdd] - Called when a new message is added
15
+ * @property {(index: number, updatedMsg: Object) => void} [onMessageUpdate] - Called when an existing message is updated
17
16
  * @property {(sessionId: string) => void} [onSessionUpdate] - Called when session ID is updated
18
17
  */
19
18
 
@@ -22,7 +21,6 @@ import { MESSAGE_ROLES } from './constants.js'
22
21
  * @property {string} sessionId
23
22
  * @property {string} sseUrl
24
23
  * @property {string} [requestId]
25
- * @property {boolean} liveAgent
26
24
  * @property {AbortController} [abortController]
27
25
  * @property {string} [lastStreamId]
28
26
  * @property {Array} messages
@@ -43,7 +41,6 @@ function createSession(callbacks = {}) {
43
41
  requestId: undefined,
44
42
  sseUrl: undefined,
45
43
  abortController: undefined,
46
- liveAgent: false,
47
44
  lastStreamId: undefined,
48
45
  messages: [],
49
46
  callbacks
@@ -196,22 +193,17 @@ export function sendMessage({ text, html }) {
196
193
  timestamp: new Date().toISOString()
197
194
  }
198
195
  currentSession.messages = [...currentSession.messages, userMessage]
199
- currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])
196
+ currentSession.callbacks.onMessageAdd?.(userMessage)
200
197
 
201
198
  await sleep(200)
202
199
 
203
- // Add loading message for bot if not in live agent mode
204
- if (!currentSession.liveAgent) {
205
- const loadingMessage = {
206
- role: MESSAGE_ROLES.BOT,
207
- text: '',
208
- loading: true
209
- }
210
- currentSession.messages = [...currentSession.messages, loadingMessage]
211
- currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])
212
- } else {
213
- resolve(currentSession.sessionId)
200
+ const loadingMessage = {
201
+ role: MESSAGE_ROLES.BOT,
202
+ text: '',
203
+ loading: true
214
204
  }
205
+ currentSession.messages = [...currentSession.messages, loadingMessage]
206
+ currentSession.callbacks.onMessageAdd?.(loadingMessage)
215
207
 
216
208
  const url = new URL(currentSession.sseUrl)
217
209
  if (currentSession.sessionId) {
@@ -254,77 +246,37 @@ export function sendMessage({ text, html }) {
254
246
  if (data.status === 'connected') {
255
247
  currentSession.sessionId = data.sessionId
256
248
  currentSession.requestId = data.requestId
257
- if (currentSession.liveAgent) {
258
- resolve(currentSession.sessionId)
259
- }
260
- } else if (data.agent) {
261
- currentSession.liveAgent = true
262
- const { type, data: payload } = data.agent
263
-
264
- switch (type) {
265
- case 'typing':
266
- currentSession.callbacks.onTyping?.(true)
267
- currentSession.callbacks.onLiveAgentMode?.(true)
268
- break
269
- case 'typingOff':
270
- currentSession.callbacks.onTyping?.(false)
271
- currentSession.callbacks.onLiveAgentMode?.(true)
272
- break
273
- case 'message':
274
- if (payload.role !== MESSAGE_ROLES.USER) {
275
- // Remove loading messages and add new message
276
- currentSession.messages = currentSession.messages.filter((msg) => !msg.loading)
277
- currentSession.messages = [...currentSession.messages, payload]
278
-
279
- const isEnded = payload.action === 'ended' || payload.action === 'left'
280
- if (isEnded) {
281
- currentSession.liveAgent = false
282
- }
283
-
284
- currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])
285
- currentSession.callbacks.onLiveAgentMode?.(!isEnded)
286
- }
287
- if (payload.action === 'ended' || payload.action === 'left') {
288
- currentSession.liveAgent = false
289
- }
290
- break
291
- default:
292
- break
293
- }
294
249
  } else if (data.message !== undefined) {
295
- let messages = currentSession.messages
296
-
297
250
  // If streamId changes, start a new assistant message
298
251
  if (data.streamId !== undefined) {
299
252
  if (currentSession.lastStreamId === undefined) {
300
253
  currentSession.lastStreamId = data.streamId
301
254
  } else if (data.streamId !== currentSession.lastStreamId) {
302
255
  currentSession.lastStreamId = data.streamId
303
- messages = [
304
- ...messages,
305
- {
306
- role: MESSAGE_ROLES.BOT,
307
- text: '',
308
- loading: true
309
- }
310
- ]
256
+ const newBotMessage = {
257
+ role: MESSAGE_ROLES.BOT,
258
+ text: '',
259
+ loading: true
260
+ }
261
+ currentSession.messages = [...currentSession.messages, newBotMessage]
262
+ currentSession.callbacks.onMessageAdd?.(newBotMessage)
311
263
  }
312
264
  }
313
265
 
314
266
  // Update the last message with new content
315
- currentSession.messages = messages.map((msg, index) => {
316
- if (index === messages.length - 1) {
317
- return {
318
- ...msg,
319
- loading: false,
320
- text: (msg.text || '') + data.message,
321
- done: data.done ?? msg.done
322
- }
323
- }
324
- return msg
325
- })
267
+ const lastIndex = currentSession.messages.length - 1
268
+ const lastMsg = currentSession.messages[lastIndex]
269
+ const updatedMsg = {
270
+ ...lastMsg,
271
+ loading: false,
272
+ text: (lastMsg.text || '') + data.message,
273
+ done: data.done ?? lastMsg.done
274
+ }
275
+ currentSession.messages = currentSession.messages.map((msg, index) =>
276
+ index === lastIndex ? updatedMsg : msg
277
+ )
326
278
 
327
- currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])
279
+ currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)
328
280
 
329
281
  if (data.done) {
330
282
  resolve(currentSession.sessionId)
@@ -335,17 +287,17 @@ export function sendMessage({ text, html }) {
335
287
  currentSession.requestId = data.requestId ?? currentSession.requestId
336
288
  } else if (data.error) {
337
289
  const errorMessage = 'Failed to connect to the system'
338
- currentSession.messages = currentSession.messages.map((msg, index) => {
339
- if (index === currentSession.messages.length - 1) {
340
- return {
341
- ...msg,
342
- loading: false,
343
- errorText: errorMessage
344
- }
345
- }
346
- return msg
347
- })
348
- currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])
290
+ const lastIndex = currentSession.messages.length - 1
291
+ const lastMsg = currentSession.messages[lastIndex]
292
+ const updatedMsg = {
293
+ ...lastMsg,
294
+ loading: false,
295
+ errorText: errorMessage
296
+ }
297
+ currentSession.messages = currentSession.messages.map((msg, index) =>
298
+ index === lastIndex ? updatedMsg : msg
299
+ )
300
+ currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)
349
301
  reject(new Error(errorMessage))
350
302
  }
351
303
  },
@@ -357,18 +309,18 @@ export function sendMessage({ text, html }) {
357
309
  } catch (error) {
358
310
  console.error('Failed to send message: ', error)
359
311
  const errorMessage = 'Failed to connect to the system'
360
- currentSession.messages = currentSession.messages.map((msg, index) => {
361
- if (index === currentSession.messages.length - 1) {
362
- return {
363
- ...msg,
364
- loading: false,
365
- errorText: errorMessage,
366
- done: true
367
- }
368
- }
369
- return msg
370
- })
371
- currentSession.callbacks.onMessagesUpdate?.([...currentSession.messages])
312
+ const lastIndex = currentSession.messages.length - 1
313
+ const lastMsg = currentSession.messages[lastIndex]
314
+ const updatedMsg = {
315
+ ...lastMsg,
316
+ loading: false,
317
+ errorText: errorMessage,
318
+ done: true
319
+ }
320
+ currentSession.messages = currentSession.messages.map((msg, index) =>
321
+ index === lastIndex ? updatedMsg : msg
322
+ )
323
+ currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)
372
324
  reject(error)
373
325
  }
374
326
  })()