@opencx/widget 3.0.27 → 3.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,27 +1,27 @@
1
- var F = Object.defineProperty;
2
- var I = (n) => {
1
+ var L = Object.defineProperty;
2
+ var M = (n) => {
3
3
  throw TypeError(n);
4
4
  };
5
- var L = (n, t, e) => t in n ? F(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
6
- var s = (n, t, e) => L(n, typeof t != "symbol" ? t + "" : t, e), M = (n, t, e) => t.has(n) || I("Cannot " + e);
7
- var h = (n, t, e) => (M(n, t, "read from private field"), e ? e.call(n) : t.get(n)), w = (n, t, e) => t.has(n) ? I("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(n) : t.set(n, e), p = (n, t, e, i) => (M(n, t, "write to private field"), i ? i.call(n, e) : t.set(n, e), e);
8
- import O from "axios";
9
- import T from "openapi-fetch";
10
- import E from "lodash.isequal";
11
- import { v4 as D } from "uuid";
12
- const _ = (n) => {
5
+ var O = (n, t, e) => t in n ? L(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
6
+ var s = (n, t, e) => O(n, typeof t != "symbol" ? t + "" : t, e), R = (n, t, e) => t.has(n) || M("Cannot " + e);
7
+ var h = (n, t, e) => (R(n, t, "read from private field"), e ? e.call(n) : t.get(n)), w = (n, t, e) => t.has(n) ? M("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(n) : t.set(n, e), p = (n, t, e, i) => (R(n, t, "write to private field"), i ? i.call(n, e) : t.set(n, e), e);
8
+ import T from "axios";
9
+ import E from "openapi-fetch";
10
+ import D from "lodash.isequal";
11
+ import { v4 as _ } from "uuid";
12
+ const B = (n) => {
13
13
  console.log(n.error);
14
- }, B = (n) => {
15
- const t = T({
14
+ }, q = (n) => {
15
+ const t = E({
16
16
  baseUrl: n.baseUrl
17
17
  }), e = {
18
18
  onRequest: n.onRequest,
19
19
  onResponse: n.onResponse,
20
- onError: n.onError || _
20
+ onError: n.onError || B
21
21
  };
22
22
  return t.use(e), t;
23
23
  };
24
- class q {
24
+ class H {
25
25
  constructor({
26
26
  config: t
27
27
  }) {
@@ -40,7 +40,7 @@ class q {
40
40
  s(this, "createOpenAPIClient", ({
41
41
  baseUrl: t,
42
42
  headers: e
43
- }) => B({
43
+ }) => q({
44
44
  baseUrl: t,
45
45
  onRequest: ({ request: i }) => {
46
46
  Object.entries(e).forEach(([a, r]) => {
@@ -51,7 +51,7 @@ class q {
51
51
  s(this, "createAxiosUploadClient", ({
52
52
  baseUrl: t,
53
53
  headers: e
54
- }) => O.create({
54
+ }) => T.create({
55
55
  baseURL: `${t}/backend/widget/v2/upload`,
56
56
  headers: e
57
57
  }));
@@ -181,7 +181,7 @@ class f {
181
181
  this.emitLifecycle("beforeUpdate", {
182
182
  previousState: h(this, c),
183
183
  nextState: t
184
- }), E(h(this, c), t) || (p(this, c, t), p(this, u, Date.now()), this.emitLifecycle("stateChange", { state: t }), this.notifySubscribers(t)), this.emitLifecycle("afterUpdate", { state: t });
184
+ }), D(h(this, c), t) || (p(this, c, t), p(this, u, Date.now()), this.emitLifecycle("stateChange", { state: t }), this.notifySubscribers(t)), this.emitLifecycle("afterUpdate", { state: t });
185
185
  });
186
186
  // TODO make this provide prev state
187
187
  s(this, "setPartial", (t) => {
@@ -206,7 +206,7 @@ class f {
206
206
  }
207
207
  }
208
208
  c = new WeakMap(), u = new WeakMap();
209
- class H {
209
+ class G {
210
210
  constructor({
211
211
  config: t,
212
212
  api: e
@@ -279,9 +279,9 @@ class v {
279
279
  }
280
280
  }
281
281
  function P() {
282
- return D();
282
+ return _();
283
283
  }
284
- class G {
284
+ class j {
285
285
  constructor({
286
286
  config: t,
287
287
  api: e,
@@ -381,7 +381,7 @@ class G {
381
381
  this.config = t, this.api = e, this.contactCtx = i, this.registerActiveSessionPolling(), this.registerInitialSessionsFetch();
382
382
  }
383
383
  }
384
- class j {
384
+ class N {
385
385
  constructor({
386
386
  config: t,
387
387
  api: e,
@@ -409,10 +409,11 @@ class j {
409
409
  });
410
410
  });
411
411
  s(this, "sendMessage", async (t) => {
412
- var a, r, o, g, C, m, y, x, A;
412
+ var r, o, g, C, m, y, x, A, U;
413
413
  this.sendMessageAbortController = new AbortController();
414
- const e = this.state.get().isSendingMessage, i = ((a = this.sessionCtx.sessionState.get().session) == null ? void 0 : a.assignee.kind) === "ai";
415
- if (e && i) {
414
+ const e = this.state.get().isSendingMessage, i = ((r = this.sessionCtx.sessionState.get().session) == null ? void 0 : r.assignee.kind) === "ai", a = this.state.get().messages.at(-1);
415
+ if (i && e || // If last message is from user, then bot response did not arrive yet
416
+ i && (a == null ? void 0 : a.type) === "FROM_USER") {
416
417
  console.warn("Cannot send messages while awaiting AI response");
417
418
  return;
418
419
  }
@@ -422,23 +423,23 @@ class j {
422
423
  const S = this.toUserMessage(
423
424
  t.content,
424
425
  t.attachments || void 0
425
- ), R = this.state.get().messages;
426
+ ), k = this.state.get().messages;
426
427
  if (this.state.setPartial({
427
- messages: [...R, S]
428
- }), !((r = this.sessionCtx.sessionState.get().session) != null && r.id) && !await this.sessionCtx.createSession()) {
428
+ messages: [...k, S]
429
+ }), !((o = this.sessionCtx.sessionState.get().session) != null && o.id) && !await this.sessionCtx.createSession()) {
429
430
  console.error("Failed to create session");
430
431
  return;
431
432
  }
432
- const U = (o = this.sessionCtx.sessionState.get().session) == null ? void 0 : o.id;
433
- if (!U) return;
433
+ const I = (g = this.sessionCtx.sessionState.get().session) == null ? void 0 : g.id;
434
+ if (!I) return;
434
435
  const { data: l } = await this.api.sendMessage(
435
436
  {
436
437
  uuid: S.id,
437
438
  bot_token: this.config.token,
438
439
  headers: this.config.headers,
439
440
  query_params: this.config.queryParams,
440
- session_id: U,
441
- user: (g = this.config.user) == null ? void 0 : g.data,
441
+ session_id: I,
442
+ user: (C = this.config.user) == null ? void 0 : C.data,
442
443
  ...t
443
444
  },
444
445
  this.sendMessageAbortController.signal
@@ -448,21 +449,21 @@ class j {
448
449
  if (d) {
449
450
  const b = this.state.get().messages;
450
451
  if (!!b.some(
451
- (k) => k.id === d.id
452
+ (F) => F.id === d.id
452
453
  )) {
453
454
  this.state.setPartial({
454
- lastAIResMightSolveUserIssue: ((C = l.autopilotResponse) == null ? void 0 : C.mightSolveUserIssue) || ((m = l.uiResponse) == null ? void 0 : m.mightSolveUserIssue)
455
+ lastAIResMightSolveUserIssue: ((m = l.autopilotResponse) == null ? void 0 : m.mightSolveUserIssue) || ((y = l.uiResponse) == null ? void 0 : y.mightSolveUserIssue)
455
456
  });
456
457
  return;
457
458
  }
458
459
  this.state.setPartial({
459
460
  messages: [...b, d],
460
- lastAIResMightSolveUserIssue: ((y = l.autopilotResponse) == null ? void 0 : y.mightSolveUserIssue) || ((x = l.uiResponse) == null ? void 0 : x.mightSolveUserIssue)
461
+ lastAIResMightSolveUserIssue: ((x = l.autopilotResponse) == null ? void 0 : x.mightSolveUserIssue) || ((A = l.uiResponse) == null ? void 0 : A.mightSolveUserIssue)
461
462
  });
462
463
  }
463
464
  } else {
464
465
  const d = this.toBotErrorMessage(
465
- ((A = l == null ? void 0 : l.error) == null ? void 0 : A.message) || "Unknown error occurred"
466
+ ((U = l == null ? void 0 : l.error) == null ? void 0 : U.message) || "Unknown error occurred"
466
467
  ), b = this.state.get().messages;
467
468
  this.state.setPartial({
468
469
  messages: [...b, d]
@@ -583,7 +584,7 @@ class j {
583
584
  this.config = t, this.api = e, this.sessionCtx = i, this.registerPolling();
584
585
  }
585
586
  }
586
- class N {
587
+ class X {
587
588
  constructor({
588
589
  contactCtx: t,
589
590
  sessionCtx: e,
@@ -617,7 +618,7 @@ class N {
617
618
  }), this.contactCtx = t, this.sessionCtx = e, this.resetChat = i, this.registerRoutingListener();
618
619
  }
619
620
  }
620
- class Q {
621
+ class V {
621
622
  constructor({ config: t }) {
622
623
  s(this, "config");
623
624
  s(this, "api");
@@ -628,18 +629,18 @@ class Q {
628
629
  s(this, "resetChat", () => {
629
630
  this.sessionCtx.reset(), this.messageCtx.reset();
630
631
  });
631
- this.config = t, this.api = new q({ config: t }), this.contactCtx = new H({
632
+ this.config = t, this.api = new H({ config: t }), this.contactCtx = new G({
632
633
  api: this.api,
633
634
  config: this.config
634
- }), this.sessionCtx = new G({
635
+ }), this.sessionCtx = new j({
635
636
  config: this.config,
636
637
  api: this.api,
637
638
  contactCtx: this.contactCtx
638
- }), this.messageCtx = new j({
639
+ }), this.messageCtx = new N({
639
640
  config: this.config,
640
641
  api: this.api,
641
642
  sessionCtx: this.sessionCtx
642
- }), this.routerCtx = new N({
643
+ }), this.routerCtx = new X({
643
644
  contactCtx: this.contactCtx,
644
645
  sessionCtx: this.sessionCtx,
645
646
  resetChat: this.resetChat
@@ -648,6 +649,6 @@ class Q {
648
649
  }
649
650
  export {
650
651
  f as P,
651
- Q as W
652
+ V as W
652
653
  };
653
- //# sourceMappingURL=widget.ctx-BEmMe_Pd.js.map
654
+ //# sourceMappingURL=widget.ctx-D5QEquB0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget.ctx-D5QEquB0.js","sources":["../src/headless/core/sdk/index.ts","../src/headless/core/api.ts","../src/headless/core/utils/PrimitiveState.ts","../src/headless/core/context/contact.ctx.ts","../src/headless/core/utils/Poller.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/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 axios, { type AxiosInstance, type AxiosRequestConfig } from \"axios\";\nimport { type Dto, type Endpoint, basicClient } from \"./sdk\";\nimport type { WidgetConfig } from \"./types/WidgetConfig\";\nimport type { SendMessageDto, VoteInputDto } from \"./types/schemas\";\n\nexport class ApiCaller {\n private client: ReturnType<typeof basicClient>;\n private uploadFileClient: AxiosInstance;\n private config: WidgetConfig;\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 this.uploadFileClient = this.createAxiosUploadClient({ baseUrl, headers });\n }\n\n private constructClientOptions = (token: string | null | undefined) => {\n const baseUrl = 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 private createAxiosUploadClient = ({\n baseUrl,\n headers,\n }: ReturnType<typeof this.constructClientOptions>) => {\n const uploadPath = \"/backend/widget/v2/upload\" satisfies Endpoint;\n return axios.create({\n baseURL: `${baseUrl}${uploadPath}`,\n headers,\n });\n };\n\n setAuthToken = (token: string) => {\n const { baseUrl, headers } = this.constructClientOptions(token);\n this.client = this.createOpenAPIClient({ baseUrl, headers });\n this.uploadFileClient = this.createAxiosUploadClient({ baseUrl, headers });\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 getSessionHistory = 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(\n \"/backend/widget/v2/session/history/{sessionId}\",\n { params: { path: { sessionId }, query }, 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[\"CreateWidgetChatSessionDto\"]) => {\n return await this.client.POST(\"/backend/widget/v2/create-session\", {\n body,\n });\n };\n\n getSession = async ({\n sessionId,\n abortSignal,\n }: { sessionId: string; abortSignal: AbortSignal }) => {\n return await this.client.GET(\"/backend/widget/v2/session/{sessionId}\", {\n params: { path: { sessionId } },\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 uploadFile = async (\n file: {\n id: string;\n file: File;\n },\n config: Partial<AxiosRequestConfig> = {},\n ) => {\n const formData = new FormData();\n formData.append(\"file\", file.file);\n\n // Couldn't get this to work with the openapi client... dunno why...\n const { data } = await this.uploadFileClient.post<\n Dto[\"UploadWidgetFileResponseDto\"]\n >(\"\", formData, {\n headers: {\n \"Content-Type\": \"multipart/form-data\",\n },\n ...config,\n });\n return data;\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 enum LifecycleEvent {\n INIT = \"init\",\n STATE_CHANGE = \"stateChange\",\n BEFORE_UPDATE = \"beforeUpdate\",\n AFTER_UPDATE = \"afterUpdate\",\n DESTROY = \"destroy\",\n ERROR = \"error\",\n}\n\ntype LifecycleListener = (event: {\n type: LifecycleEvent;\n timestamp: number;\n data?: any;\n}) => void;\n\nexport class PrimitiveState<S> {\n private subscribers = new Set<Subscriber<S>>();\n #state: S;\n private initialState: S;\n #lastUpdated: number | null;\n private lifecycleListeners: Map<LifecycleEvent, Set<LifecycleListener>> =\n new Map();\n\n constructor(state: S) {\n this.#state = state;\n this.initialState = state;\n this.#lastUpdated = Date.now();\n this.emitLifecycle(LifecycleEvent.INIT, { initialState: this.#state });\n }\n\n private emitLifecycle = (event: LifecycleEvent, data?: any) => {\n const listeners = this.lifecycleListeners.get(event);\n if (listeners) {\n const eventData = {\n type: event,\n timestamp: Date.now(),\n data,\n };\n listeners.forEach((listener) => {\n try {\n listener(eventData);\n } catch {\n // ignore error\n }\n });\n }\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 this.emitLifecycle(LifecycleEvent.ERROR, { error });\n }\n });\n };\n\n /**\n * Subscribe to state changes\n * @param callback Function to call when state changes\n * @returns Unsubscribe function\n */\n subscribe = (callback: Subscriber<S>): (() => void) => {\n this.subscribers.add(callback);\n // Don't call the callback immediately with current state\n return () => {\n this.subscribers.delete(callback);\n };\n };\n\n onLifecycle = (\n event: LifecycleEvent,\n listener: LifecycleListener,\n ): (() => void) => {\n if (!this.lifecycleListeners.has(event)) {\n this.lifecycleListeners.set(event, new Set());\n }\n const listeners = this.lifecycleListeners.get(event)!;\n listeners.add(listener);\n\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0) {\n this.lifecycleListeners.delete(event);\n }\n };\n };\n\n /** Get the current state */\n get = (): S => {\n return this.#state;\n };\n\n // TODO make this provide prev state\n /**\n * Set the state and notify subscribers if the state changes\n * @param newState The new state to set\n */\n set = (newState: S): void => {\n this.emitLifecycle(LifecycleEvent.BEFORE_UPDATE, {\n previousState: this.#state,\n nextState: newState,\n });\n\n if (!isEqual(this.#state, newState)) {\n this.#state = newState;\n this.#lastUpdated = Date.now();\n this.emitLifecycle(LifecycleEvent.STATE_CHANGE, { state: newState });\n this.notifySubscribers(newState);\n }\n\n this.emitLifecycle(LifecycleEvent.AFTER_UPDATE, { state: newState });\n };\n\n // TODO make this provide prev state\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 /**\n * Clear all subscriptions\n */\n clear = (): void => {\n this.emitLifecycle(LifecycleEvent.DESTROY);\n this.subscribers = new Set(); // Create a new Set instead of just clearing\n this.lifecycleListeners = new Map();\n };\n\n reset = (): void => {\n this.set(this.initialState);\n };\n\n lastUpdated = (): number | null => {\n return this.#lastUpdated;\n };\n}\n","import { PrimitiveState } from \"../utils/PrimitiveState\";\nimport { ApiCaller } from \"../api\";\nimport { type WidgetConfig } from \"../types/WidgetConfig\";\nimport { type Dto } from \"../sdk\";\n\ntype ContactState = {\n contact: { token: string } | null;\n isCreatingUnverifiedContact: boolean;\n isErrorCreatingUnverifiedContact: boolean;\n};\n\nexport class ContactCtx {\n private config: WidgetConfig;\n private api: ApiCaller;\n state: PrimitiveState<ContactState>;\n\n constructor({\n config,\n api,\n }: {\n api: ApiCaller;\n config: WidgetConfig;\n }) {\n this.config = config;\n this.api = api;\n\n this.state = new PrimitiveState<ContactState>({\n contact: config.user?.token ? { token: config.user?.token } : null,\n isCreatingUnverifiedContact: false,\n isErrorCreatingUnverifiedContact: false,\n });\n\n if (!config.user?.token && !config.collectUserData) {\n this.autoCreateUnverifiedUser();\n }\n }\n\n shouldCollectData = (): boolean => {\n const currentState = this.state.get();\n\n if (!currentState.contact?.token && this.config.collectUserData) {\n return true;\n } else {\n return false;\n }\n };\n\n private autoCreateUnverifiedUser = async () => {\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 ): Promise<void> => {\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 this.api.setAuthToken(data.token);\n // Set token in state after setting the token in the api handler\n this.state.setPartial({ contact: { token: data.token } });\n } else {\n this.state.setPartial({ isErrorCreatingUnverifiedContact: true });\n }\n } finally {\n this.state.setPartial({ isCreatingUnverifiedContact: false });\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 stopPolling: (() => void) | null = null;\n\n startPolling = (\n cb: (abortSignal: AbortSignal) => Promise<void>,\n interval: 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 } else {\n console.error(\"Failed to poll:\", error);\n this.state.setPartial({ isError: true });\n }\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, interval));\n }\n };\n\n poll();\n\n this.stopPolling = () => {\n timeouts.forEach(clearTimeout);\n this.state.reset();\n };\n };\n}\n","import { v4 as uuidv4 } from \"uuid\";\n\nexport function genUuid() {\n return uuidv4();\n}\n","import type { ApiCaller } from \"../api\";\nimport type { SessionDto } from \"../types/schemas\";\nimport type { WidgetConfig } from \"../types/WidgetConfig\";\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 config: WidgetConfig;\n private api: ApiCaller;\n private contactCtx: ContactCtx;\n private activeSessionPoller = new Poller();\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 config,\n api,\n contactCtx,\n }: { config: WidgetConfig; api: ApiCaller; contactCtx: ContactCtx }) {\n this.config = config;\n this.api = api;\n this.contactCtx = contactCtx;\n\n this.registerActiveSessionPolling();\n this.registerInitialSessionsFetch();\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 // The poller should automatically reset, since we're subscribed to the session state, and whenever it's null, the poller resets... but just in case, let's reset it here as well\n this.activeSessionPoller.reset();\n };\n\n private registerActiveSessionPolling = () => {\n this.sessionState.subscribe(({ session }) => {\n if (session?.id) {\n this.activeSessionPoller.startPolling(async (abortSignal) => {\n const { data } = await this.api.getSession({\n sessionId: session.id,\n abortSignal,\n });\n data && this.sessionState.setPartial({ session: data });\n }, 1000);\n } else {\n this.activeSessionPoller.reset();\n }\n });\n };\n\n private registerInitialSessionsFetch = () => {\n const initialFetch = async () => {\n this.sessionsState.setPartial({ didStartInitialFetch: true });\n // Call this for the first time to get the first page of sessions\n await this.loadMoreSessions();\n this.sessionsState.setPartial({ isInitialFetchLoading: false });\n };\n\n // If the widget config was initially provided with a contact token, no state change would be triggered, so we just fetch\n if (\n this.contactCtx.state.get().contact?.token &&\n !this.sessionsState.get().didStartInitialFetch\n ) {\n initialFetch();\n this.registerSessionsRefresher();\n }\n\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 initialFetch();\n this.registerSessionsRefresher();\n }\n });\n };\n\n private registerSessionsRefresher = () => {\n this.sessionsRefresher.startPolling(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 }, 10000);\n };\n\n createSession = async () => {\n this.sessionState.setPartial({ session: null, isCreatingSession: true });\n\n const { data: session, error } = await this.api.createSession({\n customData: this.config.user?.externalId\n ? {\n external_id: this.config.user?.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 /**\n * Let's keep this private for now until we figure out how to do paginated fetching in tandem with the interval refreshing\n */\n private 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 return await this.api.getSessions({\n cursor,\n filters: this.config.user?.externalId\n ? {\n external_id: this.config.user.externalId,\n }\n : {},\n });\n };\n}\n","import { ApiCaller } from \"../api\";\nimport type { WidgetConfig } from \"../types/WidgetConfig\";\nimport type { SafeOmit, SomeOptional } from \"../types/helpers\";\nimport type {\n BotMessageType,\n MessageType,\n UserMessageType,\n} from \"../types/messages\";\nimport type {\n MessageAttachmentType,\n MessageDto,\n SendMessageDto,\n SendMessageOutputDto,\n} from \"../types/schemas\";\nimport { Poller } from \"../utils/Poller\";\nimport { PrimitiveState } from \"../utils/PrimitiveState\";\nimport { genUuid } from \"../utils/uuid\";\nimport { SessionCtx } from \"./session.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 sessionCtx: SessionCtx;\n private poller = new Poller();\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 }: { config: WidgetConfig; api: ApiCaller; sessionCtx: SessionCtx }) {\n this.config = config;\n this.api = api;\n this.sessionCtx = sessionCtx;\n\n this.registerPolling();\n }\n\n reset = () => {\n this.sendMessageAbortController.abort(\"Resetting chat\");\n this.state.reset();\n // The poller should automatically reset, since we're subscribed to the session state, and whenever it's null, the poller resets... but just in case, let's reset it here as well\n this.poller.reset();\n };\n\n private registerPolling = () => {\n this.sessionCtx.sessionState.subscribe(({ session }) => {\n if (session?.id) {\n this.poller.startPolling(async (abortSignal) => {\n await this.fetchAndSetHistory(session.id, abortSignal);\n }, 1000);\n } else {\n this.poller.reset();\n }\n });\n };\n\n sendMessage = async (\n input: SomeOptional<\n SafeOmit<SendMessageDto, \"bot_token\" | \"uuid\">,\n \"session_id\" | \"user\"\n >,\n ): Promise<void> => {\n this.sendMessageAbortController = new AbortController();\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 lastMessage = this.state.get().messages.at(-1);\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 /* ------------------------------------------------------ */\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,\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 const sessionId = this.sessionCtx.sessionState.get().session?.id;\n if (!sessionId) return;\n\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 ...input,\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 fetchAndSetHistory = 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.state.get().messages.length === 0) {\n this.state.setPartial({ isInitialFetchLoading: true });\n }\n\n const lastMessageTimestamp = this.state.get().messages.at(-1)?.timestamp;\n\n const { data: response } = await this.api.getSessionHistory({\n sessionId,\n lastMessageTimestamp,\n abortSignal,\n });\n\n if (response && response.length > 0) {\n // Get a fresh reference to current messages after the poll is done\n const prevMessages = this.state.get().messages;\n const newMessages = response\n .map(this.mapHistoryToMessage)\n .filter(\n (newMsg) =>\n !prevMessages.some((existingMsg) => existingMsg.id === newMsg.id),\n );\n this.state.setPartial({\n messages: [...prevMessages, ...newMessages],\n });\n }\n\n if (this.state.get().isInitialFetchLoading) {\n this.state.setPartial({ isInitialFetchLoading: false });\n }\n };\n\n /** Not the best name but whatever */\n private 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 = history.actionCalls?.at(-1);\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 ? { name: action.actionName, data: action.result }\n : undefined,\n },\n };\n };\n\n private toUserMessage = (\n content: string,\n attachments?: MessageAttachmentType[],\n ): UserMessageType => {\n return {\n id: genUuid(),\n type: \"FROM_USER\",\n content,\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 { 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 contactCtx: ContactCtx;\n private sessionCtx: SessionCtx;\n private resetChat: WidgetCtx[\"resetChat\"];\n\n constructor({\n contactCtx,\n sessionCtx,\n resetChat,\n }: {\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.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\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 { ApiCaller } from \"../api\";\nimport type { WidgetConfig } from \"../types/WidgetConfig\";\nimport { ContactCtx } from \"./contact.ctx\";\nimport { MessageCtx } from \"./message.ctx\";\nimport { RouterCtx } from \"./router.ctx\";\nimport { SessionCtx } from \"./session.ctx\";\n\nexport class WidgetCtx {\n public config: WidgetConfig;\n public api: ApiCaller;\n public contactCtx: ContactCtx;\n public sessionCtx: SessionCtx;\n public messageCtx: MessageCtx;\n public routerCtx: RouterCtx;\n\n constructor({ config }: { config: WidgetConfig }) {\n this.config = config;\n this.api = new ApiCaller({ config });\n\n this.contactCtx = new ContactCtx({\n api: this.api,\n config: this.config,\n });\n\n this.sessionCtx = new SessionCtx({\n config: this.config,\n api: this.api,\n contactCtx: this.contactCtx,\n });\n\n this.messageCtx = new MessageCtx({\n config: this.config,\n api: this.api,\n sessionCtx: this.sessionCtx,\n });\n\n this.routerCtx = new RouterCtx({\n contactCtx: this.contactCtx,\n sessionCtx: this.sessionCtx,\n resetChat: this.resetChat,\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","__publicField","token","baseUrl","headers","request","key","value","axios","body","abortSignal","sessionId","lastMessageTimestamp","query","cursor","filters","file","formData","data","_a","PrimitiveState","state","__privateAdd","_state","_lastUpdated","event","listeners","eventData","listener","callback","error","__privateGet","newState","isEqual","__privateSet","_s","ContactCtx","api","_b","_d","_c","payload","Poller","cb","interval","timeouts","poll","genUuid","uuidv4","SessionCtx","contactCtx","session","initialFetch","contact","sessions","s","i","self","deduped","MessageCtx","sessionCtx","input","isSending","isAssignedToAI","lastMessage","userMessage","currentMessages","botMessage","prevMessages","m","_e","_f","_g","_h","errorMessage","_i","response","newMessages","newMsg","existingMsg","history","commonFields","action","content","attachments","message","RouterCtx","resetChat","WidgetCtx"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";var F=Object.defineProperty;var I=n=>{throw TypeError(n)};var L=(n,t,e)=>t in n?F(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var s=(n,t,e)=>L(n,typeof t!="symbol"?t+"":t,e),M=(n,t,e)=>t.has(n)||I("Cannot "+e);var h=(n,t,e)=>(M(n,t,"read from private field"),e?e.call(n):t.get(n)),w=(n,t,e)=>t.has(n)?I("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(n):t.set(n,e),p=(n,t,e,i)=>(M(n,t,"write to private field"),i?i.call(n,e):t.set(n,e),e);const O=require("axios"),T=require("openapi-fetch"),E=require("lodash.isequal"),D=require("uuid"),q=n=>{console.log(n.error)},_=n=>{const t=T({baseUrl:n.baseUrl}),e={onRequest:n.onRequest,onResponse:n.onResponse,onError:n.onError||q};return t.use(e),t};class B{constructor({config:t}){s(this,"client");s(this,"uploadFileClient");s(this,"config");s(this,"constructClientOptions",t=>{const e=this.config.apiUrl||"https://api.open.cx",i={"X-Bot-Token":this.config.token,"Content-Type":"application/json",Accept:"application/json",Authorization:t?`Bearer ${t}`:void 0};return{baseUrl:e,headers:i}});s(this,"createOpenAPIClient",({baseUrl:t,headers:e})=>_({baseUrl:t,onRequest:({request:i})=>{Object.entries(e).forEach(([a,r])=>{r&&i.headers.set(a,r)})}}));s(this,"createAxiosUploadClient",({baseUrl:t,headers:e})=>O.create({baseURL:`${t}/backend/widget/v2/upload`,headers:e}));s(this,"setAuthToken",t=>{const{baseUrl:e,headers:i}=this.constructClientOptions(t);this.client=this.createOpenAPIClient({baseUrl:e,headers:i}),this.uploadFileClient=this.createAxiosUploadClient({baseUrl:e,headers:i})});s(this,"widgetPrelude",async()=>await this.client.GET("/backend/widget/v2/prelude",{params:{header:{"X-Bot-Token":this.config.token}}}));s(this,"sendMessage",async(t,e)=>await this.client.POST("/backend/widget/v2/chat/send",{body:t,signal:e}));s(this,"getSessionHistory",async({sessionId:t,lastMessageTimestamp:e,abortSignal:i})=>{const a=e?{lastMessageTimestamp:e}:void 0;return await this.client.GET("/backend/widget/v2/session/history/{sessionId}",{params:{path:{sessionId:t},query:a},signal:i})});s(this,"createUnverifiedContact",async t=>await this.client.POST("/backend/widget/v2/contact/create-unverified",{params:{header:{"x-bot-token":this.config.token}},body:t}));s(this,"createSession",async t=>await this.client.POST("/backend/widget/v2/create-session",{body:t}));s(this,"getSession",async({sessionId:t,abortSignal:e})=>await this.client.GET("/backend/widget/v2/session/{sessionId}",{params:{path:{sessionId:t}},signal:e}));s(this,"getSessions",async({cursor:t,filters:e,abortSignal:i})=>await this.client.GET("/backend/widget/v2/sessions",{params:{query:{cursor:t,filters:JSON.stringify(e)}},signal:i}));s(this,"uploadFile",async(t,e={})=>{const i=new FormData;i.append("file",t.file);const{data:a}=await this.uploadFileClient.post("",i,{headers:{"Content-Type":"multipart/form-data"},...e});return a});s(this,"vote",async t=>await this.client.POST("/backend/widget/v2/chat/vote",{body:t}));var a;this.config=t;const{baseUrl:e,headers:i}=this.constructClientOptions((a=t.user)==null?void 0:a.token);this.client=this.createOpenAPIClient({baseUrl:e,headers:i}),this.uploadFileClient=this.createAxiosUploadClient({baseUrl:e,headers:i})}}var c,f;class g{constructor(t){s(this,"subscribers",new Set);w(this,c);s(this,"initialState");w(this,f);s(this,"lifecycleListeners",new Map);s(this,"emitLifecycle",(t,e)=>{const i=this.lifecycleListeners.get(t);if(i){const a={type:t,timestamp:Date.now(),data:e};i.forEach(r=>{try{r(a)}catch{}})}});s(this,"notifySubscribers",t=>{Array.from(this.subscribers).forEach(i=>{try{i(t)}catch(a){this.emitLifecycle("error",{error:a})}})});s(this,"subscribe",t=>(this.subscribers.add(t),()=>{this.subscribers.delete(t)}));s(this,"onLifecycle",(t,e)=>{this.lifecycleListeners.has(t)||this.lifecycleListeners.set(t,new Set);const i=this.lifecycleListeners.get(t);return i.add(e),()=>{i.delete(e),i.size===0&&this.lifecycleListeners.delete(t)}});s(this,"get",()=>h(this,c));s(this,"set",t=>{this.emitLifecycle("beforeUpdate",{previousState:h(this,c),nextState:t}),E(h(this,c),t)||(p(this,c,t),p(this,f,Date.now()),this.emitLifecycle("stateChange",{state:t}),this.notifySubscribers(t)),this.emitLifecycle("afterUpdate",{state:t})});s(this,"setPartial",t=>{if(t==null)return;const e={...h(this,c),...t};this.set(e)});s(this,"clear",()=>{this.emitLifecycle("destroy"),this.subscribers=new Set,this.lifecycleListeners=new Map});s(this,"reset",()=>{this.set(this.initialState)});s(this,"lastUpdated",()=>h(this,f));p(this,c,t),this.initialState=t,p(this,f,Date.now()),this.emitLifecycle("init",{initialState:h(this,c)})}}c=new WeakMap,f=new WeakMap;class H{constructor({config:t,api:e}){s(this,"config");s(this,"api");s(this,"state");s(this,"shouldCollectData",()=>{var e;return!!(!((e=this.state.get().contact)!=null&&e.token)&&this.config.collectUserData)});s(this,"autoCreateUnverifiedUser",async()=>{var t,e,i,a;await this.createUnverifiedContact({name:((e=(t=this.config.user)==null?void 0:t.data)==null?void 0:e.name)||"Anonymous",email:(a=(i=this.config.user)==null?void 0:i.data)==null?void 0:a.email})});s(this,"createUnverifiedContact",async t=>{try{this.state.setPartial({isCreatingUnverifiedContact:!0,isErrorCreatingUnverifiedContact:!1});const{data:e}=await this.api.createUnverifiedContact(t);e!=null&&e.token?(this.api.setAuthToken(e.token),this.state.setPartial({contact:{token:e.token}})):this.state.setPartial({isErrorCreatingUnverifiedContact:!0})}finally{this.state.setPartial({isCreatingUnverifiedContact:!1})}});var i,a,r;this.config=t,this.api=e,this.state=new g({contact:(i=t.user)!=null&&i.token?{token:(a=t.user)==null?void 0:a.token}:null,isCreatingUnverifiedContact:!1,isErrorCreatingUnverifiedContact:!1}),!((r=t.user)!=null&&r.token)&&!t.collectUserData&&this.autoCreateUnverifiedUser()}}class v{constructor(){s(this,"state",new g({isPolling:!1,isError:!1}));s(this,"abortController",new AbortController);s(this,"reset",()=>{var t;this.abortController.abort("Resetting poller"),(t=this.stopPolling)==null||t.call(this),this.stopPolling=null});s(this,"stopPolling",null);s(this,"startPolling",(t,e)=>{if(this.stopPolling)return;const i=[],a=async()=>{this.abortController=new AbortController,this.state.setPartial({isPolling:!0});try{await t(this.abortController.signal)}catch(r){if(this.abortController.signal.aborted)return;console.error("Failed to poll:",r),this.state.setPartial({isError:!0})}finally{this.state.setPartial({isPolling:!1})}this.abortController.signal.aborted?console.log("Poller aborted, not scheduling anymore"):i.push(setTimeout(a,e))};a(),this.stopPolling=()=>{i.forEach(clearTimeout),this.state.reset()}})}}function P(){return D.v4()}class G{constructor({config:t,api:e,contactCtx:i}){s(this,"config");s(this,"api");s(this,"contactCtx");s(this,"activeSessionPoller",new v);s(this,"sessionsRefresher",new v);s(this,"sessionState",new g({session:null,isCreatingSession:!1}));s(this,"sessionsState",new g({data:[],cursor:void 0,isLastPage:!1,didStartInitialFetch:!1,isInitialFetchLoading:!0}));s(this,"reset",async()=>{this.sessionState.reset(),this.activeSessionPoller.reset()});s(this,"registerActiveSessionPolling",()=>{this.sessionState.subscribe(({session:t})=>{t!=null&&t.id?this.activeSessionPoller.startPolling(async e=>{const{data:i}=await this.api.getSession({sessionId:t.id,abortSignal:e});i&&this.sessionState.setPartial({session:i})},1e3):this.activeSessionPoller.reset()})});s(this,"registerInitialSessionsFetch",()=>{var e;const t=async()=>{this.sessionsState.setPartial({didStartInitialFetch:!0}),await this.loadMoreSessions(),this.sessionsState.setPartial({isInitialFetchLoading:!1})};(e=this.contactCtx.state.get().contact)!=null&&e.token&&!this.sessionsState.get().didStartInitialFetch&&(t(),this.registerSessionsRefresher()),this.contactCtx.state.subscribe(({contact:i})=>{i!=null&&i.token&&!this.sessionsState.get().didStartInitialFetch&&(t(),this.registerSessionsRefresher())})});s(this,"registerSessionsRefresher",()=>{this.sessionsRefresher.startPolling(async()=>{const{data:t}=await this.getSessions({cursor:void 0});if(!t)return;const e=[...t.items,...this.sessionsState.get().data].filter((i,a,r)=>a===r.findIndex(o=>i.id===o.id));this.sessionsState.setPartial({data:e})},1e4)});s(this,"createSession",async()=>{var i,a;this.sessionState.setPartial({session:null,isCreatingSession:!0});const{data:t,error:e}=await this.api.createSession({customData:(i=this.config.user)!=null&&i.externalId?{external_id:(a=this.config.user)==null?void 0:a.externalId}:void 0});return t?(this.sessionState.setPartial({session:t,isCreatingSession:!1}),t):(console.error("Failed to create session:",e),null)});s(this,"loadMoreSessions",async()=>{if(this.sessionsState.get().isLastPage)return;const{data:t}=await this.getSessions({cursor:this.sessionsState.get().cursor});if(t){const i=[...this.sessionsState.get().data,...t.items].filter((a,r,o)=>r===o.findIndex(d=>a.id===d.id));this.sessionsState.setPartial({data:i,cursor:t.next||void 0,isLastPage:t.next===null})}});s(this,"getSessions",async({cursor:t})=>{var e,i;return(e=this.contactCtx.state.get().contact)!=null&&e.token?await this.api.getSessions({cursor:t,filters:(i=this.config.user)!=null&&i.externalId?{external_id:this.config.user.externalId}:{}}):{data:null}});this.config=t,this.api=e,this.contactCtx=i,this.registerActiveSessionPolling(),this.registerInitialSessionsFetch()}}class j{constructor({config:t,api:e,sessionCtx:i}){s(this,"config");s(this,"api");s(this,"sessionCtx");s(this,"poller",new v);s(this,"state",new g({messages:[],isSendingMessage:!1,lastAIResMightSolveUserIssue:!1,isInitialFetchLoading:!1}));s(this,"sendMessageAbortController",new AbortController);s(this,"reset",()=>{this.sendMessageAbortController.abort("Resetting chat"),this.state.reset(),this.poller.reset()});s(this,"registerPolling",()=>{this.sessionCtx.sessionState.subscribe(({session:t})=>{t!=null&&t.id?this.poller.startPolling(async e=>{await this.fetchAndSetHistory(t.id,e)},1e3):this.poller.reset()})});s(this,"sendMessage",async t=>{var a,r,o,d,C,S,y,x,A;this.sendMessageAbortController=new AbortController;const e=this.state.get().isSendingMessage,i=((a=this.sessionCtx.sessionState.get().session)==null?void 0:a.assignee.kind)==="ai";if(e&&i){console.warn("Cannot send messages while awaiting AI response");return}this.state.setPartial({lastAIResMightSolveUserIssue:!1});try{this.state.setPartial({isSendingMessage:!0});const m=this.toUserMessage(t.content,t.attachments||void 0),R=this.state.get().messages;if(this.state.setPartial({messages:[...R,m]}),!((r=this.sessionCtx.sessionState.get().session)!=null&&r.id)&&!await this.sessionCtx.createSession()){console.error("Failed to create session");return}const U=(o=this.sessionCtx.sessionState.get().session)==null?void 0:o.id;if(!U)return;const{data:l}=await this.api.sendMessage({uuid:m.id,bot_token:this.config.token,headers:this.config.headers,query_params:this.config.queryParams,session_id:U,user:(d=this.config.user)==null?void 0:d.data,...t},this.sendMessageAbortController.signal);if(l!=null&&l.success){const u=this.toBotMessage(l);if(u){const b=this.state.get().messages;if(!!b.some(k=>k.id===u.id)){this.state.setPartial({lastAIResMightSolveUserIssue:((C=l.autopilotResponse)==null?void 0:C.mightSolveUserIssue)||((S=l.uiResponse)==null?void 0:S.mightSolveUserIssue)});return}this.state.setPartial({messages:[...b,u],lastAIResMightSolveUserIssue:((y=l.autopilotResponse)==null?void 0:y.mightSolveUserIssue)||((x=l.uiResponse)==null?void 0:x.mightSolveUserIssue)})}}else{const u=this.toBotErrorMessage(((A=l==null?void 0:l.error)==null?void 0:A.message)||"Unknown error occurred"),b=this.state.get().messages;this.state.setPartial({messages:[...b,u]})}}catch(m){this.sendMessageAbortController.signal.aborted||console.error("Failed to send message:",m)}finally{this.state.setPartial({isSendingMessage:!1})}});s(this,"fetchAndSetHistory",async(t,e)=>{var r;this.state.get().messages.length===0&&this.state.setPartial({isInitialFetchLoading:!0});const i=(r=this.state.get().messages.at(-1))==null?void 0:r.timestamp,{data:a}=await this.api.getSessionHistory({sessionId:t,lastMessageTimestamp:i,abortSignal:e});if(a&&a.length>0){const o=this.state.get().messages,d=a.map(this.mapHistoryToMessage).filter(C=>!o.some(S=>S.id===C.id));this.state.setPartial({messages:[...o,...d]})}this.state.get().isInitialFetchLoading&&this.state.setPartial({isInitialFetchLoading:!1})});s(this,"mapHistoryToMessage",t=>{var a,r,o;const e={id:t.publicId,timestamp:t.sentAt||"",attachments:t.attachments||void 0};if(t.sender.kind==="user")return{...e,type:"FROM_USER",content:t.content.text||"",deliveredAt:t.sentAt||""};if(t.sender.kind==="agent")return{...e,type:"FROM_AGENT",component:"agent_message",data:{message:t.content.text||""},agent:{name:t.sender.name||"",avatar:t.sender.avatar||"",id:null,isAi:!1}};const i=(a=t.actionCalls)==null?void 0:a.at(-1);return{...e,type:"FROM_BOT",component:"bot_message",agent:{id:null,name:((r=this.config.bot)==null?void 0:r.name)||"",isAi:!0,avatar:((o=this.config.bot)==null?void 0:o.avatar)||""},data:{message:t.content.text||"",action:i?{name:i.actionName,data:i.result}:void 0}}});s(this,"toUserMessage",(t,e)=>({id:P(),type:"FROM_USER",content:t,deliveredAt:new Date().toISOString(),attachments:e,timestamp:new Date().toISOString()}));s(this,"toBotMessage",t=>{var e;return t.success&&t.autopilotResponse?{type:"FROM_BOT",id:t.autopilotResponse.id||P(),timestamp:new Date().toISOString(),component:"bot_message",agent:this.config.bot?{name:this.config.bot.name||"",isAi:!0,avatar:this.config.bot.avatar||"",id:null}:void 0,data:{message:t.autopilotResponse.value.content,action:(e=t.uiResponse)!=null&&e.value.name?{name:t.uiResponse.value.name,data:t.uiResponse.value.request_response}:void 0}}:null});s(this,"toBotErrorMessage",t=>({type:"FROM_BOT",id:P(),timestamp:new Date().toISOString(),component:"TEXT",data:{message:t,variant:"error",action:void 0}}));this.config=t,this.api=e,this.sessionCtx=i,this.registerPolling()}}class N{constructor({contactCtx:t,sessionCtx:e,resetChat:i}){s(this,"state");s(this,"contactCtx");s(this,"sessionCtx");s(this,"resetChat");s(this,"registerRoutingListener",()=>{this.contactCtx.state.subscribe(({contact:t})=>{t!=null&&t.token&&this.state.get().screen==="welcome"&&this.state.setPartial({screen:"sessions"})})});s(this,"toSessionsScreen",()=>{this.resetChat(),this.state.setPartial({screen:"sessions"})});s(this,"toChatScreen",t=>{if(this.resetChat(),t){const e=this.sessionCtx.sessionsState.get().data.find(i=>i.id===t);if(!e)return;this.sessionCtx.sessionState.setPartial({session:e})}this.state.setPartial({screen:"chat"})});this.state=new g({screen:t.shouldCollectData()?"welcome":"sessions"}),this.contactCtx=t,this.sessionCtx=e,this.resetChat=i,this.registerRoutingListener()}}class X{constructor({config:t}){s(this,"config");s(this,"api");s(this,"contactCtx");s(this,"sessionCtx");s(this,"messageCtx");s(this,"routerCtx");s(this,"resetChat",()=>{this.sessionCtx.reset(),this.messageCtx.reset()});this.config=t,this.api=new B({config:t}),this.contactCtx=new H({api:this.api,config:this.config}),this.sessionCtx=new G({config:this.config,api:this.api,contactCtx:this.contactCtx}),this.messageCtx=new j({config:this.config,api:this.api,sessionCtx:this.sessionCtx}),this.routerCtx=new N({contactCtx:this.contactCtx,sessionCtx:this.sessionCtx,resetChat:this.resetChat})}}exports.PrimitiveState=g;exports.WidgetCtx=X;
2
- //# sourceMappingURL=widget.ctx-CJUG7f9A.cjs.map
1
+ "use strict";var L=Object.defineProperty;var M=n=>{throw TypeError(n)};var O=(n,t,e)=>t in n?L(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var s=(n,t,e)=>O(n,typeof t!="symbol"?t+"":t,e),R=(n,t,e)=>t.has(n)||M("Cannot "+e);var h=(n,t,e)=>(R(n,t,"read from private field"),e?e.call(n):t.get(n)),w=(n,t,e)=>t.has(n)?M("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(n):t.set(n,e),p=(n,t,e,i)=>(R(n,t,"write to private field"),i?i.call(n,e):t.set(n,e),e);const T=require("axios"),E=require("openapi-fetch"),D=require("lodash.isequal"),_=require("uuid"),q=n=>{console.log(n.error)},B=n=>{const t=E({baseUrl:n.baseUrl}),e={onRequest:n.onRequest,onResponse:n.onResponse,onError:n.onError||q};return t.use(e),t};class H{constructor({config:t}){s(this,"client");s(this,"uploadFileClient");s(this,"config");s(this,"constructClientOptions",t=>{const e=this.config.apiUrl||"https://api.open.cx",i={"X-Bot-Token":this.config.token,"Content-Type":"application/json",Accept:"application/json",Authorization:t?`Bearer ${t}`:void 0};return{baseUrl:e,headers:i}});s(this,"createOpenAPIClient",({baseUrl:t,headers:e})=>B({baseUrl:t,onRequest:({request:i})=>{Object.entries(e).forEach(([a,r])=>{r&&i.headers.set(a,r)})}}));s(this,"createAxiosUploadClient",({baseUrl:t,headers:e})=>T.create({baseURL:`${t}/backend/widget/v2/upload`,headers:e}));s(this,"setAuthToken",t=>{const{baseUrl:e,headers:i}=this.constructClientOptions(t);this.client=this.createOpenAPIClient({baseUrl:e,headers:i}),this.uploadFileClient=this.createAxiosUploadClient({baseUrl:e,headers:i})});s(this,"widgetPrelude",async()=>await this.client.GET("/backend/widget/v2/prelude",{params:{header:{"X-Bot-Token":this.config.token}}}));s(this,"sendMessage",async(t,e)=>await this.client.POST("/backend/widget/v2/chat/send",{body:t,signal:e}));s(this,"getSessionHistory",async({sessionId:t,lastMessageTimestamp:e,abortSignal:i})=>{const a=e?{lastMessageTimestamp:e}:void 0;return await this.client.GET("/backend/widget/v2/session/history/{sessionId}",{params:{path:{sessionId:t},query:a},signal:i})});s(this,"createUnverifiedContact",async t=>await this.client.POST("/backend/widget/v2/contact/create-unverified",{params:{header:{"x-bot-token":this.config.token}},body:t}));s(this,"createSession",async t=>await this.client.POST("/backend/widget/v2/create-session",{body:t}));s(this,"getSession",async({sessionId:t,abortSignal:e})=>await this.client.GET("/backend/widget/v2/session/{sessionId}",{params:{path:{sessionId:t}},signal:e}));s(this,"getSessions",async({cursor:t,filters:e,abortSignal:i})=>await this.client.GET("/backend/widget/v2/sessions",{params:{query:{cursor:t,filters:JSON.stringify(e)}},signal:i}));s(this,"uploadFile",async(t,e={})=>{const i=new FormData;i.append("file",t.file);const{data:a}=await this.uploadFileClient.post("",i,{headers:{"Content-Type":"multipart/form-data"},...e});return a});s(this,"vote",async t=>await this.client.POST("/backend/widget/v2/chat/vote",{body:t}));var a;this.config=t;const{baseUrl:e,headers:i}=this.constructClientOptions((a=t.user)==null?void 0:a.token);this.client=this.createOpenAPIClient({baseUrl:e,headers:i}),this.uploadFileClient=this.createAxiosUploadClient({baseUrl:e,headers:i})}}var c,f;class g{constructor(t){s(this,"subscribers",new Set);w(this,c);s(this,"initialState");w(this,f);s(this,"lifecycleListeners",new Map);s(this,"emitLifecycle",(t,e)=>{const i=this.lifecycleListeners.get(t);if(i){const a={type:t,timestamp:Date.now(),data:e};i.forEach(r=>{try{r(a)}catch{}})}});s(this,"notifySubscribers",t=>{Array.from(this.subscribers).forEach(i=>{try{i(t)}catch(a){this.emitLifecycle("error",{error:a})}})});s(this,"subscribe",t=>(this.subscribers.add(t),()=>{this.subscribers.delete(t)}));s(this,"onLifecycle",(t,e)=>{this.lifecycleListeners.has(t)||this.lifecycleListeners.set(t,new Set);const i=this.lifecycleListeners.get(t);return i.add(e),()=>{i.delete(e),i.size===0&&this.lifecycleListeners.delete(t)}});s(this,"get",()=>h(this,c));s(this,"set",t=>{this.emitLifecycle("beforeUpdate",{previousState:h(this,c),nextState:t}),D(h(this,c),t)||(p(this,c,t),p(this,f,Date.now()),this.emitLifecycle("stateChange",{state:t}),this.notifySubscribers(t)),this.emitLifecycle("afterUpdate",{state:t})});s(this,"setPartial",t=>{if(t==null)return;const e={...h(this,c),...t};this.set(e)});s(this,"clear",()=>{this.emitLifecycle("destroy"),this.subscribers=new Set,this.lifecycleListeners=new Map});s(this,"reset",()=>{this.set(this.initialState)});s(this,"lastUpdated",()=>h(this,f));p(this,c,t),this.initialState=t,p(this,f,Date.now()),this.emitLifecycle("init",{initialState:h(this,c)})}}c=new WeakMap,f=new WeakMap;class G{constructor({config:t,api:e}){s(this,"config");s(this,"api");s(this,"state");s(this,"shouldCollectData",()=>{var e;return!!(!((e=this.state.get().contact)!=null&&e.token)&&this.config.collectUserData)});s(this,"autoCreateUnverifiedUser",async()=>{var t,e,i,a;await this.createUnverifiedContact({name:((e=(t=this.config.user)==null?void 0:t.data)==null?void 0:e.name)||"Anonymous",email:(a=(i=this.config.user)==null?void 0:i.data)==null?void 0:a.email})});s(this,"createUnverifiedContact",async t=>{try{this.state.setPartial({isCreatingUnverifiedContact:!0,isErrorCreatingUnverifiedContact:!1});const{data:e}=await this.api.createUnverifiedContact(t);e!=null&&e.token?(this.api.setAuthToken(e.token),this.state.setPartial({contact:{token:e.token}})):this.state.setPartial({isErrorCreatingUnverifiedContact:!0})}finally{this.state.setPartial({isCreatingUnverifiedContact:!1})}});var i,a,r;this.config=t,this.api=e,this.state=new g({contact:(i=t.user)!=null&&i.token?{token:(a=t.user)==null?void 0:a.token}:null,isCreatingUnverifiedContact:!1,isErrorCreatingUnverifiedContact:!1}),!((r=t.user)!=null&&r.token)&&!t.collectUserData&&this.autoCreateUnverifiedUser()}}class v{constructor(){s(this,"state",new g({isPolling:!1,isError:!1}));s(this,"abortController",new AbortController);s(this,"reset",()=>{var t;this.abortController.abort("Resetting poller"),(t=this.stopPolling)==null||t.call(this),this.stopPolling=null});s(this,"stopPolling",null);s(this,"startPolling",(t,e)=>{if(this.stopPolling)return;const i=[],a=async()=>{this.abortController=new AbortController,this.state.setPartial({isPolling:!0});try{await t(this.abortController.signal)}catch(r){if(this.abortController.signal.aborted)return;console.error("Failed to poll:",r),this.state.setPartial({isError:!0})}finally{this.state.setPartial({isPolling:!1})}this.abortController.signal.aborted?console.log("Poller aborted, not scheduling anymore"):i.push(setTimeout(a,e))};a(),this.stopPolling=()=>{i.forEach(clearTimeout),this.state.reset()}})}}function P(){return _.v4()}class j{constructor({config:t,api:e,contactCtx:i}){s(this,"config");s(this,"api");s(this,"contactCtx");s(this,"activeSessionPoller",new v);s(this,"sessionsRefresher",new v);s(this,"sessionState",new g({session:null,isCreatingSession:!1}));s(this,"sessionsState",new g({data:[],cursor:void 0,isLastPage:!1,didStartInitialFetch:!1,isInitialFetchLoading:!0}));s(this,"reset",async()=>{this.sessionState.reset(),this.activeSessionPoller.reset()});s(this,"registerActiveSessionPolling",()=>{this.sessionState.subscribe(({session:t})=>{t!=null&&t.id?this.activeSessionPoller.startPolling(async e=>{const{data:i}=await this.api.getSession({sessionId:t.id,abortSignal:e});i&&this.sessionState.setPartial({session:i})},1e3):this.activeSessionPoller.reset()})});s(this,"registerInitialSessionsFetch",()=>{var e;const t=async()=>{this.sessionsState.setPartial({didStartInitialFetch:!0}),await this.loadMoreSessions(),this.sessionsState.setPartial({isInitialFetchLoading:!1})};(e=this.contactCtx.state.get().contact)!=null&&e.token&&!this.sessionsState.get().didStartInitialFetch&&(t(),this.registerSessionsRefresher()),this.contactCtx.state.subscribe(({contact:i})=>{i!=null&&i.token&&!this.sessionsState.get().didStartInitialFetch&&(t(),this.registerSessionsRefresher())})});s(this,"registerSessionsRefresher",()=>{this.sessionsRefresher.startPolling(async()=>{const{data:t}=await this.getSessions({cursor:void 0});if(!t)return;const e=[...t.items,...this.sessionsState.get().data].filter((i,a,r)=>a===r.findIndex(o=>i.id===o.id));this.sessionsState.setPartial({data:e})},1e4)});s(this,"createSession",async()=>{var i,a;this.sessionState.setPartial({session:null,isCreatingSession:!0});const{data:t,error:e}=await this.api.createSession({customData:(i=this.config.user)!=null&&i.externalId?{external_id:(a=this.config.user)==null?void 0:a.externalId}:void 0});return t?(this.sessionState.setPartial({session:t,isCreatingSession:!1}),t):(console.error("Failed to create session:",e),null)});s(this,"loadMoreSessions",async()=>{if(this.sessionsState.get().isLastPage)return;const{data:t}=await this.getSessions({cursor:this.sessionsState.get().cursor});if(t){const i=[...this.sessionsState.get().data,...t.items].filter((a,r,o)=>r===o.findIndex(d=>a.id===d.id));this.sessionsState.setPartial({data:i,cursor:t.next||void 0,isLastPage:t.next===null})}});s(this,"getSessions",async({cursor:t})=>{var e,i;return(e=this.contactCtx.state.get().contact)!=null&&e.token?await this.api.getSessions({cursor:t,filters:(i=this.config.user)!=null&&i.externalId?{external_id:this.config.user.externalId}:{}}):{data:null}});this.config=t,this.api=e,this.contactCtx=i,this.registerActiveSessionPolling(),this.registerInitialSessionsFetch()}}class N{constructor({config:t,api:e,sessionCtx:i}){s(this,"config");s(this,"api");s(this,"sessionCtx");s(this,"poller",new v);s(this,"state",new g({messages:[],isSendingMessage:!1,lastAIResMightSolveUserIssue:!1,isInitialFetchLoading:!1}));s(this,"sendMessageAbortController",new AbortController);s(this,"reset",()=>{this.sendMessageAbortController.abort("Resetting chat"),this.state.reset(),this.poller.reset()});s(this,"registerPolling",()=>{this.sessionCtx.sessionState.subscribe(({session:t})=>{t!=null&&t.id?this.poller.startPolling(async e=>{await this.fetchAndSetHistory(t.id,e)},1e3):this.poller.reset()})});s(this,"sendMessage",async t=>{var r,o,d,C,S,y,x,A,U;this.sendMessageAbortController=new AbortController;const e=this.state.get().isSendingMessage,i=((r=this.sessionCtx.sessionState.get().session)==null?void 0:r.assignee.kind)==="ai",a=this.state.get().messages.at(-1);if(i&&e||i&&(a==null?void 0:a.type)==="FROM_USER"){console.warn("Cannot send messages while awaiting AI response");return}this.state.setPartial({lastAIResMightSolveUserIssue:!1});try{this.state.setPartial({isSendingMessage:!0});const m=this.toUserMessage(t.content,t.attachments||void 0),k=this.state.get().messages;if(this.state.setPartial({messages:[...k,m]}),!((o=this.sessionCtx.sessionState.get().session)!=null&&o.id)&&!await this.sessionCtx.createSession()){console.error("Failed to create session");return}const I=(d=this.sessionCtx.sessionState.get().session)==null?void 0:d.id;if(!I)return;const{data:l}=await this.api.sendMessage({uuid:m.id,bot_token:this.config.token,headers:this.config.headers,query_params:this.config.queryParams,session_id:I,user:(C=this.config.user)==null?void 0:C.data,...t},this.sendMessageAbortController.signal);if(l!=null&&l.success){const u=this.toBotMessage(l);if(u){const b=this.state.get().messages;if(!!b.some(F=>F.id===u.id)){this.state.setPartial({lastAIResMightSolveUserIssue:((S=l.autopilotResponse)==null?void 0:S.mightSolveUserIssue)||((y=l.uiResponse)==null?void 0:y.mightSolveUserIssue)});return}this.state.setPartial({messages:[...b,u],lastAIResMightSolveUserIssue:((x=l.autopilotResponse)==null?void 0:x.mightSolveUserIssue)||((A=l.uiResponse)==null?void 0:A.mightSolveUserIssue)})}}else{const u=this.toBotErrorMessage(((U=l==null?void 0:l.error)==null?void 0:U.message)||"Unknown error occurred"),b=this.state.get().messages;this.state.setPartial({messages:[...b,u]})}}catch(m){this.sendMessageAbortController.signal.aborted||console.error("Failed to send message:",m)}finally{this.state.setPartial({isSendingMessage:!1})}});s(this,"fetchAndSetHistory",async(t,e)=>{var r;this.state.get().messages.length===0&&this.state.setPartial({isInitialFetchLoading:!0});const i=(r=this.state.get().messages.at(-1))==null?void 0:r.timestamp,{data:a}=await this.api.getSessionHistory({sessionId:t,lastMessageTimestamp:i,abortSignal:e});if(a&&a.length>0){const o=this.state.get().messages,d=a.map(this.mapHistoryToMessage).filter(C=>!o.some(S=>S.id===C.id));this.state.setPartial({messages:[...o,...d]})}this.state.get().isInitialFetchLoading&&this.state.setPartial({isInitialFetchLoading:!1})});s(this,"mapHistoryToMessage",t=>{var a,r,o;const e={id:t.publicId,timestamp:t.sentAt||"",attachments:t.attachments||void 0};if(t.sender.kind==="user")return{...e,type:"FROM_USER",content:t.content.text||"",deliveredAt:t.sentAt||""};if(t.sender.kind==="agent")return{...e,type:"FROM_AGENT",component:"agent_message",data:{message:t.content.text||""},agent:{name:t.sender.name||"",avatar:t.sender.avatar||"",id:null,isAi:!1}};const i=(a=t.actionCalls)==null?void 0:a.at(-1);return{...e,type:"FROM_BOT",component:"bot_message",agent:{id:null,name:((r=this.config.bot)==null?void 0:r.name)||"",isAi:!0,avatar:((o=this.config.bot)==null?void 0:o.avatar)||""},data:{message:t.content.text||"",action:i?{name:i.actionName,data:i.result}:void 0}}});s(this,"toUserMessage",(t,e)=>({id:P(),type:"FROM_USER",content:t,deliveredAt:new Date().toISOString(),attachments:e,timestamp:new Date().toISOString()}));s(this,"toBotMessage",t=>{var e;return t.success&&t.autopilotResponse?{type:"FROM_BOT",id:t.autopilotResponse.id||P(),timestamp:new Date().toISOString(),component:"bot_message",agent:this.config.bot?{name:this.config.bot.name||"",isAi:!0,avatar:this.config.bot.avatar||"",id:null}:void 0,data:{message:t.autopilotResponse.value.content,action:(e=t.uiResponse)!=null&&e.value.name?{name:t.uiResponse.value.name,data:t.uiResponse.value.request_response}:void 0}}:null});s(this,"toBotErrorMessage",t=>({type:"FROM_BOT",id:P(),timestamp:new Date().toISOString(),component:"TEXT",data:{message:t,variant:"error",action:void 0}}));this.config=t,this.api=e,this.sessionCtx=i,this.registerPolling()}}class X{constructor({contactCtx:t,sessionCtx:e,resetChat:i}){s(this,"state");s(this,"contactCtx");s(this,"sessionCtx");s(this,"resetChat");s(this,"registerRoutingListener",()=>{this.contactCtx.state.subscribe(({contact:t})=>{t!=null&&t.token&&this.state.get().screen==="welcome"&&this.state.setPartial({screen:"sessions"})})});s(this,"toSessionsScreen",()=>{this.resetChat(),this.state.setPartial({screen:"sessions"})});s(this,"toChatScreen",t=>{if(this.resetChat(),t){const e=this.sessionCtx.sessionsState.get().data.find(i=>i.id===t);if(!e)return;this.sessionCtx.sessionState.setPartial({session:e})}this.state.setPartial({screen:"chat"})});this.state=new g({screen:t.shouldCollectData()?"welcome":"sessions"}),this.contactCtx=t,this.sessionCtx=e,this.resetChat=i,this.registerRoutingListener()}}class ${constructor({config:t}){s(this,"config");s(this,"api");s(this,"contactCtx");s(this,"sessionCtx");s(this,"messageCtx");s(this,"routerCtx");s(this,"resetChat",()=>{this.sessionCtx.reset(),this.messageCtx.reset()});this.config=t,this.api=new H({config:t}),this.contactCtx=new G({api:this.api,config:this.config}),this.sessionCtx=new j({config:this.config,api:this.api,contactCtx:this.contactCtx}),this.messageCtx=new N({config:this.config,api:this.api,sessionCtx:this.sessionCtx}),this.routerCtx=new X({contactCtx:this.contactCtx,sessionCtx:this.sessionCtx,resetChat:this.resetChat})}}exports.PrimitiveState=g;exports.WidgetCtx=$;
2
+ //# sourceMappingURL=widget.ctx-YXE36VK3.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget.ctx-YXE36VK3.cjs","sources":["../src/headless/core/sdk/index.ts","../src/headless/core/api.ts","../src/headless/core/utils/PrimitiveState.ts","../src/headless/core/context/contact.ctx.ts","../src/headless/core/utils/Poller.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/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 axios, { type AxiosInstance, type AxiosRequestConfig } from \"axios\";\nimport { type Dto, type Endpoint, basicClient } from \"./sdk\";\nimport type { WidgetConfig } from \"./types/WidgetConfig\";\nimport type { SendMessageDto, VoteInputDto } from \"./types/schemas\";\n\nexport class ApiCaller {\n private client: ReturnType<typeof basicClient>;\n private uploadFileClient: AxiosInstance;\n private config: WidgetConfig;\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 this.uploadFileClient = this.createAxiosUploadClient({ baseUrl, headers });\n }\n\n private constructClientOptions = (token: string | null | undefined) => {\n const baseUrl = 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 private createAxiosUploadClient = ({\n baseUrl,\n headers,\n }: ReturnType<typeof this.constructClientOptions>) => {\n const uploadPath = \"/backend/widget/v2/upload\" satisfies Endpoint;\n return axios.create({\n baseURL: `${baseUrl}${uploadPath}`,\n headers,\n });\n };\n\n setAuthToken = (token: string) => {\n const { baseUrl, headers } = this.constructClientOptions(token);\n this.client = this.createOpenAPIClient({ baseUrl, headers });\n this.uploadFileClient = this.createAxiosUploadClient({ baseUrl, headers });\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 getSessionHistory = 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(\n \"/backend/widget/v2/session/history/{sessionId}\",\n { params: { path: { sessionId }, query }, 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[\"CreateWidgetChatSessionDto\"]) => {\n return await this.client.POST(\"/backend/widget/v2/create-session\", {\n body,\n });\n };\n\n getSession = async ({\n sessionId,\n abortSignal,\n }: { sessionId: string; abortSignal: AbortSignal }) => {\n return await this.client.GET(\"/backend/widget/v2/session/{sessionId}\", {\n params: { path: { sessionId } },\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 uploadFile = async (\n file: {\n id: string;\n file: File;\n },\n config: Partial<AxiosRequestConfig> = {},\n ) => {\n const formData = new FormData();\n formData.append(\"file\", file.file);\n\n // Couldn't get this to work with the openapi client... dunno why...\n const { data } = await this.uploadFileClient.post<\n Dto[\"UploadWidgetFileResponseDto\"]\n >(\"\", formData, {\n headers: {\n \"Content-Type\": \"multipart/form-data\",\n },\n ...config,\n });\n return data;\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 enum LifecycleEvent {\n INIT = \"init\",\n STATE_CHANGE = \"stateChange\",\n BEFORE_UPDATE = \"beforeUpdate\",\n AFTER_UPDATE = \"afterUpdate\",\n DESTROY = \"destroy\",\n ERROR = \"error\",\n}\n\ntype LifecycleListener = (event: {\n type: LifecycleEvent;\n timestamp: number;\n data?: any;\n}) => void;\n\nexport class PrimitiveState<S> {\n private subscribers = new Set<Subscriber<S>>();\n #state: S;\n private initialState: S;\n #lastUpdated: number | null;\n private lifecycleListeners: Map<LifecycleEvent, Set<LifecycleListener>> =\n new Map();\n\n constructor(state: S) {\n this.#state = state;\n this.initialState = state;\n this.#lastUpdated = Date.now();\n this.emitLifecycle(LifecycleEvent.INIT, { initialState: this.#state });\n }\n\n private emitLifecycle = (event: LifecycleEvent, data?: any) => {\n const listeners = this.lifecycleListeners.get(event);\n if (listeners) {\n const eventData = {\n type: event,\n timestamp: Date.now(),\n data,\n };\n listeners.forEach((listener) => {\n try {\n listener(eventData);\n } catch {\n // ignore error\n }\n });\n }\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 this.emitLifecycle(LifecycleEvent.ERROR, { error });\n }\n });\n };\n\n /**\n * Subscribe to state changes\n * @param callback Function to call when state changes\n * @returns Unsubscribe function\n */\n subscribe = (callback: Subscriber<S>): (() => void) => {\n this.subscribers.add(callback);\n // Don't call the callback immediately with current state\n return () => {\n this.subscribers.delete(callback);\n };\n };\n\n onLifecycle = (\n event: LifecycleEvent,\n listener: LifecycleListener,\n ): (() => void) => {\n if (!this.lifecycleListeners.has(event)) {\n this.lifecycleListeners.set(event, new Set());\n }\n const listeners = this.lifecycleListeners.get(event)!;\n listeners.add(listener);\n\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0) {\n this.lifecycleListeners.delete(event);\n }\n };\n };\n\n /** Get the current state */\n get = (): S => {\n return this.#state;\n };\n\n // TODO make this provide prev state\n /**\n * Set the state and notify subscribers if the state changes\n * @param newState The new state to set\n */\n set = (newState: S): void => {\n this.emitLifecycle(LifecycleEvent.BEFORE_UPDATE, {\n previousState: this.#state,\n nextState: newState,\n });\n\n if (!isEqual(this.#state, newState)) {\n this.#state = newState;\n this.#lastUpdated = Date.now();\n this.emitLifecycle(LifecycleEvent.STATE_CHANGE, { state: newState });\n this.notifySubscribers(newState);\n }\n\n this.emitLifecycle(LifecycleEvent.AFTER_UPDATE, { state: newState });\n };\n\n // TODO make this provide prev state\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 /**\n * Clear all subscriptions\n */\n clear = (): void => {\n this.emitLifecycle(LifecycleEvent.DESTROY);\n this.subscribers = new Set(); // Create a new Set instead of just clearing\n this.lifecycleListeners = new Map();\n };\n\n reset = (): void => {\n this.set(this.initialState);\n };\n\n lastUpdated = (): number | null => {\n return this.#lastUpdated;\n };\n}\n","import { PrimitiveState } from \"../utils/PrimitiveState\";\nimport { ApiCaller } from \"../api\";\nimport { type WidgetConfig } from \"../types/WidgetConfig\";\nimport { type Dto } from \"../sdk\";\n\ntype ContactState = {\n contact: { token: string } | null;\n isCreatingUnverifiedContact: boolean;\n isErrorCreatingUnverifiedContact: boolean;\n};\n\nexport class ContactCtx {\n private config: WidgetConfig;\n private api: ApiCaller;\n state: PrimitiveState<ContactState>;\n\n constructor({\n config,\n api,\n }: {\n api: ApiCaller;\n config: WidgetConfig;\n }) {\n this.config = config;\n this.api = api;\n\n this.state = new PrimitiveState<ContactState>({\n contact: config.user?.token ? { token: config.user?.token } : null,\n isCreatingUnverifiedContact: false,\n isErrorCreatingUnverifiedContact: false,\n });\n\n if (!config.user?.token && !config.collectUserData) {\n this.autoCreateUnverifiedUser();\n }\n }\n\n shouldCollectData = (): boolean => {\n const currentState = this.state.get();\n\n if (!currentState.contact?.token && this.config.collectUserData) {\n return true;\n } else {\n return false;\n }\n };\n\n private autoCreateUnverifiedUser = async () => {\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 ): Promise<void> => {\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 this.api.setAuthToken(data.token);\n // Set token in state after setting the token in the api handler\n this.state.setPartial({ contact: { token: data.token } });\n } else {\n this.state.setPartial({ isErrorCreatingUnverifiedContact: true });\n }\n } finally {\n this.state.setPartial({ isCreatingUnverifiedContact: false });\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 stopPolling: (() => void) | null = null;\n\n startPolling = (\n cb: (abortSignal: AbortSignal) => Promise<void>,\n interval: 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 } else {\n console.error(\"Failed to poll:\", error);\n this.state.setPartial({ isError: true });\n }\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, interval));\n }\n };\n\n poll();\n\n this.stopPolling = () => {\n timeouts.forEach(clearTimeout);\n this.state.reset();\n };\n };\n}\n","import { v4 as uuidv4 } from \"uuid\";\n\nexport function genUuid() {\n return uuidv4();\n}\n","import type { ApiCaller } from \"../api\";\nimport type { SessionDto } from \"../types/schemas\";\nimport type { WidgetConfig } from \"../types/WidgetConfig\";\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 config: WidgetConfig;\n private api: ApiCaller;\n private contactCtx: ContactCtx;\n private activeSessionPoller = new Poller();\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 config,\n api,\n contactCtx,\n }: { config: WidgetConfig; api: ApiCaller; contactCtx: ContactCtx }) {\n this.config = config;\n this.api = api;\n this.contactCtx = contactCtx;\n\n this.registerActiveSessionPolling();\n this.registerInitialSessionsFetch();\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 // The poller should automatically reset, since we're subscribed to the session state, and whenever it's null, the poller resets... but just in case, let's reset it here as well\n this.activeSessionPoller.reset();\n };\n\n private registerActiveSessionPolling = () => {\n this.sessionState.subscribe(({ session }) => {\n if (session?.id) {\n this.activeSessionPoller.startPolling(async (abortSignal) => {\n const { data } = await this.api.getSession({\n sessionId: session.id,\n abortSignal,\n });\n data && this.sessionState.setPartial({ session: data });\n }, 1000);\n } else {\n this.activeSessionPoller.reset();\n }\n });\n };\n\n private registerInitialSessionsFetch = () => {\n const initialFetch = async () => {\n this.sessionsState.setPartial({ didStartInitialFetch: true });\n // Call this for the first time to get the first page of sessions\n await this.loadMoreSessions();\n this.sessionsState.setPartial({ isInitialFetchLoading: false });\n };\n\n // If the widget config was initially provided with a contact token, no state change would be triggered, so we just fetch\n if (\n this.contactCtx.state.get().contact?.token &&\n !this.sessionsState.get().didStartInitialFetch\n ) {\n initialFetch();\n this.registerSessionsRefresher();\n }\n\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 initialFetch();\n this.registerSessionsRefresher();\n }\n });\n };\n\n private registerSessionsRefresher = () => {\n this.sessionsRefresher.startPolling(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 }, 10000);\n };\n\n createSession = async () => {\n this.sessionState.setPartial({ session: null, isCreatingSession: true });\n\n const { data: session, error } = await this.api.createSession({\n customData: this.config.user?.externalId\n ? {\n external_id: this.config.user?.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 /**\n * Let's keep this private for now until we figure out how to do paginated fetching in tandem with the interval refreshing\n */\n private 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 return await this.api.getSessions({\n cursor,\n filters: this.config.user?.externalId\n ? {\n external_id: this.config.user.externalId,\n }\n : {},\n });\n };\n}\n","import { ApiCaller } from \"../api\";\nimport type { WidgetConfig } from \"../types/WidgetConfig\";\nimport type { SafeOmit, SomeOptional } from \"../types/helpers\";\nimport type {\n BotMessageType,\n MessageType,\n UserMessageType,\n} from \"../types/messages\";\nimport type {\n MessageAttachmentType,\n MessageDto,\n SendMessageDto,\n SendMessageOutputDto,\n} from \"../types/schemas\";\nimport { Poller } from \"../utils/Poller\";\nimport { PrimitiveState } from \"../utils/PrimitiveState\";\nimport { genUuid } from \"../utils/uuid\";\nimport { SessionCtx } from \"./session.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 sessionCtx: SessionCtx;\n private poller = new Poller();\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 }: { config: WidgetConfig; api: ApiCaller; sessionCtx: SessionCtx }) {\n this.config = config;\n this.api = api;\n this.sessionCtx = sessionCtx;\n\n this.registerPolling();\n }\n\n reset = () => {\n this.sendMessageAbortController.abort(\"Resetting chat\");\n this.state.reset();\n // The poller should automatically reset, since we're subscribed to the session state, and whenever it's null, the poller resets... but just in case, let's reset it here as well\n this.poller.reset();\n };\n\n private registerPolling = () => {\n this.sessionCtx.sessionState.subscribe(({ session }) => {\n if (session?.id) {\n this.poller.startPolling(async (abortSignal) => {\n await this.fetchAndSetHistory(session.id, abortSignal);\n }, 1000);\n } else {\n this.poller.reset();\n }\n });\n };\n\n sendMessage = async (\n input: SomeOptional<\n SafeOmit<SendMessageDto, \"bot_token\" | \"uuid\">,\n \"session_id\" | \"user\"\n >,\n ): Promise<void> => {\n this.sendMessageAbortController = new AbortController();\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 lastMessage = this.state.get().messages.at(-1);\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 /* ------------------------------------------------------ */\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,\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 const sessionId = this.sessionCtx.sessionState.get().session?.id;\n if (!sessionId) return;\n\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 ...input,\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 fetchAndSetHistory = 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.state.get().messages.length === 0) {\n this.state.setPartial({ isInitialFetchLoading: true });\n }\n\n const lastMessageTimestamp = this.state.get().messages.at(-1)?.timestamp;\n\n const { data: response } = await this.api.getSessionHistory({\n sessionId,\n lastMessageTimestamp,\n abortSignal,\n });\n\n if (response && response.length > 0) {\n // Get a fresh reference to current messages after the poll is done\n const prevMessages = this.state.get().messages;\n const newMessages = response\n .map(this.mapHistoryToMessage)\n .filter(\n (newMsg) =>\n !prevMessages.some((existingMsg) => existingMsg.id === newMsg.id),\n );\n this.state.setPartial({\n messages: [...prevMessages, ...newMessages],\n });\n }\n\n if (this.state.get().isInitialFetchLoading) {\n this.state.setPartial({ isInitialFetchLoading: false });\n }\n };\n\n /** Not the best name but whatever */\n private 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 = history.actionCalls?.at(-1);\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 ? { name: action.actionName, data: action.result }\n : undefined,\n },\n };\n };\n\n private toUserMessage = (\n content: string,\n attachments?: MessageAttachmentType[],\n ): UserMessageType => {\n return {\n id: genUuid(),\n type: \"FROM_USER\",\n content,\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 { 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 contactCtx: ContactCtx;\n private sessionCtx: SessionCtx;\n private resetChat: WidgetCtx[\"resetChat\"];\n\n constructor({\n contactCtx,\n sessionCtx,\n resetChat,\n }: {\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.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\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 { ApiCaller } from \"../api\";\nimport type { WidgetConfig } from \"../types/WidgetConfig\";\nimport { ContactCtx } from \"./contact.ctx\";\nimport { MessageCtx } from \"./message.ctx\";\nimport { RouterCtx } from \"./router.ctx\";\nimport { SessionCtx } from \"./session.ctx\";\n\nexport class WidgetCtx {\n public config: WidgetConfig;\n public api: ApiCaller;\n public contactCtx: ContactCtx;\n public sessionCtx: SessionCtx;\n public messageCtx: MessageCtx;\n public routerCtx: RouterCtx;\n\n constructor({ config }: { config: WidgetConfig }) {\n this.config = config;\n this.api = new ApiCaller({ config });\n\n this.contactCtx = new ContactCtx({\n api: this.api,\n config: this.config,\n });\n\n this.sessionCtx = new SessionCtx({\n config: this.config,\n api: this.api,\n contactCtx: this.contactCtx,\n });\n\n this.messageCtx = new MessageCtx({\n config: this.config,\n api: this.api,\n sessionCtx: this.sessionCtx,\n });\n\n this.routerCtx = new RouterCtx({\n contactCtx: this.contactCtx,\n sessionCtx: this.sessionCtx,\n resetChat: this.resetChat,\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","__publicField","token","baseUrl","headers","request","key","value","axios","body","abortSignal","sessionId","lastMessageTimestamp","query","cursor","filters","file","formData","data","_a","PrimitiveState","state","__privateAdd","_state","_lastUpdated","event","listeners","eventData","listener","callback","error","__privateGet","newState","isEqual","__privateSet","_s","ContactCtx","api","_b","_d","_c","payload","Poller","cb","interval","timeouts","poll","genUuid","uuidv4","SessionCtx","contactCtx","session","initialFetch","contact","sessions","s","i","self","deduped","MessageCtx","sessionCtx","input","isSending","isAssignedToAI","lastMessage","userMessage","currentMessages","botMessage","prevMessages","m","_e","_f","_g","_h","errorMessage","_i","response","newMessages","newMsg","existingMsg","history","commonFields","action","content","attachments","message","RouterCtx","resetChat","WidgetCtx"],"mappings":"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"}