@opencx/widget 3.0.50 → 3.0.52

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.
@@ -3,21 +3,21 @@ import F from "lodash.isequal";
3
3
  import { v4 as A } from "uuid";
4
4
  const L = (g) => {
5
5
  console.log(g.error);
6
- }, D = (g) => {
7
- const a = O({
6
+ }, B = (g) => {
7
+ const n = O({
8
8
  baseUrl: g.baseUrl
9
9
  }), i = {
10
10
  onRequest: g.onRequest,
11
11
  onResponse: g.onResponse,
12
12
  onError: g.onError || L
13
13
  };
14
- return a.use(i), a;
14
+ return n.use(i), n;
15
15
  };
16
16
  class E {
17
17
  constructor({
18
- config: a
18
+ config: n
19
19
  }) {
20
- var n;
20
+ var a;
21
21
  this.userToken = null, this.constructClientOptions = (t) => {
22
22
  const s = this.config.apiUrl || "https://api.open.cx", e = {
23
23
  "X-Bot-Token": this.config.token,
@@ -29,7 +29,7 @@ class E {
29
29
  }, this.createOpenAPIClient = ({
30
30
  baseUrl: t,
31
31
  headers: s
32
- }) => D({
32
+ }) => B({
33
33
  baseUrl: t,
34
34
  onRequest: ({ request: e }) => {
35
35
  Object.entries(s).forEach(([o, r]) => {
@@ -108,15 +108,15 @@ class E {
108
108
  });
109
109
  const { baseUrl: f } = this.constructClientOptions(this.userToken), C = `${f}/backend/widget/v2/upload`;
110
110
  c.open("POST", C), c.setRequestHeader("X-Bot-Token", this.config.token), this.userToken && c.setRequestHeader("Authorization", `Bearer ${this.userToken}`), c.send(l);
111
- }), this.vote = async (t) => await this.client.POST("/backend/widget/v2/chat/vote", { body: t }), this.config = a;
111
+ }), this.vote = async (t) => await this.client.POST("/backend/widget/v2/chat/vote", { body: t }), this.config = n;
112
112
  const { baseUrl: i, headers: h } = this.constructClientOptions(
113
- (n = a.user) == null ? void 0 : n.token
113
+ (a = n.user) == null ? void 0 : a.token
114
114
  );
115
115
  this.client = this.createOpenAPIClient({ baseUrl: i, headers: h });
116
116
  }
117
117
  }
118
118
  class b {
119
- constructor(a) {
119
+ constructor(n) {
120
120
  this.subscribers = /* @__PURE__ */ new Set(), this.get = () => this.state, this.set = (i) => {
121
121
  F(this.state, i) || (this.state = i, this.notifySubscribers(i));
122
122
  }, this.setPartial = (i) => {
@@ -126,16 +126,16 @@ class b {
126
126
  }, this.reset = () => {
127
127
  this.set(this.initialState);
128
128
  }, this.notifySubscribers = (i) => {
129
- Array.from(this.subscribers).forEach((n) => {
129
+ Array.from(this.subscribers).forEach((a) => {
130
130
  try {
131
- n(i);
131
+ a(i);
132
132
  } catch (t) {
133
133
  console.error(t);
134
134
  }
135
135
  });
136
136
  }, this.subscribe = (i) => (this.subscribers.add(i), () => {
137
137
  this.subscribers.delete(i);
138
- }), this.state = a, this.initialState = a;
138
+ }), this.state = n, this.initialState = n;
139
139
  }
140
140
  }
141
141
  class T {
@@ -144,14 +144,14 @@ class T {
144
144
  isPolling: !1,
145
145
  isError: !1
146
146
  }), this.abortController = new AbortController(), this.reset = () => {
147
- var a;
148
- this.abortController.abort("Resetting poller"), (a = this.stopPolling) == null || a.call(this), this.stopPolling = null;
149
- }, this.stopPolling = null, this.startPolling = (a, i) => {
147
+ var n;
148
+ this.abortController.abort("Resetting poller"), (n = this.stopPolling) == null || n.call(this), this.stopPolling = null;
149
+ }, this.stopPolling = null, this.startPolling = (n, i) => {
150
150
  if (this.stopPolling) return;
151
- const h = [], n = async () => {
151
+ const h = [], a = async () => {
152
152
  this.abortController = new AbortController(), this.state.setPartial({ isPolling: !0 });
153
153
  try {
154
- await a(this.abortController.signal);
154
+ await n(this.abortController.signal);
155
155
  } catch (t) {
156
156
  if (this.abortController.signal.aborted)
157
157
  return;
@@ -159,20 +159,28 @@ class T {
159
159
  } finally {
160
160
  this.state.setPartial({ isPolling: !1 });
161
161
  }
162
- this.abortController.signal.aborted ? console.log("Poller aborted, not scheduling anymore") : h.push(setTimeout(n, i));
162
+ this.abortController.signal.aborted ? console.log("Poller aborted, not scheduling anymore") : h.push(setTimeout(a, i));
163
163
  };
164
- n(), this.stopPolling = () => {
164
+ a(), this.stopPolling = () => {
165
165
  h.forEach(clearTimeout), this.state.reset();
166
166
  };
167
167
  };
168
168
  }
169
169
  }
170
+ function D(g) {
171
+ try {
172
+ const n = g();
173
+ return n instanceof Promise ? n.then((i) => ({ data: i })).catch((i) => ({ error: i })) : { data: n };
174
+ } catch (n) {
175
+ return { error: n };
176
+ }
177
+ }
170
178
  class _ {
171
179
  constructor({
172
- api: a,
180
+ api: n,
173
181
  config: i,
174
182
  sessionCtx: h,
175
- messageCtx: n,
183
+ messageCtx: a,
176
184
  sessionPollingIntervalSeconds: t
177
185
  }) {
178
186
  this.poller = new T(), this.registerPolling = () => {
@@ -240,19 +248,30 @@ class _ {
240
248
  },
241
249
  data: {
242
250
  message: s.content.text || "",
243
- action: o ? { name: o.actionName, data: o.result } : void 0
251
+ action: o ? {
252
+ name: o.actionName,
253
+ data: this.extractActionResult(o)
254
+ } : void 0
244
255
  }
245
256
  };
246
- }, this.api = a, this.config = i, this.sessionCtx = h, this.messageCtx = n, this.sessionPollingIntervalSeconds = t, this.registerPolling();
257
+ }, this.extractActionResult = (s) => {
258
+ const e = s.result;
259
+ if (e === null || typeof e != "object") return e;
260
+ if ("responseBodyText" in e && typeof e.responseBodyText == "string") {
261
+ const o = e.responseBodyText, r = D(() => JSON.parse(o)).data;
262
+ if (r) return r;
263
+ }
264
+ return s.result;
265
+ }, this.api = n, this.config = i, this.sessionCtx = h, this.messageCtx = a, this.sessionPollingIntervalSeconds = t, this.registerPolling();
247
266
  }
248
267
  }
249
- class B {
268
+ class q {
250
269
  constructor({
251
- config: a,
270
+ config: n,
252
271
  api: i,
253
272
  storageCtx: h
254
273
  }) {
255
- var n;
274
+ var a;
256
275
  this.shouldCollectData = () => {
257
276
  var t;
258
277
  return !!(!((t = this.state.get().contact) != null && t.token) && this.config.collectUserData);
@@ -294,11 +313,11 @@ class B {
294
313
  var o, r, l, c;
295
314
  const s = await ((o = this.storageCtx) == null ? void 0 : o.getExternalContactId()), e = ((r = this.config.user) == null ? void 0 : r.externalId) || s || A();
296
315
  this.api.setAuthToken(t), await ((l = this.storageCtx) == null ? void 0 : l.setContactToken(t)), await ((c = this.storageCtx) == null ? void 0 : c.setExternalContactId(e)), this.state.setPartial({ contact: { token: t, externalId: e } });
297
- }, this.config = a, this.storageCtx = h, this.api = i, this.state = new b({
298
- contact: (n = a.user) != null && n.token ? {
299
- token: a.user.token,
316
+ }, this.config = n, this.storageCtx = h, this.api = i, this.state = new b({
317
+ contact: (a = n.user) != null && a.token ? {
318
+ token: n.user.token,
300
319
  // Set optional externalId from config... not local storage
301
- externalId: a.user.externalId
320
+ externalId: n.user.externalId
302
321
  } : null,
303
322
  extraCollectedData: void 0,
304
323
  isCreatingUnverifiedContact: !1,
@@ -306,12 +325,12 @@ class B {
306
325
  }), this.autoCreateUnverifiedUserIfNotExists();
307
326
  }
308
327
  }
309
- function P() {
328
+ function I() {
310
329
  return A();
311
330
  }
312
- class q {
331
+ class $ {
313
332
  constructor({
314
- api: a,
333
+ api: n,
315
334
  contactCtx: i,
316
335
  sessionsPollingIntervalSeconds: h
317
336
  }) {
@@ -330,9 +349,9 @@ class q {
330
349
  }), this.reset = async () => {
331
350
  this.sessionState.reset();
332
351
  }, this.registerSessionsRefresherWrapper = () => {
333
- var n;
352
+ var a;
334
353
  // If the widget config was initially provided with a contact token, no state change would be triggered, so we just fetch
335
- (n = this.contactCtx.state.get().contact) != null && n.token && !this.sessionsState.get().didStartInitialFetch ? this.registerSessionsRefresher() : this.contactCtx.state.subscribe(({ contact: t }) => {
354
+ (a = this.contactCtx.state.get().contact) != null && a.token && !this.sessionsState.get().didStartInitialFetch ? this.registerSessionsRefresher() : this.contactCtx.state.subscribe(({ contact: t }) => {
336
355
  t != null && t.token && !this.sessionsState.get().didStartInitialFetch && this.registerSessionsRefresher();
337
356
  });
338
357
  }, this.registerSessionsRefresher = () => {
@@ -342,53 +361,53 @@ class q {
342
361
  }, this.createSession = async () => {
343
362
  var e;
344
363
  this.sessionState.setPartial({ session: null, isCreatingSession: !0 });
345
- const n = (e = this.contactCtx.state.get().contact) == null ? void 0 : e.externalId, { data: t, error: s } = await this.api.createSession({
346
- customData: n ? {
347
- external_id: n
364
+ const a = (e = this.contactCtx.state.get().contact) == null ? void 0 : e.externalId, { data: t, error: s } = await this.api.createSession({
365
+ customData: a ? {
366
+ external_id: a
348
367
  } : void 0
349
368
  });
350
369
  return t ? (this.sessionState.setPartial({ session: t, isCreatingSession: !1 }), t) : (console.error("Failed to create session:", s), null);
351
370
  }, this.loadMoreSessions = async () => {
352
371
  if (this.sessionsState.get().isLastPage) return;
353
- const { data: n } = await this.getSessions({
372
+ const { data: a } = await this.getSessions({
354
373
  cursor: this.sessionsState.get().cursor
355
374
  });
356
- if (n) {
357
- const s = [...this.sessionsState.get().data, ...n.items].filter(
375
+ if (a) {
376
+ const s = [...this.sessionsState.get().data, ...a.items].filter(
358
377
  (e, o, r) => o === r.findIndex((l) => e.id === l.id)
359
378
  );
360
379
  this.sessionsState.setPartial({
361
380
  data: s,
362
- cursor: n.next || void 0,
363
- isLastPage: n.next === null
381
+ cursor: a.next || void 0,
382
+ isLastPage: a.next === null
364
383
  });
365
384
  }
366
- }, this.getSessions = async ({ cursor: n }) => {
385
+ }, this.getSessions = async ({ cursor: a }) => {
367
386
  var s, e;
368
387
  if (!((s = this.contactCtx.state.get().contact) != null && s.token)) return { data: null };
369
388
  const t = (e = this.contactCtx.state.get().contact) == null ? void 0 : e.externalId;
370
389
  return await this.api.getSessions({
371
- cursor: n,
390
+ cursor: a,
372
391
  filters: t ? {
373
392
  external_id: t
374
393
  } : {}
375
394
  });
376
395
  }, this.refreshSessions = async () => {
377
- const { data: n } = await this.getSessions({ cursor: void 0 });
378
- if (!n) return;
379
- const t = [...n.items, ...this.sessionsState.get().data].filter(
396
+ const { data: a } = await this.getSessions({ cursor: void 0 });
397
+ if (!a) return;
398
+ const t = [...a.items, ...this.sessionsState.get().data].filter(
380
399
  (s, e, o) => e === o.findIndex((r) => s.id === r.id)
381
400
  );
382
401
  this.sessionsState.setPartial({ data: t });
383
- }, this.api = a, this.contactCtx = i, this.sessionsPollingIntervalSeconds = h, this.registerSessionsRefresherWrapper();
402
+ }, this.api = n, this.contactCtx = i, this.sessionsPollingIntervalSeconds = h, this.registerSessionsRefresherWrapper();
384
403
  }
385
404
  }
386
- class $ {
405
+ class N {
387
406
  constructor({
388
- config: a,
407
+ config: n,
389
408
  api: i,
390
409
  sessionCtx: h,
391
- contactCtx: n
410
+ contactCtx: a
392
411
  }) {
393
412
  this.state = new b({
394
413
  messages: [],
@@ -398,7 +417,7 @@ class $ {
398
417
  }), this.sendMessageAbortController = new AbortController(), this.reset = () => {
399
418
  this.sendMessageAbortController.abort("Resetting chat"), this.state.reset();
400
419
  }, this.sendMessage = async (t) => {
401
- var l, c, f, m, C, d, x, S, k;
420
+ var l, c, f, m, C, d, x, S, y;
402
421
  if (!t.content.trim() && (!t.attachments || t.attachments.length === 0)) {
403
422
  console.warn("Cannot send an empty message of no content or attachments");
404
423
  return;
@@ -415,9 +434,9 @@ class $ {
415
434
  const w = this.toUserMessage(
416
435
  t.content.trim(),
417
436
  t.attachments || void 0
418
- ), M = this.state.get().messages;
437
+ ), R = this.state.get().messages;
419
438
  if (this.state.setPartial({
420
- messages: [...M, w]
439
+ messages: [...R, w]
421
440
  }), !((c = this.sessionCtx.sessionState.get().session) != null && c.id)) {
422
441
  if (!await this.sessionCtx.createSession()) {
423
442
  console.error("Failed to create session");
@@ -425,15 +444,15 @@ class $ {
425
444
  }
426
445
  this.sessionCtx.refreshSessions();
427
446
  }
428
- const y = (f = this.sessionCtx.sessionState.get().session) == null ? void 0 : f.id;
429
- if (!y) return;
447
+ const k = (f = this.sessionCtx.sessionState.get().session) == null ? void 0 : f.id;
448
+ if (!k) return;
430
449
  const { data: u } = await this.api.sendMessage(
431
450
  {
432
451
  uuid: w.id,
433
452
  bot_token: this.config.token,
434
453
  headers: this.config.headers,
435
454
  query_params: this.config.queryParams,
436
- session_id: y,
455
+ session_id: k,
437
456
  user: (m = this.config.user) == null ? void 0 : m.data,
438
457
  content: w.content,
439
458
  attachments: t.attachments,
@@ -444,9 +463,9 @@ class $ {
444
463
  if (u != null && u.success) {
445
464
  const v = this.toBotMessage(u);
446
465
  if (v) {
447
- const I = this.state.get().messages;
448
- if (!!I.some(
449
- (R) => R.id === v.id
466
+ const P = this.state.get().messages;
467
+ if (!!P.some(
468
+ (M) => M.id === v.id
450
469
  )) {
451
470
  this.state.setPartial({
452
471
  lastAIResMightSolveUserIssue: ((C = u.autopilotResponse) == null ? void 0 : C.mightSolveUserIssue) || ((d = u.uiResponse) == null ? void 0 : d.mightSolveUserIssue)
@@ -454,16 +473,16 @@ class $ {
454
473
  return;
455
474
  }
456
475
  this.state.setPartial({
457
- messages: [...I, v],
476
+ messages: [...P, v],
458
477
  lastAIResMightSolveUserIssue: ((x = u.autopilotResponse) == null ? void 0 : x.mightSolveUserIssue) || ((S = u.uiResponse) == null ? void 0 : S.mightSolveUserIssue)
459
478
  });
460
479
  }
461
480
  } else {
462
481
  const v = this.toBotErrorMessage(
463
- ((k = u == null ? void 0 : u.error) == null ? void 0 : k.message) || "Unknown error occurred"
464
- ), I = this.state.get().messages;
482
+ ((y = u == null ? void 0 : u.error) == null ? void 0 : y.message) || "Unknown error occurred"
483
+ ), P = this.state.get().messages;
465
484
  this.state.setPartial({
466
- messages: [...I, v]
485
+ messages: [...P, v]
467
486
  });
468
487
  }
469
488
  } catch (w) {
@@ -480,7 +499,7 @@ class $ {
480
499
  ${t}` : t;
481
500
  })();
482
501
  return {
483
- id: P(),
502
+ id: I(),
484
503
  type: "FROM_USER",
485
504
  content: e,
486
505
  deliveredAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -491,7 +510,7 @@ ${t}` : t;
491
510
  var s;
492
511
  return t.success && t.autopilotResponse ? {
493
512
  type: "FROM_BOT",
494
- id: t.autopilotResponse.id || P(),
513
+ id: t.autopilotResponse.id || I(),
495
514
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
496
515
  component: "bot_message",
497
516
  agent: this.config.bot ? {
@@ -510,7 +529,7 @@ ${t}` : t;
510
529
  } : null;
511
530
  }, this.toBotErrorMessage = (t) => ({
512
531
  type: "FROM_BOT",
513
- id: P(),
532
+ id: I(),
514
533
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
515
534
  component: "TEXT",
516
535
  data: {
@@ -518,15 +537,15 @@ ${t}` : t;
518
537
  variant: "error",
519
538
  action: void 0
520
539
  }
521
- }), this.config = a, this.api = i, this.sessionCtx = h, this.contactCtx = n;
540
+ }), this.config = n, this.api = i, this.sessionCtx = h, this.contactCtx = a;
522
541
  }
523
542
  }
524
- class N {
543
+ class H {
525
544
  constructor({
526
- config: a,
545
+ config: n,
527
546
  contactCtx: i,
528
547
  sessionCtx: h,
529
- resetChat: n
548
+ resetChat: a
530
549
  }) {
531
550
  this.registerRoutingListener = () => {
532
551
  this.contactCtx.state.subscribe(({ contact: t }) => {
@@ -548,11 +567,11 @@ class N {
548
567
  this.state.setPartial({ screen: "chat" });
549
568
  }, this.state = new b({
550
569
  screen: i.shouldCollectData() ? "welcome" : "sessions"
551
- }), this.config = a, this.contactCtx = i, this.sessionCtx = h, this.resetChat = n, this.registerRoutingListener();
570
+ }), this.config = n, this.contactCtx = i, this.sessionCtx = h, this.resetChat = a, this.registerRoutingListener();
552
571
  }
553
572
  }
554
- class H {
555
- constructor({ storage: a }) {
573
+ class X {
574
+ constructor({ storage: n }) {
556
575
  this.KEYS = {
557
576
  contactToken: "opencx__widget__contactToken",
558
577
  externalContactId: "opencx__widget__externalContactId"
@@ -560,12 +579,12 @@ class H {
560
579
  await this.storage.set(this.KEYS.contactToken, i);
561
580
  }, this.getContactToken = async () => this.storage.get(this.KEYS.contactToken), this.setExternalContactId = async (i) => {
562
581
  await this.storage.set(this.KEYS.externalContactId, i);
563
- }, this.getExternalContactId = async () => this.storage.get(this.KEYS.externalContactId), this.storage = a;
582
+ }, this.getExternalContactId = async () => this.storage.get(this.KEYS.externalContactId), this.storage = n;
564
583
  }
565
584
  }
566
585
  const p = class p {
567
586
  constructor({
568
- config: a,
587
+ config: n,
569
588
  storage: i
570
589
  }) {
571
590
  if (this.resetChat = () => {
@@ -574,15 +593,15 @@ const p = class p {
574
593
  throw Error(
575
594
  "Widget polling values are not defined, did you call WidgetCtx.initialize()"
576
595
  );
577
- this.config = a, this.api = new E({ config: a }), this.storageCtx = i ? new H({ storage: i }) : void 0, this.contactCtx = new B({
596
+ this.config = n, this.api = new E({ config: n }), this.storageCtx = i ? new X({ storage: i }) : void 0, this.contactCtx = new q({
578
597
  api: this.api,
579
598
  config: this.config,
580
599
  storageCtx: this.storageCtx
581
- }), this.sessionCtx = new q({
600
+ }), this.sessionCtx = new $({
582
601
  api: this.api,
583
602
  contactCtx: this.contactCtx,
584
603
  sessionsPollingIntervalSeconds: p.pollingIntervalsSeconds.sessions
585
- }), this.messageCtx = new $({
604
+ }), this.messageCtx = new N({
586
605
  config: this.config,
587
606
  api: this.api,
588
607
  sessionCtx: this.sessionCtx,
@@ -593,7 +612,7 @@ const p = class p {
593
612
  sessionCtx: this.sessionCtx,
594
613
  messageCtx: this.messageCtx,
595
614
  sessionPollingIntervalSeconds: p.pollingIntervalsSeconds.session
596
- }), this.routerCtx = new N({
615
+ }), this.routerCtx = new H({
597
616
  config: this.config,
598
617
  contactCtx: this.contactCtx,
599
618
  sessionCtx: this.sessionCtx,
@@ -602,18 +621,18 @@ const p = class p {
602
621
  }
603
622
  };
604
623
  p.pollingIntervalsSeconds = null, p.initialize = async ({
605
- config: a,
624
+ config: n,
606
625
  storage: i
607
626
  }) => {
608
- var n, t;
627
+ var a, t;
609
628
  const h = await new E({
610
- config: a
629
+ config: n
611
630
  }).getExternalWidgetConfig();
612
631
  return p.pollingIntervalsSeconds = {
613
- session: ((n = h.data) == null ? void 0 : n.sessionPollingIntervalSeconds) || 10,
632
+ session: ((a = h.data) == null ? void 0 : a.sessionPollingIntervalSeconds) || 10,
614
633
  sessions: ((t = h.data) == null ? void 0 : t.sessionsPollingIntervalSeconds) || 60
615
634
  }, new p({
616
- config: a,
635
+ config: n,
617
636
  storage: i
618
637
  });
619
638
  };
@@ -622,4 +641,4 @@ export {
622
641
  b as P,
623
642
  U as W
624
643
  };
625
- //# sourceMappingURL=widget.ctx-CMgNQpCm.js.map
644
+ //# sourceMappingURL=widget.ctx-DXznvVMa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget.ctx-DXznvVMa.js","sources":["../src/headless/core/api/client.ts","../src/headless/core/api/api-caller.ts","../src/headless/core/utils/PrimitiveState.ts","../src/headless/core/utils/Poller.ts","../src/headless/core/utils/run-catching.ts","../src/headless/core/context/active-session-polling.ctx.ts","../src/headless/core/context/contact.ctx.ts","../src/headless/core/utils/uuid.ts","../src/headless/core/context/session.ctx.ts","../src/headless/core/context/message.ctx.ts","../src/headless/core/context/router.ctx.ts","../src/headless/core/context/storage.ctx.ts","../src/headless/core/context/widget.ctx.ts"],"sourcesContent":["import createClient, { type Middleware } from \"openapi-fetch\";\nimport type { paths } from \"./schema\";\nimport type { components } from \"./schema\";\n\ntype Options = {\n baseUrl: string;\n onRequest?: Middleware[\"onRequest\"];\n onResponse?: Middleware[\"onResponse\"];\n onError?: Middleware[\"onError\"];\n};\n\nconst defaultOnError: Middleware[\"onError\"] = (onErrorOptions) => {\n console.log(onErrorOptions.error);\n};\n\nexport const basicClient = (options: Options) => {\n const client = createClient<paths>({\n baseUrl: options.baseUrl,\n });\n\n const middlewares: Middleware = {\n onRequest: options.onRequest,\n onResponse: options.onResponse,\n onError: options.onError || defaultOnError,\n };\n\n client.use(middlewares);\n return client;\n};\n\nexport type Endpoint = keyof paths;\nexport type Dto = components[\"schemas\"];\n","import { type Dto, type Endpoint, basicClient } from \"./client\";\nimport type { WidgetConfig } from \"../types/widget-config\";\nimport type { SendMessageDto, VoteInputDto } from \"../types/schemas\";\n\nexport class ApiCaller {\n private client: ReturnType<typeof basicClient>;\n private config: WidgetConfig;\n private userToken: string | null = null;\n\n constructor({\n config,\n }: {\n config: WidgetConfig;\n }) {\n this.config = config;\n const { baseUrl, headers } = this.constructClientOptions(\n config.user?.token,\n );\n this.client = this.createOpenAPIClient({ baseUrl, headers });\n }\n\n private constructClientOptions = (token: string | null | undefined) => {\n const baseUrl =\n import.meta.env.MODE === \"test\"\n ? \"http://localhost:8080\"\n : this.config.apiUrl || \"https://api.open.cx\";\n const headers = {\n \"X-Bot-Token\": this.config.token,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n Authorization: token ? `Bearer ${token}` : undefined,\n };\n\n return { baseUrl, headers };\n };\n\n private createOpenAPIClient = ({\n baseUrl,\n headers,\n }: ReturnType<typeof this.constructClientOptions>) => {\n return basicClient({\n baseUrl,\n onRequest: ({ request }) => {\n Object.entries(headers).forEach(([key, value]) => {\n if (value) {\n request.headers.set(key, value);\n }\n });\n },\n });\n };\n\n setAuthToken = (token: string) => {\n this.userToken = token;\n const { baseUrl, headers } = this.constructClientOptions(token);\n this.client = this.createOpenAPIClient({ baseUrl, headers });\n };\n\n getExternalWidgetConfig = async () => {\n return await this.client.GET(\"/backend/widget/v2/config\", {\n params: { header: { \"X-Bot-Token\": this.config.token } },\n });\n };\n\n widgetPrelude = async () => {\n return await this.client.GET(\"/backend/widget/v2/prelude\", {\n params: { header: { \"X-Bot-Token\": this.config.token } },\n });\n };\n\n sendMessage = async (body: SendMessageDto, abortSignal?: AbortSignal) => {\n return await this.client.POST(\"/backend/widget/v2/chat/send\", {\n body,\n signal: abortSignal,\n });\n };\n\n createUnverifiedContact = async (body: Dto[\"CreateUnverifiedContactDto\"]) => {\n return await this.client.POST(\n \"/backend/widget/v2/contact/create-unverified\",\n {\n params: { header: { \"x-bot-token\": this.config.token } },\n body,\n },\n );\n };\n\n createSession = async (body: Dto[\"CreateWidgetSessionDto\"]) => {\n return await this.client.POST(\"/backend/widget/v2/create-session\", {\n body,\n });\n };\n\n pollSessionAndHistory = async ({\n sessionId,\n lastMessageTimestamp,\n abortSignal,\n }: {\n sessionId: string;\n lastMessageTimestamp?: string;\n abortSignal: AbortSignal;\n }) => {\n const query = lastMessageTimestamp ? { lastMessageTimestamp } : undefined;\n return await this.client.GET(\"/backend/widget/v2/poll/{sessionId}\", {\n params: { path: { sessionId }, query },\n signal: abortSignal,\n });\n };\n\n getSessions = async ({\n cursor,\n filters,\n abortSignal,\n }: {\n cursor: string | undefined;\n filters: Record<string, string>;\n abortSignal?: AbortSignal;\n }) => {\n return await this.client.GET(\"/backend/widget/v2/sessions\", {\n params: { query: { cursor, filters: JSON.stringify(filters) } },\n signal: abortSignal,\n });\n };\n\n /**\n * openapi-fetch usually works fine for file uploads, but this time around it parses the payload in a weird way and results in 413 errors (payload too large)\n * Anyway, good old XHR even does it better with progress events\n */\n uploadFile = async ({\n file,\n abortSignal,\n onProgress,\n }: {\n file: File;\n abortSignal: AbortSignal;\n onProgress?: (percentage: number) => void;\n }): Promise<Dto[\"UploadWidgetFileResponseDto\"]> => {\n return new Promise((resolve, reject) => {\n const formData = new FormData();\n formData.append(\"file\", file);\n\n const xhr = new XMLHttpRequest();\n\n // Set up abort functionality\n if (abortSignal) {\n abortSignal.addEventListener(\"abort\", () => {\n xhr.abort();\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n });\n\n // If already aborted, reject immediately\n if (abortSignal.aborted) {\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n }\n\n xhr.upload.addEventListener(\"progress\", (event) => {\n if (event.lengthComputable && onProgress) {\n const percentage = Math.round((event.loaded / event.total) * 100);\n onProgress(percentage);\n }\n });\n\n // Handle completion\n xhr.addEventListener(\"load\", () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const data = JSON.parse(xhr.responseText);\n resolve(data);\n } catch (error) {\n reject(new Error(`Failed to parse response: ${error}`));\n }\n } else {\n reject(new Error(`Upload failed with status: ${xhr.status}`));\n }\n });\n\n xhr.addEventListener(\"error\", () => {\n reject(new Error(\"Network error occurred\"));\n });\n\n xhr.addEventListener(\"timeout\", () => {\n reject(new Error(\"Upload timed out\"));\n });\n\n const { baseUrl } = this.constructClientOptions(this.userToken);\n\n const path = \"/backend/widget/v2/upload\" satisfies Endpoint\n const uploadUrl = `${baseUrl}${path}`;\n xhr.open(\"POST\", uploadUrl);\n\n xhr.setRequestHeader(\"X-Bot-Token\", this.config.token);\n if (this.userToken) {\n xhr.setRequestHeader(\"Authorization\", `Bearer ${this.userToken}`);\n }\n\n xhr.send(formData);\n });\n };\n\n vote = async (body: VoteInputDto) => {\n return await this.client.POST(\"/backend/widget/v2/chat/vote\", { body });\n };\n}\n","import isEqual from \"lodash.isequal\";\n\nexport type Subscriber<T> = (data: T) => void;\n\nexport class PrimitiveState<S> {\n private subscribers = new Set<Subscriber<S>>();\n private state: S;\n private initialState: S;\n\n constructor(state: S) {\n this.state = state;\n this.initialState = state;\n }\n\n get = (): S => this.state;\n\n set = (newState: S): void => {\n if (!isEqual(this.state, newState)) {\n this.state = newState;\n this.notifySubscribers(newState);\n }\n };\n\n setPartial = (_s: Partial<S>): void => {\n if (_s === undefined || _s === null) return;\n const newState = { ...this.state, ..._s };\n this.set(newState);\n };\n\n reset = (): void => {\n this.set(this.initialState);\n };\n\n private notifySubscribers = (state: S) => {\n const subscribersArray = Array.from(this.subscribers);\n subscribersArray.forEach((callback) => {\n try {\n callback(state);\n } catch (error) {\n if (import.meta.env.MODE !== \"test\") {\n console.error(error);\n }\n }\n });\n };\n\n subscribe = (callback: Subscriber<S>): (() => void) => {\n this.subscribers.add(callback);\n\n return () => {\n this.subscribers.delete(callback);\n };\n };\n}\n","import { PrimitiveState } from \"./PrimitiveState\";\n\nexport type PollingState = {\n isPolling: boolean;\n isError: boolean;\n};\n\nexport class Poller {\n state = new PrimitiveState<PollingState>({\n isPolling: false,\n isError: false,\n });\n private abortController = new AbortController();\n\n reset = () => {\n this.abortController.abort(\"Resetting poller\");\n this.stopPolling?.();\n this.stopPolling = null;\n };\n\n private stopPolling: (() => void) | null = null;\n\n startPolling = (\n cb: (abortSignal: AbortSignal) => Promise<void>,\n intervalMs: number,\n ) => {\n if (this.stopPolling) return;\n\n const timeouts: NodeJS.Timeout[] = [];\n\n const poll = async () => {\n this.abortController = new AbortController();\n this.state.setPartial({ isPolling: true });\n\n try {\n await cb(this.abortController.signal);\n } catch (error) {\n if (this.abortController.signal.aborted) {\n // If aborted, just return and do not schedule the nest poll\n return;\n }\n console.error(\"Failed to poll:\", error);\n this.state.setPartial({ isError: true });\n } finally {\n this.state.setPartial({ isPolling: false });\n }\n\n // Another check to stop scheduling polls in case someone removes the early return in the catch above\n if (this.abortController.signal.aborted) {\n console.log(\"Poller aborted, not scheduling anymore\");\n } else {\n timeouts.push(setTimeout(poll, intervalMs));\n }\n };\n\n poll();\n\n this.stopPolling = () => {\n timeouts.forEach(clearTimeout);\n this.state.reset();\n };\n };\n}\n","export type Result<T, E> =\n | { data: T; error?: undefined }\n | { data?: undefined; error: E };\n\n/**\n * Many thanks to @m-tabaza for this utility... Kotlin vibes\n */\nexport function runCatching<T, E = unknown>(\n callback: () => Promise<T>,\n): Promise<Result<T, E>>;\nexport function runCatching<T, E = unknown>(callback: () => T): Result<T, E>;\nexport function runCatching<T, E = unknown>(\n callback: () => T | Promise<T>,\n): Result<T, E> | Promise<Result<T, E>> {\n try {\n const result = callback();\n\n if (result instanceof Promise) {\n return result.then((data) => ({ data })).catch((error: E) => ({ error }));\n }\n\n return { data: result };\n } catch (error) {\n return { error: error as E };\n }\n}\n","import type { ApiCaller } from \"../api/api-caller\";\nimport type { MessageType } from \"../types/messages\";\nimport type { ActionCallDto, MessageDto } from \"../types/schemas\";\nimport type { WidgetConfig } from \"../types/widget-config\";\nimport { Poller } from \"../utils/Poller\";\nimport { runCatching } from \"../utils/run-catching\";\nimport type { MessageCtx } from \"./message.ctx\";\nimport type { SessionCtx } from \"./session.ctx\";\n\nexport class ActiveSessionPollingCtx {\n private api: ApiCaller;\n private config: WidgetConfig;\n private sessionCtx: SessionCtx;\n private messageCtx: MessageCtx;\n private sessionPollingIntervalSeconds: number;\n\n private poller = new Poller();\n\n constructor({\n api,\n config,\n sessionCtx,\n messageCtx,\n sessionPollingIntervalSeconds,\n }: {\n api: ApiCaller;\n config: WidgetConfig;\n sessionCtx: SessionCtx;\n messageCtx: MessageCtx;\n sessionPollingIntervalSeconds: number;\n }) {\n this.api = api;\n this.config = config;\n this.sessionCtx = sessionCtx;\n this.messageCtx = messageCtx;\n this.sessionPollingIntervalSeconds = sessionPollingIntervalSeconds;\n\n this.registerPolling();\n }\n\n private registerPolling = () => {\n this.sessionCtx.sessionState.subscribe(({ session }) => {\n if (session?.id) {\n this.poller.startPolling(async (abortSignal) => {\n this.hackAndSlash(session.id, abortSignal);\n }, this.sessionPollingIntervalSeconds * 1000);\n } else {\n this.poller.reset();\n }\n });\n };\n\n private hackAndSlash = async (\n sessionId: string,\n abortSignal: AbortSignal,\n ): Promise<void> => {\n /**\n * This is a bit of an implicit contract... there are two cases here\n * 1. If there are no messages in state, it means the user selected a previous session from the sessions screen and got routed to the chat,\n * in this case, we want to show a loading indicator until the initial fetch is done\n * 2. There is a single message in state, which is the optimistically rendered user message,\n * in this case, we don't want to show a loading indicator\n */\n if (this.messageCtx.state.get().messages.length === 0) {\n this.messageCtx.state.setPartial({ isInitialFetchLoading: true });\n }\n\n const messages = this.messageCtx.state.get().messages;\n const lastMessageTimestamp =\n messages.length > 0\n ? messages[messages.length - 1]?.timestamp\n : undefined;\n\n const { data } = await this.api.pollSessionAndHistory({\n sessionId,\n abortSignal,\n lastMessageTimestamp,\n });\n\n if (data?.session) {\n this.sessionCtx.sessionState.setPartial({ session: data.session });\n }\n\n if (data?.history && data.history.length > 0) {\n // Get a fresh reference to current messages after the poll is done\n const prevMessages = this.messageCtx.state.get().messages;\n const newMessages = data.history\n .map(this.mapHistoryToMessage)\n .filter(\n (newMsg) =>\n !prevMessages.some((existingMsg) => existingMsg.id === newMsg.id),\n );\n this.messageCtx.state.setPartial({\n messages: [...prevMessages, ...newMessages],\n });\n }\n\n if (this.messageCtx.state.get().isInitialFetchLoading) {\n this.messageCtx.state.setPartial({ isInitialFetchLoading: false });\n }\n };\n\n mapHistoryToMessage = (history: MessageDto): MessageType => {\n const commonFields = {\n id: history.publicId,\n timestamp: history.sentAt || \"\",\n attachments: history.attachments || undefined,\n };\n\n if (history.sender.kind === \"user\") {\n return {\n ...commonFields,\n type: \"FROM_USER\",\n content: history.content.text || \"\",\n deliveredAt: history.sentAt || \"\",\n };\n }\n\n if (history.sender.kind === \"agent\") {\n return {\n ...commonFields,\n type: \"FROM_AGENT\",\n component: \"agent_message\",\n data: {\n message: history.content.text || \"\",\n },\n agent: {\n name: history.sender.name || \"\",\n avatar: history.sender.avatar || \"\",\n id: null,\n isAi: false,\n },\n };\n }\n\n const action =\n history.actionCalls && history.actionCalls.length > 0\n ? history.actionCalls[history.actionCalls.length - 1]\n : undefined;\n\n return {\n ...commonFields,\n type: \"FROM_BOT\",\n component: \"bot_message\",\n agent: {\n id: null,\n name: this.config.bot?.name || \"\",\n isAi: true,\n avatar: this.config.bot?.avatar || \"\",\n },\n data: {\n message: history.content.text || \"\",\n action: action\n ? {\n name: action.actionName,\n data: this.extractActionResult(action),\n }\n : undefined,\n },\n };\n };\n\n extractActionResult = (action: ActionCallDto) => {\n const result = action.result;\n\n if (result === null) return result;\n if (typeof result !== \"object\") return result;\n\n if (\n \"responseBodyText\" in result &&\n typeof result.responseBodyText === \"string\"\n ) {\n const responseBodyText = result.responseBodyText;\n const parsed = runCatching(() => JSON.parse(responseBodyText)).data;\n if (parsed) return parsed;\n }\n\n return action.result;\n };\n}\n","import { PrimitiveState } from \"../utils/PrimitiveState\";\nimport { ApiCaller } from \"../api/api-caller\";\nimport { type WidgetConfig } from \"../types/widget-config\";\nimport { type Dto } from \"../api/client\";\nimport type { StorageCtx } from \"./storage.ctx\";\nimport { v4 } from \"uuid\";\n\ntype ContactState = {\n contact: {\n token: string;\n externalId: string | undefined;\n } | null;\n extraCollectedData: Record<string, string> | undefined;\n isCreatingUnverifiedContact: boolean;\n isErrorCreatingUnverifiedContact: boolean;\n};\n\nexport class ContactCtx {\n private config: WidgetConfig;\n private storageCtx?: StorageCtx;\n private api: ApiCaller;\n state: PrimitiveState<ContactState>;\n\n constructor({\n config,\n api,\n storageCtx,\n }: {\n api: ApiCaller;\n config: WidgetConfig;\n storageCtx?: StorageCtx;\n }) {\n this.config = config;\n this.storageCtx = storageCtx;\n this.api = api;\n\n this.state = new PrimitiveState<ContactState>({\n contact: config.user?.token\n ? {\n token: config.user.token,\n // Set optional externalId from config... not local storage\n externalId: config.user.externalId,\n }\n : null,\n extraCollectedData: undefined,\n isCreatingUnverifiedContact: false,\n isErrorCreatingUnverifiedContact: false,\n });\n\n this.autoCreateUnverifiedUserIfNotExists();\n }\n\n shouldCollectData = (): boolean => {\n if (!this.state.get().contact?.token && this.config.collectUserData) {\n return true;\n }\n return false;\n };\n\n private autoCreateUnverifiedUserIfNotExists = async () => {\n /**\n * If token is passed in config... we consider it as a verified user and do nothing (we don't force generate an externalId)\n * If a non-verified user take their token and place it in the config... the backend will refuse their requests saying that a non-verified token must have an externalId to create and get sessions\n */\n if (this.config.user?.token) return;\n\n /**\n * If collectUserData is true... we check if the user entered their credentials before, otherwise, show them the welcome screen so they can enter their credentials\n */\n if (this.config.collectUserData && !this.config.user?.data?.email) {\n /**\n * If extra data collection fields are passed,\n * we do not check for a persisted token.\n * This will force the contact to enter the extra data fields every time they visit the page.\n */\n if (this.config.extraDataCollectionFields?.length) {\n return;\n }\n\n const persistedToken = await this.storageCtx?.getContactToken();\n if (persistedToken) {\n await this.setUnverifiedContact(persistedToken);\n }\n // return early whether there is a persisted token or not\n return;\n }\n\n /**\n * If there is no email, then it is an anonymous contact, we check if the contact is persisted or we create a new one\n */\n if (!this.config.user?.data?.email) {\n const persistedToken = await this.storageCtx?.getContactToken();\n if (persistedToken) {\n await this.setUnverifiedContact(persistedToken);\n // return early only if there is a persisted token\n return;\n }\n }\n\n /**\n * If we reach here... then it is one of two\n * 1. There is an email passed in the config, let's just upsert the unverified contact without checking for persistence; maybe the email in the config did change.\n * 2. It is an anonymous contact (without an email) using this device for the first time.\n *\n * This is still safe even if the email in the config is tampered with by the contact, because there is a client-side externalId that will be generated for the current device...\n * So, only sessions created on this device will be accessible.\n */\n await this.createUnverifiedContact({\n name: this.config.user?.data?.name || \"Anonymous\",\n email: this.config.user?.data?.email,\n });\n };\n\n createUnverifiedContact = async (\n payload: Dto[\"CreateUnverifiedContactDto\"],\n extraCollectedData?: Record<string, string>,\n ): Promise<void> => {\n this.state.setPartial({ extraCollectedData });\n\n try {\n this.state.setPartial({\n isCreatingUnverifiedContact: true,\n isErrorCreatingUnverifiedContact: false,\n });\n\n const { data } = await this.api.createUnverifiedContact(payload);\n if (data?.token) {\n await this.setUnverifiedContact(data.token);\n } else {\n this.state.setPartial({ isErrorCreatingUnverifiedContact: true });\n }\n } finally {\n this.state.setPartial({ isCreatingUnverifiedContact: false });\n }\n };\n\n setUnverifiedContact = async (token: string) => {\n const persistedExternalId = await this.storageCtx?.getExternalContactId();\n /** Give priority to `externalId` from the config */\n const externalId: string =\n this.config.user?.externalId || persistedExternalId || v4();\n this.api.setAuthToken(token);\n // Set token in state after setting the token in the api handler\n await this.storageCtx?.setContactToken(token);\n await this.storageCtx?.setExternalContactId(externalId);\n this.state.setPartial({ contact: { token, externalId } });\n };\n}\n","import { v4 as uuidv4 } from \"uuid\";\n\nexport function genUuid() {\n return uuidv4();\n}\n","import type { ApiCaller } from \"../api/api-caller\";\nimport type { SessionDto } from \"../types/schemas\";\nimport { Poller } from \"../utils/Poller\";\nimport { PrimitiveState } from \"../utils/PrimitiveState\";\nimport type { ContactCtx } from \"./contact.ctx\";\n\ntype SessionState = {\n /**\n * The currently selected session.\n * Can be null if no session is selected, or if in chat screen and the session is not created yet.\n */\n session: SessionDto | null;\n isCreatingSession: boolean;\n};\ntype SessionsState = {\n /** List of all user sessions */\n data: SessionDto[];\n /** A cursor to get the next page of sessions */\n cursor: string | undefined;\n /** Indicates if no more pages are left */\n isLastPage: boolean;\n /** Did fetch for the first time */\n didStartInitialFetch: boolean;\n isInitialFetchLoading: boolean;\n};\n\nexport class SessionCtx {\n private api: ApiCaller;\n private contactCtx: ContactCtx;\n private sessionsPollingIntervalSeconds: number;\n private sessionsRefresher = new Poller();\n\n public sessionState = new PrimitiveState<SessionState>({\n session: null,\n isCreatingSession: false,\n });\n public sessionsState = new PrimitiveState<SessionsState>({\n data: [],\n cursor: undefined,\n isLastPage: false,\n didStartInitialFetch: false,\n /**\n * Initialize this as `true` so it always starts loading until the first fetch is done\n */\n isInitialFetchLoading: true,\n });\n\n constructor({\n api,\n contactCtx,\n sessionsPollingIntervalSeconds,\n }: {\n api: ApiCaller;\n contactCtx: ContactCtx;\n sessionsPollingIntervalSeconds: number;\n }) {\n this.api = api;\n this.contactCtx = contactCtx;\n this.sessionsPollingIntervalSeconds = sessionsPollingIntervalSeconds;\n\n this.registerSessionsRefresherWrapper();\n }\n\n /** Clears the session and stops polling */\n reset = async () => {\n // Reset the session only, leave sessions as-is\n this.sessionState.reset();\n };\n\n private registerSessionsRefresherWrapper = () => {\n if (\n // If the widget config was initially provided with a contact token, no state change would be triggered, so we just fetch\n this.contactCtx.state.get().contact?.token &&\n !this.sessionsState.get().didStartInitialFetch\n ) {\n this.registerSessionsRefresher();\n } else {\n // In other cases where auto authenticate is fired, the token would be eventually set in state, so we wait for it\n this.contactCtx.state.subscribe(({ contact }) => {\n if (contact?.token && !this.sessionsState.get().didStartInitialFetch) {\n this.registerSessionsRefresher();\n }\n });\n }\n };\n\n private registerSessionsRefresher = () => {\n this.sessionsRefresher.startPolling(async () => {\n if (this.sessionsState.get().didStartInitialFetch === false) {\n this.sessionsState.setPartial({ didStartInitialFetch: true });\n }\n\n await this.refreshSessions();\n\n if (this.sessionsState.get().isInitialFetchLoading === true) {\n this.sessionsState.setPartial({ isInitialFetchLoading: false });\n }\n }, this.sessionsPollingIntervalSeconds * 1000);\n };\n\n createSession = async () => {\n this.sessionState.setPartial({ session: null, isCreatingSession: true });\n\n const externalId = this.contactCtx.state.get().contact?.externalId;\n const { data: session, error } = await this.api.createSession({\n customData: externalId\n ? {\n external_id: externalId,\n }\n : undefined,\n });\n if (session) {\n this.sessionState.setPartial({ session, isCreatingSession: false });\n return session;\n }\n\n console.error(\"Failed to create session:\", error);\n return null;\n };\n\n loadMoreSessions = async () => {\n if (this.sessionsState.get().isLastPage) return;\n\n const { data } = await this.getSessions({\n cursor: this.sessionsState.get().cursor,\n });\n\n if (data) {\n const allSessions = [...this.sessionsState.get().data, ...data.items];\n // TODO sort by updated at\n const deduped = allSessions.filter(\n (s, i, self) => i === self.findIndex((_s) => s.id === _s.id),\n );\n\n this.sessionsState.setPartial({\n data: deduped,\n cursor: data.next || undefined,\n isLastPage: data.next === null,\n });\n }\n };\n\n private getSessions = async ({ cursor }: { cursor: string | undefined }) => {\n if (!this.contactCtx.state.get().contact?.token) return { data: null };\n\n const externalId = this.contactCtx.state.get().contact?.externalId;\n return await this.api.getSessions({\n cursor,\n filters: externalId\n ? {\n external_id: externalId,\n }\n : {},\n });\n };\n\n refreshSessions = async () => {\n // Get the first page only (pass no `cursor`)\n const { data } = await this.getSessions({ cursor: undefined });\n if (!data) return;\n const sessions = [...data.items, ...this.sessionsState.get().data].filter(\n (s, i, self) => i === self.findIndex((_s) => s.id === _s.id),\n );\n this.sessionsState.setPartial({ data: sessions });\n };\n}\n","import { ApiCaller } from \"../api/api-caller\";\nimport type { WidgetConfig } from \"../types/widget-config\";\nimport type {\n BotMessageType,\n MessageType,\n UserMessageType,\n} from \"../types/messages\";\nimport type {\n MessageAttachmentType,\n SendMessageDto,\n SendMessageOutputDto,\n} from \"../types/schemas\";\nimport { PrimitiveState } from \"../utils/PrimitiveState\";\nimport { genUuid } from \"../utils/uuid\";\nimport { SessionCtx } from \"./session.ctx\";\nimport type { ContactCtx } from \"./contact.ctx\";\n\ntype MessageCtxState = {\n messages: MessageType[];\n isSendingMessage: boolean;\n lastAIResMightSolveUserIssue: boolean;\n isInitialFetchLoading: boolean;\n};\n\nexport class MessageCtx {\n private config: WidgetConfig;\n private api: ApiCaller;\n private contactCtx: ContactCtx;\n private sessionCtx: SessionCtx;\n\n public state = new PrimitiveState<MessageCtxState>({\n messages: [],\n isSendingMessage: false,\n lastAIResMightSolveUserIssue: false,\n isInitialFetchLoading: false,\n });\n\n private sendMessageAbortController = new AbortController();\n\n constructor({\n config,\n api,\n sessionCtx,\n contactCtx,\n }: {\n config: WidgetConfig;\n api: ApiCaller;\n sessionCtx: SessionCtx;\n contactCtx: ContactCtx;\n }) {\n this.config = config;\n this.api = api;\n this.sessionCtx = sessionCtx;\n this.contactCtx = contactCtx;\n }\n\n reset = () => {\n this.sendMessageAbortController.abort(\"Resetting chat\");\n this.state.reset();\n };\n\n sendMessage = async (input: {\n content: SendMessageDto[\"content\"];\n attachments?: SendMessageDto[\"attachments\"];\n }): Promise<void> => {\n /* ------------------------------------------------------ */\n /* Prevent sending if there is no content */\n /* ------------------------------------------------------ */\n if (\n !input.content.trim() &&\n (!input.attachments || input.attachments.length === 0)\n ) {\n console.warn(\"Cannot send an empty message of no content or attachments\");\n return;\n }\n /* ------------------------------------------------------ */\n /* Prevent sending while waiting for AI res */\n /* ------------------------------------------------------ */\n const isSending = this.state.get().isSendingMessage;\n const isAssignedToAI =\n this.sessionCtx.sessionState.get().session?.assignee.kind === \"ai\";\n const _messages = this.state.get().messages;\n const lastMessage =\n _messages.length > 0 ? _messages[_messages.length - 1] : undefined;\n if (\n (isAssignedToAI && isSending) ||\n // If last message is from user, then bot response did not arrive yet\n (isAssignedToAI && lastMessage?.type === \"FROM_USER\")\n ) {\n console.warn(\"Cannot send messages while awaiting AI response\");\n return;\n }\n\n this.sendMessageAbortController = new AbortController();\n\n /* ------------------------------------------------------ */\n /* Clear last AI response might solve user issue */\n /* ------------------------------------------------------ */\n this.state.setPartial({ lastAIResMightSolveUserIssue: false });\n\n try {\n this.state.setPartial({ isSendingMessage: true });\n /* ------------------------------------------------------ */\n /* Optimistically add message to rendered messages */\n /* ------------------------------------------------------ */\n const userMessage = this.toUserMessage(\n input.content.trim(),\n input.attachments || undefined,\n );\n const currentMessages = this.state.get().messages;\n this.state.setPartial({\n messages: [...currentMessages, userMessage],\n });\n\n /* ------------------------------------------------------ */\n /* Create session if not exists */\n /* ------------------------------------------------------ */\n if (!this.sessionCtx.sessionState.get().session?.id) {\n const createdSession = await this.sessionCtx.createSession();\n\n // TODO: apply some retry logic here\n if (!createdSession) {\n console.error(\"Failed to create session\");\n return;\n }\n\n // Refresh sessions list instantly to get the newly created session in the sessions list\n void this.sessionCtx.refreshSessions();\n }\n const sessionId = this.sessionCtx.sessionState.get().session?.id;\n if (!sessionId) return;\n /* ------------------------------------------------------ */\n /* Send and wait for bot response */\n /* ------------------------------------------------------ */\n const { data } = await this.api.sendMessage(\n {\n uuid: userMessage.id,\n bot_token: this.config.token,\n headers: this.config.headers,\n query_params: this.config.queryParams,\n session_id: sessionId,\n user: this.config.user?.data,\n content: userMessage.content,\n attachments: input.attachments,\n clientContext: this.config.context,\n },\n this.sendMessageAbortController.signal,\n );\n\n if (data?.success) {\n /* ------------------------------------------------------ */\n /* Append bot reply if not fetched from polling */\n /* ------------------------------------------------------ */\n const botMessage = this.toBotMessage(data);\n if (botMessage) {\n const prevMessages = this.state.get().messages;\n const shouldAppend = !prevMessages.some(\n (m) => m.id === botMessage.id,\n );\n if (!shouldAppend) {\n this.state.setPartial({\n lastAIResMightSolveUserIssue:\n data.autopilotResponse?.mightSolveUserIssue ||\n data.uiResponse?.mightSolveUserIssue,\n });\n return;\n }\n this.state.setPartial({\n messages: [...prevMessages, botMessage],\n lastAIResMightSolveUserIssue:\n data.autopilotResponse?.mightSolveUserIssue ||\n data.uiResponse?.mightSolveUserIssue,\n });\n }\n } else {\n const errorMessage = this.toBotErrorMessage(\n data?.error?.message || \"Unknown error occurred\",\n );\n const currentMessages = this.state.get().messages;\n this.state.setPartial({\n messages: [...currentMessages, errorMessage],\n });\n }\n } catch (error) {\n if (!this.sendMessageAbortController.signal.aborted) {\n console.error(\"Failed to send message:\", error);\n }\n } finally {\n this.state.setPartial({ isSendingMessage: false });\n }\n };\n\n private toUserMessage = (\n content: string,\n attachments?: MessageAttachmentType[],\n ): UserMessageType => {\n const messageContent = (() => {\n const extraCollectedData = this.contactCtx.state.get().extraCollectedData;\n // Prepend extra collected data if this is the first message in the session\n if (\n this.state.get().messages.length === 0 &&\n extraCollectedData &&\n Object.keys(extraCollectedData).length > 0\n ) {\n const data = Object.entries(extraCollectedData)\n .filter(([_, value]) => !!value)\n .map(([key, value]) => `${key}: ${value}`)\n .join(\" \\n\");\n return `${data} \\n\\n${content}`;\n }\n\n return content;\n })();\n\n return {\n id: genUuid(),\n type: \"FROM_USER\",\n content: messageContent,\n deliveredAt: new Date().toISOString(),\n attachments,\n timestamp: new Date().toISOString(),\n };\n };\n\n private toBotMessage = (\n response: SendMessageOutputDto,\n ): BotMessageType | null => {\n if (response.success && response.autopilotResponse) {\n return {\n type: \"FROM_BOT\",\n id: response.autopilotResponse.id || genUuid(),\n timestamp: new Date().toISOString(),\n component: \"bot_message\",\n agent: this.config.bot\n ? {\n name: this.config.bot.name || \"\",\n isAi: true,\n avatar: this.config.bot.avatar || \"\",\n id: null,\n }\n : undefined,\n data: {\n message: response.autopilotResponse.value.content,\n action: response.uiResponse?.value.name\n ? {\n name: response.uiResponse.value.name,\n data: response.uiResponse.value.request_response,\n }\n : undefined,\n },\n };\n }\n\n return null;\n };\n\n private toBotErrorMessage = (message: string): BotMessageType => {\n return {\n type: \"FROM_BOT\",\n id: genUuid(),\n timestamp: new Date().toISOString(),\n component: \"TEXT\",\n data: {\n message,\n variant: \"error\",\n action: undefined,\n },\n };\n };\n}\n","import type { WidgetConfig } from \"../types/widget-config\";\nimport { PrimitiveState } from \"../utils/PrimitiveState\";\nimport type { ContactCtx } from \"./contact.ctx\";\nimport type { SessionCtx } from \"./session.ctx\";\nimport type { WidgetCtx } from \"./widget.ctx\";\n\ntype RouterState = {\n screen:\n | /** A welcome screen to collect user data. Useful in public non-logged-in environments */\n \"welcome\"\n /** Show a list of the user's previous sessions */\n | \"sessions\"\n /** Self-explanatory */\n | \"chat\";\n};\n\nexport class RouterCtx {\n state: PrimitiveState<RouterState>;\n\n private config: WidgetConfig;\n private contactCtx: ContactCtx;\n private sessionCtx: SessionCtx;\n private resetChat: WidgetCtx[\"resetChat\"];\n\n constructor({\n config,\n contactCtx,\n sessionCtx,\n resetChat,\n }: {\n config: WidgetConfig;\n contactCtx: ContactCtx;\n sessionCtx: SessionCtx;\n resetChat: WidgetCtx[\"resetChat\"];\n }) {\n this.state = new PrimitiveState<RouterState>({\n screen: contactCtx.shouldCollectData() ? \"welcome\" : \"sessions\",\n });\n this.config = config;\n this.contactCtx = contactCtx;\n this.sessionCtx = sessionCtx;\n this.resetChat = resetChat;\n\n this.registerRoutingListener();\n }\n\n private registerRoutingListener = () => {\n this.contactCtx.state.subscribe(({ contact }) => {\n // Auto navigate to sessions screen after collecting user data\n if (contact?.token && this.state.get().screen === \"welcome\") {\n this.state.setPartial({ screen: \"sessions\" });\n }\n });\n\n this.sessionCtx.sessionsState.subscribe(\n ({ isInitialFetchLoading, data }) => {\n if (data.length) return;\n if (this.config.router?.goToChatIfNoSessions === false) return;\n\n // Auto navigate to chat screen if contact has no previous sessions\n if (!isInitialFetchLoading && this.state.get().screen !== \"chat\") {\n this.toChatScreen();\n }\n },\n );\n };\n\n toSessionsScreen = () => {\n this.resetChat();\n this.state.setPartial({ screen: \"sessions\" });\n };\n\n /**\n * @param sessionId The ID of the session to open, or `undefined` if it is a new chat session\n */\n toChatScreen = (sessionId?: string) => {\n this.resetChat();\n\n if (sessionId) {\n const session = this.sessionCtx.sessionsState\n .get()\n .data.find((s) => s.id === sessionId);\n // Do not navigate if session is not found (this shouldn't happen, unless a wrong ID is passed)\n if (!session) return;\n this.sessionCtx.sessionState.setPartial({ session });\n }\n\n this.state.setPartial({ screen: \"chat\" });\n };\n}\n","import type { ExternalStorage } from \"../types/external-storage\";\n\nexport class StorageCtx {\n private storage: ExternalStorage;\n private KEYS = {\n contactToken: \"opencx__widget__contactToken\",\n externalContactId: \"opencx__widget__externalContactId\",\n };\n\n constructor({ storage }: { storage: ExternalStorage }) {\n this.storage = storage;\n }\n\n setContactToken = async (token: string) => {\n await this.storage.set(this.KEYS.contactToken, token);\n };\n getContactToken = async () => {\n return this.storage.get(this.KEYS.contactToken);\n };\n\n setExternalContactId = async (id: string) => {\n await this.storage.set(this.KEYS.externalContactId, id);\n };\n getExternalContactId = async () => {\n return this.storage.get(this.KEYS.externalContactId);\n };\n}\n","import { ApiCaller } from \"../api/api-caller\";\nimport type { ExternalStorage } from \"../types/external-storage\";\nimport type { WidgetConfig } from \"../types/widget-config\";\nimport { ActiveSessionPollingCtx } from \"./active-session-polling.ctx\";\nimport { ContactCtx } from \"./contact.ctx\";\nimport { MessageCtx } from \"./message.ctx\";\nimport { RouterCtx } from \"./router.ctx\";\nimport { SessionCtx } from \"./session.ctx\";\nimport { StorageCtx } from \"./storage.ctx\";\n\nexport class WidgetCtx {\n public config: WidgetConfig;\n public api: ApiCaller;\n\n public contactCtx: ContactCtx;\n public sessionCtx: SessionCtx;\n public messageCtx: MessageCtx;\n public routerCtx: RouterCtx;\n public storageCtx?: StorageCtx;\n\n private static pollingIntervalsSeconds: {\n session: number;\n sessions: number;\n } | null = null;\n private activeSessionPollingCtx: ActiveSessionPollingCtx;\n\n private constructor({\n config,\n storage,\n }: { config: WidgetConfig; storage?: ExternalStorage }) {\n if (!WidgetCtx.pollingIntervalsSeconds) {\n throw Error(\n \"Widget polling values are not defined, did you call WidgetCtx.initialize()\",\n );\n }\n\n this.config = config;\n this.api = new ApiCaller({ config });\n this.storageCtx = storage ? new StorageCtx({ storage }) : undefined;\n\n this.contactCtx = new ContactCtx({\n api: this.api,\n config: this.config,\n storageCtx: this.storageCtx,\n });\n\n this.sessionCtx = new SessionCtx({\n api: this.api,\n contactCtx: this.contactCtx,\n sessionsPollingIntervalSeconds:\n WidgetCtx.pollingIntervalsSeconds.sessions,\n });\n\n this.messageCtx = new MessageCtx({\n config: this.config,\n api: this.api,\n sessionCtx: this.sessionCtx,\n contactCtx: this.contactCtx,\n });\n\n this.activeSessionPollingCtx = new ActiveSessionPollingCtx({\n api: this.api,\n config: this.config,\n sessionCtx: this.sessionCtx,\n messageCtx: this.messageCtx,\n sessionPollingIntervalSeconds: WidgetCtx.pollingIntervalsSeconds.session,\n });\n\n this.routerCtx = new RouterCtx({\n config: this.config,\n contactCtx: this.contactCtx,\n sessionCtx: this.sessionCtx,\n resetChat: this.resetChat,\n });\n }\n\n static initialize = async ({\n config,\n storage,\n }: { config: WidgetConfig; storage?: ExternalStorage }) => {\n const externalConfig = await new ApiCaller({\n config,\n }).getExternalWidgetConfig();\n\n this.pollingIntervalsSeconds = {\n session: externalConfig.data?.sessionPollingIntervalSeconds || 10,\n sessions: externalConfig.data?.sessionsPollingIntervalSeconds || 60,\n };\n\n return new WidgetCtx({\n config,\n storage,\n });\n };\n\n resetChat = () => {\n this.sessionCtx.reset();\n this.messageCtx.reset();\n };\n}\n"],"names":["defaultOnError","onErrorOptions","basicClient","options","client","createClient","middlewares","ApiCaller","config","token","baseUrl","headers","request","key","value","body","abortSignal","sessionId","lastMessageTimestamp","query","cursor","filters","file","onProgress","resolve","reject","formData","xhr","event","percentage","data","error","uploadUrl","_a","PrimitiveState","state","newState","isEqual","_s","callback","Poller","cb","intervalMs","timeouts","poll","runCatching","result","ActiveSessionPollingCtx","api","sessionCtx","messageCtx","sessionPollingIntervalSeconds","session","messages","prevMessages","newMessages","newMsg","existingMsg","history","commonFields","action","_b","responseBodyText","parsed","ContactCtx","storageCtx","_c","_d","persistedToken","_e","_g","_f","_h","_j","_i","_l","_k","payload","extraCollectedData","persistedExternalId","externalId","v4","genUuid","uuidv4","SessionCtx","contactCtx","sessionsPollingIntervalSeconds","contact","deduped","s","i","self","sessions","MessageCtx","input","isSending","isAssignedToAI","_messages","lastMessage","userMessage","currentMessages","botMessage","m","errorMessage","content","attachments","messageContent","_","response","message","RouterCtx","resetChat","isInitialFetchLoading","StorageCtx","storage","id","_WidgetCtx","externalConfig","WidgetCtx"],"mappings":"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"}