@opencx/widget 3.0.89 → 3.0.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/designs.cjs +31 -336
  2. package/dist/designs.cjs.map +1 -1
  3. package/dist/designs.js +9593 -27892
  4. package/dist/designs.js.map +1 -1
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.js +4 -6
  8. package/dist/index.js.map +1 -1
  9. package/dist/is-exhaustive-9o43S91P.cjs +2 -0
  10. package/dist/is-exhaustive-9o43S91P.cjs.map +1 -0
  11. package/dist/is-exhaustive-DGJzQK69.js +7 -0
  12. package/dist/is-exhaustive-DGJzQK69.js.map +1 -0
  13. package/dist/react.cjs +1 -1
  14. package/dist/react.cjs.map +1 -1
  15. package/dist/react.js +17 -16
  16. package/dist/react.js.map +1 -1
  17. package/dist/src/designs/react/index.d.ts +2 -3
  18. package/dist/src/headless/core/index.d.ts +1 -1
  19. package/dist/src/headless/core/types/widget-config.d.ts +20 -0
  20. package/dist/src/headless/react/WidgetProvider.d.ts +1 -4
  21. package/dist/src/headless/react/hooks/useModes.d.ts +2 -2
  22. package/dist/src/headless/react/index.d.ts +0 -1
  23. package/dist/useModes-CAashveE.cjs +2 -0
  24. package/dist/useModes-CAashveE.cjs.map +1 -0
  25. package/dist/useModes-COzOEDch.js +259 -0
  26. package/dist/useModes-COzOEDch.js.map +1 -0
  27. package/dist/widget.ctx-6xcbtF7q.cjs +5 -0
  28. package/dist/widget.ctx-6xcbtF7q.cjs.map +1 -0
  29. package/dist/widget.ctx-uAWzif3-.js +688 -0
  30. package/dist/widget.ctx-uAWzif3-.js.map +1 -0
  31. package/dist-embed/script.js +18 -18
  32. package/dist-embed/script.js.map +1 -1
  33. package/package.json +1 -1
  34. package/dist/src/headless/react/types/modes.components.d.ts +0 -11
  35. package/dist/useModes-BAr0RJcP.js +0 -3183
  36. package/dist/useModes-BAr0RJcP.js.map +0 -1
  37. package/dist/useModes-C4Sdixy0.cjs +0 -85
  38. package/dist/useModes-C4Sdixy0.cjs.map +0 -1
  39. package/dist/widget.ctx-Db3DyLM5.js +0 -1564
  40. package/dist/widget.ctx-Db3DyLM5.js.map +0 -1
  41. package/dist/widget.ctx-RfaE5VPy.cjs +0 -5
  42. package/dist/widget.ctx-RfaE5VPy.cjs.map +0 -1
@@ -0,0 +1,688 @@
1
+ import M from "openapi-fetch";
2
+ import O from "lodash.isequal";
3
+ import { v4 as E } from "uuid";
4
+ const F = (g) => {
5
+ console.log(g.error);
6
+ }, _ = (g) => {
7
+ const a = M({
8
+ baseUrl: g.baseUrl
9
+ }), o = {
10
+ onRequest: g.onRequest,
11
+ onResponse: g.onResponse,
12
+ onError: g.onError || F
13
+ };
14
+ return a.use(o), a;
15
+ };
16
+ class T {
17
+ constructor({ config: a }) {
18
+ var n, e;
19
+ this.userToken = null, this.constructClientOptions = (t) => {
20
+ const s = this.config.apiUrl || "https://api.open.cx", i = {
21
+ "X-Bot-Token": this.config.token,
22
+ "Content-Type": "application/json",
23
+ Accept: "application/json",
24
+ Authorization: t ? `Bearer ${t}` : void 0
25
+ };
26
+ return { baseUrl: s, headers: i };
27
+ }, this.createOpenAPIClient = ({
28
+ baseUrl: t,
29
+ headers: s
30
+ }) => _({
31
+ baseUrl: t,
32
+ onRequest: ({ request: i }) => {
33
+ Object.entries(s).forEach(([c, r]) => {
34
+ r && i.headers.set(c, r);
35
+ });
36
+ }
37
+ }), this.setAuthToken = (t) => {
38
+ this.userToken = t;
39
+ const { baseUrl: s, headers: i } = this.constructClientOptions(t);
40
+ this.client = this.createOpenAPIClient({ baseUrl: s, headers: i });
41
+ }, this.getExternalWidgetConfig = async () => await this.client.GET("/backend/widget/v2/config", {
42
+ params: { header: { "X-Bot-Token": this.config.token } }
43
+ }), this.widgetPrelude = async () => await this.client.GET("/backend/widget/v2/prelude", {
44
+ params: { header: { "X-Bot-Token": this.config.token } }
45
+ }), this.sendMessage = async (t, s) => await this.client.POST("/backend/widget/v2/chat/send", {
46
+ body: t,
47
+ signal: s
48
+ }), this.createUnverifiedContact = async (t) => await this.client.POST(
49
+ "/backend/widget/v2/contact/create-unverified",
50
+ {
51
+ params: { header: { "x-bot-token": this.config.token } },
52
+ body: t
53
+ }
54
+ ), this.createSession = async (t) => await this.client.POST("/backend/widget/v2/create-session", {
55
+ body: t
56
+ }), this.pollSessionAndHistory = async ({
57
+ sessionId: t,
58
+ lastMessageTimestamp: s,
59
+ abortSignal: i
60
+ }) => {
61
+ const c = s ? { lastMessageTimestamp: s } : void 0;
62
+ return await this.client.GET("/backend/widget/v2/poll/{sessionId}", {
63
+ params: { path: { sessionId: t }, query: c },
64
+ signal: i
65
+ });
66
+ }, this.getSessions = async ({
67
+ cursor: t,
68
+ filters: s,
69
+ abortSignal: i
70
+ }) => await this.client.GET("/backend/widget/v2/sessions", {
71
+ params: { query: { cursor: t, filters: JSON.stringify(s) } },
72
+ signal: i
73
+ }), this.uploadFile = async ({
74
+ file: t,
75
+ abortSignal: s,
76
+ onProgress: i
77
+ }) => new Promise((c, r) => {
78
+ var v;
79
+ const d = new FormData();
80
+ d.append("file", t);
81
+ const l = new XMLHttpRequest();
82
+ if (s && (s.addEventListener("abort", () => {
83
+ l.abort(), r(new DOMException("Aborted", "AbortError"));
84
+ }), s.aborted)) {
85
+ r(new DOMException("Aborted", "AbortError"));
86
+ return;
87
+ }
88
+ l.upload.addEventListener("progress", (u) => {
89
+ if (u.lengthComputable && i) {
90
+ const S = Math.round(u.loaded / u.total * 100);
91
+ i(S);
92
+ }
93
+ }), l.addEventListener("load", () => {
94
+ if (l.status >= 200 && l.status < 300)
95
+ try {
96
+ const u = JSON.parse(l.responseText);
97
+ c(u);
98
+ } catch (u) {
99
+ r(new Error(`Failed to parse response: ${u}`));
100
+ }
101
+ else
102
+ r(new Error(`Upload failed with status: ${l.status}`));
103
+ }), l.addEventListener("error", () => {
104
+ r(new Error("Network error occurred"));
105
+ }), l.addEventListener("timeout", () => {
106
+ r(new Error("Upload timed out"));
107
+ });
108
+ const { baseUrl: C } = this.constructClientOptions(this.userToken), p = `${C}/backend/widget/v2/upload`;
109
+ l.open("POST", p), l.setRequestHeader("X-Bot-Token", this.config.token), this.userToken ?? ((v = this.config.user) == null ? void 0 : v.token) ? l.setRequestHeader("Authorization", `Bearer ${this.userToken}`) : console.error("User token not set"), l.send(d);
110
+ }), this.vote = async (t) => await this.client.POST("/backend/widget/v2/chat/vote", { body: t }), this.resolveSession = async (t, s) => await this.client.POST("/backend/widget/v2/session/resolve", {
111
+ body: t,
112
+ signal: s
113
+ }), this.createStateCheckpoint = async (t) => await this.client.POST("/backend/widget/v2/checkpoint", {
114
+ body: t
115
+ }), this.config = a, this.userToken = ((n = a.user) == null ? void 0 : n.token) || null;
116
+ const { baseUrl: o, headers: h } = this.constructClientOptions(
117
+ (e = a.user) == null ? void 0 : e.token
118
+ );
119
+ this.client = this.createOpenAPIClient({ baseUrl: o, headers: h });
120
+ }
121
+ }
122
+ class P {
123
+ constructor(a) {
124
+ this.subscribers = /* @__PURE__ */ new Set(), this.get = () => this.state, this.set = (o) => {
125
+ O(this.state, o) || (this.state = o, this.notifySubscribers(o));
126
+ }, this.setPartial = (o) => {
127
+ if (o == null) return;
128
+ const h = { ...this.state, ...o };
129
+ this.set(h);
130
+ }, this.reset = () => {
131
+ this.set(this.initialState);
132
+ }, this.notifySubscribers = (o) => {
133
+ Array.from(this.subscribers).forEach((n) => {
134
+ try {
135
+ n(o);
136
+ } catch (e) {
137
+ console.error(e);
138
+ }
139
+ });
140
+ }, this.subscribe = (o) => (this.subscribers.add(o), () => {
141
+ this.subscribers.delete(o);
142
+ }), this.state = a, this.initialState = a;
143
+ }
144
+ }
145
+ class R {
146
+ constructor() {
147
+ this.state = new P({
148
+ isPolling: !1,
149
+ isError: !1
150
+ }), this.abortController = new AbortController(), this.reset = () => {
151
+ var a;
152
+ this.abortController.abort("Resetting poller"), (a = this.stopPolling) == null || a.call(this), this.stopPolling = null;
153
+ }, this.stopPolling = null, this.startPolling = (a, o) => {
154
+ if (this.stopPolling) return;
155
+ const h = [], n = async () => {
156
+ this.abortController = new AbortController(), this.state.setPartial({ isPolling: !0 });
157
+ try {
158
+ await a(this.abortController.signal);
159
+ } catch (e) {
160
+ if (this.abortController.signal.aborted)
161
+ return;
162
+ console.error("Failed to poll:", e), this.state.setPartial({ isError: !0 });
163
+ } finally {
164
+ this.state.setPartial({ isPolling: !1 });
165
+ }
166
+ this.abortController.signal.aborted ? console.log("Poller aborted, not scheduling anymore") : h.push(setTimeout(n, o));
167
+ };
168
+ n(), this.stopPolling = () => {
169
+ h.forEach(clearTimeout), this.state.reset();
170
+ };
171
+ };
172
+ }
173
+ }
174
+ function D(g) {
175
+ try {
176
+ const a = g();
177
+ return a instanceof Promise ? a.then((o) => ({ data: o })).catch((o) => ({ error: o })) : { data: a };
178
+ } catch (a) {
179
+ return { error: a };
180
+ }
181
+ }
182
+ class L {
183
+ constructor({
184
+ api: a,
185
+ config: o,
186
+ sessionCtx: h,
187
+ messageCtx: n,
188
+ sessionPollingIntervalSeconds: e
189
+ }) {
190
+ this.poller = new R(), this.registerPolling = () => {
191
+ this.sessionCtx.sessionState.subscribe(({ session: t }) => {
192
+ t != null && t.id ? this.poller.startPolling(async (s) => {
193
+ this.hackAndSlash(t.id, s);
194
+ }, this.sessionPollingIntervalSeconds * 1e3) : this.poller.reset();
195
+ });
196
+ }, this.hackAndSlash = async (t, s) => {
197
+ var d;
198
+ this.messageCtx.state.get().messages.length === 0 && this.messageCtx.state.setPartial({ isInitialFetchLoading: !0 });
199
+ const i = this.messageCtx.state.get().messages, c = i.length > 0 ? (d = i[i.length - 1]) == null ? void 0 : d.timestamp : void 0, { data: r } = await this.api.pollSessionAndHistory({
200
+ sessionId: t,
201
+ abortSignal: s,
202
+ lastMessageTimestamp: c
203
+ });
204
+ if (r != null && r.session && (this.sessionCtx.sessionState.setPartial({ session: r.session }), this.sessionCtx.setSessions([r.session])), r != null && r.history && r.history.length > 0) {
205
+ const l = this.messageCtx.state.get().messages, C = r.history.map(this.mapHistoryToMessage).filter(
206
+ (x) => !l.some((p) => p.id === x.id)
207
+ );
208
+ this.messageCtx.state.setPartial({
209
+ messages: [...l, ...C]
210
+ });
211
+ }
212
+ this.messageCtx.state.get().isInitialFetchLoading && this.messageCtx.state.setPartial({ isInitialFetchLoading: !1 });
213
+ }, this.mapHistoryToMessage = (t) => {
214
+ var c, r;
215
+ const s = {
216
+ id: t.publicId,
217
+ timestamp: t.sentAt || "",
218
+ attachments: t.attachments || void 0
219
+ };
220
+ if (t.sender.kind === "user")
221
+ return {
222
+ ...s,
223
+ type: "FROM_USER",
224
+ content: t.content.text || "",
225
+ deliveredAt: t.sentAt || ""
226
+ };
227
+ if (t.sender.kind === "agent")
228
+ return {
229
+ ...s,
230
+ type: "FROM_AGENT",
231
+ component: "agent_message",
232
+ data: {
233
+ message: t.content.text || ""
234
+ },
235
+ agent: {
236
+ name: t.sender.name || "",
237
+ avatar: t.sender.avatar || "",
238
+ id: null,
239
+ isAi: !1
240
+ }
241
+ };
242
+ const i = t.actionCalls && t.actionCalls.length > 0 ? t.actionCalls[t.actionCalls.length - 1] : void 0;
243
+ return {
244
+ ...s,
245
+ type: "FROM_BOT",
246
+ component: "bot_message",
247
+ agent: {
248
+ id: null,
249
+ name: ((c = this.config.bot) == null ? void 0 : c.name) || "",
250
+ isAi: !0,
251
+ avatar: ((r = this.config.bot) == null ? void 0 : r.avatar) || ""
252
+ },
253
+ data: {
254
+ message: t.content.text || "",
255
+ action: i ? {
256
+ name: i.actionName,
257
+ data: this.extractActionResult(i)
258
+ } : void 0
259
+ }
260
+ };
261
+ }, this.extractActionResult = (t) => {
262
+ const s = t.result;
263
+ if (s === null || typeof s != "object") return s;
264
+ if ("responseBodyText" in s && typeof s.responseBodyText == "string") {
265
+ const i = s.responseBodyText, c = D(() => JSON.parse(i)).data;
266
+ if (c) return c;
267
+ }
268
+ return t.result;
269
+ }, this.api = a, this.config = o, this.sessionCtx = h, this.messageCtx = n, this.sessionPollingIntervalSeconds = e, this.registerPolling();
270
+ }
271
+ }
272
+ class B {
273
+ constructor({
274
+ config: a,
275
+ api: o,
276
+ storageCtx: h
277
+ }) {
278
+ var n;
279
+ this.shouldCollectData = () => {
280
+ var e;
281
+ return !!(!((e = this.state.get().contact) != null && e.token) && this.config.collectUserData);
282
+ }, this.autoCreateUnverifiedUserIfNotExists = async () => {
283
+ var e, t, s, i, c, r, d, l, C, x, p, w, v, u;
284
+ if (!((e = this.config.user) != null && e.token)) {
285
+ if (this.config.collectUserData && !((s = (t = this.config.user) == null ? void 0 : t.data) != null && s.email)) {
286
+ if ((i = this.config.extraDataCollectionFields) != null && i.length)
287
+ return;
288
+ const S = await ((c = this.storageCtx) == null ? void 0 : c.getContactToken());
289
+ S && await this.setUnverifiedContact(S);
290
+ return;
291
+ }
292
+ if (!((d = (r = this.config.user) == null ? void 0 : r.data) != null && d.email)) {
293
+ const S = await ((l = this.storageCtx) == null ? void 0 : l.getContactToken());
294
+ if (S) {
295
+ await this.setUnverifiedContact(S);
296
+ return;
297
+ }
298
+ }
299
+ await this.createUnverifiedContact({
300
+ email: (x = (C = this.config.user) == null ? void 0 : C.data) == null ? void 0 : x.email,
301
+ non_verified_name: ((w = (p = this.config.user) == null ? void 0 : p.data) == null ? void 0 : w.name) || "Anonymous",
302
+ non_verified_custom_data: (u = (v = this.config.user) == null ? void 0 : v.data) == null ? void 0 : u.customData
303
+ });
304
+ }
305
+ }, this.createUnverifiedContact = async (e, t) => {
306
+ this.state.setPartial({ extraCollectedData: t });
307
+ try {
308
+ this.state.setPartial({
309
+ isCreatingUnverifiedContact: !0,
310
+ isErrorCreatingUnverifiedContact: !1
311
+ });
312
+ const { data: s } = await this.api.createUnverifiedContact(e);
313
+ s != null && s.token ? await this.setUnverifiedContact(s.token) : this.state.setPartial({ isErrorCreatingUnverifiedContact: !0 });
314
+ } finally {
315
+ this.state.setPartial({ isCreatingUnverifiedContact: !1 });
316
+ }
317
+ }, this.setUnverifiedContact = async (e) => {
318
+ var i, c, r, d;
319
+ const t = await ((i = this.storageCtx) == null ? void 0 : i.getExternalContactId()), s = ((c = this.config.user) == null ? void 0 : c.externalId) || t || E();
320
+ this.api.setAuthToken(e), await ((r = this.storageCtx) == null ? void 0 : r.setContactToken(e)), await ((d = this.storageCtx) == null ? void 0 : d.setExternalContactId(s)), this.state.setPartial({ contact: { token: e, externalId: s } });
321
+ }, this.config = a, this.storageCtx = h, this.api = o, this.state = new P({
322
+ contact: (n = a.user) != null && n.token ? {
323
+ token: a.user.token,
324
+ // Set optional externalId from config... not local storage
325
+ externalId: a.user.externalId
326
+ } : null,
327
+ extraCollectedData: void 0,
328
+ isCreatingUnverifiedContact: !1,
329
+ isErrorCreatingUnverifiedContact: !1
330
+ }), this.autoCreateUnverifiedUserIfNotExists();
331
+ }
332
+ }
333
+ function y() {
334
+ return E();
335
+ }
336
+ class q {
337
+ constructor({
338
+ api: a,
339
+ contactCtx: o,
340
+ sessionsPollingIntervalSeconds: h
341
+ }) {
342
+ this.sessionsRefresher = new R(), this.sessionState = new P({
343
+ session: null,
344
+ isCreatingSession: !1,
345
+ isResolvingSession: !1
346
+ }), this.sessionsState = new P({
347
+ data: [],
348
+ cursor: void 0,
349
+ isLastPage: !1,
350
+ didStartInitialFetch: !1,
351
+ /**
352
+ * Initialize this as `true` so it always starts loading until the first fetch is done
353
+ */
354
+ isInitialFetchLoading: !0
355
+ }), this.reset = async () => {
356
+ this.sessionState.reset();
357
+ }, this.registerSessionsRefresherWrapper = () => {
358
+ var n;
359
+ // If the widget config was initially provided with a contact token, no state change would be triggered, so we just fetch
360
+ (n = this.contactCtx.state.get().contact) != null && n.token && !this.sessionsState.get().didStartInitialFetch ? this.registerSessionsRefresher() : this.contactCtx.state.subscribe(({ contact: e }) => {
361
+ e != null && e.token && !this.sessionsState.get().didStartInitialFetch && this.registerSessionsRefresher();
362
+ });
363
+ }, this.registerSessionsRefresher = () => {
364
+ this.sessionsRefresher.startPolling(async () => {
365
+ this.sessionsState.get().didStartInitialFetch === !1 && this.sessionsState.setPartial({ didStartInitialFetch: !0 }), await this.refreshSessions(), this.sessionsState.get().isInitialFetchLoading === !0 && this.sessionsState.setPartial({ isInitialFetchLoading: !1 });
366
+ }, this.sessionsPollingIntervalSeconds * 1e3);
367
+ }, this.createSession = async () => {
368
+ var s;
369
+ this.sessionState.setPartial({ session: null, isCreatingSession: !0 });
370
+ const n = (s = this.contactCtx.state.get().contact) == null ? void 0 : s.externalId, { data: e, error: t } = await this.api.createSession({
371
+ customData: n ? {
372
+ external_id: n
373
+ } : void 0
374
+ });
375
+ return e ? (this.sessionState.setPartial({ session: e, isCreatingSession: !1 }), e) : (this.sessionState.setPartial({ isCreatingSession: !1 }), console.error("Failed to create session:", t), null);
376
+ }, this.loadMoreSessions = async () => {
377
+ if (this.sessionsState.get().isLastPage) return;
378
+ const { data: n } = await this.getSessions({
379
+ cursor: this.sessionsState.get().cursor
380
+ });
381
+ if (n) {
382
+ const t = [...this.sessionsState.get().data, ...n.items].filter(
383
+ (s, i, c) => i === c.findIndex((r) => s.id === r.id)
384
+ );
385
+ this.sessionsState.setPartial({
386
+ data: t,
387
+ cursor: n.next || void 0,
388
+ isLastPage: n.next === null
389
+ });
390
+ }
391
+ }, this.getSessions = async ({ cursor: n }) => {
392
+ var t, s;
393
+ if (!((t = this.contactCtx.state.get().contact) != null && t.token)) return { data: null };
394
+ const e = (s = this.contactCtx.state.get().contact) == null ? void 0 : s.externalId;
395
+ return await this.api.getSessions({
396
+ cursor: n,
397
+ filters: e ? {
398
+ external_id: e
399
+ } : {}
400
+ });
401
+ }, this.setSessions = (n) => {
402
+ const e = [...n, ...this.sessionsState.get().data].filter(
403
+ (t, s, i) => s === i.findIndex((c) => t.id === c.id)
404
+ );
405
+ this.sessionsState.setPartial({ data: e });
406
+ }, this.refreshSessions = async () => {
407
+ const { data: n } = await this.getSessions({ cursor: void 0 });
408
+ n && this.setSessions(n.items);
409
+ }, this.resolveSession = async () => {
410
+ const n = this.sessionState.get().session;
411
+ if (!n || !n.isOpened)
412
+ return { success: !1, error: "Session is not opened" };
413
+ this.sessionState.setPartial({ isResolvingSession: !0 });
414
+ const { data: e, error: t } = await this.api.resolveSession({
415
+ session_id: n.id
416
+ });
417
+ return e ? (this.sessionState.setPartial({ session: e, isResolvingSession: !1 }), { success: !0, data: e }) : (this.sessionState.setPartial({ isResolvingSession: !1 }), { success: !1, error: t });
418
+ }, this.createStateCheckpoint = async (n) => {
419
+ var i;
420
+ const e = (i = this.sessionState.get().session) == null ? void 0 : i.id;
421
+ if (!e) return;
422
+ const { data: t, error: s } = await this.api.createStateCheckpoint({
423
+ session_id: e,
424
+ payload: n
425
+ });
426
+ return t ? { data: t } : { success: !1, error: s };
427
+ }, this.api = a, this.contactCtx = o, this.sessionsPollingIntervalSeconds = h, this.registerSessionsRefresherWrapper();
428
+ }
429
+ }
430
+ class $ {
431
+ constructor({
432
+ config: a,
433
+ api: o,
434
+ sessionCtx: h,
435
+ contactCtx: n
436
+ }) {
437
+ this.state = new P({
438
+ messages: [],
439
+ isSendingMessage: !1,
440
+ lastAIResMightSolveUserIssue: !1,
441
+ isInitialFetchLoading: !1
442
+ }), this.sendMessageAbortController = new AbortController(), this.reset = () => {
443
+ this.sendMessageAbortController.abort("Resetting chat"), this.state.reset();
444
+ }, this.sendMessage = async (e) => {
445
+ var r, d, l, C, x, p, w, v;
446
+ if (!e.content.trim() && (!e.attachments || e.attachments.length === 0)) {
447
+ console.warn("Cannot send an empty message of no content or attachments");
448
+ return;
449
+ }
450
+ const t = this.state.get().isSendingMessage, s = ((r = this.sessionCtx.sessionState.get().session) == null ? void 0 : r.assignee.kind) === "ai", i = this.state.get().messages, c = i.length > 0 ? i[i.length - 1] : void 0;
451
+ if (s && t || // If last message is from user, then bot response did not arrive yet
452
+ s && (c == null ? void 0 : c.type) === "FROM_USER") {
453
+ console.warn("Cannot send messages while awaiting AI response");
454
+ return;
455
+ }
456
+ this.sendMessageAbortController = new AbortController(), this.state.setPartial({ lastAIResMightSolveUserIssue: !1 });
457
+ try {
458
+ this.state.setPartial({ isSendingMessage: !0 });
459
+ const u = this.toUserMessage(
460
+ e.content.trim(),
461
+ e.attachments || void 0
462
+ ), S = this.state.get().messages;
463
+ if (this.state.setPartial({
464
+ messages: [...S, u]
465
+ }), !((d = this.sessionCtx.sessionState.get().session) != null && d.id)) {
466
+ if (!await this.sessionCtx.createSession()) {
467
+ console.error("Failed to create session");
468
+ return;
469
+ }
470
+ this.sessionCtx.refreshSessions();
471
+ }
472
+ const k = (l = this.sessionCtx.sessionState.get().session) == null ? void 0 : l.id;
473
+ if (!k) return;
474
+ const { data: f } = await this.api.sendMessage(
475
+ {
476
+ uuid: u.id,
477
+ bot_token: this.config.token,
478
+ headers: this.config.headers,
479
+ query_params: this.config.queryParams,
480
+ body_properties: this.config.bodyProperties,
481
+ session_id: k,
482
+ content: u.content,
483
+ attachments: e.attachments,
484
+ clientContext: this.config.context,
485
+ custom_data: {
486
+ ...this.config.messageCustomData || {},
487
+ ...e.customData || {}
488
+ },
489
+ language: this.config.language,
490
+ exit_mode_prompt: e.exitModePrompt
491
+ },
492
+ this.sendMessageAbortController.signal
493
+ );
494
+ if (f != null && f.success) {
495
+ const b = this.toBotMessage(f);
496
+ if (b) {
497
+ const I = this.state.get().messages;
498
+ if (!!I.some(
499
+ (A) => A.id === b.id
500
+ )) {
501
+ this.state.setPartial({
502
+ lastAIResMightSolveUserIssue: ((C = f.autopilotResponse) == null ? void 0 : C.mightSolveUserIssue) || ((x = f.uiResponse) == null ? void 0 : x.mightSolveUserIssue)
503
+ });
504
+ return;
505
+ }
506
+ this.state.setPartial({
507
+ messages: [...I, b],
508
+ lastAIResMightSolveUserIssue: ((p = f.autopilotResponse) == null ? void 0 : p.mightSolveUserIssue) || ((w = f.uiResponse) == null ? void 0 : w.mightSolveUserIssue)
509
+ });
510
+ }
511
+ f.session && this.sessionCtx.sessionState.setPartial({ session: f.session });
512
+ } else {
513
+ const b = this.toBotErrorMessage(
514
+ ((v = f == null ? void 0 : f.error) == null ? void 0 : v.message) || "Unknown error occurred"
515
+ ), I = this.state.get().messages;
516
+ this.state.setPartial({
517
+ messages: [...I, b]
518
+ });
519
+ }
520
+ } catch (u) {
521
+ this.sendMessageAbortController.signal.aborted || console.error("Failed to send message:", u);
522
+ } finally {
523
+ this.state.setPartial({ isSendingMessage: !1 });
524
+ }
525
+ }, this.toUserMessage = (e, t) => {
526
+ const s = (() => {
527
+ const i = this.contactCtx.state.get().extraCollectedData;
528
+ return this.state.get().messages.length === 0 && i && Object.keys(i).length > 0 ? `${Object.entries(i).filter(([r, d]) => !!d).map(([r, d]) => `${r}: ${d}`).join(`
529
+ `)}
530
+
531
+ ${e}` : e;
532
+ })();
533
+ return {
534
+ id: y(),
535
+ type: "FROM_USER",
536
+ content: s,
537
+ deliveredAt: (/* @__PURE__ */ new Date()).toISOString(),
538
+ attachments: t,
539
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
540
+ };
541
+ }, this.toBotMessage = (e) => {
542
+ var t;
543
+ return e.success && e.autopilotResponse ? {
544
+ type: "FROM_BOT",
545
+ id: e.autopilotResponse.id || y(),
546
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
547
+ component: "bot_message",
548
+ agent: this.config.bot ? {
549
+ name: this.config.bot.name || "",
550
+ isAi: !0,
551
+ avatar: this.config.bot.avatar || "",
552
+ id: null
553
+ } : void 0,
554
+ data: {
555
+ message: e.autopilotResponse.value.content,
556
+ action: (t = e.uiResponse) != null && t.value.name ? {
557
+ name: e.uiResponse.value.name,
558
+ data: e.uiResponse.value.request_response
559
+ } : void 0
560
+ }
561
+ } : null;
562
+ }, this.toBotErrorMessage = (e) => ({
563
+ type: "FROM_BOT",
564
+ id: y(),
565
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
566
+ component: "TEXT",
567
+ data: {
568
+ message: e,
569
+ variant: "error",
570
+ action: void 0
571
+ }
572
+ }), this.config = a, this.api = o, this.sessionCtx = h, this.contactCtx = n;
573
+ }
574
+ }
575
+ class N {
576
+ constructor({
577
+ config: a,
578
+ contactCtx: o,
579
+ sessionCtx: h,
580
+ resetChat: n
581
+ }) {
582
+ var e;
583
+ this.registerRoutingListener = () => {
584
+ this.contactCtx.state.subscribe(({ contact: t }) => {
585
+ var s;
586
+ t != null && t.token && this.state.get().screen === "welcome" && this.state.setPartial({
587
+ screen: (s = this.config.router) != null && s.chatScreenOnly ? "chat" : "sessions"
588
+ });
589
+ }), this.sessionCtx.sessionsState.subscribe(
590
+ ({ isInitialFetchLoading: t, data: s }) => {
591
+ var i, c, r, d;
592
+ if ((i = this.config.router) != null && i.chatScreenOnly && // Do not route to a chat if we are currently inside one already
593
+ // This also applies to newly created sessions; the new session will be in `sessionState` before it is refreshed and included in `sessionsState`
594
+ !((c = this.sessionCtx.sessionState.get().session) != null && c.id)) {
595
+ const l = (r = s.find((C) => C.isOpened)) == null ? void 0 : r.id;
596
+ return l ? this.toChatScreen(l) : void 0;
597
+ }
598
+ s.length || ((d = this.config.router) == null ? void 0 : d.goToChatIfNoSessions) !== !1 && !t && this.state.get().screen !== "chat" && this.toChatScreen();
599
+ }
600
+ );
601
+ }, this.toSessionsScreen = () => {
602
+ this.resetChat(), this.state.setPartial({ screen: "sessions" });
603
+ }, this.toChatScreen = (t) => {
604
+ if (this.resetChat(), t) {
605
+ const s = this.sessionCtx.sessionsState.get().data.find((i) => i.id === t);
606
+ if (!s) return;
607
+ this.sessionCtx.sessionState.setPartial({ session: s });
608
+ }
609
+ this.state.setPartial({ screen: "chat" });
610
+ }, this.config = a, this.contactCtx = o, this.sessionCtx = h, this.resetChat = n, this.state = new P({
611
+ screen: this.contactCtx.shouldCollectData() ? "welcome" : (e = this.config.router) != null && e.chatScreenOnly ? "chat" : "sessions"
612
+ }), this.registerRoutingListener();
613
+ }
614
+ }
615
+ class H {
616
+ constructor({ storage: a }) {
617
+ this.KEYS = {
618
+ contactToken: "opencx__widget__contactToken",
619
+ externalContactId: "opencx__widget__externalContactId"
620
+ }, this.setContactToken = async (o) => {
621
+ await this.storage.set(this.KEYS.contactToken, o);
622
+ }, this.getContactToken = async () => this.storage.get(this.KEYS.contactToken), this.setExternalContactId = async (o) => {
623
+ await this.storage.set(this.KEYS.externalContactId, o);
624
+ }, this.getExternalContactId = async () => this.storage.get(this.KEYS.externalContactId), this.storage = a;
625
+ }
626
+ }
627
+ const m = class m {
628
+ constructor({
629
+ config: a,
630
+ storage: o,
631
+ modes: h
632
+ }) {
633
+ if (this.modes = [], this.resetChat = () => {
634
+ this.sessionCtx.reset(), this.messageCtx.reset();
635
+ }, !m.pollingIntervalsSeconds)
636
+ throw Error(
637
+ "Widget polling values are not defined, did you call WidgetCtx.initialize()"
638
+ );
639
+ this.config = a, this.api = new T({ config: a }), this.storageCtx = o ? new H({ storage: o }) : void 0, this.modes = h, this.contactCtx = new B({
640
+ api: this.api,
641
+ config: this.config,
642
+ storageCtx: this.storageCtx
643
+ }), this.sessionCtx = new q({
644
+ api: this.api,
645
+ contactCtx: this.contactCtx,
646
+ sessionsPollingIntervalSeconds: m.pollingIntervalsSeconds.sessions
647
+ }), this.messageCtx = new $({
648
+ config: this.config,
649
+ api: this.api,
650
+ sessionCtx: this.sessionCtx,
651
+ contactCtx: this.contactCtx
652
+ }), this.activeSessionPollingCtx = new L({
653
+ api: this.api,
654
+ config: this.config,
655
+ sessionCtx: this.sessionCtx,
656
+ messageCtx: this.messageCtx,
657
+ sessionPollingIntervalSeconds: m.pollingIntervalsSeconds.session
658
+ }), this.routerCtx = new N({
659
+ config: this.config,
660
+ contactCtx: this.contactCtx,
661
+ sessionCtx: this.sessionCtx,
662
+ resetChat: this.resetChat
663
+ });
664
+ }
665
+ };
666
+ m.pollingIntervalsSeconds = null, m.initialize = async ({
667
+ config: a,
668
+ storage: o
669
+ }) => {
670
+ var n, e, t;
671
+ const h = await new T({
672
+ config: a
673
+ }).getExternalWidgetConfig();
674
+ return m.pollingIntervalsSeconds = {
675
+ session: ((n = h.data) == null ? void 0 : n.sessionPollingIntervalSeconds) || 10,
676
+ sessions: ((e = h.data) == null ? void 0 : e.sessionsPollingIntervalSeconds) || 60
677
+ }, new m({
678
+ config: a,
679
+ storage: o,
680
+ modes: ((t = h.data) == null ? void 0 : t.modes) || []
681
+ });
682
+ };
683
+ let U = m;
684
+ export {
685
+ P,
686
+ U as W
687
+ };
688
+ //# sourceMappingURL=widget.ctx-uAWzif3-.js.map