@spilki/widget 1.0.33 → 1.0.35
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 +236 -213
- 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/state.d.ts +3 -5
- package/dist/core/state.d.ts.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 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/widget.es.js +239 -216
- package/dist/widget.es.js.map +1 -1
- package/dist/widget.umd.js +7 -7
- 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,13 +71,13 @@ 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
|
-
e.setAttribute("part", "bubble-root"), e.setAttribute("data-position",
|
|
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
|
-
return s.addEventListener("click", () =>
|
|
80
|
+
return s.addEventListener("click", () => r.onClick()), {
|
|
81
81
|
element: e,
|
|
82
82
|
mount() {
|
|
83
83
|
document.body.appendChild(e);
|
|
@@ -85,20 +85,20 @@ function R(o) {
|
|
|
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",
|
|
@@ -109,57 +109,57 @@ const K = "https://api.spilki.app", C = {
|
|
|
109
109
|
offline: "Unable to connect. Please try again later.",
|
|
110
110
|
title: "Spilki Assistant"
|
|
111
111
|
}, w = {
|
|
112
|
-
apiBase:
|
|
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,
|
|
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
|
-
...
|
|
127
|
-
apiBase: (s =
|
|
126
|
+
...r,
|
|
127
|
+
apiBase: (s = r.apiBase) != null ? s : w.apiBase,
|
|
128
128
|
i18n: e,
|
|
129
|
-
welcome: (i =
|
|
130
|
-
position: (
|
|
131
|
-
theme: (
|
|
132
|
-
color: (n =
|
|
133
|
-
persist: (
|
|
134
|
-
sound: (g =
|
|
129
|
+
welcome: (i = r.welcome) != null ? i : e.welcome,
|
|
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
|
|
138
|
-
return typeof crypto != "undefined" && crypto.randomUUID ? crypto.randomUUID() : `${
|
|
137
|
+
function _(r = "msg") {
|
|
138
|
+
return typeof crypto != "undefined" && crypto.randomUUID ? crypto.randomUUID() : `${r}-${Math.random().toString(16).slice(2)}`;
|
|
139
139
|
}
|
|
140
|
-
function
|
|
141
|
-
var
|
|
142
|
-
return (e = (
|
|
140
|
+
function q() {
|
|
141
|
+
var r, e;
|
|
142
|
+
return (e = (r = window.matchMedia) == null ? void 0 : r.call(window, "(prefers-color-scheme: dark)").matches) != null ? e : !1;
|
|
143
143
|
}
|
|
144
|
-
function P(
|
|
145
|
-
return
|
|
144
|
+
function P(r) {
|
|
145
|
+
return r === "light" || r === "dark" ? r : q() ? "dark" : "light";
|
|
146
146
|
}
|
|
147
|
-
function
|
|
148
|
-
return
|
|
147
|
+
function S(r, e = 30) {
|
|
148
|
+
return r.slice(-e);
|
|
149
149
|
}
|
|
150
|
-
function G(
|
|
151
|
-
if (!
|
|
150
|
+
function G(r) {
|
|
151
|
+
if (!r || r.length === 0) return;
|
|
152
152
|
const e = window.location.origin;
|
|
153
|
-
|
|
154
|
-
`SpilkiWidget: current origin ${e} not in allowedOriginsHint: ${
|
|
153
|
+
r.includes(e) || console.warn(
|
|
154
|
+
`SpilkiWidget: current origin ${e} not in allowedOriginsHint: ${r.join(", ")}`
|
|
155
155
|
);
|
|
156
156
|
}
|
|
157
|
-
const
|
|
158
|
-
function Y(
|
|
159
|
-
const e = new Date(
|
|
160
|
-
return n ===
|
|
157
|
+
const V = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
158
|
+
function Y(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}` : `${V[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 E(
|
|
215
|
-
return
|
|
214
|
+
function E(r) {
|
|
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 = E(e.i18n.title), s = E(e.i18n.typing), i = E(e.i18n.offline),
|
|
232
|
+
const t = E(e.i18n.title), s = E(e.i18n.typing), i = E(e.i18n.offline), o = E(e.i18n.placeholder), l = E(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>
|
|
@@ -248,7 +248,7 @@ class Q {
|
|
|
248
248
|
<div class="emoji-picker" aria-label="Emoji picker"></div>
|
|
249
249
|
<div class="input-area">
|
|
250
250
|
<div class="input-wrap">
|
|
251
|
-
<textarea rows="1" placeholder="${
|
|
251
|
+
<textarea rows="1" placeholder="${o}" aria-label="${o}"></textarea>
|
|
252
252
|
<div class="input-actions">
|
|
253
253
|
<button class="emoji-btn" type="button" aria-label="Insert emoji">
|
|
254
254
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
@@ -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),
|
|
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);
|
|
@@ -397,15 +397,15 @@ class Q {
|
|
|
397
397
|
const s = document.createElement("div");
|
|
398
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 = Y(e);
|
|
399
399
|
const i = () => {
|
|
400
|
-
const
|
|
401
|
-
s.setAttribute("aria-expanded", String(
|
|
400
|
+
const o = t.classList.toggle("expanded");
|
|
401
|
+
s.setAttribute("aria-expanded", String(o)), s.setAttribute(
|
|
402
402
|
"aria-label",
|
|
403
|
-
|
|
403
|
+
o ? "Hide previous conversation" : "Show previous conversation"
|
|
404
404
|
);
|
|
405
405
|
};
|
|
406
|
-
return s.addEventListener("click", i), s.addEventListener("keydown", (
|
|
407
|
-
const
|
|
408
|
-
(
|
|
406
|
+
return s.addEventListener("click", i), s.addEventListener("keydown", (o) => {
|
|
407
|
+
const l = o;
|
|
408
|
+
(l.key === "Enter" || l.key === " ") && (l.preventDefault(), i());
|
|
409
409
|
}), s;
|
|
410
410
|
}
|
|
411
411
|
createHistoryContainer(e) {
|
|
@@ -414,8 +414,8 @@ class Q {
|
|
|
414
414
|
let s = null;
|
|
415
415
|
return e.forEach((i) => {
|
|
416
416
|
this.appendDateSeparatorIfNeeded(s, i, t);
|
|
417
|
-
const { item:
|
|
418
|
-
t.appendChild(
|
|
417
|
+
const { item: o } = this.createMessageElement(i);
|
|
418
|
+
t.appendChild(o), s = i;
|
|
419
419
|
}), t;
|
|
420
420
|
}
|
|
421
421
|
appendTimelineMessage(e) {
|
|
@@ -431,24 +431,24 @@ 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");
|
|
444
|
-
const
|
|
445
|
-
return this.relativeTimeFormat.format(-
|
|
444
|
+
const o = Math.max(1, Math.round(i / 60));
|
|
445
|
+
return this.relativeTimeFormat.format(-o, "hour");
|
|
446
446
|
}
|
|
447
447
|
return this.absoluteTimeFormat.format(new Date(e));
|
|
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,11 +513,11 @@ 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
|
-
const
|
|
520
|
-
this.input.setSelectionRange(
|
|
519
|
+
const o = s + e.length;
|
|
520
|
+
this.input.setSelectionRange(o, o), this.input.dispatchEvent(new Event("input", { bubbles: !0 })), this.input.focus();
|
|
521
521
|
}
|
|
522
522
|
collectFocusable() {
|
|
523
523
|
const e = this.shadow.querySelectorAll(
|
|
@@ -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 v = 1500,
|
|
537
|
-
class
|
|
536
|
+
const v = 1500, L = 8e3;
|
|
537
|
+
class te {
|
|
538
538
|
constructor(e, t) {
|
|
539
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: {
|
|
@@ -577,15 +604,16 @@ class ee {
|
|
|
577
604
|
});
|
|
578
605
|
if (!i.ok)
|
|
579
606
|
throw new Error(`SpilkiWidget: connect failed (${i.status})`);
|
|
580
|
-
const
|
|
581
|
-
return this.sessionId =
|
|
607
|
+
const o = await i.json();
|
|
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");
|
|
@@ -593,7 +621,7 @@ class ee {
|
|
|
593
621
|
this.ws.send(JSON.stringify({ type: "message", payload: s }));
|
|
594
622
|
return;
|
|
595
623
|
}
|
|
596
|
-
const i = `${this.options.apiBase.replace(/\/$/, "")}/widget/message`,
|
|
624
|
+
const i = `${this.options.apiBase.replace(/\/$/, "")}/widget/message`, o = await fetch(i, {
|
|
597
625
|
method: "POST",
|
|
598
626
|
headers: {
|
|
599
627
|
"Content-Type": "application/json",
|
|
@@ -601,8 +629,8 @@ class ee {
|
|
|
601
629
|
},
|
|
602
630
|
body: JSON.stringify(s)
|
|
603
631
|
});
|
|
604
|
-
if (!
|
|
605
|
-
throw new Error(`SpilkiWidget: send failed (${
|
|
632
|
+
if (!o.ok)
|
|
633
|
+
throw new Error(`SpilkiWidget: send failed (${o.status})`);
|
|
606
634
|
}
|
|
607
635
|
// #1: accept resetBackoff param; #8 #9: clear retryTimer
|
|
608
636
|
stop(e = !0) {
|
|
@@ -632,7 +660,7 @@ class ee {
|
|
|
632
660
|
return;
|
|
633
661
|
}
|
|
634
662
|
this.currentKind = "ws", this.handlers.onOpen("ws"), this.backoff = v, t();
|
|
635
|
-
}, this.wsOnMessage = (
|
|
663
|
+
}, this.wsOnMessage = (o) => this.handleIncoming(o.data), this.wsOnClose = () => {
|
|
636
664
|
this.stopped || this.retryFallback("ws");
|
|
637
665
|
}, this.wsOnError = () => {
|
|
638
666
|
this.handlers.onError(new Error("SpilkiWidget: websocket error")), i.readyState !== WebSocket.OPEN && s(new Error("WebSocket failed"));
|
|
@@ -652,8 +680,8 @@ class ee {
|
|
|
652
680
|
"X-Authorization": `Bearer ${this.options.accessToken}`
|
|
653
681
|
},
|
|
654
682
|
signal: i.signal
|
|
655
|
-
}).then((
|
|
656
|
-
if (!
|
|
683
|
+
}).then((o) => {
|
|
684
|
+
if (!o.ok || !o.body) {
|
|
657
685
|
s(new Error("SSE failed"));
|
|
658
686
|
return;
|
|
659
687
|
}
|
|
@@ -662,20 +690,20 @@ class ee {
|
|
|
662
690
|
return;
|
|
663
691
|
}
|
|
664
692
|
this.currentKind = "sse", this.handlers.onOpen("sse"), this.backoff = v, t();
|
|
665
|
-
const
|
|
666
|
-
let
|
|
693
|
+
const l = o.body.getReader(), n = new TextDecoder();
|
|
694
|
+
let a = "";
|
|
667
695
|
const g = () => {
|
|
668
|
-
|
|
696
|
+
l.read().then(({ done: u, value: h }) => {
|
|
669
697
|
var m;
|
|
670
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 d =
|
|
702
|
+
a += n.decode(h, { stream: !0 });
|
|
703
|
+
const d = a.split(`
|
|
676
704
|
|
|
677
705
|
`);
|
|
678
|
-
|
|
706
|
+
a = (m = d.pop()) != null ? m : "";
|
|
679
707
|
for (const f of d)
|
|
680
708
|
for (const p of f.split(`
|
|
681
709
|
`))
|
|
@@ -686,8 +714,8 @@ class ee {
|
|
|
686
714
|
});
|
|
687
715
|
};
|
|
688
716
|
g();
|
|
689
|
-
}).catch((
|
|
690
|
-
i.signal.aborted || s(
|
|
717
|
+
}).catch((o) => {
|
|
718
|
+
i.signal.aborted || s(o);
|
|
691
719
|
});
|
|
692
720
|
});
|
|
693
721
|
}
|
|
@@ -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,22 +763,22 @@ 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
|
|
746
|
-
if (typeof
|
|
747
|
-
const e =
|
|
748
|
-
return
|
|
772
|
+
const se = /* @__PURE__ */ new Set(["TYPING", "THINKING", "SEARCHING", "EXECUTING_TOOL"]);
|
|
773
|
+
function ie(r) {
|
|
774
|
+
if (typeof r != "object" || r === null) return !1;
|
|
775
|
+
const e = r;
|
|
776
|
+
return se.has(e.eventType);
|
|
749
777
|
}
|
|
750
|
-
const
|
|
778
|
+
const U = 30 * 60 * 1e3, re = 3e4, A = 30;
|
|
751
779
|
class oe {
|
|
752
780
|
constructor(e, t) {
|
|
753
|
-
this.org = e, this.listeners = /* @__PURE__ */ new Set(), this.activityTimer = null, this.
|
|
781
|
+
this.org = e, this.listeners = /* @__PURE__ */ new Set(), this.activityTimer = null, this.state = {
|
|
754
782
|
isOpen: !1,
|
|
755
783
|
agentActivity: null,
|
|
756
784
|
isConnected: !1,
|
|
@@ -774,27 +802,16 @@ class oe {
|
|
|
774
802
|
close() {
|
|
775
803
|
this.state.isOpen && (this.state.isOpen = !1, this.emit());
|
|
776
804
|
}
|
|
777
|
-
handleAgentEvent(e
|
|
778
|
-
|
|
805
|
+
handleAgentEvent(e) {
|
|
806
|
+
this.activityTimer && (clearTimeout(this.activityTimer), this.activityTimer = null), this.activityTimer = setTimeout(() => {
|
|
807
|
+
this.state.agentActivity = null, this.activityTimer = null, this.emit();
|
|
808
|
+
}, re), this.state.agentActivity !== e && (this.state.agentActivity = e, this.emit());
|
|
779
809
|
}
|
|
780
|
-
|
|
781
|
-
this.
|
|
810
|
+
clearAgentActivity() {
|
|
811
|
+
this.resetAgentActivity() && this.emit();
|
|
782
812
|
}
|
|
783
|
-
|
|
784
|
-
this.activityTimer && (clearTimeout(this.activityTimer), this.activityTimer = null), this.
|
|
785
|
-
this.activeEvents.clear(), this.state.agentActivity = null, this.activityTimer = null, this.emit();
|
|
786
|
-
}, ie));
|
|
787
|
-
const e = this.resolveTopActivity();
|
|
788
|
-
this.state.agentActivity !== e && (this.state.agentActivity = e, this.emit());
|
|
789
|
-
}
|
|
790
|
-
resolveTopActivity() {
|
|
791
|
-
var t;
|
|
792
|
-
return this.activeEvents.size === 0 ? null : (t = [
|
|
793
|
-
"EXECUTING_TOOL",
|
|
794
|
-
"SEARCHING",
|
|
795
|
-
"THINKING",
|
|
796
|
-
"TYPING"
|
|
797
|
-
].find((s) => this.activeEvents.has(s))) != null ? t : null;
|
|
813
|
+
resetAgentActivity() {
|
|
814
|
+
return this.activityTimer && (clearTimeout(this.activityTimer), this.activityTimer = null), this.state.agentActivity === null ? !1 : (this.state.agentActivity = null, !0);
|
|
798
815
|
}
|
|
799
816
|
setConnected(e) {
|
|
800
817
|
this.state.isConnected !== e && (this.state.isConnected = e, this.emit());
|
|
@@ -802,15 +819,15 @@ class oe {
|
|
|
802
819
|
addMessage(e) {
|
|
803
820
|
var s, i;
|
|
804
821
|
const t = {
|
|
805
|
-
id: (s = e.id) != null ? s :
|
|
822
|
+
id: (s = e.id) != null ? s : _("msg"),
|
|
806
823
|
ts: (i = e.ts) != null ? i : Date.now(),
|
|
807
824
|
author: e.author,
|
|
808
825
|
text: e.text
|
|
809
826
|
};
|
|
810
|
-
return this.state.messages.some((
|
|
827
|
+
return this.state.messages.some((o) => o.id === t.id) ? null : (this.state.messages = S([...this.state.messages, t], A), this.resetAgentActivity(), this.persistMessages(), this.touchActivity(), this.emit(), t);
|
|
811
828
|
}
|
|
812
829
|
setMessages(e) {
|
|
813
|
-
this.state.messages =
|
|
830
|
+
this.state.messages = S(e, A), this.persistMessages(), this.emit();
|
|
814
831
|
}
|
|
815
832
|
clearMessages() {
|
|
816
833
|
this.state.messages = [], this.persistMessages(), this.emit();
|
|
@@ -902,7 +919,7 @@ class oe {
|
|
|
902
919
|
}
|
|
903
920
|
isSessionExpired() {
|
|
904
921
|
const e = this.lastActivityTs;
|
|
905
|
-
return e === 0 ? !1 : Date.now() - e >=
|
|
922
|
+
return e === 0 ? !1 : Date.now() - e >= U;
|
|
906
923
|
}
|
|
907
924
|
getConversationGroups() {
|
|
908
925
|
const e = this.state.messages;
|
|
@@ -910,7 +927,7 @@ class oe {
|
|
|
910
927
|
const t = [];
|
|
911
928
|
let s = { startTs: e[0].ts, messages: [e[0]] };
|
|
912
929
|
for (let i = 1; i < e.length; i++)
|
|
913
|
-
e[i].ts - e[i - 1].ts >=
|
|
930
|
+
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
931
|
return t.push(s), t;
|
|
915
932
|
}
|
|
916
933
|
emit() {
|
|
@@ -930,14 +947,14 @@ class oe {
|
|
|
930
947
|
const e = localStorage.getItem(this.historyKey);
|
|
931
948
|
if (!e) return [];
|
|
932
949
|
const t = JSON.parse(e);
|
|
933
|
-
return Array.isArray(t) ?
|
|
950
|
+
return Array.isArray(t) ? S(t, A) : [];
|
|
934
951
|
} catch (e) {
|
|
935
952
|
return console.error("SpilkiWidget: unable to load messages", e), [];
|
|
936
953
|
}
|
|
937
954
|
}
|
|
938
955
|
}
|
|
939
|
-
function
|
|
940
|
-
const e =
|
|
956
|
+
function ne(r) {
|
|
957
|
+
const e = r.replace(/-/g, "+").replace(/_/g, "/"), t = e.padEnd(e.length + (4 - e.length % 4) % 4, "=");
|
|
941
958
|
if (typeof atob == "function")
|
|
942
959
|
return decodeURIComponent(
|
|
943
960
|
Array.prototype.map.call(atob(t), (i) => `%${`00${i.charCodeAt(0).toString(16)}`.slice(-2)}`).join("")
|
|
@@ -947,24 +964,24 @@ function re(o) {
|
|
|
947
964
|
return s.from(t, "base64").toString("utf8");
|
|
948
965
|
throw new Error("SpilkiWidget: no base64 decoder available");
|
|
949
966
|
}
|
|
950
|
-
function
|
|
951
|
-
if (!
|
|
952
|
-
const e =
|
|
967
|
+
function ae(r) {
|
|
968
|
+
if (!r) return null;
|
|
969
|
+
const e = r.split(".");
|
|
953
970
|
if (e.length < 2) return null;
|
|
954
971
|
try {
|
|
955
|
-
const t =
|
|
972
|
+
const t = ne(e[1]);
|
|
956
973
|
return JSON.parse(t);
|
|
957
974
|
} catch (t) {
|
|
958
975
|
return console.error("SpilkiWidget: unable to parse JWT", t), null;
|
|
959
976
|
}
|
|
960
977
|
}
|
|
961
|
-
function
|
|
962
|
-
const e =
|
|
978
|
+
function le(r) {
|
|
979
|
+
const e = ae(r);
|
|
963
980
|
if (!(e != null && e.exp) || typeof e.exp != "number") return !0;
|
|
964
981
|
const t = Math.floor(Date.now() / 1e3);
|
|
965
982
|
return e.exp < t + 60;
|
|
966
983
|
}
|
|
967
|
-
const
|
|
984
|
+
const ce = {
|
|
968
985
|
onOpen() {
|
|
969
986
|
},
|
|
970
987
|
onClose() {
|
|
@@ -976,8 +993,8 @@ const le = {
|
|
|
976
993
|
onTransportChange() {
|
|
977
994
|
}
|
|
978
995
|
};
|
|
979
|
-
async function
|
|
980
|
-
const s = `${
|
|
996
|
+
async function he(r, e, t) {
|
|
997
|
+
const s = `${r.replace(/\/$/, "")}/widget/install`, i = await fetch(s, {
|
|
981
998
|
method: "POST",
|
|
982
999
|
headers: { "Content-Type": "application/json", Origin: window.location.origin },
|
|
983
1000
|
body: JSON.stringify({ token: e, organisationId: t })
|
|
@@ -985,29 +1002,29 @@ async function ce(o, e, t) {
|
|
|
985
1002
|
if (!i.ok) throw new Error(`SpilkiWidget: install failed (${i.status})`);
|
|
986
1003
|
return (await i.json()).accessToken;
|
|
987
1004
|
}
|
|
988
|
-
async function
|
|
989
|
-
const t = `${
|
|
1005
|
+
async function de(r, e) {
|
|
1006
|
+
const t = `${r.replace(/\/$/, "")}/widget/refresh`, s = await fetch(t, {
|
|
990
1007
|
method: "POST",
|
|
991
1008
|
headers: { "X-Authorization": `Bearer ${e}`, Origin: window.location.origin }
|
|
992
1009
|
});
|
|
993
1010
|
if (!s.ok) throw new Error(`SpilkiWidget: refresh failed (${s.status})`);
|
|
994
1011
|
return (await s.json()).accessToken;
|
|
995
1012
|
}
|
|
996
|
-
function
|
|
1013
|
+
function pe(r) {
|
|
997
1014
|
let e = !1, t = null;
|
|
998
1015
|
const s = [], i = () => {
|
|
999
1016
|
var n;
|
|
1000
|
-
if (!
|
|
1017
|
+
if (!r) return null;
|
|
1001
1018
|
if (t) return t;
|
|
1002
1019
|
try {
|
|
1003
|
-
const
|
|
1004
|
-
if (!
|
|
1005
|
-
t = new
|
|
1020
|
+
const a = (n = window.AudioContext) != null ? n : window.webkitAudioContext;
|
|
1021
|
+
if (!a) return null;
|
|
1022
|
+
t = new a();
|
|
1006
1023
|
} catch {
|
|
1007
1024
|
return null;
|
|
1008
1025
|
}
|
|
1009
1026
|
return t;
|
|
1010
|
-
},
|
|
1027
|
+
}, o = () => {
|
|
1011
1028
|
e = !0;
|
|
1012
1029
|
try {
|
|
1013
1030
|
const n = i();
|
|
@@ -1015,73 +1032,73 @@ function de(o) {
|
|
|
1015
1032
|
});
|
|
1016
1033
|
} catch {
|
|
1017
1034
|
}
|
|
1018
|
-
},
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1035
|
+
}, l = (n) => {
|
|
1036
|
+
const a = () => {
|
|
1037
|
+
o(), window.removeEventListener(n, a, !0);
|
|
1021
1038
|
};
|
|
1022
|
-
s.push({ type: n, listener:
|
|
1039
|
+
s.push({ type: n, listener: a }), window.addEventListener(n, a, { capture: !0, passive: !0 });
|
|
1023
1040
|
};
|
|
1024
|
-
return
|
|
1025
|
-
markUserInteraction:
|
|
1041
|
+
return l("pointerdown"), l("keydown"), {
|
|
1042
|
+
markUserInteraction: o,
|
|
1026
1043
|
play() {
|
|
1027
|
-
if (!
|
|
1044
|
+
if (!r || !e) return;
|
|
1028
1045
|
const n = i();
|
|
1029
1046
|
if (!n || n.state !== "running") return;
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1047
|
+
const a = n.createGain();
|
|
1048
|
+
a.gain.value = 0.15, a.connect(n.destination);
|
|
1032
1049
|
const g = (h, d, m) => {
|
|
1033
1050
|
const f = n.createOscillator(), p = n.createGain();
|
|
1034
|
-
f.type = "sine", f.frequency.setValueAtTime(h, d), p.gain.setValueAtTime(1e-4, d), p.gain.exponentialRampToValueAtTime(1, d + 0.012), p.gain.exponentialRampToValueAtTime(1e-4, d + m), f.connect(p), p.connect(
|
|
1051
|
+
f.type = "sine", f.frequency.setValueAtTime(h, d), p.gain.setValueAtTime(1e-4, d), p.gain.exponentialRampToValueAtTime(1, d + 0.012), p.gain.exponentialRampToValueAtTime(1e-4, d + m), f.connect(p), p.connect(a), f.start(d), f.stop(d + m + 0.02);
|
|
1035
1052
|
}, u = n.currentTime;
|
|
1036
1053
|
g(880, u, 0.08), g(1175, u + 0.09, 0.08);
|
|
1037
1054
|
},
|
|
1038
1055
|
destroy() {
|
|
1039
|
-
s.forEach(({ type: n, listener:
|
|
1040
|
-
window.removeEventListener(n,
|
|
1056
|
+
s.forEach(({ type: n, listener: a }) => {
|
|
1057
|
+
window.removeEventListener(n, a, !0);
|
|
1041
1058
|
}), s.length = 0, t && t.close().catch(() => {
|
|
1042
1059
|
}), t = null;
|
|
1043
1060
|
}
|
|
1044
1061
|
};
|
|
1045
1062
|
}
|
|
1046
|
-
function
|
|
1047
|
-
var
|
|
1048
|
-
if (!
|
|
1063
|
+
function $(r) {
|
|
1064
|
+
var O, M, B, j;
|
|
1065
|
+
if (!r.org)
|
|
1049
1066
|
throw new Error("SpilkiWidget: org is required");
|
|
1050
|
-
const e =
|
|
1067
|
+
const e = z(r);
|
|
1051
1068
|
G(e.allowedOriginsHint);
|
|
1052
|
-
const t = { ...
|
|
1053
|
-
let
|
|
1069
|
+
const t = { ...ce, ...(O = e.hooks) != null ? O : {} }, s = new oe(e.org, { persist: e.persist }), i = pe(e.sound);
|
|
1070
|
+
let o = (M = s.accessToken) != null ? M : void 0, l = null;
|
|
1054
1071
|
const n = () => {
|
|
1055
1072
|
u.setBadge(s.countUnread());
|
|
1056
|
-
},
|
|
1073
|
+
}, a = () => {
|
|
1057
1074
|
s.markRead(), u.setBadge(0);
|
|
1058
|
-
}, g = async () =>
|
|
1075
|
+
}, g = async () => l || (l = (async () => {
|
|
1059
1076
|
try {
|
|
1060
|
-
if (
|
|
1077
|
+
if (o && le(o))
|
|
1061
1078
|
try {
|
|
1062
|
-
|
|
1079
|
+
o = await de(e.apiBase, o), s.persistAccessToken(o), d.setAccessToken(o);
|
|
1063
1080
|
return;
|
|
1064
1081
|
} catch {
|
|
1065
|
-
|
|
1082
|
+
o = void 0, s.clearAccessToken();
|
|
1066
1083
|
}
|
|
1067
|
-
if (!
|
|
1068
|
-
if (!
|
|
1069
|
-
if (!
|
|
1070
|
-
|
|
1084
|
+
if (!o) {
|
|
1085
|
+
if (!r.installationToken) throw new Error("SpilkiWidget: missing installationToken");
|
|
1086
|
+
if (!r.org) throw new Error("SpilkiWidget: missing org");
|
|
1087
|
+
o = await he(e.apiBase, r.installationToken, r.org), s.persistAccessToken(o), d.setAccessToken(o);
|
|
1071
1088
|
}
|
|
1072
1089
|
} finally {
|
|
1073
|
-
|
|
1090
|
+
l = null;
|
|
1074
1091
|
}
|
|
1075
|
-
})(),
|
|
1092
|
+
})(), l), u = K({
|
|
1076
1093
|
color: e.color,
|
|
1077
|
-
position: (
|
|
1094
|
+
position: (B = e.position) != null ? B : "bottom-right",
|
|
1078
1095
|
onClick: () => {
|
|
1079
|
-
s.snapshot.isOpen ? (s.close(), t.onClose()) : (i.markUserInteraction(), s.open(),
|
|
1096
|
+
s.snapshot.isOpen ? (s.close(), t.onClose()) : (i.markUserInteraction(), s.open(), a(), t.onOpen());
|
|
1080
1097
|
}
|
|
1081
|
-
}), h = new
|
|
1098
|
+
}), h = new ee({
|
|
1082
1099
|
color: e.color,
|
|
1083
1100
|
theme: P(e.theme),
|
|
1084
|
-
position: (
|
|
1101
|
+
position: (j = e.position) != null ? j : "bottom-right",
|
|
1085
1102
|
i18n: e.i18n,
|
|
1086
1103
|
onClose: () => {
|
|
1087
1104
|
s.close(), t.onClose();
|
|
@@ -1092,26 +1109,26 @@ function U(o) {
|
|
|
1092
1109
|
t.onError(b), s.setConnected(!1), h.setOffline(!0);
|
|
1093
1110
|
}));
|
|
1094
1111
|
}
|
|
1095
|
-
}), d = new
|
|
1112
|
+
}), d = new te(
|
|
1096
1113
|
{
|
|
1097
1114
|
apiBase: e.apiBase,
|
|
1098
|
-
accessToken:
|
|
1115
|
+
accessToken: o,
|
|
1099
1116
|
org: e.org,
|
|
1100
1117
|
sessionId: s.sessionId
|
|
1101
1118
|
},
|
|
1102
1119
|
{
|
|
1103
1120
|
onOpen(c) {
|
|
1104
|
-
|
|
1121
|
+
C.transport = c, t.onTransportChange(c), s.setConnected(!0), h.setOffline(!1);
|
|
1105
1122
|
},
|
|
1106
1123
|
onMessage(c) {
|
|
1107
1124
|
const b = c.suggestedReplies, y = s.addMessage(c);
|
|
1108
1125
|
y && (h.appendMessage(y), y.author === "bot" && b && b.length > 0 && h.setSuggestedReplies(b), !s.snapshot.isOpen && y.author === "bot" && (n(), i.play()), t.onMessage(y));
|
|
1109
1126
|
},
|
|
1110
|
-
onTyping(
|
|
1111
|
-
s.
|
|
1127
|
+
onTyping() {
|
|
1128
|
+
s.handleAgentEvent("TYPING");
|
|
1112
1129
|
},
|
|
1113
1130
|
onAgentEvent(c) {
|
|
1114
|
-
s.handleAgentEvent(c.eventType
|
|
1131
|
+
s.handleAgentEvent(c.eventType);
|
|
1115
1132
|
},
|
|
1116
1133
|
onError(c) {
|
|
1117
1134
|
t.onError(c), s.setConnected(!1), s.snapshot.isOpen && h.setOffline(!0);
|
|
@@ -1129,55 +1146,58 @@ function U(o) {
|
|
|
1129
1146
|
};
|
|
1130
1147
|
s.addMessage(c), h.appendMessage(c);
|
|
1131
1148
|
} else f && m.length > 0 ? h.renderWithConversations(p, []) : p.length > 1 ? h.renderWithConversations(p.slice(0, -1), p[p.length - 1].messages) : h.updateMessages(m);
|
|
1132
|
-
let
|
|
1133
|
-
const
|
|
1149
|
+
let T = !1;
|
|
1150
|
+
const W = s.subscribe(() => {
|
|
1134
1151
|
const c = s.snapshot;
|
|
1135
1152
|
if (u.setOpen(c.isOpen), h.setAgentActivity(c.agentActivity, e.i18n), h.setOffline(!c.isConnected), h.updateTheme(P(e.theme)), c.isOpen) {
|
|
1136
|
-
if (!
|
|
1153
|
+
if (!T) {
|
|
1137
1154
|
const k = s.countUnread() > 0, b = s.lastReadTs;
|
|
1138
|
-
|
|
1155
|
+
a(), k && h.scrollToFirstUnread(b);
|
|
1139
1156
|
}
|
|
1140
|
-
|
|
1157
|
+
T = !0, h.show();
|
|
1141
1158
|
} else
|
|
1142
|
-
|
|
1143
|
-
}),
|
|
1159
|
+
T = !1, h.hide();
|
|
1160
|
+
}), F = m.length === 0 || f;
|
|
1144
1161
|
n(), g().then(
|
|
1145
1162
|
() => d.connect().then((c) => {
|
|
1146
1163
|
var b, y;
|
|
1147
1164
|
e.persist && s.persistSession(c.sessionId), s.setConnected(!0), t.onTransportChange((b = d.kind) != null ? b : "ws");
|
|
1148
1165
|
const k = (y = c.suggestedReplies) != null ? y : [];
|
|
1149
|
-
k.length > 0 &&
|
|
1166
|
+
k.length > 0 && F && h.setSuggestedReplies(k);
|
|
1150
1167
|
})
|
|
1151
1168
|
).catch((c) => {
|
|
1152
1169
|
t.onError(c), s.setConnected(!1), h.setOffline(!0);
|
|
1153
1170
|
});
|
|
1154
|
-
const
|
|
1171
|
+
const C = {
|
|
1155
1172
|
transport: null,
|
|
1156
1173
|
open() {
|
|
1157
|
-
i.markUserInteraction(), s.open(),
|
|
1174
|
+
i.markUserInteraction(), s.open(), a(), t.onOpen();
|
|
1158
1175
|
},
|
|
1159
1176
|
close() {
|
|
1160
1177
|
s.close(), t.onClose();
|
|
1161
1178
|
},
|
|
1179
|
+
identify(c) {
|
|
1180
|
+
d.setUser(c);
|
|
1181
|
+
},
|
|
1162
1182
|
destroy() {
|
|
1163
|
-
|
|
1183
|
+
W(), d.stop(), i.destroy(), u.destroy(), h.destroy(), x === C && (x = null);
|
|
1164
1184
|
}
|
|
1165
1185
|
};
|
|
1166
|
-
return
|
|
1186
|
+
return C;
|
|
1167
1187
|
}
|
|
1168
1188
|
function N() {
|
|
1169
1189
|
var s, i;
|
|
1170
1190
|
if (typeof document == "undefined") return;
|
|
1171
|
-
const
|
|
1172
|
-
if (!
|
|
1173
|
-
const e =
|
|
1191
|
+
const r = document.currentScript;
|
|
1192
|
+
if (!r) return;
|
|
1193
|
+
const e = r.dataset;
|
|
1174
1194
|
if (e.autoinit === "false") return;
|
|
1175
1195
|
const t = e.org;
|
|
1176
1196
|
if (!t) {
|
|
1177
1197
|
console.error("SpilkiWidget: data-org and is required for auto init");
|
|
1178
1198
|
return;
|
|
1179
1199
|
}
|
|
1180
|
-
|
|
1200
|
+
x = $({
|
|
1181
1201
|
org: t,
|
|
1182
1202
|
installationToken: e.installationToken,
|
|
1183
1203
|
apiBase: e.apiBase,
|
|
@@ -1185,7 +1205,10 @@ function N() {
|
|
|
1185
1205
|
theme: (i = e.theme) != null ? i : void 0
|
|
1186
1206
|
});
|
|
1187
1207
|
}
|
|
1188
|
-
|
|
1208
|
+
let x = null;
|
|
1209
|
+
typeof window != "undefined" && (window.SpilkiWidget = window.SpilkiWidget || {}, window.SpilkiWidget.init = (r) => (x = $(r), x), window.SpilkiWidget.identify = (r) => {
|
|
1210
|
+
x ? x.identify(r) : console.warn("SpilkiWidget: call init() before identify()");
|
|
1211
|
+
});
|
|
1189
1212
|
N();
|
|
1190
1213
|
N();
|
|
1191
1214
|
//# sourceMappingURL=bootstrap.es.js.map
|