@spilki/widget 1.0.32 → 1.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bootstrap.es.js +217 -183
- package/dist/bootstrap.es.js.map +1 -1
- package/dist/bootstrap.umd.js +8 -8
- package/dist/bootstrap.umd.js.map +1 -1
- package/dist/core/transport.d.ts +4 -1
- package/dist/core/transport.d.ts.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/widget.es.js +220 -186
- package/dist/widget.es.js.map +1 -1
- package/dist/widget.umd.js +8 -8
- package/dist/widget.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const R = `
|
|
2
2
|
<style>
|
|
3
3
|
:host {
|
|
4
4
|
all: initial;
|
|
@@ -71,11 +71,11 @@ const F = `
|
|
|
71
71
|
<span class="badge" hidden aria-hidden="true">0</span>
|
|
72
72
|
</button>
|
|
73
73
|
`;
|
|
74
|
-
function
|
|
74
|
+
function K(r) {
|
|
75
75
|
const e = document.createElement("div");
|
|
76
76
|
e.setAttribute("part", "bubble-root"), e.setAttribute("data-position", r.position), e.style.setProperty("--spilki-accent", r.color);
|
|
77
77
|
const t = e.attachShadow({ mode: "open" });
|
|
78
|
-
t.innerHTML =
|
|
78
|
+
t.innerHTML = R;
|
|
79
79
|
const s = t.querySelector("button"), i = t.querySelector(".badge");
|
|
80
80
|
return s.addEventListener("click", () => r.onClick()), {
|
|
81
81
|
element: e,
|
|
@@ -85,81 +85,81 @@ function R(r) {
|
|
|
85
85
|
destroy() {
|
|
86
86
|
e.remove();
|
|
87
87
|
},
|
|
88
|
-
setOpen(
|
|
89
|
-
s.setAttribute("aria-expanded", String(
|
|
88
|
+
setOpen(l) {
|
|
89
|
+
s.setAttribute("aria-expanded", String(l)), s.setAttribute("aria-label", l ? "Close chat" : "Open chat");
|
|
90
90
|
},
|
|
91
|
-
setBadge(
|
|
92
|
-
const n = Math.max(0,
|
|
91
|
+
setBadge(l) {
|
|
92
|
+
const n = Math.max(0, l), a = s.getAttribute("aria-expanded") === "true";
|
|
93
93
|
if (n === 0) {
|
|
94
|
-
i.toggleAttribute("hidden", !0), i.textContent = "0",
|
|
94
|
+
i.toggleAttribute("hidden", !0), i.textContent = "0", a || s.setAttribute("aria-label", "Open chat");
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
|
-
i.toggleAttribute("hidden", !1), i.textContent = n > 99 ? "99+" : String(n),
|
|
97
|
+
i.toggleAttribute("hidden", !1), i.textContent = n > 99 ? "99+" : String(n), a || s.setAttribute("aria-label", `Open chat, ${n} unread`);
|
|
98
98
|
}
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
|
-
const
|
|
101
|
+
const H = "https://api.spilki.app", I = {
|
|
102
102
|
welcome: "Hi! I'm your assistant.",
|
|
103
103
|
placeholder: "Type a message…",
|
|
104
104
|
sendLabel: "Send",
|
|
105
|
-
typing: "Assistant is typing
|
|
106
|
-
thinking: "Assistant is thinking
|
|
107
|
-
searching: "Searching
|
|
108
|
-
executingTool: "Working on it
|
|
105
|
+
typing: "Assistant is typing",
|
|
106
|
+
thinking: "Assistant is thinking",
|
|
107
|
+
searching: "Searching",
|
|
108
|
+
executingTool: "Working on it",
|
|
109
109
|
offline: "Unable to connect. Please try again later.",
|
|
110
110
|
title: "Spilki Assistant"
|
|
111
|
-
},
|
|
112
|
-
apiBase:
|
|
111
|
+
}, w = {
|
|
112
|
+
apiBase: H,
|
|
113
113
|
position: "bottom-right",
|
|
114
114
|
theme: "auto",
|
|
115
115
|
color: "#6366f1",
|
|
116
|
-
welcome:
|
|
116
|
+
welcome: I.welcome,
|
|
117
117
|
persist: !0,
|
|
118
118
|
sound: !0,
|
|
119
|
-
i18n:
|
|
119
|
+
i18n: I
|
|
120
120
|
};
|
|
121
|
-
function
|
|
122
|
-
var t, s, i, o,
|
|
123
|
-
const e = { ...
|
|
121
|
+
function z(r) {
|
|
122
|
+
var t, s, i, o, l, n, a, g;
|
|
123
|
+
const e = { ...I, ...(t = r.i18n) != null ? t : {} };
|
|
124
124
|
return {
|
|
125
|
-
...
|
|
125
|
+
...w,
|
|
126
126
|
...r,
|
|
127
|
-
apiBase: (s = r.apiBase) != null ? s :
|
|
127
|
+
apiBase: (s = r.apiBase) != null ? s : w.apiBase,
|
|
128
128
|
i18n: e,
|
|
129
129
|
welcome: (i = r.welcome) != null ? i : e.welcome,
|
|
130
|
-
position: (o = r.position) != null ? o :
|
|
131
|
-
theme: (
|
|
132
|
-
color: (n = r.color) != null ? n :
|
|
133
|
-
persist: (
|
|
134
|
-
sound: (
|
|
130
|
+
position: (o = r.position) != null ? o : w.position,
|
|
131
|
+
theme: (l = r.theme) != null ? l : w.theme,
|
|
132
|
+
color: (n = r.color) != null ? n : w.color,
|
|
133
|
+
persist: (a = r.persist) != null ? a : w.persist,
|
|
134
|
+
sound: (g = r.sound) != null ? g : w.sound
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
|
-
function
|
|
137
|
+
function _(r = "msg") {
|
|
138
138
|
return typeof crypto != "undefined" && crypto.randomUUID ? crypto.randomUUID() : `${r}-${Math.random().toString(16).slice(2)}`;
|
|
139
139
|
}
|
|
140
|
-
function
|
|
140
|
+
function G() {
|
|
141
141
|
var r, e;
|
|
142
142
|
return (e = (r = window.matchMedia) == null ? void 0 : r.call(window, "(prefers-color-scheme: dark)").matches) != null ? e : !1;
|
|
143
143
|
}
|
|
144
144
|
function P(r) {
|
|
145
|
-
return r === "light" || r === "dark" ? r :
|
|
145
|
+
return r === "light" || r === "dark" ? r : G() ? "dark" : "light";
|
|
146
146
|
}
|
|
147
|
-
function
|
|
147
|
+
function S(r, e = 30) {
|
|
148
148
|
return r.slice(-e);
|
|
149
149
|
}
|
|
150
|
-
function
|
|
150
|
+
function q(r) {
|
|
151
151
|
if (!r || r.length === 0) return;
|
|
152
152
|
const e = window.location.origin;
|
|
153
153
|
r.includes(e) || console.warn(
|
|
154
154
|
`SpilkiWidget: current origin ${e} not in allowedOriginsHint: ${r.join(", ")}`
|
|
155
155
|
);
|
|
156
156
|
}
|
|
157
|
-
const
|
|
158
|
-
function
|
|
159
|
-
const e = new Date(r), t = /* @__PURE__ */ new Date(), s = (
|
|
160
|
-
return n === o ? `Today at ${i}` : n ===
|
|
157
|
+
const Y = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
158
|
+
function V(r) {
|
|
159
|
+
const e = new Date(r), t = /* @__PURE__ */ new Date(), s = (a) => String(a).padStart(2, "0"), i = `${s(e.getHours())}:${s(e.getMinutes())}`, o = new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime(), l = o - 864e5, n = new Date(e.getFullYear(), e.getMonth(), e.getDate()).getTime();
|
|
160
|
+
return n === o ? `Today at ${i}` : n === l ? `Yesterday at ${i}` : `${Y[e.getMonth()]} ${e.getDate()}, ${i}`;
|
|
161
161
|
}
|
|
162
|
-
const
|
|
162
|
+
const J = ':host{--spilki-bg-light: #ffffff;--spilki-bg-dark: #0f172a;--spilki-text-light: #0f172a;--spilki-text-dark: #f8fafc;--spilki-border-light: rgba(15, 23, 42, .1);--spilki-border-dark: rgba(148, 163, 184, .25);--spilki-muted-light: #64748b;--spilki-muted-dark: #94a3b8;--spilki-shadow: 0 10px 40px rgba(15, 23, 42, .2);--spilki-radius: 16px;--spilki-font: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;color:inherit;font-family:var(--spilki-font)}.wrapper{position:relative;width:100%;height:100%;display:flex;flex-direction:column;background:var(--spilki-surface);color:var(--spilki-text);border-radius:var(--spilki-radius);box-shadow:var(--spilki-shadow);border:1px solid var(--spilki-border);overflow:hidden}header{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;background:var(--spilki-surface);border-bottom:1px solid var(--spilki-border)}header h1{font-size:1rem;margin:0;display:flex;align-items:center;gap:.5rem}header button.close{border:none;background:transparent;color:inherit;font-size:1.25rem;cursor:pointer}header button.close:focus-visible{outline:2px solid var(--spilki-accent);outline-offset:2px;border-radius:4px}header .status-dot{width:10px;height:10px;border-radius:999px;background:var(--spilki-accent)}.messages{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.75rem;scrollbar-width:thin;scrollbar-color:rgba(148,163,184,.3) transparent;scroll-behavior:smooth}.message{display:flex;flex-direction:column;gap:.15rem;max-width:85%;width:fit-content;line-height:1.4;word-wrap:break-word;overflow-wrap:anywhere;white-space:pre-wrap}.message.user{align-self:flex-end;align-items:flex-end}.message .bubble{padding:.6rem .8rem;border-radius:1rem;background:#6366f126}.message.user .bubble{background:var(--spilki-accent);color:#fff}.message.bot .bubble{background:#94a3b826}.msg-time{font-size:.7rem;color:var(--spilki-muted);margin-top:2px}.date-separator{display:flex;align-items:center;gap:.5rem;padding:.4rem 0;font-size:.72rem;color:var(--spilki-muted);white-space:nowrap}.date-separator:before,.date-separator:after{content:"";flex:1;height:1px;background:var(--spilki-border)}.scroll-bottom{position:absolute;right:1rem;bottom:88px;width:38px;height:38px;border:none;border-radius:999px;background:var(--spilki-accent);color:#fff;box-shadow:0 8px 20px #0f172a40;cursor:pointer;opacity:0;pointer-events:none;transform:translateY(4px);transition:opacity .18s ease,transform .18s ease;z-index:3}.scroll-bottom.visible{opacity:1;pointer-events:auto;transform:translateY(0)}.scroll-arrow{font-size:.8rem;line-height:1}.scroll-count{position:absolute;top:-5px;right:-5px;min-width:16px;height:16px;border-radius:999px;background:#ef4444;color:#fff;font-size:10px;line-height:16px;text-align:center;padding:0 4px}.suggested-replies{display:flex;flex-wrap:wrap;gap:.4rem;padding:.5rem 1rem;border-top:1px solid var(--spilki-border)}.suggested-chip{border:1px solid var(--spilki-accent);background:transparent;color:var(--spilki-accent);border-radius:999px;padding:.35rem .75rem;font-size:.8rem;font-family:inherit;cursor:pointer;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:background .15s,color .15s}.suggested-chip:hover{background:var(--spilki-accent);color:#fff}.suggested-chip:focus-visible{outline:2px solid var(--spilki-accent);outline-offset:2px}.input-area{padding:.5rem .75rem}.input-wrap{display:flex;align-items:center;border:1px solid var(--spilki-border);border-radius:1.5rem;background:transparent;padding-left:0}.input-area textarea{flex:1;resize:none;min-height:2.4rem;max-height:6rem;border:0;border-radius:0;outline:0;background:transparent;box-shadow:none;-webkit-box-shadow:none;-webkit-appearance:none;appearance:none;padding:.55rem 0 .55rem 1rem;font-family:inherit;font-size:.95rem;color:var(--spilki-text);scrollbar-width:thin;scrollbar-color:rgba(148,163,184,.3) transparent}.input-actions{display:flex;align-items:center;gap:.25rem;padding:.25rem .35rem;flex-shrink:0}.input-actions button{width:32px;height:32px;display:grid;place-items:center;border:none;border-radius:50%;cursor:pointer;padding:0;transition:opacity .15s}.emoji-btn{background:#6366f126;color:var(--spilki-accent)}.emoji-btn:hover{background:#6366f140}.emoji-btn:focus-visible{outline:2px solid var(--spilki-accent);outline-offset:1px}.send-btn{background:var(--spilki-accent);color:#fff}.send-btn:hover{opacity:.85}.send-btn:focus-visible{outline:2px solid var(--spilki-accent);outline-offset:2px}.emoji-picker{position:absolute;right:1rem;bottom:80px;width:240px;max-height:180px;overflow-y:auto;display:none;grid-template-columns:repeat(10,minmax(0,1fr));gap:.25rem;padding:.5rem;background:var(--spilki-surface);border:1px solid var(--spilki-border);border-radius:12px;box-shadow:0 14px 30px #0f172a40;z-index:4}.emoji-option{width:100%;aspect-ratio:1;border:none;border-radius:8px;background:transparent;font-size:1rem;cursor:pointer}.emoji-option:hover,.emoji-option:focus-visible{background:#94a3b833}.typing{font-size:.75rem;color:var(--spilki-muted);padding:0 1rem .75rem}.typing:after{content:"";animation:dots 1.2s steps(4,end) infinite}@keyframes dots{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}}.offline{font-size:.8rem;padding:0 1rem;color:#f97316}:host([data-theme="dark"]){--spilki-surface: var(--spilki-bg-dark);--spilki-text: var(--spilki-text-dark);--spilki-border: var(--spilki-border-dark);--spilki-muted: var(--spilki-muted-dark)}:host([data-theme="dark"]) .messages,:host([data-theme="dark"]) .input-area textarea,:host([data-theme="dark"]) .emoji-picker{scrollbar-color:rgba(255,255,255,.2) transparent}:host([data-theme="light"]){--spilki-surface: var(--spilki-bg-light);--spilki-text: var(--spilki-text-light);--spilki-border: var(--spilki-border-light);--spilki-muted: var(--spilki-muted-light)}:host([data-theme="dark"]) .message .bubble{background:#94a3b81f}:host([data-theme="dark"]) .message.bot .bubble{background:#6366f126}:host([data-theme="dark"]) .input-area textarea{background:transparent}.messages::-webkit-scrollbar,.input-area textarea::-webkit-scrollbar,.emoji-picker::-webkit-scrollbar{width:6px}.messages::-webkit-scrollbar-track,.input-area textarea::-webkit-scrollbar-track,.emoji-picker::-webkit-scrollbar-track{background:transparent}.messages::-webkit-scrollbar-thumb,.input-area textarea::-webkit-scrollbar-thumb,.emoji-picker::-webkit-scrollbar-thumb{background:#94a3b84d;border-radius:999px}.messages::-webkit-scrollbar-thumb:hover,.input-area textarea::-webkit-scrollbar-thumb:hover,.emoji-picker::-webkit-scrollbar-thumb:hover{background:#94a3b880}:host([data-theme="dark"]) .messages::-webkit-scrollbar-thumb,:host([data-theme="dark"]) .input-area textarea::-webkit-scrollbar-thumb,:host([data-theme="dark"]) .emoji-picker::-webkit-scrollbar-thumb{background:#fff3}:host([data-theme="dark"]) .messages::-webkit-scrollbar-thumb:hover,:host([data-theme="dark"]) .input-area textarea::-webkit-scrollbar-thumb:hover,:host([data-theme="dark"]) .emoji-picker::-webkit-scrollbar-thumb:hover{background:#ffffff59}.conversation-separator{display:flex;align-items:center;gap:.5rem;padding:.5rem 0;cursor:pointer;user-select:none;font-size:.7rem;color:var(--spilki-muted);white-space:nowrap}.conversation-separator:before,.conversation-separator:after{content:"";flex:1;height:1px;background:var(--spilki-border)}.conversation-separator:hover{color:var(--spilki-text)}.conversation-separator:focus-visible{outline:2px solid var(--spilki-accent);outline-offset:2px;border-radius:4px}.conversation-history{display:none;flex-direction:column;gap:.5rem}.conversation-history.expanded{display:flex}', D = 24 * 60 * 60 * 1e3, X = 2 * 60 * 1e3, Z = 200, Q = [
|
|
163
163
|
"😀",
|
|
164
164
|
"😂",
|
|
165
165
|
"🤣",
|
|
@@ -211,10 +211,10 @@ const V = ':host{--spilki-bg-light: #ffffff;--spilki-bg-dark: #0f172a;--spilki-t
|
|
|
211
211
|
"☕",
|
|
212
212
|
"🍕"
|
|
213
213
|
];
|
|
214
|
-
function
|
|
214
|
+
function x(r) {
|
|
215
215
|
return r.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
216
216
|
}
|
|
217
|
-
class
|
|
217
|
+
class ee {
|
|
218
218
|
constructor(e) {
|
|
219
219
|
this.options = e, this.relativeTimeFormat = new Intl.RelativeTimeFormat(void 0, {
|
|
220
220
|
numeric: "auto"
|
|
@@ -229,9 +229,9 @@ class Q {
|
|
|
229
229
|
day: "numeric",
|
|
230
230
|
year: "numeric"
|
|
231
231
|
}), this.renderedMessages = [], this.focusable = [], this.seenIds = /* @__PURE__ */ new Set(), this.lastTimelineMessage = null, this.scrollUnreadCount = 0, this.emojiPickerOpen = !1, this.open = !1, this.host = document.createElement("div"), this.host.setAttribute("part", "panel-root"), this.host.style.position = "fixed", this.host.style.bottom = "96px", this.host.style[e.position === "bottom-right" ? "right" : "left"] = "24px", this.host.style.width = "360px", this.host.style.maxWidth = "calc(100vw - 32px)", this.host.style.height = "520px", this.host.style.display = "none", this.host.style.zIndex = "2147483001", this.shadow = this.host.attachShadow({ mode: "open" });
|
|
232
|
-
const t =
|
|
232
|
+
const t = x(e.i18n.title), s = x(e.i18n.typing), i = x(e.i18n.offline), o = x(e.i18n.placeholder), l = x(e.i18n.sendLabel);
|
|
233
233
|
this.shadow.innerHTML = `
|
|
234
|
-
<style>${
|
|
234
|
+
<style>${J}</style>
|
|
235
235
|
<div class="wrapper" role="dialog" aria-modal="true" aria-label="${t}">
|
|
236
236
|
<header>
|
|
237
237
|
<h1><span class="status-dot" aria-hidden="true"></span>${t}</h1>
|
|
@@ -258,7 +258,7 @@ class Q {
|
|
|
258
258
|
<circle cx="15" cy="10" r="1" fill="currentColor"/>
|
|
259
259
|
</svg>
|
|
260
260
|
</button>
|
|
261
|
-
<button type="button" class="send-btn" aria-label="${
|
|
261
|
+
<button type="button" class="send-btn" aria-label="${l}">
|
|
262
262
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
263
263
|
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" fill="currentColor"/>
|
|
264
264
|
</svg>
|
|
@@ -278,23 +278,23 @@ class Q {
|
|
|
278
278
|
this.options.onClose();
|
|
279
279
|
}
|
|
280
280
|
}, this.handleShadowKeydown = (n) => {
|
|
281
|
-
const
|
|
282
|
-
if (
|
|
281
|
+
const a = n;
|
|
282
|
+
if (a.key === "Escape") {
|
|
283
283
|
if (this.emojiPickerOpen) {
|
|
284
|
-
|
|
284
|
+
a.preventDefault(), this.closeEmojiPicker();
|
|
285
285
|
return;
|
|
286
286
|
}
|
|
287
287
|
this.options.onClose();
|
|
288
288
|
}
|
|
289
|
-
|
|
289
|
+
a.key === "Tab" && this.trapFocus(a);
|
|
290
290
|
}, this.handleFocusin = () => this.collectFocusable(), this.handleMessagesScroll = () => this.updateScrollBottomState(), this.handleScrollBottomClick = () => {
|
|
291
291
|
this.scrollToBottom(), this.resetScrollUnreadCount();
|
|
292
292
|
}, this.handleEmojiClick = () => {
|
|
293
293
|
this.toggleEmojiPicker();
|
|
294
294
|
}, this.handleDocumentPointerDown = (n) => {
|
|
295
295
|
if (!this.emojiPickerOpen) return;
|
|
296
|
-
const
|
|
297
|
-
|
|
296
|
+
const a = n.composedPath();
|
|
297
|
+
a.includes(this.emojiPickerEl) || a.includes(this.emojiButton) || this.closeEmojiPicker();
|
|
298
298
|
}, this.closeButton.addEventListener("click", this.handleCloseClick), this.sendButton.addEventListener("click", this.handleSendClick), this.emojiButton.addEventListener("click", this.handleEmojiClick), this.scrollBottomButton.addEventListener("click", this.handleScrollBottomClick), this.input.addEventListener("keydown", this.handleInputKeydown), this.messagesEl.addEventListener("scroll", this.handleMessagesScroll), this.shadow.addEventListener("keydown", this.handleShadowKeydown), this.shadow.addEventListener("focusin", this.handleFocusin), document.addEventListener("pointerdown", this.handleDocumentPointerDown, !0), this.renderEmojiPicker(), this.updateScrollBottomState(), this.collectFocusable();
|
|
299
299
|
}
|
|
300
300
|
mount() {
|
|
@@ -329,8 +329,8 @@ class Q {
|
|
|
329
329
|
this.messagesEl.innerHTML = "", this.seenIds.clear(), this.renderedMessages.length = 0, this.lastTimelineMessage = null;
|
|
330
330
|
for (const s of e) {
|
|
331
331
|
s.messages.forEach((n) => this.seenIds.add(n.id));
|
|
332
|
-
const i = this.createHistoryContainer(s.messages), o = s.messages[s.messages.length - 1].ts,
|
|
333
|
-
this.messagesEl.appendChild(i), this.messagesEl.appendChild(
|
|
332
|
+
const i = this.createHistoryContainer(s.messages), o = s.messages[s.messages.length - 1].ts, l = this.createSeparatorElement(o, i);
|
|
333
|
+
this.messagesEl.appendChild(i), this.messagesEl.appendChild(l);
|
|
334
334
|
}
|
|
335
335
|
t.forEach((s) => {
|
|
336
336
|
this.seenIds.add(s.id), this.appendTimelineMessage(s);
|
|
@@ -395,7 +395,7 @@ class Q {
|
|
|
395
395
|
}
|
|
396
396
|
createSeparatorElement(e, t) {
|
|
397
397
|
const s = document.createElement("div");
|
|
398
|
-
s.className = "conversation-separator", s.setAttribute("role", "button"), s.setAttribute("tabindex", "0"), s.setAttribute("aria-expanded", "false"), s.setAttribute("aria-label", "Show previous conversation"), s.textContent =
|
|
398
|
+
s.className = "conversation-separator", s.setAttribute("role", "button"), s.setAttribute("tabindex", "0"), s.setAttribute("aria-expanded", "false"), s.setAttribute("aria-label", "Show previous conversation"), s.textContent = V(e);
|
|
399
399
|
const i = () => {
|
|
400
400
|
const o = t.classList.toggle("expanded");
|
|
401
401
|
s.setAttribute("aria-expanded", String(o)), s.setAttribute(
|
|
@@ -404,8 +404,8 @@ class Q {
|
|
|
404
404
|
);
|
|
405
405
|
};
|
|
406
406
|
return s.addEventListener("click", i), s.addEventListener("keydown", (o) => {
|
|
407
|
-
const
|
|
408
|
-
(
|
|
407
|
+
const l = o;
|
|
408
|
+
(l.key === "Enter" || l.key === " ") && (l.preventDefault(), i());
|
|
409
409
|
}), s;
|
|
410
410
|
}
|
|
411
411
|
createHistoryContainer(e) {
|
|
@@ -431,13 +431,13 @@ class Q {
|
|
|
431
431
|
}
|
|
432
432
|
updateTimestampVisibility() {
|
|
433
433
|
for (let e = 0; e < this.renderedMessages.length; e += 1) {
|
|
434
|
-
const t = this.renderedMessages[e], s = this.renderedMessages[e + 1], i = !!s && s.message.author === t.message.author && s.message.ts - t.message.ts <=
|
|
434
|
+
const t = this.renderedMessages[e], s = this.renderedMessages[e + 1], i = !!s && s.message.author === t.message.author && s.message.ts - t.message.ts <= X && s.message.ts >= t.message.ts;
|
|
435
435
|
t.timeEl.toggleAttribute("hidden", i), t.timeEl.textContent = this.formatMessageTimestamp(t.message.ts);
|
|
436
436
|
}
|
|
437
437
|
}
|
|
438
438
|
formatMessageTimestamp(e) {
|
|
439
439
|
const s = Date.now() - e;
|
|
440
|
-
if (s <
|
|
440
|
+
if (s < D) {
|
|
441
441
|
const i = Math.max(1, Math.round(s / 6e4));
|
|
442
442
|
if (i < 60)
|
|
443
443
|
return this.relativeTimeFormat.format(-i, "minute");
|
|
@@ -448,7 +448,7 @@ class Q {
|
|
|
448
448
|
}
|
|
449
449
|
formatDateSeparator(e) {
|
|
450
450
|
const t = new Date(e), s = this.startOfDay(Date.now()), i = this.startOfDay(e);
|
|
451
|
-
return i === s ? "Today" : i === s -
|
|
451
|
+
return i === s ? "Today" : i === s - D ? "Yesterday" : this.dateSeparatorFormat.format(t);
|
|
452
452
|
}
|
|
453
453
|
isSameDay(e, t) {
|
|
454
454
|
return this.startOfDay(e) === this.startOfDay(t);
|
|
@@ -458,7 +458,7 @@ class Q {
|
|
|
458
458
|
return new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime();
|
|
459
459
|
}
|
|
460
460
|
isScrolledUp() {
|
|
461
|
-
return this.distanceFromBottom() >
|
|
461
|
+
return this.distanceFromBottom() > Z;
|
|
462
462
|
}
|
|
463
463
|
distanceFromBottom() {
|
|
464
464
|
return this.messagesEl.scrollHeight - this.messagesEl.scrollTop - this.messagesEl.clientHeight;
|
|
@@ -505,7 +505,7 @@ class Q {
|
|
|
505
505
|
this.emojiPickerOpen && (this.emojiPickerOpen = !1, this.emojiPickerEl.style.display = "none", this.emojiButton.setAttribute("aria-expanded", "false"), this.collectFocusable());
|
|
506
506
|
}
|
|
507
507
|
renderEmojiPicker() {
|
|
508
|
-
this.emojiPickerEl.replaceChildren(),
|
|
508
|
+
this.emojiPickerEl.replaceChildren(), Q.forEach((e) => {
|
|
509
509
|
const t = document.createElement("button");
|
|
510
510
|
t.type = "button", t.className = "emoji-option", t.textContent = e, t.setAttribute("aria-label", `Insert ${e}`), t.addEventListener("click", () => {
|
|
511
511
|
this.insertEmojiAtCursor(e), this.closeEmojiPicker();
|
|
@@ -513,8 +513,8 @@ class Q {
|
|
|
513
513
|
});
|
|
514
514
|
}
|
|
515
515
|
insertEmojiAtCursor(e) {
|
|
516
|
-
var
|
|
517
|
-
const t = this.input.value, s = (
|
|
516
|
+
var l, n;
|
|
517
|
+
const t = this.input.value, s = (l = this.input.selectionStart) != null ? l : t.length, i = (n = this.input.selectionEnd) != null ? n : t.length;
|
|
518
518
|
this.input.value = `${t.slice(0, s)}${e}${t.slice(i)}`;
|
|
519
519
|
const o = s + e.length;
|
|
520
520
|
this.input.setSelectionRange(o, o), this.input.dispatchEvent(new Event("input", { bubbles: !0 })), this.input.focus();
|
|
@@ -533,14 +533,40 @@ class Q {
|
|
|
533
533
|
e.shiftKey && i === t ? (e.preventDefault(), s.focus()) : !e.shiftKey && i === s && (e.preventDefault(), t.focus());
|
|
534
534
|
}
|
|
535
535
|
}
|
|
536
|
-
const
|
|
537
|
-
class
|
|
536
|
+
const v = 1500, L = 8e3;
|
|
537
|
+
class te {
|
|
538
538
|
constructor(e, t) {
|
|
539
|
-
this.sessionId = null, this.currentKind = null, this.stopped = !1, this.backoff =
|
|
539
|
+
this.sessionId = null, this.currentKind = null, this.stopped = !1, this.backoff = v, this.connectPromise = null, this.options = e, this.handlers = t;
|
|
540
540
|
}
|
|
541
541
|
setAccessToken(e) {
|
|
542
542
|
this.options.accessToken = e;
|
|
543
543
|
}
|
|
544
|
+
setUser(e) {
|
|
545
|
+
const t = {};
|
|
546
|
+
for (const [s, i] of Object.entries(e))
|
|
547
|
+
if (typeof i == "string") {
|
|
548
|
+
const o = i.trim();
|
|
549
|
+
o && (t[s] = o);
|
|
550
|
+
}
|
|
551
|
+
this.user = t, this.sessionId && this.sendIdentify().catch(
|
|
552
|
+
(s) => this.handlers.onError(s)
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
async sendIdentify() {
|
|
556
|
+
const e = `${this.options.apiBase.replace(/\/$/, "")}/widget/identify`, t = await fetch(e, {
|
|
557
|
+
method: "POST",
|
|
558
|
+
headers: {
|
|
559
|
+
"Content-Type": "application/json",
|
|
560
|
+
...this.options.accessToken ? { "X-Authorization": `Bearer ${this.options.accessToken}` } : {}
|
|
561
|
+
},
|
|
562
|
+
body: JSON.stringify({
|
|
563
|
+
sessionId: this.sessionId,
|
|
564
|
+
user: this.user
|
|
565
|
+
})
|
|
566
|
+
});
|
|
567
|
+
if (!t.ok)
|
|
568
|
+
throw new Error(`SpilkiWidget: identify failed (${t.status})`);
|
|
569
|
+
}
|
|
544
570
|
get kind() {
|
|
545
571
|
return this.currentKind;
|
|
546
572
|
}
|
|
@@ -559,14 +585,15 @@ class ee {
|
|
|
559
585
|
}
|
|
560
586
|
}
|
|
561
587
|
async doConnect() {
|
|
562
|
-
var
|
|
588
|
+
var l, n;
|
|
563
589
|
this.stopped = !1;
|
|
564
|
-
const e = `${this.options.apiBase.replace(/\/$/, "")}/widget/session`, t = (n = (
|
|
590
|
+
const e = `${this.options.apiBase.replace(/\/$/, "")}/widget/session`, t = (n = (l = this.sessionId) != null ? l : this.options.sessionId) != null ? n : void 0, s = {
|
|
565
591
|
organisationId: this.options.org,
|
|
566
592
|
sessionId: t,
|
|
567
593
|
userAgent: typeof navigator != "undefined" ? navigator.userAgent : "",
|
|
568
594
|
referrer: typeof document != "undefined" ? document.referrer : "",
|
|
569
|
-
origin: typeof window != "undefined" ? window.location.origin : ""
|
|
595
|
+
origin: typeof window != "undefined" ? window.location.origin : "",
|
|
596
|
+
...this.user ? { user: this.user } : {}
|
|
570
597
|
}, i = await fetch(e, {
|
|
571
598
|
method: "POST",
|
|
572
599
|
headers: {
|
|
@@ -578,14 +605,15 @@ class ee {
|
|
|
578
605
|
if (!i.ok)
|
|
579
606
|
throw new Error(`SpilkiWidget: connect failed (${i.status})`);
|
|
580
607
|
const o = await i.json();
|
|
581
|
-
return this.sessionId = o.sessionId, this.options.sessionId = o.sessionId, this.backoff =
|
|
608
|
+
return this.sessionId = o.sessionId, this.options.sessionId = o.sessionId, this.backoff = v, await this.startTransport(o), o;
|
|
582
609
|
}
|
|
583
610
|
async send(e, t) {
|
|
584
|
-
var
|
|
611
|
+
var l, n, a;
|
|
585
612
|
const s = {
|
|
586
|
-
sessionId: (n = (
|
|
613
|
+
sessionId: (n = (l = this.sessionId) != null ? l : this.options.sessionId) != null ? n : "",
|
|
587
614
|
text: e,
|
|
588
|
-
...t ? { messageId: t } : {}
|
|
615
|
+
...t ? { messageId: t } : {},
|
|
616
|
+
...(a = this.user) != null && a.userId ? { userId: this.user.userId } : {}
|
|
589
617
|
};
|
|
590
618
|
if (!s.sessionId)
|
|
591
619
|
throw new Error("SpilkiWidget: missing session id");
|
|
@@ -606,7 +634,7 @@ class ee {
|
|
|
606
634
|
}
|
|
607
635
|
// #1: accept resetBackoff param; #8 #9: clear retryTimer
|
|
608
636
|
stop(e = !0) {
|
|
609
|
-
this.stopped = !0, e && (this.backoff =
|
|
637
|
+
this.stopped = !0, e && (this.backoff = v), this.retryTimer && (clearTimeout(this.retryTimer), this.retryTimer = void 0), this.ws && (this.wsOnOpen && this.ws.removeEventListener("open", this.wsOnOpen), this.wsOnMessage && this.ws.removeEventListener("message", this.wsOnMessage), this.wsOnClose && this.ws.removeEventListener("close", this.wsOnClose), this.wsOnError && this.ws.removeEventListener("error", this.wsOnError), this.ws.close(), this.ws = void 0), this.wsOnOpen = this.wsOnMessage = this.wsOnClose = this.wsOnError = void 0, this.sseAbort && (this.sseAbort.abort(), this.sseAbort = void 0), this.pollTimer && (clearTimeout(this.pollTimer), this.pollTimer = void 0), this.currentKind = null;
|
|
610
638
|
}
|
|
611
639
|
async startTransport(e) {
|
|
612
640
|
if (this.stopped) return;
|
|
@@ -631,7 +659,7 @@ class ee {
|
|
|
631
659
|
i.close();
|
|
632
660
|
return;
|
|
633
661
|
}
|
|
634
|
-
this.currentKind = "ws", this.handlers.onOpen("ws"), this.backoff =
|
|
662
|
+
this.currentKind = "ws", this.handlers.onOpen("ws"), this.backoff = v, t();
|
|
635
663
|
}, this.wsOnMessage = (o) => this.handleIncoming(o.data), this.wsOnClose = () => {
|
|
636
664
|
this.stopped || this.retryFallback("ws");
|
|
637
665
|
}, this.wsOnError = () => {
|
|
@@ -661,31 +689,31 @@ class ee {
|
|
|
661
689
|
i.abort();
|
|
662
690
|
return;
|
|
663
691
|
}
|
|
664
|
-
this.currentKind = "sse", this.handlers.onOpen("sse"), this.backoff =
|
|
665
|
-
const
|
|
666
|
-
let
|
|
667
|
-
const
|
|
668
|
-
|
|
669
|
-
var
|
|
670
|
-
if (
|
|
692
|
+
this.currentKind = "sse", this.handlers.onOpen("sse"), this.backoff = v, t();
|
|
693
|
+
const l = o.body.getReader(), n = new TextDecoder();
|
|
694
|
+
let a = "";
|
|
695
|
+
const g = () => {
|
|
696
|
+
l.read().then(({ done: u, value: d }) => {
|
|
697
|
+
var m;
|
|
698
|
+
if (u || this.stopped) {
|
|
671
699
|
this.stopped || (this.handlers.onError(new Error("SpilkiWidget: SSE stream ended")), this.retryFallback("sse"));
|
|
672
700
|
return;
|
|
673
701
|
}
|
|
674
|
-
|
|
675
|
-
const
|
|
702
|
+
a += n.decode(d, { stream: !0 });
|
|
703
|
+
const h = a.split(`
|
|
676
704
|
|
|
677
705
|
`);
|
|
678
|
-
|
|
679
|
-
for (const
|
|
680
|
-
for (const p of
|
|
706
|
+
a = (m = h.pop()) != null ? m : "";
|
|
707
|
+
for (const f of h)
|
|
708
|
+
for (const p of f.split(`
|
|
681
709
|
`))
|
|
682
710
|
p.startsWith("data:") && this.handleIncoming(p.slice(5).trim());
|
|
683
|
-
|
|
684
|
-
}).catch((
|
|
685
|
-
i.signal.aborted || (this.handlers.onError(
|
|
711
|
+
g();
|
|
712
|
+
}).catch((u) => {
|
|
713
|
+
i.signal.aborted || (this.handlers.onError(u), this.stopped || this.retryFallback("sse"));
|
|
686
714
|
});
|
|
687
715
|
};
|
|
688
|
-
|
|
716
|
+
g();
|
|
689
717
|
}).catch((o) => {
|
|
690
718
|
i.signal.aborted || s(o);
|
|
691
719
|
});
|
|
@@ -693,7 +721,7 @@ class ee {
|
|
|
693
721
|
}
|
|
694
722
|
// #15: add auth header to poll fetch
|
|
695
723
|
async startPoll(e) {
|
|
696
|
-
this.currentKind = "poll", this.handlers.onOpen("poll"), this.backoff =
|
|
724
|
+
this.currentKind = "poll", this.handlers.onOpen("poll"), this.backoff = v;
|
|
697
725
|
const t = async () => {
|
|
698
726
|
if (!this.stopped)
|
|
699
727
|
try {
|
|
@@ -704,9 +732,9 @@ class ee {
|
|
|
704
732
|
});
|
|
705
733
|
if (!s.ok) throw new Error(`Poll failed ${s.status}`);
|
|
706
734
|
const i = await s.json();
|
|
707
|
-
|
|
735
|
+
S(i).forEach((o) => this.handlers.onMessage(o)), this.backoff = v;
|
|
708
736
|
} catch (s) {
|
|
709
|
-
this.handlers.onError(s), this.backoff = Math.min(this.backoff * 1.5,
|
|
737
|
+
this.handlers.onError(s), this.backoff = Math.min(this.backoff * 1.5, L);
|
|
710
738
|
} finally {
|
|
711
739
|
this.stopped || (this.pollTimer = window.setTimeout(t, this.backoff));
|
|
712
740
|
}
|
|
@@ -715,7 +743,7 @@ class ee {
|
|
|
715
743
|
}
|
|
716
744
|
// #1: preserve backoff by calling stop(false); #8: check stopped before reconnect
|
|
717
745
|
retryFallback(e) {
|
|
718
|
-
this.stopped || (this.stop(!1), this.backoff = Math.min(this.backoff * 1.5,
|
|
746
|
+
this.stopped || (this.stop(!1), this.backoff = Math.min(this.backoff * 1.5, L), this.retryTimer = window.setTimeout(() => {
|
|
719
747
|
this.stopped || (this.handlers.onError(new Error(`SpilkiWidget: retrying after ${e}`)), this.connect().catch((t) => this.handlers.onError(t)));
|
|
720
748
|
}, this.backoff));
|
|
721
749
|
}
|
|
@@ -735,20 +763,20 @@ class ee {
|
|
|
735
763
|
dispatchIncoming(e) {
|
|
736
764
|
var t;
|
|
737
765
|
if ("type" in e) {
|
|
738
|
-
e.type === "message" ? this.handlers.onMessage(e.payload) : e.type === "typing" ? this.handlers.onTyping(!!((t = e.payload) != null && t.active)) : e.type === "AGENT_EVENT" &&
|
|
766
|
+
e.type === "message" ? this.handlers.onMessage(e.payload) : e.type === "typing" ? this.handlers.onTyping(!!((t = e.payload) != null && t.active)) : e.type === "AGENT_EVENT" && ie(e.payload) && this.handlers.onAgentEvent(e.payload);
|
|
739
767
|
return;
|
|
740
768
|
}
|
|
741
769
|
this.handlers.onMessage(e);
|
|
742
770
|
}
|
|
743
771
|
}
|
|
744
|
-
const
|
|
745
|
-
function
|
|
772
|
+
const se = /* @__PURE__ */ new Set(["TYPING", "THINKING", "SEARCHING", "EXECUTING_TOOL"]);
|
|
773
|
+
function ie(r) {
|
|
746
774
|
if (typeof r != "object" || r === null) return !1;
|
|
747
775
|
const e = r;
|
|
748
|
-
return
|
|
776
|
+
return se.has(e.eventType) && typeof e.active == "boolean";
|
|
749
777
|
}
|
|
750
|
-
const
|
|
751
|
-
class
|
|
778
|
+
const U = 30 * 60 * 1e3, re = 3e4, A = 30;
|
|
779
|
+
class oe {
|
|
752
780
|
constructor(e, t) {
|
|
753
781
|
this.org = e, this.listeners = /* @__PURE__ */ new Set(), this.activityTimer = null, this.activeEvents = /* @__PURE__ */ new Set(), this.state = {
|
|
754
782
|
isOpen: !1,
|
|
@@ -783,7 +811,7 @@ class re {
|
|
|
783
811
|
updateDisplayedActivity() {
|
|
784
812
|
this.activityTimer && (clearTimeout(this.activityTimer), this.activityTimer = null), this.activeEvents.size > 0 && (this.activityTimer = setTimeout(() => {
|
|
785
813
|
this.activeEvents.clear(), this.state.agentActivity = null, this.activityTimer = null, this.emit();
|
|
786
|
-
},
|
|
814
|
+
}, re));
|
|
787
815
|
const e = this.resolveTopActivity();
|
|
788
816
|
this.state.agentActivity !== e && (this.state.agentActivity = e, this.emit());
|
|
789
817
|
}
|
|
@@ -802,15 +830,15 @@ class re {
|
|
|
802
830
|
addMessage(e) {
|
|
803
831
|
var s, i;
|
|
804
832
|
const t = {
|
|
805
|
-
id: (s = e.id) != null ? s :
|
|
833
|
+
id: (s = e.id) != null ? s : _("msg"),
|
|
806
834
|
ts: (i = e.ts) != null ? i : Date.now(),
|
|
807
835
|
author: e.author,
|
|
808
836
|
text: e.text
|
|
809
837
|
};
|
|
810
|
-
return this.state.messages.some((o) => o.id === t.id) ? null : (this.state.messages =
|
|
838
|
+
return this.state.messages.some((o) => o.id === t.id) ? null : (this.state.messages = S([...this.state.messages, t], A), this.persistMessages(), this.touchActivity(), this.emit(), t);
|
|
811
839
|
}
|
|
812
840
|
setMessages(e) {
|
|
813
|
-
this.state.messages =
|
|
841
|
+
this.state.messages = S(e, A), this.persistMessages(), this.emit();
|
|
814
842
|
}
|
|
815
843
|
clearMessages() {
|
|
816
844
|
this.state.messages = [], this.persistMessages(), this.emit();
|
|
@@ -902,7 +930,7 @@ class re {
|
|
|
902
930
|
}
|
|
903
931
|
isSessionExpired() {
|
|
904
932
|
const e = this.lastActivityTs;
|
|
905
|
-
return e === 0 ? !1 : Date.now() - e >=
|
|
933
|
+
return e === 0 ? !1 : Date.now() - e >= U;
|
|
906
934
|
}
|
|
907
935
|
getConversationGroups() {
|
|
908
936
|
const e = this.state.messages;
|
|
@@ -910,7 +938,7 @@ class re {
|
|
|
910
938
|
const t = [];
|
|
911
939
|
let s = { startTs: e[0].ts, messages: [e[0]] };
|
|
912
940
|
for (let i = 1; i < e.length; i++)
|
|
913
|
-
e[i].ts - e[i - 1].ts >=
|
|
941
|
+
e[i].ts - e[i - 1].ts >= U ? (t.push(s), s = { startTs: e[i].ts, messages: [e[i]] }) : s.messages.push(e[i]);
|
|
914
942
|
return t.push(s), t;
|
|
915
943
|
}
|
|
916
944
|
emit() {
|
|
@@ -930,13 +958,13 @@ class re {
|
|
|
930
958
|
const e = localStorage.getItem(this.historyKey);
|
|
931
959
|
if (!e) return [];
|
|
932
960
|
const t = JSON.parse(e);
|
|
933
|
-
return Array.isArray(t) ?
|
|
961
|
+
return Array.isArray(t) ? S(t, A) : [];
|
|
934
962
|
} catch (e) {
|
|
935
963
|
return console.error("SpilkiWidget: unable to load messages", e), [];
|
|
936
964
|
}
|
|
937
965
|
}
|
|
938
966
|
}
|
|
939
|
-
function
|
|
967
|
+
function ne(r) {
|
|
940
968
|
const e = r.replace(/-/g, "+").replace(/_/g, "/"), t = e.padEnd(e.length + (4 - e.length % 4) % 4, "=");
|
|
941
969
|
if (typeof atob == "function")
|
|
942
970
|
return decodeURIComponent(
|
|
@@ -947,24 +975,24 @@ function oe(r) {
|
|
|
947
975
|
return s.from(t, "base64").toString("utf8");
|
|
948
976
|
throw new Error("SpilkiWidget: no base64 decoder available");
|
|
949
977
|
}
|
|
950
|
-
function
|
|
978
|
+
function ae(r) {
|
|
951
979
|
if (!r) return null;
|
|
952
980
|
const e = r.split(".");
|
|
953
981
|
if (e.length < 2) return null;
|
|
954
982
|
try {
|
|
955
|
-
const t =
|
|
983
|
+
const t = ne(e[1]);
|
|
956
984
|
return JSON.parse(t);
|
|
957
985
|
} catch (t) {
|
|
958
986
|
return console.error("SpilkiWidget: unable to parse JWT", t), null;
|
|
959
987
|
}
|
|
960
988
|
}
|
|
961
|
-
function
|
|
962
|
-
const e =
|
|
989
|
+
function le(r) {
|
|
990
|
+
const e = ae(r);
|
|
963
991
|
if (!(e != null && e.exp) || typeof e.exp != "number") return !0;
|
|
964
992
|
const t = Math.floor(Date.now() / 1e3);
|
|
965
993
|
return e.exp < t + 60;
|
|
966
994
|
}
|
|
967
|
-
const
|
|
995
|
+
const ce = {
|
|
968
996
|
onOpen() {
|
|
969
997
|
},
|
|
970
998
|
onClose() {
|
|
@@ -976,7 +1004,7 @@ const le = {
|
|
|
976
1004
|
onTransportChange() {
|
|
977
1005
|
}
|
|
978
1006
|
};
|
|
979
|
-
async function
|
|
1007
|
+
async function de(r, e, t) {
|
|
980
1008
|
const s = `${r.replace(/\/$/, "")}/widget/install`, i = await fetch(s, {
|
|
981
1009
|
method: "POST",
|
|
982
1010
|
headers: { "Content-Type": "application/json", Origin: window.location.origin },
|
|
@@ -993,16 +1021,16 @@ async function he(r, e) {
|
|
|
993
1021
|
if (!s.ok) throw new Error(`SpilkiWidget: refresh failed (${s.status})`);
|
|
994
1022
|
return (await s.json()).accessToken;
|
|
995
1023
|
}
|
|
996
|
-
function
|
|
1024
|
+
function pe(r) {
|
|
997
1025
|
let e = !1, t = null;
|
|
998
1026
|
const s = [], i = () => {
|
|
999
1027
|
var n;
|
|
1000
1028
|
if (!r) return null;
|
|
1001
1029
|
if (t) return t;
|
|
1002
1030
|
try {
|
|
1003
|
-
const
|
|
1004
|
-
if (!
|
|
1005
|
-
t = new
|
|
1031
|
+
const a = (n = window.AudioContext) != null ? n : window.webkitAudioContext;
|
|
1032
|
+
if (!a) return null;
|
|
1033
|
+
t = new a();
|
|
1006
1034
|
} catch {
|
|
1007
1035
|
return null;
|
|
1008
1036
|
}
|
|
@@ -1015,51 +1043,51 @@ function de(r) {
|
|
|
1015
1043
|
});
|
|
1016
1044
|
} catch {
|
|
1017
1045
|
}
|
|
1018
|
-
},
|
|
1019
|
-
const
|
|
1020
|
-
o(), window.removeEventListener(n,
|
|
1046
|
+
}, l = (n) => {
|
|
1047
|
+
const a = () => {
|
|
1048
|
+
o(), window.removeEventListener(n, a, !0);
|
|
1021
1049
|
};
|
|
1022
|
-
s.push({ type: n, listener:
|
|
1050
|
+
s.push({ type: n, listener: a }), window.addEventListener(n, a, { capture: !0, passive: !0 });
|
|
1023
1051
|
};
|
|
1024
|
-
return
|
|
1052
|
+
return l("pointerdown"), l("keydown"), {
|
|
1025
1053
|
markUserInteraction: o,
|
|
1026
1054
|
play() {
|
|
1027
1055
|
if (!r || !e) return;
|
|
1028
1056
|
const n = i();
|
|
1029
1057
|
if (!n || n.state !== "running") return;
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1032
|
-
const
|
|
1033
|
-
const
|
|
1034
|
-
|
|
1035
|
-
},
|
|
1036
|
-
|
|
1058
|
+
const a = n.createGain();
|
|
1059
|
+
a.gain.value = 0.15, a.connect(n.destination);
|
|
1060
|
+
const g = (d, h, m) => {
|
|
1061
|
+
const f = n.createOscillator(), p = n.createGain();
|
|
1062
|
+
f.type = "sine", f.frequency.setValueAtTime(d, h), p.gain.setValueAtTime(1e-4, h), p.gain.exponentialRampToValueAtTime(1, h + 0.012), p.gain.exponentialRampToValueAtTime(1e-4, h + m), f.connect(p), p.connect(a), f.start(h), f.stop(h + m + 0.02);
|
|
1063
|
+
}, u = n.currentTime;
|
|
1064
|
+
g(880, u, 0.08), g(1175, u + 0.09, 0.08);
|
|
1037
1065
|
},
|
|
1038
1066
|
destroy() {
|
|
1039
|
-
s.forEach(({ type: n, listener:
|
|
1040
|
-
window.removeEventListener(n,
|
|
1067
|
+
s.forEach(({ type: n, listener: a }) => {
|
|
1068
|
+
window.removeEventListener(n, a, !0);
|
|
1041
1069
|
}), s.length = 0, t && t.close().catch(() => {
|
|
1042
1070
|
}), t = null;
|
|
1043
1071
|
}
|
|
1044
1072
|
};
|
|
1045
1073
|
}
|
|
1046
|
-
function
|
|
1047
|
-
var
|
|
1074
|
+
function $(r) {
|
|
1075
|
+
var O, M, B, j;
|
|
1048
1076
|
if (!r.org)
|
|
1049
1077
|
throw new Error("SpilkiWidget: org is required");
|
|
1050
|
-
const e =
|
|
1051
|
-
|
|
1052
|
-
const t = { ...
|
|
1053
|
-
let o = (
|
|
1078
|
+
const e = z(r);
|
|
1079
|
+
q(e.allowedOriginsHint);
|
|
1080
|
+
const t = { ...ce, ...(O = e.hooks) != null ? O : {} }, s = new oe(e.org, { persist: e.persist }), i = pe(e.sound);
|
|
1081
|
+
let o = (M = s.accessToken) != null ? M : void 0, l = null;
|
|
1054
1082
|
const n = () => {
|
|
1055
|
-
|
|
1056
|
-
},
|
|
1057
|
-
s.markRead(),
|
|
1058
|
-
},
|
|
1083
|
+
u.setBadge(s.countUnread());
|
|
1084
|
+
}, a = () => {
|
|
1085
|
+
s.markRead(), u.setBadge(0);
|
|
1086
|
+
}, g = async () => l || (l = (async () => {
|
|
1059
1087
|
try {
|
|
1060
|
-
if (o &&
|
|
1088
|
+
if (o && le(o))
|
|
1061
1089
|
try {
|
|
1062
|
-
o = await he(e.apiBase, o), s.persistAccessToken(o),
|
|
1090
|
+
o = await he(e.apiBase, o), s.persistAccessToken(o), h.setAccessToken(o);
|
|
1063
1091
|
return;
|
|
1064
1092
|
} catch {
|
|
1065
1093
|
o = void 0, s.clearAccessToken();
|
|
@@ -1067,32 +1095,32 @@ function U(r) {
|
|
|
1067
1095
|
if (!o) {
|
|
1068
1096
|
if (!r.installationToken) throw new Error("SpilkiWidget: missing installationToken");
|
|
1069
1097
|
if (!r.org) throw new Error("SpilkiWidget: missing org");
|
|
1070
|
-
o = await
|
|
1098
|
+
o = await de(e.apiBase, r.installationToken, r.org), s.persistAccessToken(o), h.setAccessToken(o);
|
|
1071
1099
|
}
|
|
1072
1100
|
} finally {
|
|
1073
|
-
|
|
1101
|
+
l = null;
|
|
1074
1102
|
}
|
|
1075
|
-
})(),
|
|
1103
|
+
})(), l), u = K({
|
|
1076
1104
|
color: e.color,
|
|
1077
|
-
position: (
|
|
1105
|
+
position: (B = e.position) != null ? B : "bottom-right",
|
|
1078
1106
|
onClick: () => {
|
|
1079
|
-
s.snapshot.isOpen ? (s.close(), t.onClose()) : (i.markUserInteraction(), s.open(),
|
|
1107
|
+
s.snapshot.isOpen ? (s.close(), t.onClose()) : (i.markUserInteraction(), s.open(), a(), t.onOpen());
|
|
1080
1108
|
}
|
|
1081
|
-
}),
|
|
1109
|
+
}), d = new ee({
|
|
1082
1110
|
color: e.color,
|
|
1083
1111
|
theme: P(e.theme),
|
|
1084
|
-
position: (
|
|
1112
|
+
position: (j = e.position) != null ? j : "bottom-right",
|
|
1085
1113
|
i18n: e.i18n,
|
|
1086
1114
|
onClose: () => {
|
|
1087
1115
|
s.close(), t.onClose();
|
|
1088
1116
|
},
|
|
1089
1117
|
onSend: (c) => {
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1092
|
-
t.onError(
|
|
1118
|
+
const k = s.addMessage({ author: "user", text: c });
|
|
1119
|
+
k && (d.appendMessage(k), g().then(() => h.send(c, k.id)).catch((b) => {
|
|
1120
|
+
t.onError(b), s.setConnected(!1), d.setOffline(!0);
|
|
1093
1121
|
}));
|
|
1094
1122
|
}
|
|
1095
|
-
}),
|
|
1123
|
+
}), h = new te(
|
|
1096
1124
|
{
|
|
1097
1125
|
apiBase: e.apiBase,
|
|
1098
1126
|
accessToken: o,
|
|
@@ -1101,11 +1129,11 @@ function U(r) {
|
|
|
1101
1129
|
},
|
|
1102
1130
|
{
|
|
1103
1131
|
onOpen(c) {
|
|
1104
|
-
C.transport = c, t.onTransportChange(c), s.setConnected(!0),
|
|
1132
|
+
C.transport = c, t.onTransportChange(c), s.setConnected(!0), d.setOffline(!1);
|
|
1105
1133
|
},
|
|
1106
1134
|
onMessage(c) {
|
|
1107
|
-
const
|
|
1108
|
-
|
|
1135
|
+
const b = c.suggestedReplies, y = s.addMessage(c);
|
|
1136
|
+
y && (d.appendMessage(y), y.author === "bot" && b && b.length > 0 && d.setSuggestedReplies(b), !s.snapshot.isOpen && y.author === "bot" && (n(), i.play()), t.onMessage(y));
|
|
1109
1137
|
},
|
|
1110
1138
|
onTyping(c) {
|
|
1111
1139
|
s.setTyping(c);
|
|
@@ -1114,53 +1142,56 @@ function U(r) {
|
|
|
1114
1142
|
s.handleAgentEvent(c.eventType, c.active);
|
|
1115
1143
|
},
|
|
1116
1144
|
onError(c) {
|
|
1117
|
-
t.onError(c), s.setConnected(!1), s.snapshot.isOpen &&
|
|
1145
|
+
t.onError(c), s.setConnected(!1), s.snapshot.isOpen && d.setOffline(!0);
|
|
1118
1146
|
}
|
|
1119
1147
|
}
|
|
1120
1148
|
);
|
|
1121
|
-
|
|
1122
|
-
const
|
|
1123
|
-
if (
|
|
1149
|
+
u.mount(), d.mount();
|
|
1150
|
+
const m = s.snapshot.messages, f = s.isSessionExpired(), p = s.getConversationGroups();
|
|
1151
|
+
if (m.length === 0 && e.welcome) {
|
|
1124
1152
|
const c = {
|
|
1125
1153
|
id: "welcome",
|
|
1126
1154
|
author: "bot",
|
|
1127
1155
|
text: e.welcome,
|
|
1128
1156
|
ts: Date.now()
|
|
1129
1157
|
};
|
|
1130
|
-
s.addMessage(c),
|
|
1131
|
-
} else
|
|
1132
|
-
let
|
|
1133
|
-
const
|
|
1158
|
+
s.addMessage(c), d.appendMessage(c);
|
|
1159
|
+
} else f && m.length > 0 ? d.renderWithConversations(p, []) : p.length > 1 ? d.renderWithConversations(p.slice(0, -1), p[p.length - 1].messages) : d.updateMessages(m);
|
|
1160
|
+
let T = !1;
|
|
1161
|
+
const W = s.subscribe(() => {
|
|
1134
1162
|
const c = s.snapshot;
|
|
1135
|
-
if (
|
|
1136
|
-
if (!
|
|
1137
|
-
const
|
|
1138
|
-
|
|
1163
|
+
if (u.setOpen(c.isOpen), d.setAgentActivity(c.agentActivity, e.i18n), d.setOffline(!c.isConnected), d.updateTheme(P(e.theme)), c.isOpen) {
|
|
1164
|
+
if (!T) {
|
|
1165
|
+
const k = s.countUnread() > 0, b = s.lastReadTs;
|
|
1166
|
+
a(), k && d.scrollToFirstUnread(b);
|
|
1139
1167
|
}
|
|
1140
|
-
|
|
1168
|
+
T = !0, d.show();
|
|
1141
1169
|
} else
|
|
1142
|
-
|
|
1143
|
-
}),
|
|
1144
|
-
n(),
|
|
1145
|
-
() =>
|
|
1146
|
-
var
|
|
1147
|
-
e.persist && s.persistSession(c.sessionId), s.setConnected(!0), t.onTransportChange((
|
|
1148
|
-
const
|
|
1149
|
-
|
|
1170
|
+
T = !1, d.hide();
|
|
1171
|
+
}), F = m.length === 0 || f;
|
|
1172
|
+
n(), g().then(
|
|
1173
|
+
() => h.connect().then((c) => {
|
|
1174
|
+
var b, y;
|
|
1175
|
+
e.persist && s.persistSession(c.sessionId), s.setConnected(!0), t.onTransportChange((b = h.kind) != null ? b : "ws");
|
|
1176
|
+
const k = (y = c.suggestedReplies) != null ? y : [];
|
|
1177
|
+
k.length > 0 && F && d.setSuggestedReplies(k);
|
|
1150
1178
|
})
|
|
1151
1179
|
).catch((c) => {
|
|
1152
|
-
t.onError(c), s.setConnected(!1),
|
|
1180
|
+
t.onError(c), s.setConnected(!1), d.setOffline(!0);
|
|
1153
1181
|
});
|
|
1154
1182
|
const C = {
|
|
1155
1183
|
transport: null,
|
|
1156
1184
|
open() {
|
|
1157
|
-
i.markUserInteraction(), s.open(),
|
|
1185
|
+
i.markUserInteraction(), s.open(), a(), t.onOpen();
|
|
1158
1186
|
},
|
|
1159
1187
|
close() {
|
|
1160
1188
|
s.close(), t.onClose();
|
|
1161
1189
|
},
|
|
1190
|
+
identify(c) {
|
|
1191
|
+
h.setUser(c);
|
|
1192
|
+
},
|
|
1162
1193
|
destroy() {
|
|
1163
|
-
|
|
1194
|
+
W(), h.stop(), i.destroy(), u.destroy(), d.destroy(), E === C && (E = null);
|
|
1164
1195
|
}
|
|
1165
1196
|
};
|
|
1166
1197
|
return C;
|
|
@@ -1177,7 +1208,7 @@ function N() {
|
|
|
1177
1208
|
console.error("SpilkiWidget: data-org and is required for auto init");
|
|
1178
1209
|
return;
|
|
1179
1210
|
}
|
|
1180
|
-
|
|
1211
|
+
E = $({
|
|
1181
1212
|
org: t,
|
|
1182
1213
|
installationToken: e.installationToken,
|
|
1183
1214
|
apiBase: e.apiBase,
|
|
@@ -1185,7 +1216,10 @@ function N() {
|
|
|
1185
1216
|
theme: (i = e.theme) != null ? i : void 0
|
|
1186
1217
|
});
|
|
1187
1218
|
}
|
|
1188
|
-
|
|
1219
|
+
let E = null;
|
|
1220
|
+
typeof window != "undefined" && (window.SpilkiWidget = window.SpilkiWidget || {}, window.SpilkiWidget.init = (r) => (E = $(r), E), window.SpilkiWidget.identify = (r) => {
|
|
1221
|
+
E ? E.identify(r) : console.warn("SpilkiWidget: call init() before identify()");
|
|
1222
|
+
});
|
|
1189
1223
|
N();
|
|
1190
1224
|
N();
|
|
1191
1225
|
//# sourceMappingURL=bootstrap.es.js.map
|