@opencx/widget 3.0.85 → 3.0.87

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.
Files changed (52) hide show
  1. package/dist/designs.cjs +24 -24
  2. package/dist/designs.cjs.map +1 -1
  3. package/dist/designs.js +3458 -3179
  4. package/dist/designs.js.map +1 -1
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.js +5 -3
  7. package/dist/index.js.map +1 -1
  8. package/dist/is-exhaustive-9o43S91P.cjs +2 -0
  9. package/dist/is-exhaustive-9o43S91P.cjs.map +1 -0
  10. package/dist/is-exhaustive-DGJzQK69.js +7 -0
  11. package/dist/is-exhaustive-DGJzQK69.js.map +1 -0
  12. package/dist/react.cjs +1 -1
  13. package/dist/react.cjs.map +1 -1
  14. package/dist/react.js +12 -11
  15. package/dist/src/designs/react/components/Header.d.ts +3 -0
  16. package/dist/src/designs/react/components/lib/DynamicIcon.d.ts +6 -0
  17. package/dist/src/designs/react/components/lib/dialog.d.ts +8 -2
  18. package/dist/src/designs/react/hooks/useCanvas.d.ts +3 -0
  19. package/dist/src/designs/react/hooks/useSetWidgetSize.d.ts +8 -0
  20. package/dist/src/designs/react/hooks/useTheme.d.ts +6 -0
  21. package/dist/src/designs/react/screens/chat/ChatCanvas.d.ts +2 -0
  22. package/dist/src/headless/core/__tests__/test-utils.d.ts +2 -2
  23. package/dist/src/headless/core/api/api-caller.d.ts +2 -2
  24. package/dist/src/headless/core/api/schema.d.ts +176 -75
  25. package/dist/src/headless/core/context/session.ctx.d.ts +40 -1
  26. package/dist/src/headless/core/context/widget.ctx.d.ts +2 -0
  27. package/dist/src/headless/core/index.d.ts +3 -1
  28. package/dist/src/headless/core/types/dtos.d.ts +3 -2
  29. package/dist/src/headless/core/types/icons.d.ts +3 -0
  30. package/dist/src/headless/core/types/widget-config.d.ts +43 -0
  31. package/dist/src/headless/core/utils/is-exhaustive.d.ts +1 -0
  32. package/dist/src/headless/react/hooks/useModes.d.ts +12 -0
  33. package/dist/src/headless/react/hooks/useSessions.d.ts +44 -0
  34. package/dist/src/headless/react/index.d.ts +1 -0
  35. package/dist/{useWidgetTrigger-Be2RN31V.cjs → useModes-C5Jd3NZU.cjs} +4 -4
  36. package/dist/useModes-C5Jd3NZU.cjs.map +1 -0
  37. package/dist/{useWidgetTrigger-D94qDfz7.js → useModes-CCwRYrkY.js} +248 -238
  38. package/dist/useModes-CCwRYrkY.js.map +1 -0
  39. package/dist/widget.ctx-BIrCsbNY.cjs +5 -0
  40. package/dist/widget.ctx-BIrCsbNY.cjs.map +1 -0
  41. package/dist/{widget.ctx-0z1bMkkT.js → widget.ctx-D-BdBFz5.js} +66 -60
  42. package/dist/widget.ctx-D-BdBFz5.js.map +1 -0
  43. package/dist-embed/script.js +147 -82
  44. package/dist-embed/script.js.map +1 -1
  45. package/package.json +2 -1
  46. package/dist/src/designs/react/components/WidgetHeader.d.ts +0 -2
  47. package/dist/src/designs/react/hooks/useWidgetSize.d.ts +0 -4
  48. package/dist/useWidgetTrigger-Be2RN31V.cjs.map +0 -1
  49. package/dist/useWidgetTrigger-D94qDfz7.js.map +0 -1
  50. package/dist/widget.ctx-0z1bMkkT.js.map +0 -1
  51. package/dist/widget.ctx-BOpwwK5L.cjs +0 -5
  52. package/dist/widget.ctx-BOpwwK5L.cjs.map +0 -1
@@ -76,8 +76,8 @@ class T {
76
76
  onProgress: i
77
77
  }) => new Promise((c, r) => {
78
78
  var v;
79
- const h = new FormData();
80
- h.append("file", t);
79
+ const g = new FormData();
80
+ g.append("file", t);
81
81
  const l = new XMLHttpRequest();
82
82
  if (s && (s.addEventListener("abort", () => {
83
83
  l.abort(), r(new DOMException("Aborted", "AbortError"));
@@ -105,16 +105,16 @@ class T {
105
105
  }), l.addEventListener("timeout", () => {
106
106
  r(new Error("Upload timed out"));
107
107
  });
108
- const { baseUrl: f } = this.constructClientOptions(this.userToken), p = `${f}/backend/widget/v2/upload`;
109
- l.open("POST", p), l.setRequestHeader("X-Bot-Token", this.config.token), this.userToken ?? ((v = this.config.user) == null ? void 0 : v.token) ? l.setRequestHeader("Authorization", `Bearer ${this.userToken}`) : console.error("User token not set"), l.send(h);
108
+ const { baseUrl: C } = this.constructClientOptions(this.userToken), p = `${C}/backend/widget/v2/upload`;
109
+ l.open("POST", p), l.setRequestHeader("X-Bot-Token", this.config.token), this.userToken ?? ((v = this.config.user) == null ? void 0 : v.token) ? l.setRequestHeader("Authorization", `Bearer ${this.userToken}`) : console.error("User token not set"), l.send(g);
110
110
  }), this.vote = async (t) => await this.client.POST("/backend/widget/v2/chat/vote", { body: t }), this.resolveSession = async (t, s) => await this.client.POST("/backend/widget/v2/session/resolve", {
111
111
  body: t,
112
112
  signal: s
113
113
  }), this.config = n, this.userToken = ((o = n.user) == null ? void 0 : o.token) || null;
114
- const { baseUrl: a, headers: g } = this.constructClientOptions(
114
+ const { baseUrl: a, headers: h } = this.constructClientOptions(
115
115
  (e = n.user) == null ? void 0 : e.token
116
116
  );
117
- this.client = this.createOpenAPIClient({ baseUrl: a, headers: g });
117
+ this.client = this.createOpenAPIClient({ baseUrl: a, headers: h });
118
118
  }
119
119
  }
120
120
  class P {
@@ -123,8 +123,8 @@ class P {
123
123
  O(this.state, a) || (this.state = a, this.notifySubscribers(a));
124
124
  }, this.setPartial = (a) => {
125
125
  if (a == null) return;
126
- const g = { ...this.state, ...a };
127
- this.set(g);
126
+ const h = { ...this.state, ...a };
127
+ this.set(h);
128
128
  }, this.reset = () => {
129
129
  this.set(this.initialState);
130
130
  }, this.notifySubscribers = (a) => {
@@ -140,7 +140,7 @@ class P {
140
140
  }), this.state = n, this.initialState = n;
141
141
  }
142
142
  }
143
- class A {
143
+ class R {
144
144
  constructor() {
145
145
  this.state = new P({
146
146
  isPolling: !1,
@@ -150,7 +150,7 @@ class A {
150
150
  this.abortController.abort("Resetting poller"), (n = this.stopPolling) == null || n.call(this), this.stopPolling = null;
151
151
  }, this.stopPolling = null, this.startPolling = (n, a) => {
152
152
  if (this.stopPolling) return;
153
- const g = [], o = async () => {
153
+ const h = [], o = async () => {
154
154
  this.abortController = new AbortController(), this.state.setPartial({ isPolling: !0 });
155
155
  try {
156
156
  await n(this.abortController.signal);
@@ -161,10 +161,10 @@ class A {
161
161
  } finally {
162
162
  this.state.setPartial({ isPolling: !1 });
163
163
  }
164
- this.abortController.signal.aborted ? console.log("Poller aborted, not scheduling anymore") : g.push(setTimeout(o, a));
164
+ this.abortController.signal.aborted ? console.log("Poller aborted, not scheduling anymore") : h.push(setTimeout(o, a));
165
165
  };
166
166
  o(), this.stopPolling = () => {
167
- g.forEach(clearTimeout), this.state.reset();
167
+ h.forEach(clearTimeout), this.state.reset();
168
168
  };
169
169
  };
170
170
  }
@@ -181,30 +181,30 @@ class L {
181
181
  constructor({
182
182
  api: n,
183
183
  config: a,
184
- sessionCtx: g,
184
+ sessionCtx: h,
185
185
  messageCtx: o,
186
186
  sessionPollingIntervalSeconds: e
187
187
  }) {
188
- this.poller = new A(), this.registerPolling = () => {
188
+ this.poller = new R(), this.registerPolling = () => {
189
189
  this.sessionCtx.sessionState.subscribe(({ session: t }) => {
190
190
  t != null && t.id ? this.poller.startPolling(async (s) => {
191
191
  this.hackAndSlash(t.id, s);
192
192
  }, this.sessionPollingIntervalSeconds * 1e3) : this.poller.reset();
193
193
  });
194
194
  }, this.hackAndSlash = async (t, s) => {
195
- var h;
195
+ var g;
196
196
  this.messageCtx.state.get().messages.length === 0 && this.messageCtx.state.setPartial({ isInitialFetchLoading: !0 });
197
- const i = this.messageCtx.state.get().messages, c = i.length > 0 ? (h = i[i.length - 1]) == null ? void 0 : h.timestamp : void 0, { data: r } = await this.api.pollSessionAndHistory({
197
+ const i = this.messageCtx.state.get().messages, c = i.length > 0 ? (g = i[i.length - 1]) == null ? void 0 : g.timestamp : void 0, { data: r } = await this.api.pollSessionAndHistory({
198
198
  sessionId: t,
199
199
  abortSignal: s,
200
200
  lastMessageTimestamp: c
201
201
  });
202
202
  if (r != null && r.session && (this.sessionCtx.sessionState.setPartial({ session: r.session }), this.sessionCtx.setSessions([r.session])), r != null && r.history && r.history.length > 0) {
203
- const l = this.messageCtx.state.get().messages, f = r.history.map(this.mapHistoryToMessage).filter(
203
+ const l = this.messageCtx.state.get().messages, C = r.history.map(this.mapHistoryToMessage).filter(
204
204
  (x) => !l.some((p) => p.id === x.id)
205
205
  );
206
206
  this.messageCtx.state.setPartial({
207
- messages: [...l, ...f]
207
+ messages: [...l, ...C]
208
208
  });
209
209
  }
210
210
  this.messageCtx.state.get().isInitialFetchLoading && this.messageCtx.state.setPartial({ isInitialFetchLoading: !1 });
@@ -264,21 +264,21 @@ class L {
264
264
  if (c) return c;
265
265
  }
266
266
  return t.result;
267
- }, this.api = n, this.config = a, this.sessionCtx = g, this.messageCtx = o, this.sessionPollingIntervalSeconds = e, this.registerPolling();
267
+ }, this.api = n, this.config = a, this.sessionCtx = h, this.messageCtx = o, this.sessionPollingIntervalSeconds = e, this.registerPolling();
268
268
  }
269
269
  }
270
270
  class B {
271
271
  constructor({
272
272
  config: n,
273
273
  api: a,
274
- storageCtx: g
274
+ storageCtx: h
275
275
  }) {
276
276
  var o;
277
277
  this.shouldCollectData = () => {
278
278
  var e;
279
279
  return !!(!((e = this.state.get().contact) != null && e.token) && this.config.collectUserData);
280
280
  }, this.autoCreateUnverifiedUserIfNotExists = async () => {
281
- var e, t, s, i, c, r, h, l, f, x, p, b, v, u;
281
+ var e, t, s, i, c, r, g, l, C, x, p, b, v, u;
282
282
  if (!((e = this.config.user) != null && e.token)) {
283
283
  if (this.config.collectUserData && !((s = (t = this.config.user) == null ? void 0 : t.data) != null && s.email)) {
284
284
  if ((i = this.config.extraDataCollectionFields) != null && i.length)
@@ -287,7 +287,7 @@ class B {
287
287
  S && await this.setUnverifiedContact(S);
288
288
  return;
289
289
  }
290
- if (!((h = (r = this.config.user) == null ? void 0 : r.data) != null && h.email)) {
290
+ if (!((g = (r = this.config.user) == null ? void 0 : r.data) != null && g.email)) {
291
291
  const S = await ((l = this.storageCtx) == null ? void 0 : l.getContactToken());
292
292
  if (S) {
293
293
  await this.setUnverifiedContact(S);
@@ -295,7 +295,7 @@ class B {
295
295
  }
296
296
  }
297
297
  await this.createUnverifiedContact({
298
- email: (x = (f = this.config.user) == null ? void 0 : f.data) == null ? void 0 : x.email,
298
+ email: (x = (C = this.config.user) == null ? void 0 : C.data) == null ? void 0 : x.email,
299
299
  non_verified_name: ((b = (p = this.config.user) == null ? void 0 : p.data) == null ? void 0 : b.name) || "Anonymous",
300
300
  non_verified_custom_data: (u = (v = this.config.user) == null ? void 0 : v.data) == null ? void 0 : u.customData
301
301
  });
@@ -313,10 +313,10 @@ class B {
313
313
  this.state.setPartial({ isCreatingUnverifiedContact: !1 });
314
314
  }
315
315
  }, this.setUnverifiedContact = async (e) => {
316
- var i, c, r, h;
316
+ var i, c, r, g;
317
317
  const t = await ((i = this.storageCtx) == null ? void 0 : i.getExternalContactId()), s = ((c = this.config.user) == null ? void 0 : c.externalId) || t || E();
318
- this.api.setAuthToken(e), await ((r = this.storageCtx) == null ? void 0 : r.setContactToken(e)), await ((h = this.storageCtx) == null ? void 0 : h.setExternalContactId(s)), this.state.setPartial({ contact: { token: e, externalId: s } });
319
- }, this.config = n, this.storageCtx = g, this.api = a, this.state = new P({
318
+ this.api.setAuthToken(e), await ((r = this.storageCtx) == null ? void 0 : r.setContactToken(e)), await ((g = this.storageCtx) == null ? void 0 : g.setExternalContactId(s)), this.state.setPartial({ contact: { token: e, externalId: s } });
319
+ }, this.config = n, this.storageCtx = h, this.api = a, this.state = new P({
320
320
  contact: (o = n.user) != null && o.token ? {
321
321
  token: n.user.token,
322
322
  // Set optional externalId from config... not local storage
@@ -335,11 +335,12 @@ class q {
335
335
  constructor({
336
336
  api: n,
337
337
  contactCtx: a,
338
- sessionsPollingIntervalSeconds: g
338
+ sessionsPollingIntervalSeconds: h
339
339
  }) {
340
- this.sessionsRefresher = new A(), this.sessionState = new P({
340
+ this.sessionsRefresher = new R(), this.sessionState = new P({
341
341
  session: null,
342
- isCreatingSession: !1
342
+ isCreatingSession: !1,
343
+ isResolvingSession: !1
343
344
  }), this.sessionsState = new P({
344
345
  data: [],
345
346
  cursor: void 0,
@@ -369,7 +370,7 @@ class q {
369
370
  external_id: o
370
371
  } : void 0
371
372
  });
372
- return e ? (this.sessionState.setPartial({ session: e, isCreatingSession: !1 }), e) : (console.error("Failed to create session:", t), null);
373
+ return e ? (this.sessionState.setPartial({ session: e, isCreatingSession: !1 }), e) : (this.sessionState.setPartial({ isCreatingSession: !1 }), console.error("Failed to create session:", t), null);
373
374
  }, this.loadMoreSessions = async () => {
374
375
  if (this.sessionsState.get().isLastPage) return;
375
376
  const { data: o } = await this.getSessions({
@@ -405,19 +406,21 @@ class q {
405
406
  o && this.setSessions(o.items);
406
407
  }, this.resolveSession = async () => {
407
408
  const o = this.sessionState.get().session;
408
- if (!o || !o.isOpened) return;
409
- const { data: e } = await this.api.resolveSession({
409
+ if (!o || !o.isOpened)
410
+ return { success: !1, error: "Session is not opened" };
411
+ this.sessionState.setPartial({ isResolvingSession: !0 });
412
+ const { data: e, error: t } = await this.api.resolveSession({
410
413
  session_id: o.id
411
414
  });
412
- e && this.sessionState.setPartial({ session: e });
413
- }, this.api = n, this.contactCtx = a, this.sessionsPollingIntervalSeconds = g, this.registerSessionsRefresherWrapper();
415
+ return e ? (this.sessionState.setPartial({ session: e, isResolvingSession: !1 }), { success: !0, data: e }) : (this.sessionState.setPartial({ isResolvingSession: !1 }), { success: !1, error: t });
416
+ }, this.api = n, this.contactCtx = a, this.sessionsPollingIntervalSeconds = h, this.registerSessionsRefresherWrapper();
414
417
  }
415
418
  }
416
419
  class $ {
417
420
  constructor({
418
421
  config: n,
419
422
  api: a,
420
- sessionCtx: g,
423
+ sessionCtx: h,
421
424
  contactCtx: o
422
425
  }) {
423
426
  this.state = new P({
@@ -428,7 +431,7 @@ class $ {
428
431
  }), this.sendMessageAbortController = new AbortController(), this.reset = () => {
429
432
  this.sendMessageAbortController.abort("Resetting chat"), this.state.reset();
430
433
  }, this.sendMessage = async (e) => {
431
- var r, h, l, f, x, p, b, v;
434
+ var r, g, l, C, x, p, b, v;
432
435
  if (!e.content.trim() && (!e.attachments || e.attachments.length === 0)) {
433
436
  console.warn("Cannot send an empty message of no content or attachments");
434
437
  return;
@@ -448,7 +451,7 @@ class $ {
448
451
  ), S = this.state.get().messages;
449
452
  if (this.state.setPartial({
450
453
  messages: [...S, u]
451
- }), !((h = this.sessionCtx.sessionState.get().session) != null && h.id)) {
454
+ }), !((g = this.sessionCtx.sessionState.get().session) != null && g.id)) {
452
455
  if (!await this.sessionCtx.createSession()) {
453
456
  console.error("Failed to create session");
454
457
  return;
@@ -457,7 +460,7 @@ class $ {
457
460
  }
458
461
  const k = (l = this.sessionCtx.sessionState.get().session) == null ? void 0 : l.id;
459
462
  if (!k) return;
460
- const { data: C } = await this.api.sendMessage(
463
+ const { data: f } = await this.api.sendMessage(
461
464
  {
462
465
  uuid: u.id,
463
466
  bot_token: this.config.token,
@@ -476,26 +479,27 @@ class $ {
476
479
  },
477
480
  this.sendMessageAbortController.signal
478
481
  );
479
- if (C != null && C.success) {
480
- const w = this.toBotMessage(C);
482
+ if (f != null && f.success) {
483
+ const w = this.toBotMessage(f);
481
484
  if (w) {
482
485
  const I = this.state.get().messages;
483
486
  if (!!I.some(
484
- (R) => R.id === w.id
487
+ (A) => A.id === w.id
485
488
  )) {
486
489
  this.state.setPartial({
487
- lastAIResMightSolveUserIssue: ((f = C.autopilotResponse) == null ? void 0 : f.mightSolveUserIssue) || ((x = C.uiResponse) == null ? void 0 : x.mightSolveUserIssue)
490
+ lastAIResMightSolveUserIssue: ((C = f.autopilotResponse) == null ? void 0 : C.mightSolveUserIssue) || ((x = f.uiResponse) == null ? void 0 : x.mightSolveUserIssue)
488
491
  });
489
492
  return;
490
493
  }
491
494
  this.state.setPartial({
492
495
  messages: [...I, w],
493
- lastAIResMightSolveUserIssue: ((p = C.autopilotResponse) == null ? void 0 : p.mightSolveUserIssue) || ((b = C.uiResponse) == null ? void 0 : b.mightSolveUserIssue)
496
+ lastAIResMightSolveUserIssue: ((p = f.autopilotResponse) == null ? void 0 : p.mightSolveUserIssue) || ((b = f.uiResponse) == null ? void 0 : b.mightSolveUserIssue)
494
497
  });
495
498
  }
499
+ f.session && this.sessionCtx.sessionState.setPartial({ session: f.session });
496
500
  } else {
497
501
  const w = this.toBotErrorMessage(
498
- ((v = C == null ? void 0 : C.error) == null ? void 0 : v.message) || "Unknown error occurred"
502
+ ((v = f == null ? void 0 : f.error) == null ? void 0 : v.message) || "Unknown error occurred"
499
503
  ), I = this.state.get().messages;
500
504
  this.state.setPartial({
501
505
  messages: [...I, w]
@@ -509,7 +513,7 @@ class $ {
509
513
  }, this.toUserMessage = (e, t) => {
510
514
  const s = (() => {
511
515
  const i = this.contactCtx.state.get().extraCollectedData;
512
- return this.state.get().messages.length === 0 && i && Object.keys(i).length > 0 ? `${Object.entries(i).filter(([r, h]) => !!h).map(([r, h]) => `${r}: ${h}`).join(`
516
+ return this.state.get().messages.length === 0 && i && Object.keys(i).length > 0 ? `${Object.entries(i).filter(([r, g]) => !!g).map(([r, g]) => `${r}: ${g}`).join(`
513
517
  `)}
514
518
 
515
519
  ${e}` : e;
@@ -553,14 +557,14 @@ ${e}` : e;
553
557
  variant: "error",
554
558
  action: void 0
555
559
  }
556
- }), this.config = n, this.api = a, this.sessionCtx = g, this.contactCtx = o;
560
+ }), this.config = n, this.api = a, this.sessionCtx = h, this.contactCtx = o;
557
561
  }
558
562
  }
559
563
  class N {
560
564
  constructor({
561
565
  config: n,
562
566
  contactCtx: a,
563
- sessionCtx: g,
567
+ sessionCtx: h,
564
568
  resetChat: o
565
569
  }) {
566
570
  var e;
@@ -572,14 +576,14 @@ class N {
572
576
  });
573
577
  }), this.sessionCtx.sessionsState.subscribe(
574
578
  ({ isInitialFetchLoading: t, data: s }) => {
575
- var i, c, r, h;
579
+ var i, c, r, g;
576
580
  if ((i = this.config.router) != null && i.chatScreenOnly && // Do not route to a chat if we are currently inside one already
577
581
  // This also applies to newly created sessions; the new session will be in `sessionState` before it is refreshed and included in `sessionsState`
578
582
  !((c = this.sessionCtx.sessionState.get().session) != null && c.id)) {
579
- const l = (r = s.find((f) => f.isOpened)) == null ? void 0 : r.id;
583
+ const l = (r = s.find((C) => C.isOpened)) == null ? void 0 : r.id;
580
584
  return l ? this.toChatScreen(l) : void 0;
581
585
  }
582
- s.length || ((h = this.config.router) == null ? void 0 : h.goToChatIfNoSessions) !== !1 && !t && this.state.get().screen !== "chat" && this.toChatScreen();
586
+ s.length || ((g = this.config.router) == null ? void 0 : g.goToChatIfNoSessions) !== !1 && !t && this.state.get().screen !== "chat" && this.toChatScreen();
583
587
  }
584
588
  );
585
589
  }, this.toSessionsScreen = () => {
@@ -591,7 +595,7 @@ class N {
591
595
  this.sessionCtx.sessionState.setPartial({ session: s });
592
596
  }
593
597
  this.state.setPartial({ screen: "chat" });
594
- }, this.config = n, this.contactCtx = a, this.sessionCtx = g, this.resetChat = o, this.state = new P({
598
+ }, this.config = n, this.contactCtx = a, this.sessionCtx = h, this.resetChat = o, this.state = new P({
595
599
  screen: this.contactCtx.shouldCollectData() ? "welcome" : (e = this.config.router) != null && e.chatScreenOnly ? "chat" : "sessions"
596
600
  }), this.registerRoutingListener();
597
601
  }
@@ -611,15 +615,16 @@ class H {
611
615
  const m = class m {
612
616
  constructor({
613
617
  config: n,
614
- storage: a
618
+ storage: a,
619
+ modes: h
615
620
  }) {
616
- if (this.resetChat = () => {
621
+ if (this.modes = [], this.resetChat = () => {
617
622
  this.sessionCtx.reset(), this.messageCtx.reset();
618
623
  }, !m.pollingIntervalsSeconds)
619
624
  throw Error(
620
625
  "Widget polling values are not defined, did you call WidgetCtx.initialize()"
621
626
  );
622
- this.config = n, this.api = new T({ config: n }), this.storageCtx = a ? new H({ storage: a }) : void 0, this.contactCtx = new B({
627
+ this.config = n, this.api = new T({ config: n }), this.storageCtx = a ? new H({ storage: a }) : void 0, this.modes = h, this.contactCtx = new B({
623
628
  api: this.api,
624
629
  config: this.config,
625
630
  storageCtx: this.storageCtx
@@ -650,16 +655,17 @@ m.pollingIntervalsSeconds = null, m.initialize = async ({
650
655
  config: n,
651
656
  storage: a
652
657
  }) => {
653
- var o, e;
654
- const g = await new T({
658
+ var o, e, t;
659
+ const h = await new T({
655
660
  config: n
656
661
  }).getExternalWidgetConfig();
657
662
  return m.pollingIntervalsSeconds = {
658
- session: ((o = g.data) == null ? void 0 : o.sessionPollingIntervalSeconds) || 10,
659
- sessions: ((e = g.data) == null ? void 0 : e.sessionsPollingIntervalSeconds) || 60
663
+ session: ((o = h.data) == null ? void 0 : o.sessionPollingIntervalSeconds) || 10,
664
+ sessions: ((e = h.data) == null ? void 0 : e.sessionsPollingIntervalSeconds) || 60
660
665
  }, new m({
661
666
  config: n,
662
- storage: a
667
+ storage: a,
668
+ modes: ((t = h.data) == null ? void 0 : t.modes) || []
663
669
  });
664
670
  };
665
671
  let U = m;
@@ -667,4 +673,4 @@ export {
667
673
  P,
668
674
  U as W
669
675
  };
670
- //# sourceMappingURL=widget.ctx-0z1bMkkT.js.map
676
+ //# sourceMappingURL=widget.ctx-D-BdBFz5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget.ctx-D-BdBFz5.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 {\n ResolveSessionDto,\n SendMessageDto,\n VoteInputDto,\n} from '../types/dtos';\n\nexport class ApiCaller {\n private client: ReturnType<typeof basicClient>;\n private config: WidgetConfig;\n private userToken: string | null = null;\n\n constructor({ config }: { config: WidgetConfig }) {\n this.config = config;\n this.userToken = config.user?.token || null;\n\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 const userToken = this.userToken ?? this.config.user?.token;\n if (userToken) {\n xhr.setRequestHeader('Authorization', `Bearer ${this.userToken}`);\n } else {\n console.error('User token not set');\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 resolveSession = async (\n body: ResolveSessionDto,\n abortSignal?: AbortSignal,\n ) => {\n return await this.client.POST('/backend/widget/v2/session/resolve', {\n body,\n signal: abortSignal,\n });\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/dtos';\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 this.sessionCtx.setSessions([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 email: this.config.user?.data?.email,\n non_verified_name: this.config.user?.data?.name || 'Anonymous',\n non_verified_custom_data: this.config.user?.data?.customData,\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/dtos';\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 isResolvingSession: 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 isResolvingSession: 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 this.sessionState.setPartial({ isCreatingSession: false });\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 setSessions = (data: SessionDto[]) => {\n const sessions = [...data, ...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 refreshSessions = async () => {\n // Get the first page only (pass no `cursor`)\n const { data } = await this.getSessions({ cursor: undefined });\n if (!data) return;\n this.setSessions(data.items);\n };\n\n resolveSession = async () => {\n const currentSession = this.sessionState.get().session;\n if (!currentSession || !currentSession.isOpened) {\n return { success: false, error: 'Session is not opened' } as const;\n }\n\n this.sessionState.setPartial({ isResolvingSession: true });\n\n const { data: session, error } = await this.api.resolveSession({\n session_id: currentSession.id,\n });\n\n if (session) {\n this.sessionState.setPartial({ session, isResolvingSession: false });\n return { success: true, data: session } as const;\n }\n\n this.sessionState.setPartial({ isResolvingSession: false });\n return { success: false, error } as const;\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/dtos';\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 customData?: SendMessageDto['custom_data'];\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 body_properties: this.config.bodyProperties,\n session_id: sessionId,\n content: userMessage.content,\n attachments: input.attachments,\n clientContext: this.config.context,\n custom_data: {\n ...(this.config.messageCustomData || {}),\n ...(input.customData || {}),\n },\n language: this.config.language,\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 if (data.session) {\n this.sessionCtx.sessionState.setPartial({ session: data.session });\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\nexport type ScreenU =\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\ntype RouterState = {\n screen: ScreenU;\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.config = config;\n this.contactCtx = contactCtx;\n this.sessionCtx = sessionCtx;\n this.resetChat = resetChat;\n this.state = new PrimitiveState<RouterState>({\n screen: this.contactCtx.shouldCollectData()\n ? 'welcome'\n : this.config.router?.chatScreenOnly\n ? 'chat'\n : 'sessions',\n });\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({\n screen: this.config.router?.chatScreenOnly ? 'chat' : 'sessions',\n });\n }\n });\n\n this.sessionCtx.sessionsState.subscribe(\n ({ isInitialFetchLoading, data }) => {\n if (\n this.config.router?.chatScreenOnly &&\n // Do not route to a chat if we are currently inside one already\n // This also applies to newly created sessions; the new session will be in `sessionState` before it is refreshed and included in `sessionsState`\n !this.sessionCtx.sessionState.get().session?.id\n ) {\n const mostRecentOpenSessionId = data.find((s) => s.isOpened)?.id;\n return mostRecentOpenSessionId\n ? this.toChatScreen(mostRecentOpenSessionId)\n : undefined;\n }\n\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 { ModeDto } from '../types/dtos';\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 public modes: ModeDto[] = [];\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 modes,\n }: {\n config: WidgetConfig;\n storage?: ExternalStorage;\n modes: ModeDto[];\n }) {\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 this.modes = modes;\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 }: {\n config: WidgetConfig;\n storage?: ExternalStorage;\n }) => {\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 modes: externalConfig.data?.modes || [],\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","_b","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","responseBodyText","parsed","ContactCtx","storageCtx","_c","_d","persistedToken","_e","_g","_f","_h","_j","_i","_l","_k","_n","_m","payload","extraCollectedData","persistedExternalId","externalId","v4","genUuid","uuidv4","SessionCtx","contactCtx","sessionsPollingIntervalSeconds","contact","deduped","self","sessions","s","i","currentSession","MessageCtx","input","isSending","isAssignedToAI","_messages","lastMessage","userMessage","currentMessages","botMessage","m","errorMessage","content","attachments","messageContent","_","response","message","RouterCtx","resetChat","isInitialFetchLoading","mostRecentOpenSessionId","StorageCtx","storage","id","_WidgetCtx","modes","externalConfig","WidgetCtx"],"mappings":";;;AAWA,MAAMA,IAAwC,CAACC,MAAmB;AACxD,UAAA,IAAIA,EAAe,KAAK;AAClC,GAEaC,IAAc,CAACC,MAAqB;AAC/C,QAAMC,IAASC,EAAoB;AAAA,IACjC,SAASF,EAAQ;AAAA,EAAA,CAClB,GAEKG,IAA0B;AAAA,IAC9B,WAAWH,EAAQ;AAAA,IACnB,YAAYA,EAAQ;AAAA,IACpB,SAASA,EAAQ,WAAWH;AAAA,EAAA;AAG9B,SAAAI,EAAO,IAAIE,CAAW,GACfF;AACT;ACpBO,MAAMG,EAAU;AAAA,EAKrB,YAAY,EAAE,QAAAC,KAAoC;;AAFlD,SAAQ,YAA2B,MAY3B,KAAA,yBAAyB,CAACC,MAAqC;AAC/D,YAAAC,IAGA,KAAK,OAAO,UAAU,uBACtBC,IAAU;AAAA,QACd,eAAe,KAAK,OAAO;AAAA,QAC3B,gBAAgB;AAAA,QAChB,QAAQ;AAAA,QACR,eAAeF,IAAQ,UAAUA,CAAK,KAAK;AAAA,MAAA;AAGtC,aAAA,EAAE,SAAAC,GAAS,SAAAC,EAAQ;AAAA,IAAA,GAG5B,KAAQ,sBAAsB,CAAC;AAAA,MAC7B,SAAAD;AAAAA,MACA,SAAAC;AAAAA,IAAA,MAEOT,EAAY;AAAA,MACjB,SAAAQ;AAAAA,MACA,WAAW,CAAC,EAAE,SAAAE,QAAc;AACnB,eAAA,QAAQD,CAAO,EAAE,QAAQ,CAAC,CAACE,GAAKC,CAAK,MAAM;AAChD,UAAIA,KACMF,EAAA,QAAQ,IAAIC,GAAKC,CAAK;AAAA,QAChC,CACD;AAAA,MACH;AAAA,IAAA,CACD,GAGH,KAAA,eAAe,CAACL,MAAkB;AAChC,WAAK,YAAYA;AACX,YAAA,EAAE,SAAAC,GAAS,SAAAC,MAAY,KAAK,uBAAuBF,CAAK;AACzD,WAAA,SAAS,KAAK,oBAAoB,EAAE,SAAAC,GAAS,SAAAC,GAAS;AAAA,IAAA,GAG7D,KAAA,0BAA0B,YACjB,MAAM,KAAK,OAAO,IAAI,6BAA6B;AAAA,MACxD,QAAQ,EAAE,QAAQ,EAAE,eAAe,KAAK,OAAO,QAAQ;AAAA,IAAA,CACxD,GAGH,KAAA,gBAAgB,YACP,MAAM,KAAK,OAAO,IAAI,8BAA8B;AAAA,MACzD,QAAQ,EAAE,QAAQ,EAAE,eAAe,KAAK,OAAO,QAAQ;AAAA,IAAA,CACxD,GAGW,KAAA,cAAA,OAAOI,GAAsBC,MAClC,MAAM,KAAK,OAAO,KAAK,gCAAgC;AAAA,MAC5D,MAAAD;AAAA,MACA,QAAQC;AAAA,IAAA,CACT,GAGH,KAAA,0BAA0B,OAAOD,MACxB,MAAM,KAAK,OAAO;AAAA,MACvB;AAAA,MACA;AAAA,QACE,QAAQ,EAAE,QAAQ,EAAE,eAAe,KAAK,OAAO,QAAQ;AAAA,QACvD,MAAAA;AAAA,MACF;AAAA,IAAA,GAIJ,KAAA,gBAAgB,OAAOA,MACd,MAAM,KAAK,OAAO,KAAK,qCAAqC;AAAA,MACjE,MAAAA;AAAA,IAAA,CACD,GAGH,KAAA,wBAAwB,OAAO;AAAA,MAC7B,WAAAE;AAAA,MACA,sBAAAC;AAAA,MACA,aAAAF;AAAA,IAAA,MAKI;AACJ,YAAMG,IAAQD,IAAuB,EAAE,sBAAAA,EAAyB,IAAA;AAChE,aAAO,MAAM,KAAK,OAAO,IAAI,uCAAuC;AAAA,QAClE,QAAQ,EAAE,MAAM,EAAE,WAAAD,EAAA,GAAa,OAAAE,EAAM;AAAA,QACrC,QAAQH;AAAA,MAAA,CACT;AAAA,IAAA,GAGH,KAAA,cAAc,OAAO;AAAA,MACnB,QAAAI;AAAA,MACA,SAAAC;AAAA,MACA,aAAAL;AAAA,IAAA,MAMO,MAAM,KAAK,OAAO,IAAI,+BAA+B;AAAA,MAC1D,QAAQ,EAAE,OAAO,EAAE,QAAAI,GAAQ,SAAS,KAAK,UAAUC,CAAO,IAAI;AAAA,MAC9D,QAAQL;AAAA,IAAA,CACT,GAOH,KAAA,aAAa,OAAO;AAAA,MAClB,MAAAM;AAAA,MACA,aAAAN;AAAA,MACA,YAAAO;AAAA,IAAA,MAMO,IAAI,QAAQ,CAACC,GAASC,MAAW;;AAChC,YAAAC,IAAW,IAAI;AACZ,MAAAA,EAAA,OAAO,QAAQJ,CAAI;AAEtB,YAAAK,IAAM,IAAI;AAGhB,UAAIX,MACUA,EAAA,iBAAiB,SAAS,MAAM;AAC1C,QAAAW,EAAI,MAAM,GACVF,EAAO,IAAI,aAAa,WAAW,YAAY,CAAC;AAAA,MAAA,CACjD,GAGGT,EAAY,UAAS;AACvB,QAAAS,EAAO,IAAI,aAAa,WAAW,YAAY,CAAC;AAChD;AAAA,MACF;AAGF,MAAAE,EAAI,OAAO,iBAAiB,YAAY,CAACC,MAAU;AAC7C,YAAAA,EAAM,oBAAoBL,GAAY;AACxC,gBAAMM,IAAa,KAAK,MAAOD,EAAM,SAASA,EAAM,QAAS,GAAG;AAChE,UAAAL,EAAWM,CAAU;AAAA,QACvB;AAAA,MAAA,CACD,GAGGF,EAAA,iBAAiB,QAAQ,MAAM;AACjC,YAAIA,EAAI,UAAU,OAAOA,EAAI,SAAS;AAChC,cAAA;AACF,kBAAMG,IAAO,KAAK,MAAMH,EAAI,YAAY;AACxC,YAAAH,EAAQM,CAAI;AAAA,mBACLC,GAAO;AACd,YAAAN,EAAO,IAAI,MAAM,6BAA6BM,CAAK,EAAE,CAAC;AAAA,UACxD;AAAA;AAEA,UAAAN,EAAO,IAAI,MAAM,8BAA8BE,EAAI,MAAM,EAAE,CAAC;AAAA,MAC9D,CACD,GAEGA,EAAA,iBAAiB,SAAS,MAAM;AAC3B,QAAAF,EAAA,IAAI,MAAM,wBAAwB,CAAC;AAAA,MAAA,CAC3C,GAEGE,EAAA,iBAAiB,WAAW,MAAM;AAC7B,QAAAF,EAAA,IAAI,MAAM,kBAAkB,CAAC;AAAA,MAAA,CACrC;AAED,YAAM,EAAE,SAAAf,MAAY,KAAK,uBAAuB,KAAK,SAAS,GAGxDsB,IAAY,GAAGtB,CAAO;AACxB,MAAAiB,EAAA,KAAK,QAAQK,CAAS,GAE1BL,EAAI,iBAAiB,eAAe,KAAK,OAAO,KAAK,GACnC,KAAK,eAAaM,IAAA,KAAK,OAAO,SAAZ,gBAAAA,EAAkB,SAEpDN,EAAI,iBAAiB,iBAAiB,UAAU,KAAK,SAAS,EAAE,IAEhE,QAAQ,MAAM,oBAAoB,GAGpCA,EAAI,KAAKD,CAAQ;AAAA,IAAA,CAClB,GAGH,KAAA,OAAO,OAAOX,MACL,MAAM,KAAK,OAAO,KAAK,gCAAgC,EAAE,MAAAA,GAAM,GAGvD,KAAA,iBAAA,OACfA,GACAC,MAEO,MAAM,KAAK,OAAO,KAAK,sCAAsC;AAAA,MAClE,MAAAD;AAAA,MACA,QAAQC;AAAA,IAAA,CACT,GA3MD,KAAK,SAASR,GACT,KAAA,cAAYyB,IAAAzB,EAAO,SAAP,gBAAAyB,EAAa,UAAS;AAEvC,UAAM,EAAE,SAAAvB,GAAS,SAAAC,EAAQ,IAAI,KAAK;AAAA,OAChCuB,IAAA1B,EAAO,SAAP,gBAAA0B,EAAa;AAAA,IAAA;AAEf,SAAK,SAAS,KAAK,oBAAoB,EAAE,SAAAxB,GAAS,SAAAC,GAAS;AAAA,EAC7D;AAsMF;ACvNO,MAAMwB,EAAkB;AAAA,EAK7B,YAAYC,GAAU;AAJd,SAAA,kCAAkB,OAS1B,KAAA,MAAM,MAAS,KAAK,OAEpB,KAAA,MAAM,CAACC,MAAsB;AAC3B,MAAKC,EAAQ,KAAK,OAAOD,CAAQ,MAC/B,KAAK,QAAQA,GACb,KAAK,kBAAkBA,CAAQ;AAAA,IACjC,GAGF,KAAA,aAAa,CAACE,MAAyB;AACjC,UAAoBA,KAAO,KAAM;AACrC,YAAMF,IAAW,EAAE,GAAG,KAAK,OAAO,GAAGE,EAAG;AACxC,WAAK,IAAIF,CAAQ;AAAA,IAAA,GAGnB,KAAA,QAAQ,MAAY;AACb,WAAA,IAAI,KAAK,YAAY;AAAA,IAAA,GAGpB,KAAA,oBAAoB,CAACD,MAAa;AAEvB,MADQ,MAAM,KAAK,KAAK,WAAW,EACnC,QAAQ,CAACI,MAAa;AACjC,YAAA;AACF,UAAAA,EAASJ,CAAK;AAAA,iBACPL,GAAO;AAEZ,kBAAQ,MAAMA,CAAK;AAAA,QAEvB;AAAA,MAAA,CACD;AAAA,IAAA,GAGH,KAAA,YAAY,CAACS,OACN,KAAA,YAAY,IAAIA,CAAQ,GAEtB,MAAM;AACN,WAAA,YAAY,OAAOA,CAAQ;AAAA,IAAA,IAxClC,KAAK,QAAQJ,GACb,KAAK,eAAeA;AAAA,EACtB;AAyCF;AC9CO,MAAMK,EAAO;AAAA,EAAb,cAAA;AACL,SAAA,QAAQ,IAAIN,EAA6B;AAAA,MACvC,WAAW;AAAA,MACX,SAAS;AAAA,IAAA,CACV,GACO,KAAA,kBAAkB,IAAI,mBAE9B,KAAA,QAAQ,MAAM;;AACP,WAAA,gBAAgB,MAAM,kBAAkB,IAC7CF,IAAA,KAAK,gBAAL,QAAAA,EAAA,YACA,KAAK,cAAc;AAAA,IAAA,GAGrB,KAAQ,cAAmC,MAE5B,KAAA,eAAA,CACbS,GACAC,MACG;AACH,UAAI,KAAK,YAAa;AAEtB,YAAMC,IAA6B,CAAA,GAE7BC,IAAO,YAAY;AAClB,aAAA,kBAAkB,IAAI,mBAC3B,KAAK,MAAM,WAAW,EAAE,WAAW,GAAM,CAAA;AAErC,YAAA;AACI,gBAAAH,EAAG,KAAK,gBAAgB,MAAM;AAAA,iBAC7BX,GAAO;AACV,cAAA,KAAK,gBAAgB,OAAO;AAE9B;AAEM,kBAAA,MAAM,mBAAmBA,CAAK,GACtC,KAAK,MAAM,WAAW,EAAE,SAAS,GAAM,CAAA;AAAA,QAAA,UACvC;AACA,eAAK,MAAM,WAAW,EAAE,WAAW,GAAO,CAAA;AAAA,QAC5C;AAGI,QAAA,KAAK,gBAAgB,OAAO,UAC9B,QAAQ,IAAI,wCAAwC,IAEpDa,EAAS,KAAK,WAAWC,GAAMF,CAAU,CAAC;AAAA,MAC5C;AAGG,MAAAE,KAEL,KAAK,cAAc,MAAM;AACvB,QAAAD,EAAS,QAAQ,YAAY,GAC7B,KAAK,MAAM;MAAM;AAAA,IACnB;AAAA,EACF;AACF;ACnDO,SAASE,EACdN,GACsC;AAClC,MAAA;AACF,UAAMO,IAASP;AAEf,WAAIO,aAAkB,UACbA,EAAO,KAAK,CAACjB,OAAU,EAAE,MAAAA,EAAO,EAAA,EAAE,MAAM,CAACC,OAAc,EAAE,OAAAA,IAAQ,IAGnE,EAAE,MAAMgB;WACRhB,GAAO;AACd,WAAO,EAAE,OAAAA,EAAkB;AAAA,EAC7B;AACF;AChBO,MAAMiB,EAAwB;AAAA,EASnC,YAAY;AAAA,IACV,KAAAC;AAAA,IACA,QAAAzC;AAAA,IACA,YAAA0C;AAAA,IACA,YAAAC;AAAA,IACA,+BAAAC;AAAA,EAAA,GAOC;AAdK,SAAA,SAAS,IAAIX,KAwBrB,KAAQ,kBAAkB,MAAM;AAC9B,WAAK,WAAW,aAAa,UAAU,CAAC,EAAE,SAAAY,QAAc;AACtD,QAAIA,KAAA,QAAAA,EAAS,KACN,KAAA,OAAO,aAAa,OAAOrC,MAAgB;AACzC,eAAA,aAAaqC,EAAQ,IAAIrC,CAAW;AAAA,QAAA,GACxC,KAAK,gCAAgC,GAAI,IAE5C,KAAK,OAAO;MACd,CACD;AAAA,IAAA,GAGK,KAAA,eAAe,OACrBC,GACAD,MACkB;;AAQlB,MAAI,KAAK,WAAW,MAAM,MAAM,SAAS,WAAW,KAClD,KAAK,WAAW,MAAM,WAAW,EAAE,uBAAuB,IAAM;AAGlE,YAAMsC,IAAW,KAAK,WAAW,MAAM,IAAM,EAAA,UACvCpC,IACJoC,EAAS,SAAS,KACdrB,IAAAqB,EAASA,EAAS,SAAS,CAAC,MAA5B,gBAAArB,EAA+B,YAC/B,QAEA,EAAE,MAAAH,EAAK,IAAI,MAAM,KAAK,IAAI,sBAAsB;AAAA,QACpD,WAAAb;AAAA,QACA,aAAAD;AAAA,QACA,sBAAAE;AAAA,MAAA,CACD;AAOD,UALIY,KAAA,QAAAA,EAAM,YACR,KAAK,WAAW,aAAa,WAAW,EAAE,SAASA,EAAK,SAAS,GACjE,KAAK,WAAW,YAAY,CAACA,EAAK,OAAO,CAAC,IAGxCA,KAAA,QAAAA,EAAM,WAAWA,EAAK,QAAQ,SAAS,GAAG;AAE5C,cAAMyB,IAAe,KAAK,WAAW,MAAM,IAAM,EAAA,UAC3CC,IAAc1B,EAAK,QACtB,IAAI,KAAK,mBAAmB,EAC5B;AAAA,UACC,CAAC2B,MACC,CAACF,EAAa,KAAK,CAACG,MAAgBA,EAAY,OAAOD,EAAO,EAAE;AAAA,QAAA;AAEjE,aAAA,WAAW,MAAM,WAAW;AAAA,UAC/B,UAAU,CAAC,GAAGF,GAAc,GAAGC,CAAW;AAAA,QAAA,CAC3C;AAAA,MACH;AAEA,MAAI,KAAK,WAAW,MAAM,IAAA,EAAM,yBAC9B,KAAK,WAAW,MAAM,WAAW,EAAE,uBAAuB,IAAO;AAAA,IACnE,GAGF,KAAA,sBAAsB,CAACG,MAAqC;;AAC1D,YAAMC,IAAe;AAAA,QACnB,IAAID,EAAQ;AAAA,QACZ,WAAWA,EAAQ,UAAU;AAAA,QAC7B,aAAaA,EAAQ,eAAe;AAAA,MAAA;AAGlC,UAAAA,EAAQ,OAAO,SAAS;AACnB,eAAA;AAAA,UACL,GAAGC;AAAA,UACH,MAAM;AAAA,UACN,SAASD,EAAQ,QAAQ,QAAQ;AAAA,UACjC,aAAaA,EAAQ,UAAU;AAAA,QAAA;AAI/B,UAAAA,EAAQ,OAAO,SAAS;AACnB,eAAA;AAAA,UACL,GAAGC;AAAA,UACH,MAAM;AAAA,UACN,WAAW;AAAA,UACX,MAAM;AAAA,YACJ,SAASD,EAAQ,QAAQ,QAAQ;AAAA,UACnC;AAAA,UACA,OAAO;AAAA,YACL,MAAMA,EAAQ,OAAO,QAAQ;AAAA,YAC7B,QAAQA,EAAQ,OAAO,UAAU;AAAA,YACjC,IAAI;AAAA,YACJ,MAAM;AAAA,UACR;AAAA,QAAA;AAIJ,YAAME,IACJF,EAAQ,eAAeA,EAAQ,YAAY,SAAS,IAChDA,EAAQ,YAAYA,EAAQ,YAAY,SAAS,CAAC,IAClD;AAEC,aAAA;AAAA,QACL,GAAGC;AAAA,QACH,MAAM;AAAA,QACN,WAAW;AAAA,QACX,OAAO;AAAA,UACL,IAAI;AAAA,UACJ,QAAM3B,IAAA,KAAK,OAAO,QAAZ,gBAAAA,EAAiB,SAAQ;AAAA,UAC/B,MAAM;AAAA,UACN,UAAQC,IAAA,KAAK,OAAO,QAAZ,gBAAAA,EAAiB,WAAU;AAAA,QACrC;AAAA,QACA,MAAM;AAAA,UACJ,SAASyB,EAAQ,QAAQ,QAAQ;AAAA,UACjC,QAAQE,IACJ;AAAA,YACE,MAAMA,EAAO;AAAA,YACb,MAAM,KAAK,oBAAoBA,CAAM;AAAA,UAEvC,IAAA;AAAA,QACN;AAAA,MAAA;AAAA,IACF,GAGF,KAAA,sBAAsB,CAACA,MAA0B;AAC/C,YAAMd,IAASc,EAAO;AAGlB,UADAd,MAAW,QACX,OAAOA,KAAW,SAAiB,QAAAA;AAEvC,UACE,sBAAsBA,KACtB,OAAOA,EAAO,oBAAqB,UACnC;AACA,cAAMe,IAAmBf,EAAO,kBAC1BgB,IAASjB,EAAY,MAAM,KAAK,MAAMgB,CAAgB,CAAC,EAAE;AAC/D,YAAIC,EAAe,QAAAA;AAAA,MACrB;AAEA,aAAOF,EAAO;AAAA,IAAA,GAnJd,KAAK,MAAMZ,GACX,KAAK,SAASzC,GACd,KAAK,aAAa0C,GAClB,KAAK,aAAaC,GAClB,KAAK,gCAAgCC,GAErC,KAAK,gBAAgB;AAAA,EACvB;AA8IF;ACnKO,MAAMY,EAAW;AAAA,EAMtB,YAAY;AAAA,IACV,QAAAxD;AAAA,IACA,KAAAyC;AAAA,IACA,YAAAgB;AAAA,EAAA,GAKC;;AAqBH,SAAA,oBAAoB,MAAe;;AAC7B,aAAA,MAAChC,IAAA,KAAK,MAAM,MAAM,YAAjB,QAAAA,EAA0B,UAAS,KAAK,OAAO;AAAA,IAG7C,GAGT,KAAQ,sCAAsC,YAAY;;AAKpD,UAAA,GAAAA,IAAA,KAAK,OAAO,SAAZ,QAAAA,EAAkB,QAKlB;AAAA,YAAA,KAAK,OAAO,mBAAmB,GAACiC,KAAAhC,IAAA,KAAK,OAAO,SAAZ,gBAAAA,EAAkB,SAAlB,QAAAgC,EAAwB,QAAO;AAM7D,eAAAC,IAAA,KAAK,OAAO,8BAAZ,QAAAA,EAAuC;AACzC;AAGF,gBAAMC,IAAiB,QAAMC,IAAA,KAAK,eAAL,gBAAAA,EAAiB;AAC9C,UAAID,KACI,MAAA,KAAK,qBAAqBA,CAAc;AAGhD;AAAA,QACF;AAKA,YAAI,GAACE,KAAAC,IAAA,KAAK,OAAO,SAAZ,gBAAAA,EAAkB,SAAlB,QAAAD,EAAwB,QAAO;AAClC,gBAAMF,IAAiB,QAAMI,IAAA,KAAK,eAAL,gBAAAA,EAAiB;AAC9C,cAAIJ,GAAgB;AACZ,kBAAA,KAAK,qBAAqBA,CAAc;AAE9C;AAAA,UACF;AAAA,QACF;AAUA,cAAM,KAAK,wBAAwB;AAAA,UACjC,QAAOK,KAAAC,IAAA,KAAK,OAAO,SAAZ,gBAAAA,EAAkB,SAAlB,gBAAAD,EAAwB;AAAA,UAC/B,qBAAmBE,KAAAC,IAAA,KAAK,OAAO,SAAZ,gBAAAA,EAAkB,SAAlB,gBAAAD,EAAwB,SAAQ;AAAA,UACnD,2BAA0BE,KAAAC,IAAA,KAAK,OAAO,SAAZ,gBAAAA,EAAkB,SAAlB,gBAAAD,EAAwB;AAAA,QAAA,CACnD;AAAA;AAAA,IAAA,GAGuB,KAAA,0BAAA,OACxBE,GACAC,MACkB;AAClB,WAAK,MAAM,WAAW,EAAE,oBAAAA,EAAoB,CAAA;AAExC,UAAA;AACF,aAAK,MAAM,WAAW;AAAA,UACpB,6BAA6B;AAAA,UAC7B,kCAAkC;AAAA,QAAA,CACnC;AAED,cAAM,EAAE,MAAAlD,EAAK,IAAI,MAAM,KAAK,IAAI,wBAAwBiD,CAAO;AAC/D,QAAIjD,KAAA,QAAAA,EAAM,QACF,MAAA,KAAK,qBAAqBA,EAAK,KAAK,IAE1C,KAAK,MAAM,WAAW,EAAE,kCAAkC,GAAM,CAAA;AAAA,MAClE,UACA;AACA,aAAK,MAAM,WAAW,EAAE,6BAA6B,GAAO,CAAA;AAAA,MAC9D;AAAA,IAAA,GAGF,KAAA,uBAAuB,OAAOrB,MAAkB;;AAC9C,YAAMwE,IAAsB,QAAMhD,IAAA,KAAK,eAAL,gBAAAA,EAAiB,yBAE7CiD,MACJhD,IAAA,KAAK,OAAO,SAAZ,gBAAAA,EAAkB,eAAc+C,KAAuBE;AACpD,WAAA,IAAI,aAAa1E,CAAK,GAErB,QAAAyD,IAAA,KAAK,eAAL,gBAAAA,EAAiB,gBAAgBzD,KACjC,QAAA0D,IAAA,KAAK,eAAL,gBAAAA,EAAiB,qBAAqBe,KACvC,KAAA,MAAM,WAAW,EAAE,SAAS,EAAE,OAAAzE,GAAO,YAAAyE,KAAc;AAAA,IAAA,GAlHxD,KAAK,SAAS1E,GACd,KAAK,aAAayD,GAClB,KAAK,MAAMhB,GAEN,KAAA,QAAQ,IAAId,EAA6B;AAAA,MAC5C,UAASF,IAAAzB,EAAO,SAAP,QAAAyB,EAAa,QAClB;AAAA,QACE,OAAOzB,EAAO,KAAK;AAAA;AAAA,QAEnB,YAAYA,EAAO,KAAK;AAAA,MAAA,IAE1B;AAAA,MACJ,oBAAoB;AAAA,MACpB,6BAA6B;AAAA,MAC7B,kCAAkC;AAAA,IAAA,CACnC,GAED,KAAK,oCAAoC;AAAA,EAC3C;AAkGF;AClJO,SAAS4E,IAAU;AACxB,SAAOC,EAAO;AAChB;ACuBO,MAAMC,EAAW;AAAA,EAsBtB,YAAY;AAAA,IACV,KAAArC;AAAA,IACA,YAAAsC;AAAA,IACA,gCAAAC;AAAA,EAAA,GAKC;AA1BK,SAAA,oBAAoB,IAAI/C,KAEzB,KAAA,eAAe,IAAIN,EAA6B;AAAA,MACrD,SAAS;AAAA,MACT,mBAAmB;AAAA,MACnB,oBAAoB;AAAA,IAAA,CACrB,GACM,KAAA,gBAAgB,IAAIA,EAA8B;AAAA,MACvD,MAAM,CAAC;AAAA,MACP,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,sBAAsB;AAAA;AAAA;AAAA;AAAA,MAItB,uBAAuB;AAAA,IAAA,CACxB,GAmBD,KAAA,QAAQ,YAAY;AAElB,WAAK,aAAa;IAAM,GAG1B,KAAQ,mCAAmC,MAAM;;AAC/C;AAAA,OAEEF,IAAA,KAAK,WAAW,MAAM,MAAM,YAA5B,QAAAA,EAAqC,SACrC,CAAC,KAAK,cAAc,IAAM,EAAA,uBAE1B,KAAK,0BAA0B,IAG/B,KAAK,WAAW,MAAM,UAAU,CAAC,EAAE,SAAAwD,QAAc;AAC/C,QAAIA,KAAA,QAAAA,EAAS,SAAS,CAAC,KAAK,cAAc,MAAM,wBAC9C,KAAK,0BAA0B;AAAA,MACjC,CACD;AAAA,IACH,GAGF,KAAQ,4BAA4B,MAAM;AACnC,WAAA,kBAAkB,aAAa,YAAY;AAC9C,QAAI,KAAK,cAAc,IAAI,EAAE,yBAAyB,MACpD,KAAK,cAAc,WAAW,EAAE,sBAAsB,GAAM,CAAA,GAG9D,MAAM,KAAK,mBAEP,KAAK,cAAc,IAAI,EAAE,0BAA0B,MACrD,KAAK,cAAc,WAAW,EAAE,uBAAuB,GAAO,CAAA;AAAA,MAChE,GACC,KAAK,iCAAiC,GAAI;AAAA,IAAA,GAG/C,KAAA,gBAAgB,YAAY;;AAC1B,WAAK,aAAa,WAAW,EAAE,SAAS,MAAM,mBAAmB,IAAM;AAEvE,YAAMP,KAAajD,IAAA,KAAK,WAAW,MAAM,MAAM,YAA5B,gBAAAA,EAAqC,YAClD,EAAE,MAAMoB,GAAS,OAAAtB,MAAU,MAAM,KAAK,IAAI,cAAc;AAAA,QAC5D,YAAYmD,IACR;AAAA,UACE,aAAaA;AAAA,QAEf,IAAA;AAAA,MAAA,CACL;AACD,aAAI7B,KACF,KAAK,aAAa,WAAW,EAAE,SAAAA,GAAS,mBAAmB,IAAO,GAC3DA,MAGT,KAAK,aAAa,WAAW,EAAE,mBAAmB,GAAO,CAAA,GACjD,QAAA,MAAM,6BAA6BtB,CAAK,GACzC;AAAA,IAAA,GAGT,KAAA,mBAAmB,YAAY;AAC7B,UAAI,KAAK,cAAc,IAAI,EAAE,WAAY;AAEzC,YAAM,EAAE,MAAAD,EAAA,IAAS,MAAM,KAAK,YAAY;AAAA,QACtC,QAAQ,KAAK,cAAc,IAAM,EAAA;AAAA,MAAA,CAClC;AAED,UAAIA,GAAM;AAGR,cAAM4D,IAFc,CAAC,GAAG,KAAK,cAAc,IAAM,EAAA,MAAM,GAAG5D,EAAK,KAAK,EAExC;AAAA,UAC1B,CAAC,GAAG,GAAG6D,MAAS,MAAMA,EAAK,UAAU,CAACpD,MAAO,EAAE,OAAOA,EAAG,EAAE;AAAA,QAAA;AAG7D,aAAK,cAAc,WAAW;AAAA,UAC5B,MAAMmD;AAAA,UACN,QAAQ5D,EAAK,QAAQ;AAAA,UACrB,YAAYA,EAAK,SAAS;AAAA,QAAA,CAC3B;AAAA,MACH;AAAA,IAAA,GAGF,KAAQ,cAAc,OAAO,EAAE,QAAAV,QAA6C;;AACtE,UAAA,GAACa,IAAA,KAAK,WAAW,MAAM,IAAA,EAAM,YAA5B,QAAAA,EAAqC,OAAO,QAAO,EAAE,MAAM,KAAK;AAErE,YAAMiD,KAAahD,IAAA,KAAK,WAAW,MAAM,MAAM,YAA5B,gBAAAA,EAAqC;AACjD,aAAA,MAAM,KAAK,IAAI,YAAY;AAAA,QAChC,QAAAd;AAAA,QACA,SAAS8D,IACL;AAAA,UACE,aAAaA;AAAA,QAAA,IAEf,CAAC;AAAA,MAAA,CACN;AAAA,IAAA,GAGH,KAAA,cAAc,CAACpD,MAAuB;AAC9B,YAAA8D,IAAW,CAAC,GAAG9D,GAAM,GAAG,KAAK,cAAc,IAAA,EAAM,IAAI,EAAE;AAAA,QAC3D,CAAC+D,GAAGC,GAAGH,MAASG,MAAMH,EAAK,UAAU,CAACpD,MAAOsD,EAAE,OAAOtD,EAAG,EAAE;AAAA,MAAA;AAE7D,WAAK,cAAc,WAAW,EAAE,MAAMqD,EAAU,CAAA;AAAA,IAAA,GAGlD,KAAA,kBAAkB,YAAY;AAEtB,YAAA,EAAE,MAAA9D,EAAS,IAAA,MAAM,KAAK,YAAY,EAAE,QAAQ,OAAA,CAAW;AAC7D,MAAKA,KACA,KAAA,YAAYA,EAAK,KAAK;AAAA,IAAA,GAG7B,KAAA,iBAAiB,YAAY;AAC3B,YAAMiE,IAAiB,KAAK,aAAa,IAAA,EAAM;AAC/C,UAAI,CAACA,KAAkB,CAACA,EAAe;AACrC,eAAO,EAAE,SAAS,IAAO,OAAO,wBAAwB;AAG1D,WAAK,aAAa,WAAW,EAAE,oBAAoB,GAAM,CAAA;AAEnD,YAAA,EAAE,MAAM1C,GAAS,OAAAtB,MAAU,MAAM,KAAK,IAAI,eAAe;AAAA,QAC7D,YAAYgE,EAAe;AAAA,MAAA,CAC5B;AAED,aAAI1C,KACF,KAAK,aAAa,WAAW,EAAE,SAAAA,GAAS,oBAAoB,IAAO,GAC5D,EAAE,SAAS,IAAM,MAAMA,EAAQ,MAGxC,KAAK,aAAa,WAAW,EAAE,oBAAoB,GAAO,CAAA,GACnD,EAAE,SAAS,IAAO,OAAAtB;IAAM,GArI/B,KAAK,MAAMkB,GACX,KAAK,aAAasC,GAClB,KAAK,iCAAiCC,GAEtC,KAAK,iCAAiC;AAAA,EACxC;AAkIF;ACzKO,MAAMQ,EAAW;AAAA,EAetB,YAAY;AAAA,IACV,QAAAxF;AAAA,IACA,KAAAyC;AAAA,IACA,YAAAC;AAAA,IACA,YAAAqC;AAAA,EAAA,GAMC;AAnBI,SAAA,QAAQ,IAAIpD,EAAgC;AAAA,MACjD,UAAU,CAAC;AAAA,MACX,kBAAkB;AAAA,MAClB,8BAA8B;AAAA,MAC9B,uBAAuB;AAAA,IAAA,CACxB,GAEO,KAAA,6BAA6B,IAAI,mBAmBzC,KAAA,QAAQ,MAAM;AACP,WAAA,2BAA2B,MAAM,gBAAgB,GACtD,KAAK,MAAM;IAAM,GAGnB,KAAA,cAAc,OAAO8D,MAIA;;AAKjB,UAAA,CAACA,EAAM,QAAQ,KAAK,MACnB,CAACA,EAAM,eAAeA,EAAM,YAAY,WAAW,IACpD;AACA,gBAAQ,KAAK,2DAA2D;AACxE;AAAA,MACF;AAIA,YAAMC,IAAY,KAAK,MAAM,IAAA,EAAM,kBAC7BC,MACJlE,IAAA,KAAK,WAAW,aAAa,IAAM,EAAA,YAAnC,gBAAAA,EAA4C,SAAS,UAAS,MAC1DmE,IAAY,KAAK,MAAM,IAAA,EAAM,UAC7BC,IACJD,EAAU,SAAS,IAAIA,EAAUA,EAAU,SAAS,CAAC,IAAI;AAC3D,UACGD,KAAkBD;AAAA,MAElBC,MAAkBE,KAAA,gBAAAA,EAAa,UAAS,aACzC;AACA,gBAAQ,KAAK,iDAAiD;AAC9D;AAAA,MACF;AAEK,WAAA,6BAA6B,IAAI,mBAKtC,KAAK,MAAM,WAAW,EAAE,8BAA8B,GAAO,CAAA;AAEzD,UAAA;AACF,aAAK,MAAM,WAAW,EAAE,kBAAkB,GAAM,CAAA;AAIhD,cAAMC,IAAc,KAAK;AAAA,UACvBL,EAAM,QAAQ,KAAK;AAAA,UACnBA,EAAM,eAAe;AAAA,QAAA,GAEjBM,IAAkB,KAAK,MAAM,IAAA,EAAM;AAQzC,YAPA,KAAK,MAAM,WAAW;AAAA,UACpB,UAAU,CAAC,GAAGA,GAAiBD,CAAW;AAAA,QAAA,CAC3C,GAKG,GAACpE,IAAA,KAAK,WAAW,aAAa,IAAI,EAAE,YAAnC,QAAAA,EAA4C,KAAI;AAInD,cAAI,CAHmB,MAAM,KAAK,WAAW,cAAc,GAGtC;AACnB,oBAAQ,MAAM,0BAA0B;AACxC;AAAA,UACF;AAGK,UAAA,KAAK,WAAW;QACvB;AACA,cAAMjB,KAAYiD,IAAA,KAAK,WAAW,aAAa,MAAM,YAAnC,gBAAAA,EAA4C;AAC9D,YAAI,CAACjD,EAAW;AAIhB,cAAM,EAAE,MAAAa,EAAS,IAAA,MAAM,KAAK,IAAI;AAAA,UAC9B;AAAA,YACE,MAAMwE,EAAY;AAAA,YAClB,WAAW,KAAK,OAAO;AAAA,YACvB,SAAS,KAAK,OAAO;AAAA,YACrB,cAAc,KAAK,OAAO;AAAA,YAC1B,iBAAiB,KAAK,OAAO;AAAA,YAC7B,YAAYrF;AAAA,YACZ,SAASqF,EAAY;AAAA,YACrB,aAAaL,EAAM;AAAA,YACnB,eAAe,KAAK,OAAO;AAAA,YAC3B,aAAa;AAAA,cACX,GAAI,KAAK,OAAO,qBAAqB,CAAC;AAAA,cACtC,GAAIA,EAAM,cAAc,CAAC;AAAA,YAC3B;AAAA,YACA,UAAU,KAAK,OAAO;AAAA,UACxB;AAAA,UACA,KAAK,2BAA2B;AAAA,QAAA;AAGlC,YAAInE,KAAA,QAAAA,EAAM,SAAS;AAIX,gBAAA0E,IAAa,KAAK,aAAa1E,CAAI;AACzC,cAAI0E,GAAY;AACd,kBAAMjD,IAAe,KAAK,MAAM,IAAA,EAAM;AAItC,gBAAI,CAHiB,CAACA,EAAa;AAAA,cACjC,CAACkD,MAAMA,EAAE,OAAOD,EAAW;AAAA,YAAA,GAEV;AACjB,mBAAK,MAAM,WAAW;AAAA,gBACpB,gCACErC,IAAArC,EAAK,sBAAL,gBAAAqC,EAAwB,0BACxBE,IAAAvC,EAAK,eAAL,gBAAAuC,EAAiB;AAAA,cAAA,CACpB;AACD;AAAA,YACF;AACA,iBAAK,MAAM,WAAW;AAAA,cACpB,UAAU,CAAC,GAAGd,GAAciD,CAAU;AAAA,cACtC,gCACEjC,IAAAzC,EAAK,sBAAL,gBAAAyC,EAAwB,0BACxBD,IAAAxC,EAAK,eAAL,gBAAAwC,EAAiB;AAAA,YAAA,CACpB;AAAA,UACH;AACA,UAAIxC,EAAK,WACP,KAAK,WAAW,aAAa,WAAW,EAAE,SAASA,EAAK,SAAS;AAAA,QACnE,OACK;AACL,gBAAM4E,IAAe,KAAK;AAAA,cACxBlC,IAAA1C,KAAA,gBAAAA,EAAM,UAAN,gBAAA0C,EAAa,YAAW;AAAA,UAAA,GAEpB+B,IAAkB,KAAK,MAAM,IAAA,EAAM;AACzC,eAAK,MAAM,WAAW;AAAA,YACpB,UAAU,CAAC,GAAGA,GAAiBG,CAAY;AAAA,UAAA,CAC5C;AAAA,QACH;AAAA,eACO3E,GAAO;AACd,QAAK,KAAK,2BAA2B,OAAO,WAClC,QAAA,MAAM,2BAA2BA,CAAK;AAAA,MAChD,UACA;AACA,aAAK,MAAM,WAAW,EAAE,kBAAkB,GAAO,CAAA;AAAA,MACnD;AAAA,IAAA,GAGM,KAAA,gBAAgB,CACtB4E,GACAC,MACoB;AACpB,YAAMC,KAAkB,MAAM;AAC5B,cAAM7B,IAAqB,KAAK,WAAW,MAAM,IAAM,EAAA;AAEvD,eACE,KAAK,MAAM,IAAI,EAAE,SAAS,WAAW,KACrCA,KACA,OAAO,KAAKA,CAAkB,EAAE,SAAS,IAMlC,GAJM,OAAO,QAAQA,CAAkB,EAC3C,OAAO,CAAC,CAAC8B,GAAGhG,CAAK,MAAM,CAAC,CAACA,CAAK,EAC9B,IAAI,CAAC,CAACD,GAAKC,CAAK,MAAM,GAAGD,CAAG,KAAKC,CAAK,EAAE,EACxC,KAAK;AAAA,CAAK,CACC;AAAA;AAAA,EAAQ6F,CAAO,KAGxBA;AAAA,MAAA;AAGF,aAAA;AAAA,QACL,IAAIvB,EAAQ;AAAA,QACZ,MAAM;AAAA,QACN,SAASyB;AAAA,QACT,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC,aAAAD;AAAA,QACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAAA;AAAA,IACpC,GAGM,KAAA,eAAe,CACrBG,MAC0B;;AACtB,aAAAA,EAAS,WAAWA,EAAS,oBACxB;AAAA,QACL,MAAM;AAAA,QACN,IAAIA,EAAS,kBAAkB,MAAM3B,EAAQ;AAAA,QAC7C,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC,WAAW;AAAA,QACX,OAAO,KAAK,OAAO,MACf;AAAA,UACE,MAAM,KAAK,OAAO,IAAI,QAAQ;AAAA,UAC9B,MAAM;AAAA,UACN,QAAQ,KAAK,OAAO,IAAI,UAAU;AAAA,UAClC,IAAI;AAAA,QAEN,IAAA;AAAA,QACJ,MAAM;AAAA,UACJ,SAAS2B,EAAS,kBAAkB,MAAM;AAAA,UAC1C,SAAQ9E,IAAA8E,EAAS,eAAT,QAAA9E,EAAqB,MAAM,OAC/B;AAAA,YACE,MAAM8E,EAAS,WAAW,MAAM;AAAA,YAChC,MAAMA,EAAS,WAAW,MAAM;AAAA,UAElC,IAAA;AAAA,QACN;AAAA,MAAA,IAIG;AAAA,IAAA,GAGD,KAAA,oBAAoB,CAACC,OACpB;AAAA,MACL,MAAM;AAAA,MACN,IAAI5B,EAAQ;AAAA,MACZ,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,WAAW;AAAA,MACX,MAAM;AAAA,QACJ,SAAA4B;AAAA,QACA,SAAS;AAAA,QACT,QAAQ;AAAA,MACV;AAAA,IAAA,IAjOF,KAAK,SAASxG,GACd,KAAK,MAAMyC,GACX,KAAK,aAAaC,GAClB,KAAK,aAAaqC;AAAA,EACpB;AAgOF;ACpQO,MAAM0B,EAAU;AAAA,EAQrB,YAAY;AAAA,IACV,QAAAzG;AAAA,IACA,YAAA+E;AAAA,IACA,YAAArC;AAAA,IACA,WAAAgE;AAAA,EAAA,GAMC;;AAgBH,SAAQ,0BAA0B,MAAM;AACtC,WAAK,WAAW,MAAM,UAAU,CAAC,EAAE,SAAAzB,QAAc;;AAE/C,QAAIA,KAAA,QAAAA,EAAS,SAAS,KAAK,MAAM,IAAI,EAAE,WAAW,aAChD,KAAK,MAAM,WAAW;AAAA,UACpB,SAAQxD,IAAA,KAAK,OAAO,WAAZ,QAAAA,EAAoB,iBAAiB,SAAS;AAAA,QAAA,CACvD;AAAA,MACH,CACD,GAED,KAAK,WAAW,cAAc;AAAA,QAC5B,CAAC,EAAE,uBAAAkF,GAAuB,MAAArF,QAAW;;AAEjC,eAAAG,IAAA,KAAK,OAAO,WAAZ,QAAAA,EAAoB;AAAA;AAAA,UAGpB,GAACC,IAAA,KAAK,WAAW,aAAa,IAAI,EAAE,YAAnC,QAAAA,EAA4C,KAC7C;AACA,kBAAMkF,KAA0BlD,IAAApC,EAAK,KAAK,CAAC+D,MAAMA,EAAE,QAAQ,MAA3B,gBAAA3B,EAA8B;AAC9D,mBAAOkD,IACH,KAAK,aAAaA,CAAuB,IACzC;AAAA,UACN;AAEA,UAAItF,EAAK,YACLqC,IAAA,KAAK,OAAO,WAAZ,gBAAAA,EAAoB,0BAAyB,MAG7C,CAACgD,KAAyB,KAAK,MAAM,IAAI,EAAE,WAAW,UACxD,KAAK,aAAa;AAAA,QAEtB;AAAA,MAAA;AAAA,IACF,GAGF,KAAA,mBAAmB,MAAM;AACvB,WAAK,UAAU,GACf,KAAK,MAAM,WAAW,EAAE,QAAQ,WAAY,CAAA;AAAA,IAAA,GAM9C,KAAA,eAAe,CAAClG,MAAuB;AAGrC,UAFA,KAAK,UAAU,GAEXA,GAAW;AACb,cAAMoC,IAAU,KAAK,WAAW,cAC7B,IAAI,EACJ,KAAK,KAAK,CAACwC,MAAMA,EAAE,OAAO5E,CAAS;AAEtC,YAAI,CAACoC,EAAS;AACd,aAAK,WAAW,aAAa,WAAW,EAAE,SAAAA,EAAS,CAAA;AAAA,MACrD;AAEA,WAAK,MAAM,WAAW,EAAE,QAAQ,OAAQ,CAAA;AAAA,IAAA,GAtExC,KAAK,SAAS7C,GACd,KAAK,aAAa+E,GAClB,KAAK,aAAarC,GAClB,KAAK,YAAYgE,GACZ,KAAA,QAAQ,IAAI/E,EAA4B;AAAA,MAC3C,QAAQ,KAAK,WAAW,sBACpB,aACAF,IAAA,KAAK,OAAO,WAAZ,QAAAA,EAAoB,iBAClB,SACA;AAAA,IAAA,CACP,GAED,KAAK,wBAAwB;AAAA,EAC/B;AA2DF;AC3GO,MAAMoF,EAAW;AAAA,EAOtB,YAAY,EAAE,SAAAC,KAAyC;AALvD,SAAQ,OAAO;AAAA,MACb,cAAc;AAAA,MACd,mBAAmB;AAAA,IAAA,GAOrB,KAAA,kBAAkB,OAAO7G,MAAkB;AACzC,YAAM,KAAK,QAAQ,IAAI,KAAK,KAAK,cAAcA,CAAK;AAAA,IAAA,GAEtD,KAAA,kBAAkB,YACT,KAAK,QAAQ,IAAI,KAAK,KAAK,YAAY,GAGhD,KAAA,uBAAuB,OAAO8G,MAAe;AAC3C,YAAM,KAAK,QAAQ,IAAI,KAAK,KAAK,mBAAmBA,CAAE;AAAA,IAAA,GAExD,KAAA,uBAAuB,YACd,KAAK,QAAQ,IAAI,KAAK,KAAK,iBAAiB,GAdnD,KAAK,UAAUD;AAAA,EACjB;AAeF;ACfO,MAAME,IAAN,MAAMA,EAAU;AAAA,EAiBb,YAAY;AAAA,IAClB,QAAAhH;AAAA,IACA,SAAA8G;AAAA,IACA,OAAAG;AAAA,EAAA,GAKC;AACG,QAjBN,KAAO,QAAmB,IAuF1B,KAAA,YAAY,MAAM;AAChB,WAAK,WAAW,SAChB,KAAK,WAAW;IAAM,GAxElB,CAACD,EAAU;AACP,YAAA;AAAA,QACJ;AAAA,MAAA;AAIJ,SAAK,SAAShH,GACd,KAAK,MAAM,IAAID,EAAU,EAAE,QAAAC,EAAQ,CAAA,GACnC,KAAK,aAAa8G,IAAU,IAAID,EAAW,EAAE,SAAAC,EAAS,CAAA,IAAI,QAC1D,KAAK,QAAQG,GAER,KAAA,aAAa,IAAIzD,EAAW;AAAA,MAC/B,KAAK,KAAK;AAAA,MACV,QAAQ,KAAK;AAAA,MACb,YAAY,KAAK;AAAA,IAAA,CAClB,GAEI,KAAA,aAAa,IAAIsB,EAAW;AAAA,MAC/B,KAAK,KAAK;AAAA,MACV,YAAY,KAAK;AAAA,MACjB,gCACEkC,EAAU,wBAAwB;AAAA,IAAA,CACrC,GAEI,KAAA,aAAa,IAAIxB,EAAW;AAAA,MAC/B,QAAQ,KAAK;AAAA,MACb,KAAK,KAAK;AAAA,MACV,YAAY,KAAK;AAAA,MACjB,YAAY,KAAK;AAAA,IAAA,CAClB,GAEI,KAAA,0BAA0B,IAAIhD,EAAwB;AAAA,MACzD,KAAK,KAAK;AAAA,MACV,QAAQ,KAAK;AAAA,MACb,YAAY,KAAK;AAAA,MACjB,YAAY,KAAK;AAAA,MACjB,+BAA+BwE,EAAU,wBAAwB;AAAA,IAAA,CAClE,GAEI,KAAA,YAAY,IAAIP,EAAU;AAAA,MAC7B,QAAQ,KAAK;AAAA,MACb,YAAY,KAAK;AAAA,MACjB,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,IAAA,CACjB;AAAA,EACH;AA6BF;AAzFEO,EAAe,0BAGJ,MA2DXA,EAAO,aAAa,OAAO;AAAA,EACzB,QAAAhH;AAAA,EACA,SAAA8G;AAAA,MAII;;AACE,QAAAI,IAAiB,MAAM,IAAInH,EAAU;AAAA,IACzC,QAAAC;AAAA,EAAA,CACD,EAAE,wBAAwB;AAE3B,SAAAgH,EAAK,0BAA0B;AAAA,IAC7B,WAASvF,IAAAyF,EAAe,SAAf,gBAAAzF,EAAqB,kCAAiC;AAAA,IAC/D,YAAUC,IAAAwF,EAAe,SAAf,gBAAAxF,EAAqB,mCAAkC;AAAA,EAAA,GAG5D,IAAIsF,EAAU;AAAA,IACnB,QAAAhH;AAAA,IACA,SAAA8G;AAAA,IACA,SAAOpD,IAAAwD,EAAe,SAAf,gBAAAxD,EAAqB,UAAS,CAAC;AAAA,EAAA,CACvC;AAAA;AA7FE,IAAMyD,IAANH;"}