@origonai/web-chat-sdk 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,7 +21,7 @@ yarn add @origonai/web-chat-sdk
21
21
 
22
22
  ## Quick Start
23
23
 
24
- ### Basic Chat Example
24
+ ### Chat Example
25
25
 
26
26
  ```javascript
27
27
  import {
@@ -34,11 +34,14 @@ import {
34
34
 
35
35
  // 1. Set up callbacks for state updates
36
36
  setCallbacks({
37
- onMessagesUpdate: (messages) => {
38
- console.log('Messages updated:', messages)
37
+ onMessageAdd: (message) => {
38
+ console.log('New message:', message)
39
+ },
40
+ onMessageUpdate: (index, updatedMsg) => {
41
+ console.log('Message updated at index:', index, updatedMsg)
39
42
  },
40
43
  onTyping: (isTyping) => {
41
- console.log('Agent is typing:', isTyping)
44
+ console.log('Live Agent is typing:', isTyping)
42
45
  },
43
46
  onSessionUpdate: (sessionId) => {
44
47
  console.log('Session ID:', sessionId)
@@ -63,7 +66,7 @@ await sendMessage({ text: 'Hello!' })
63
66
  disconnect()
64
67
  ```
65
68
 
66
- ### Voice Call Example
69
+ ### Call Example
67
70
 
68
71
  ```javascript
69
72
  import {
@@ -143,7 +146,8 @@ Sets callback functions for chat events.
143
146
 
144
147
  ```javascript
145
148
  setCallbacks({
146
- onMessagesUpdate: (messages: Message[]) => void,
149
+ onMessageAdd: (message: Message) => void,
150
+ onMessageUpdate: (index: number, updatedMsg: Message) => void,
147
151
  onTyping: (isTyping: boolean) => void,
148
152
  onLiveAgentMode: (isLiveAgent: boolean) => void,
149
153
  onSessionUpdate: (sessionId: string) => void
@@ -309,7 +313,8 @@ interface Message {
309
313
 
310
314
  ```typescript
311
315
  interface ChatCallbacks {
312
- onMessagesUpdate?: (messages: Message[]) => void
316
+ onMessageAdd?: (message: Message) => void
317
+ onMessageUpdate?: (index: number, updatedMsg: Message) => void
313
318
  onTyping?: (isTyping: boolean) => void
314
319
  onLiveAgentMode?: (isLiveAgent: boolean) => void
315
320
  onSessionUpdate?: (sessionId: string) => void
@@ -367,7 +372,8 @@ import {
367
372
 
368
373
  // Set up both chat and call callbacks
369
374
  setCallbacks({
370
- onMessagesUpdate: (messages) => updateChatUI(messages),
375
+ onMessageAdd: (message) => addMessageToUI(message),
376
+ onMessageUpdate: (index, updatedMsg) => updateMessageInUI(index, updatedMsg),
371
377
  onSessionUpdate: (sessionId) => saveSession(sessionId)
372
378
  })
373
379
 
@@ -1,4 +1,4 @@
1
- import { fetchEventSource as K } from "@microsoft/fetch-event-source";
1
+ import { fetchEventSource as _ } from "@microsoft/fetch-event-source";
2
2
  function j() {
3
3
  const e = Date.now(), t = new Uint8Array(16);
4
4
  crypto.getRandomValues(t), t[0] = e >> 40 & 255, t[1] = e >> 32 & 255, t[2] = e >> 24 & 255, t[3] = e >> 16 & 255, t[4] = e >> 8 & 255, t[5] = e & 255, t[6] = t[6] & 15 | 112, t[8] = t[8] & 63 | 128;
@@ -27,7 +27,7 @@ function Y(e) {
27
27
  }
28
28
  return t;
29
29
  }
30
- const b = {
30
+ const E = {
31
31
  BOT: "assistant",
32
32
  // this can be automated or LLM AI Agent response
33
33
  USER: "user",
@@ -52,32 +52,32 @@ function L(e = {}) {
52
52
  };
53
53
  }
54
54
  let o = L();
55
- function Se(e) {
55
+ function pe(e) {
56
56
  o.callbacks = { ...o.callbacks, ...e };
57
57
  }
58
- function Ce(e) {
58
+ function me(e) {
59
59
  console.log("Initializing chat...", e), o.credentials = e, e.token && (o.authenticated = !0);
60
60
  }
61
- function Z() {
61
+ function J() {
62
62
  return o.credentials;
63
63
  }
64
- function X(e) {
64
+ function Z(e) {
65
65
  var t, s;
66
66
  e && e !== o.sessionId && (o.sessionId = e, (s = (t = o.callbacks).onSessionUpdate) == null || s.call(t, e));
67
67
  }
68
- async function Ie(e = {}) {
68
+ async function Se(e = {}) {
69
69
  var t;
70
70
  try {
71
71
  console.log("startChat: ", e, o);
72
72
  let s = null;
73
- o.authenticated ? s = o.configData : (s = await oe(o.credentials), o.authenticated = !0, o.configData = s);
73
+ o.authenticated ? s = o.configData : (s = await ne(o.credentials), o.authenticated = !0, o.configData = s);
74
74
  let a = [];
75
75
  if (e.sessionId) {
76
- const d = await se(e.sessionId);
77
- a = ((t = d == null ? void 0 : d.sessionHistory) != null ? t : []).map((r) => ({
76
+ const u = await te(e.sessionId);
77
+ a = ((t = u == null ? void 0 : u.sessionHistory) != null ? t : []).map((r) => ({
78
78
  id: r.id,
79
79
  text: r.text,
80
- role: r.youtubeVideo ? b.BOT : r.role,
80
+ role: r.youtubeVideo ? E.BOT : r.role,
81
81
  timestamp: r.timestamp,
82
82
  video: r.youtubeVideo,
83
83
  channel: r.channel,
@@ -93,13 +93,13 @@ async function Ie(e = {}) {
93
93
  configData: s
94
94
  };
95
95
  } catch (s) {
96
- throw console.error(`Failed to start chat: ${s.message}`), J(), s;
96
+ throw console.error(`Failed to start chat: ${s.message}`), z(), s;
97
97
  }
98
98
  }
99
- function he() {
100
- J();
99
+ function Ce() {
100
+ z();
101
101
  }
102
- function J() {
102
+ function z() {
103
103
  o.abortController && o.abortController.abort();
104
104
  const { callbacks: e, credentials: t } = o;
105
105
  o = L(e), o.credentials = t, console.log("Chat session cleaned up");
@@ -108,45 +108,45 @@ function $() {
108
108
  var e;
109
109
  return (e = o.credentials) != null && e.externalId ? o.credentials.externalId : V();
110
110
  }
111
- function ke({ text: e, html: t }) {
111
+ function Ie({ text: e, html: t }) {
112
112
  return new Promise((s, a) => {
113
113
  (async () => {
114
- var l, d, r, h, i, k, M;
114
+ var l, u, r, k, i, w, M;
115
115
  try {
116
- const I = {
117
- role: b.USER,
116
+ const S = {
117
+ role: E.USER,
118
118
  text: e,
119
119
  html: t,
120
120
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
121
121
  };
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,
122
+ o.messages = [...o.messages, S], (u = (l = o.callbacks).onMessageAdd) == null || u.call(l, S), await Q(200);
123
+ const y = {
124
+ role: E.BOT,
125
125
  text: "",
126
126
  loading: !0
127
127
  };
128
- o.messages = [...o.messages, w], (h = (r = o.callbacks).onMessageAdd) == null || h.call(r, w);
128
+ o.messages = [...o.messages, y], (k = (r = o.callbacks).onMessageAdd) == null || k.call(r, y);
129
129
  const g = new URL(o.sseUrl);
130
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 = {
131
+ const h = {
132
132
  "Content-Type": "application/json"
133
133
  };
134
- (i = o.credentials) != null && i.token && (A.Authorization = `Bearer ${o.credentials.token}`), await K(g.toString(), {
134
+ (i = o.credentials) != null && i.token && (h.Authorization = `Bearer ${o.credentials.token}`), await _(g.toString(), {
135
135
  method: "POST",
136
- headers: A,
136
+ headers: h,
137
137
  body: JSON.stringify({
138
138
  message: e,
139
139
  html: t
140
140
  }),
141
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");
142
+ onopen: async (d) => {
143
+ if (!d.ok)
144
+ throw console.error("Failed to send message bad response: ", d), new Error("Failed to send message");
145
145
  },
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);
146
+ onmessage: (d) => {
147
+ var b, O, x, P, U, D, N, q, F;
148
+ console.log("Event: ", d);
149
+ const c = JSON.parse(d.data);
150
150
  if (c.status === "connected")
151
151
  o.sessionId = c.sessionId, o.requestId = c.requestId;
152
152
  else if (c.message !== void 0) {
@@ -156,63 +156,55 @@ function ke({ text: e, html: t }) {
156
156
  else if (c.streamId !== o.lastStreamId) {
157
157
  o.lastStreamId = c.streamId;
158
158
  const p = {
159
- role: b.BOT,
159
+ role: E.BOT,
160
160
  text: "",
161
161
  loading: !0
162
162
  };
163
- o.messages = [...o.messages, p], (O = (y = o.callbacks).onMessageAdd) == null || O.call(y, p);
163
+ o.messages = [...o.messages, p], (O = (b = o.callbacks).onMessageAdd) == null || O.call(b, p);
164
164
  }
165
165
  }
166
- const S = o.messages.length - 1, f = o.messages[S], T = {
166
+ const C = o.messages.length - 1, f = o.messages[C], T = {
167
167
  ...f,
168
168
  loading: !1,
169
169
  text: (f.text || "") + c.message,
170
170
  done: (x = c.done) != null ? x : f.done
171
171
  };
172
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;
173
+ (p, R) => R === C ? T : p
174
+ ), (U = (P = o.callbacks).onMessageUpdate) == null || U.call(P, C, 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
175
  } else if (c.error) {
176
- const S = "Failed to connect to the system", f = o.messages.length - 1, p = {
176
+ const C = "Failed to connect to the system", f = o.messages.length - 1, p = {
177
177
  ...o.messages[f],
178
178
  loading: !1,
179
- errorText: S
179
+ errorText: C
180
180
  };
181
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));
182
+ (R, K) => K === f ? p : R
183
+ ), (F = (q = o.callbacks).onMessageUpdate) == null || F.call(q, f, p), a(new Error(C));
184
184
  }
185
185
  },
186
- onerror: (u) => {
187
- throw u;
186
+ onerror: (d) => {
187
+ throw d;
188
188
  },
189
189
  openWhenHidden: !0
190
190
  });
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],
191
+ } catch (S) {
192
+ console.error("Failed to send message: ", S);
193
+ const y = "Failed to connect to the system", g = o.messages.length - 1, h = o.messages[g], d = {
194
+ ...h,
195
195
  loading: !1,
196
- errorText: w,
196
+ errorText: h.done ? void 0 : S.message || y,
197
197
  done: !0
198
198
  };
199
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);
200
+ (c, b) => b === g ? d : c
201
+ ), (M = (w = o.callbacks).onMessageUpdate) == null || M.call(w, g, d), a(S);
202
202
  }
203
203
  })();
204
204
  });
205
205
  }
206
- const ee = "Something went wrong initializing the chat", ne = "Chat SDK not initialized";
207
- let z = {
208
- endpoint: null
209
- };
210
- function te(e) {
211
- z = {
212
- endpoint: e.endpoint
213
- };
214
- }
215
- async function oe(e) {
206
+ const X = "Something went wrong initializing the chat", ee = "Chat SDK not initialized";
207
+ async function ne(e) {
216
208
  const { endpoint: t } = e, s = `${t}/config`, a = await fetch(s, {
217
209
  method: "GET",
218
210
  headers: {
@@ -221,12 +213,11 @@ async function oe(e) {
221
213
  });
222
214
  if (!a.ok) {
223
215
  const r = await a.json();
224
- throw new Error((r == null ? void 0 : r.error) || ee);
216
+ throw new Error((r == null ? void 0 : r.error) || X);
225
217
  }
226
- const d = (await a.json()).data;
227
- return te({ endpoint: t }), d;
218
+ return (await a.json()).data;
228
219
  }
229
- async function we() {
220
+ async function he() {
230
221
  const e = new URLSearchParams({
231
222
  externalId: $()
232
223
  }), t = await G(`/sessions?${e.toString()}`, "GET");
@@ -234,7 +225,7 @@ async function we() {
234
225
  throw new Error("Unable to load history, please try again later");
235
226
  return t.json();
236
227
  }
237
- async function se(e) {
228
+ async function te(e) {
238
229
  const t = new URLSearchParams({
239
230
  sessionId: e
240
231
  }), s = await G(`/session?${t.toString()}`, "GET");
@@ -243,10 +234,10 @@ async function se(e) {
243
234
  return s.json();
244
235
  }
245
236
  async function G(e, t = "GET", s = null) {
246
- const { endpoint: a } = z;
247
- if (!a)
248
- throw new Error(ne);
249
- const l = `${a}${e}`;
237
+ const a = J();
238
+ if (!(a != null && a.endpoint))
239
+ throw new Error(ee);
240
+ const l = `${endpoint}${e}`;
250
241
  return fetch(l, {
251
242
  headers: {
252
243
  "Content-Type": "application/json"
@@ -274,14 +265,14 @@ function W(e = {}) {
274
265
  };
275
266
  }
276
267
  let n = W();
277
- const ae = {
268
+ const oe = {
278
269
  iceServers: [{ urls: "stun:stun.l.google.com:19302" }, { urls: "stun:stun1.l.google.com:19302" }]
279
270
  };
280
- function ye(e) {
271
+ function ke(e) {
281
272
  n.callbacks = { ...n.callbacks, ...e };
282
273
  }
283
274
  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();
275
+ 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), A();
285
276
  const e = n.callbacks;
286
277
  n = W(e), console.log("Call session cleaned up");
287
278
  }
@@ -289,15 +280,15 @@ function m(e) {
289
280
  var t, s;
290
281
  n.callStatus = e, (s = (t = n.callbacks).onCallStatus) == null || s.call(t, e);
291
282
  }
292
- function E(e) {
283
+ function v(e) {
293
284
  var t, s;
294
285
  (s = (t = n.callbacks).onCallError) == null || s.call(t, e);
295
286
  }
296
- function v() {
287
+ function A() {
297
288
  n.pingInterval && (clearInterval(n.pingInterval), n.pingInterval = null);
298
289
  }
299
- function re() {
300
- v(), n.pingInterval = setInterval(() => {
290
+ function se() {
291
+ A(), n.pingInterval = setInterval(() => {
301
292
  if (n.socket && n.socket.readyState === WebSocket.OPEN) {
302
293
  n.pingCount++;
303
294
  const e = {
@@ -305,15 +296,15 @@ function re() {
305
296
  timestamp: Date.now(),
306
297
  count: n.pingCount
307
298
  };
308
- C(e), console.log(`Sending keep-alive ping #${n.pingCount}`);
299
+ I(e), console.log(`Sending keep-alive ping #${n.pingCount}`);
309
300
  } else
310
- console.log("Socket not open, stopping ping interval"), v();
301
+ console.log("Socket not open, stopping ping interval"), A();
311
302
  }, 1e4);
312
303
  }
313
- function ce() {
304
+ function ae() {
314
305
  n.lastPongTime = Date.now(), console.log(`Received pong #${n.pingCount}`);
315
306
  }
316
- function C(e) {
307
+ function I(e) {
317
308
  if (!n.socket) {
318
309
  console.error("Failed to send event: no socket instance");
319
310
  return;
@@ -324,7 +315,7 @@ function C(e) {
324
315
  }
325
316
  n.socket.send(JSON.stringify(e));
326
317
  }
327
- async function ie() {
318
+ async function re() {
328
319
  try {
329
320
  n.localStream = await navigator.mediaDevices.getUserMedia({
330
321
  audio: !0,
@@ -334,11 +325,11 @@ async function ie() {
334
325
  throw console.error(`Failed to get audio media: ${e.message}`), e;
335
326
  }
336
327
  }
337
- function le() {
338
- n.peerConnection = new RTCPeerConnection(ae), n.peerConnection.onicecandidate = (e) => {
328
+ function ce() {
329
+ n.peerConnection = new RTCPeerConnection(oe), n.peerConnection.onicecandidate = (e) => {
339
330
  if (e.candidate) {
340
331
  const t = JSON.stringify(e.candidate);
341
- n.peerConnection && n.peerConnection.remoteDescription ? (C({
332
+ n.peerConnection && n.peerConnection.remoteDescription ? (I({
342
333
  type: "ice",
343
334
  data: {
344
335
  candidate: t
@@ -354,14 +345,14 @@ function le() {
354
345
  console.log(`ICE connection state: ${n.peerConnection.iceConnectionState}`);
355
346
  };
356
347
  }
357
- function de(e) {
348
+ function ie(e) {
358
349
  return new Promise((t, s) => {
359
350
  if (n.socket && (n.socket.readyState === WebSocket.CONNECTING || n.socket.readyState === WebSocket.OPEN)) {
360
351
  console.log("Socket in connecting/open state, returning."), t(n.socket.readyState === WebSocket.OPEN);
361
352
  return;
362
353
  }
363
354
  console.log("Initializing socket connection..");
364
- const a = Z();
355
+ const a = J();
365
356
  if (!a || !a.endpoint) {
366
357
  s(new Error("SDK not initialized. Please initialize SDK first."));
367
358
  return;
@@ -375,58 +366,58 @@ function de(e) {
375
366
  );
376
367
  return;
377
368
  }
378
- const d = $(), r = new URLSearchParams({
379
- externalId: d
369
+ const u = $(), r = new URLSearchParams({
370
+ externalId: u
380
371
  });
381
372
  e.sessionId && r.set("sessionId", e.sessionId), a.token && r.set("token", a.token);
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);
373
+ const k = `${l}?${r.toString()}`;
374
+ n.socket = new WebSocket(k), n.socket.onopen = (i) => {
375
+ console.log("Socket connection established: ", i), se(), t(!0);
385
376
  }, n.socket.onmessage = (i) => {
386
- const k = JSON.parse(i.data);
387
- ue(k);
377
+ const w = JSON.parse(i.data);
378
+ le(w);
388
379
  }, n.socket.onerror = (i) => {
389
- console.error("Socket error: ", i), m("error"), E(i.message || "Unable to connect voice"), s(i);
380
+ console.error("Socket error: ", i), m("error"), v(i.message || "Unable to connect voice"), s(i);
390
381
  }, n.socket.onclose = (i) => {
391
- console.log("Socket connection closed: ", i), v();
382
+ console.log("Socket connection closed: ", i), A();
392
383
  };
393
384
  });
394
385
  }
395
- function ue(e) {
386
+ function le(e) {
396
387
  switch (console.log("Handling socket server event: ", e), e.type) {
397
388
  case "pong":
398
- ce();
389
+ ae();
399
390
  break;
400
391
  case "answer":
401
- ge(e.data);
392
+ de(e.data);
402
393
  break;
403
394
  case "ice":
404
- fe(e.data);
395
+ ue(e.data);
405
396
  break;
406
397
  case "renegotiationOffer":
407
- pe(e.data);
398
+ ge(e.data);
408
399
  break;
409
400
  case "end":
410
401
  H();
411
402
  break;
412
403
  case "error":
413
- m("error"), E(e.error || "Unable to connect voice");
404
+ m("error"), v(e.error || "Unable to connect voice");
414
405
  break;
415
406
  default:
416
407
  console.log("Unknown call event type: ", e.type);
417
408
  break;
418
409
  }
419
410
  }
420
- async function ge(e) {
411
+ async function de(e) {
421
412
  try {
422
- if (console.log("Received answer"), n.sessionId = e.sessionId, X(e.sessionId), n.peerConnection) {
413
+ if (console.log("Received answer"), n.sessionId = e.sessionId, Z(e.sessionId), n.peerConnection) {
423
414
  const t = new RTCSessionDescription({
424
415
  type: "answer",
425
416
  sdp: e.sdp
426
417
  });
427
418
  console.log("Setting remote description answer: ", t), await n.peerConnection.setRemoteDescription(t), console.log("Remote description set");
428
419
  for (const s of n.localIceCandidates)
429
- C({
420
+ I({
430
421
  type: "ice",
431
422
  data: {
432
423
  candidate: s
@@ -446,7 +437,7 @@ async function ge(e) {
446
437
  console.error(`Failed to handle answer: ${t.message}`);
447
438
  }
448
439
  }
449
- async function fe(e) {
440
+ async function ue(e) {
450
441
  try {
451
442
  if (n.peerConnection) {
452
443
  if (!n.peerConnection.remoteDescription) {
@@ -460,7 +451,7 @@ async function fe(e) {
460
451
  console.error(`Failed to add ICE candidate: ${t.message}`);
461
452
  }
462
453
  }
463
- async function pe(e) {
454
+ async function ge(e) {
464
455
  try {
465
456
  if (console.log("Received renegotiation offer"), n.peerConnection) {
466
457
  const t = new RTCSessionDescription({
@@ -469,7 +460,7 @@ async function pe(e) {
469
460
  });
470
461
  console.log("Setting remote description offer: ", t), await n.peerConnection.setRemoteDescription(t), console.log("Remote description set");
471
462
  const s = await n.peerConnection.createAnswer();
472
- await n.peerConnection.setLocalDescription(s), C({
463
+ await n.peerConnection.setLocalDescription(s), I({
473
464
  type: "renegotiationAnswer",
474
465
  data: {
475
466
  sdp: s.sdp
@@ -480,32 +471,32 @@ async function pe(e) {
480
471
  console.error(`Failed to handle renegotiation offer: ${t.message}`);
481
472
  }
482
473
  }
483
- async function be(e = {}) {
474
+ async function we(e = {}) {
484
475
  try {
485
476
  if (n.callStatus === "connecting" || n.callStatus === "connected") {
486
477
  console.log(`Call already in ${n.callStatus} state`);
487
478
  return;
488
479
  }
489
- console.log("Starting audio call..."), m("connecting"), E(null), n.sessionId = e.sessionId, await ie(), le(), n.localStream.getTracks().forEach((s) => {
480
+ console.log("Starting audio call..."), m("connecting"), v(null), n.sessionId = e.sessionId, await re(), ce(), n.localStream.getTracks().forEach((s) => {
490
481
  n.peerConnection.addTrack(s, n.localStream), console.log(`Added ${s.kind} track`);
491
- }), await de(e);
482
+ }), await ie(e);
492
483
  const t = await n.peerConnection.createOffer();
493
- await n.peerConnection.setLocalDescription(t), C({
484
+ await n.peerConnection.setLocalDescription(t), I({
494
485
  type: "offer",
495
486
  data: {
496
487
  sdp: t.sdp
497
488
  }
498
489
  }), console.log("Call initiated successfully");
499
490
  } 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();
491
+ console.log("error: ", t), console.error(`Failed to start call: ${t.message}`), m("error"), v(t.message || "Unable to connect voice"), B();
501
492
  }
502
493
  }
503
494
  function H() {
504
- C({
495
+ I({
505
496
  type: "end"
506
497
  }), 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();
507
498
  }
508
- function Ee() {
499
+ function ye() {
509
500
  if (n.localStream) {
510
501
  const e = n.localStream.getAudioTracks()[0];
511
502
  if (e)
@@ -513,10 +504,10 @@ function Ee() {
513
504
  }
514
505
  return !1;
515
506
  }
516
- function ve() {
507
+ function be() {
517
508
  return n.localStream;
518
509
  }
519
- function Ae() {
510
+ function Ee() {
520
511
  return new Promise((e, t) => {
521
512
  if (!n.peerConnection) {
522
513
  t(new Error("no peer connection"));
@@ -531,7 +522,7 @@ function Ae() {
531
522
  });
532
523
  });
533
524
  }
534
- function Te() {
525
+ function ve() {
535
526
  return new Promise((e, t) => {
536
527
  if (!n.peerConnection) {
537
528
  t(new Error("no peer connection"));
@@ -547,22 +538,21 @@ function Te() {
547
538
  });
548
539
  }
549
540
  export {
550
- b as MESSAGE_ROLES,
551
- oe as authenticate,
552
- te as configure,
553
- he as disconnect,
541
+ E as MESSAGE_ROLES,
542
+ ne as authenticate,
543
+ Ce as disconnect,
554
544
  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
545
+ he as getHistory,
546
+ Ee as getInboundAudioEnergy,
547
+ be as getLocalStream,
548
+ te as getMessages,
549
+ ve as getOutboundAudioEnergy,
550
+ me as initialize,
551
+ Ie as sendMessage,
552
+ ke as setCallCallbacks,
553
+ pe as setCallbacks,
554
+ we as startCall,
555
+ Se as startChat,
556
+ ye as toggleMute
567
557
  };
568
558
  //# 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 {(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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"}
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: lastMsg.done ? undefined : error.message || errorMessage,\n done: true\n }\n currentSession.messages = currentSession.messages.map((msg, index) =>\n index === lastIndex ? updatedMsg : msg\n )\n currentSession.callbacks.onMessageUpdate?.(lastIndex, updatedMsg)\n reject(error)\n }\n })()\n })\n}\n","/**\n * API Service for Chat SDK\n * Handles all HTTP requests without depending on external state\n */\n\nimport { getCredentials, getExternalId } from './chat.js'\n\nconst AUTHENTICATION_ERROR = 'Something went wrong initializing the chat'\nconst INITIALIZATION_ERROR = 'Chat SDK not initialized'\n\n/**\n * Authenticate with the chat service\n * @param {{ endpoint: string }} credentials\n * @returns {Promise<object>} Authentication response data\n */\nexport async function authenticate(payload) {\n const { endpoint } = payload\n const url = `${endpoint}/config`\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json'\n }\n })\n\n if (!response.ok) {\n const errorPayload = await response.json()\n throw new Error(errorPayload?.error || AUTHENTICATION_ERROR)\n }\n\n const res = await response.json()\n const data = res.data\n\n return data\n}\n\n/**\n * Get chat history for the current device\n * @returns {Promise<{ sessions: Array }>}\n */\nexport async function getHistory() {\n const queryParams = new URLSearchParams({\n externalId: getExternalId()\n })\n const response = await fetchRequest(`/sessions?${queryParams.toString()}`, 'GET')\n\n if (!response.ok) {\n throw new Error('Unable to load history, please try again later')\n }\n\n return response.json()\n}\n\n/**\n * Get messages for a specific session\n * @param {string} sessionId\n * @returns {Promise<{ sessionHistory: Array }>}\n */\nexport async function getMessages(sessionId) {\n const queryParams = new URLSearchParams({\n sessionId\n })\n const response = await fetchRequest(`/session?${queryParams.toString()}`, 'GET')\n\n if (!response.ok) {\n throw new Error('Unable to load messages, please try again later')\n }\n\n return response.json()\n}\n\n/**\n * Internal fetch request helper\n * @param {string} pathname\n * @param {string} method\n * @param {object|null} body\n * @returns {Promise<Response>}\n */\nasync function fetchRequest(pathname, method = 'GET', body = null) {\n const credentials = getCredentials()\n\n if (!credentials?.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","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.1",
3
+ "version": "0.1.2",
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
@@ -314,7 +314,7 @@ export function sendMessage({ text, html }) {
314
314
  const updatedMsg = {
315
315
  ...lastMsg,
316
316
  loading: false,
317
- errorText: errorMessage,
317
+ errorText: lastMsg.done ? undefined : error.message || errorMessage,
318
318
  done: true
319
319
  }
320
320
  currentSession.messages = currentSession.messages.map((msg, index) =>
package/src/http.js CHANGED
@@ -3,34 +3,11 @@
3
3
  * Handles all HTTP requests without depending on external state
4
4
  */
5
5
 
6
- import { getExternalId } from './chat.js'
6
+ import { getCredentials, getExternalId } from './chat.js'
7
7
 
8
8
  const AUTHENTICATION_ERROR = 'Something went wrong initializing the chat'
9
9
  const INITIALIZATION_ERROR = 'Chat SDK not initialized'
10
10
 
11
- // Module-level configuration
12
- let _config = {
13
- endpoint: null
14
- }
15
-
16
- /**
17
- * Configure the API service with endpoint
18
- * @param {{ endpoint: string }} credentials
19
- */
20
- export function configure(credentials) {
21
- _config = {
22
- endpoint: credentials.endpoint
23
- }
24
- }
25
-
26
- /**
27
- * Get current configuration
28
- * @returns {{ endpoint: string | null }}
29
- */
30
- export function getConfig() {
31
- return { ..._config }
32
- }
33
-
34
11
  /**
35
12
  * Authenticate with the chat service
36
13
  * @param {{ endpoint: string }} credentials
@@ -55,9 +32,6 @@ export async function authenticate(payload) {
55
32
  const res = await response.json()
56
33
  const data = res.data
57
34
 
58
- // Store endpoint for subsequent requests
59
- configure({ endpoint })
60
-
61
35
  return data
62
36
  }
63
37
 
@@ -104,9 +78,9 @@ export async function getMessages(sessionId) {
104
78
  * @returns {Promise<Response>}
105
79
  */
106
80
  async function fetchRequest(pathname, method = 'GET', body = null) {
107
- const { endpoint } = _config
81
+ const credentials = getCredentials()
108
82
 
109
- if (!endpoint) {
83
+ if (!credentials?.endpoint) {
110
84
  throw new Error(INITIALIZATION_ERROR)
111
85
  }
112
86
 
package/src/index.js CHANGED
@@ -21,7 +21,8 @@
21
21
  * // Set up callbacks for state updates
22
22
  * setCallbacks({
23
23
  * onMessage: (msg) => console.log('New message:', msg),
24
- * onMessagesUpdate: (messages) => updateUI(messages),
24
+ * onMessageAdd: (message) => updateUI(message),
25
+ * onMessageUpdate: (index, updatedMsg) => updateUI(updatedMsg),
25
26
  * onTyping: (isTyping) => showTypingIndicator(isTyping),
26
27
  * onError: (error) => console.error(error)
27
28
  * })
@@ -38,7 +39,7 @@
38
39
  */
39
40
 
40
41
  // HTTP API functions
41
- export { authenticate, getHistory, getMessages, configure } from './http.js'
42
+ export { authenticate, getHistory, getMessages } from './http.js'
42
43
 
43
44
  // Chat functions
44
45
  export { initialize, startChat, sendMessage, disconnect, setCallbacks } from './chat.js'