@spilki/widget 1.0.30 → 1.0.32
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 +151 -106
- package/dist/bootstrap.es.js.map +1 -1
- package/dist/bootstrap.umd.js +6 -6
- package/dist/bootstrap.umd.js.map +1 -1
- package/dist/core/state.d.ts +8 -2
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/transport.d.ts +2 -1
- package/dist/core/transport.d.ts.map +1 -1
- package/dist/core/utils.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/panel.d.ts +2 -1
- package/dist/ui/panel.d.ts.map +1 -1
- package/dist/widget.es.js +152 -107
- package/dist/widget.es.js.map +1 -1
- package/dist/widget.umd.js +5 -5
- package/dist/widget.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/widget.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const W = `
|
|
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 F(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 = W;
|
|
79
79
|
const s = t.querySelector("button"), i = t.querySelector(".badge");
|
|
80
80
|
return s.addEventListener("click", () => r.onClick()), {
|
|
81
81
|
element: e,
|
|
@@ -98,15 +98,18 @@ function R(r) {
|
|
|
98
98
|
}
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
|
-
const
|
|
101
|
+
const R = "https://api.spilki.app", T = {
|
|
102
102
|
welcome: "Hi! I'm your assistant.",
|
|
103
103
|
placeholder: "Type a message…",
|
|
104
104
|
sendLabel: "Send",
|
|
105
105
|
typing: "Assistant is typing…",
|
|
106
|
+
thinking: "Assistant is thinking…",
|
|
107
|
+
searching: "Searching…",
|
|
108
|
+
executingTool: "Working on it…",
|
|
106
109
|
offline: "Unable to connect. Please try again later.",
|
|
107
110
|
title: "Spilki Assistant"
|
|
108
111
|
}, k = {
|
|
109
|
-
apiBase:
|
|
112
|
+
apiBase: R,
|
|
110
113
|
position: "bottom-right",
|
|
111
114
|
theme: "auto",
|
|
112
115
|
color: "#6366f1",
|
|
@@ -115,8 +118,8 @@ const K = "https://api.spilki.app", T = {
|
|
|
115
118
|
sound: !0,
|
|
116
119
|
i18n: T
|
|
117
120
|
};
|
|
118
|
-
function
|
|
119
|
-
var t, s, i, o, a, n, l,
|
|
121
|
+
function K(r) {
|
|
122
|
+
var t, s, i, o, a, n, l, m;
|
|
120
123
|
const e = { ...T, ...(t = r.i18n) != null ? t : {} };
|
|
121
124
|
return {
|
|
122
125
|
...k,
|
|
@@ -128,7 +131,7 @@ function N(r) {
|
|
|
128
131
|
theme: (a = r.theme) != null ? a : k.theme,
|
|
129
132
|
color: (n = r.color) != null ? n : k.color,
|
|
130
133
|
persist: (l = r.persist) != null ? l : k.persist,
|
|
131
|
-
sound: (
|
|
134
|
+
sound: (m = r.sound) != null ? m : k.sound
|
|
132
135
|
};
|
|
133
136
|
}
|
|
134
137
|
function H(r = "msg") {
|
|
@@ -138,25 +141,25 @@ function z() {
|
|
|
138
141
|
var r, e;
|
|
139
142
|
return (e = (r = window.matchMedia) == null ? void 0 : r.call(window, "(prefers-color-scheme: dark)").matches) != null ? e : !1;
|
|
140
143
|
}
|
|
141
|
-
function
|
|
144
|
+
function P(r) {
|
|
142
145
|
return r === "light" || r === "dark" ? r : z() ? "dark" : "light";
|
|
143
146
|
}
|
|
144
|
-
function
|
|
147
|
+
function E(r, e = 30) {
|
|
145
148
|
return r.slice(-e);
|
|
146
149
|
}
|
|
147
|
-
function
|
|
150
|
+
function _(r) {
|
|
148
151
|
if (!r || r.length === 0) return;
|
|
149
152
|
const e = window.location.origin;
|
|
150
153
|
r.includes(e) || console.warn(
|
|
151
154
|
`SpilkiWidget: current origin ${e} not in allowedOriginsHint: ${r.join(", ")}`
|
|
152
155
|
);
|
|
153
156
|
}
|
|
154
|
-
const
|
|
155
|
-
function
|
|
157
|
+
const G = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
158
|
+
function q(r) {
|
|
156
159
|
const e = new Date(r), t = /* @__PURE__ */ new Date(), s = (l) => String(l).padStart(2, "0"), i = `${s(e.getHours())}:${s(e.getMinutes())}`, o = new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime(), a = o - 864e5, n = new Date(e.getFullYear(), e.getMonth(), e.getDate()).getTime();
|
|
157
|
-
return n === o ? `Today at ${i}` : n === a ? `Yesterday at ${i}` : `${
|
|
160
|
+
return n === o ? `Today at ${i}` : n === a ? `Yesterday at ${i}` : `${G[e.getMonth()]} ${e.getDate()}, ${i}`;
|
|
158
161
|
}
|
|
159
|
-
const
|
|
162
|
+
const Y = ':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:.5rem;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}.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}', j = 24 * 60 * 60 * 1e3, V = 2 * 60 * 1e3, J = 200, X = [
|
|
160
163
|
"😀",
|
|
161
164
|
"😂",
|
|
162
165
|
"🤣",
|
|
@@ -228,7 +231,7 @@ class Z {
|
|
|
228
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" });
|
|
229
232
|
const t = v(e.i18n.title), s = v(e.i18n.typing), i = v(e.i18n.offline), o = v(e.i18n.placeholder), a = v(e.i18n.sendLabel);
|
|
230
233
|
this.shadow.innerHTML = `
|
|
231
|
-
<style>${
|
|
234
|
+
<style>${Y}</style>
|
|
232
235
|
<div class="wrapper" role="dialog" aria-modal="true" aria-label="${t}">
|
|
233
236
|
<header>
|
|
234
237
|
<h1><span class="status-dot" aria-hidden="true"></span>${t}</h1>
|
|
@@ -355,6 +358,20 @@ class Z {
|
|
|
355
358
|
hideSuggestedReplies() {
|
|
356
359
|
this.suggestedRepliesEl.toggleAttribute("hidden", !0), this.suggestedRepliesEl.replaceChildren(), this.collectFocusable(), this.focusInput();
|
|
357
360
|
}
|
|
361
|
+
setAgentActivity(e, t) {
|
|
362
|
+
var i;
|
|
363
|
+
if (e === null) {
|
|
364
|
+
this.typingEl.toggleAttribute("hidden", !0);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const s = {
|
|
368
|
+
TYPING: t.typing,
|
|
369
|
+
THINKING: t.thinking,
|
|
370
|
+
SEARCHING: t.searching,
|
|
371
|
+
EXECUTING_TOOL: t.executingTool
|
|
372
|
+
};
|
|
373
|
+
this.typingEl.textContent = (i = s[e]) != null ? i : t.typing, this.typingEl.toggleAttribute("hidden", !1);
|
|
374
|
+
}
|
|
358
375
|
setTyping(e) {
|
|
359
376
|
this.typingEl.toggleAttribute("hidden", !e);
|
|
360
377
|
}
|
|
@@ -378,7 +395,7 @@ class Z {
|
|
|
378
395
|
}
|
|
379
396
|
createSeparatorElement(e, t) {
|
|
380
397
|
const s = document.createElement("div");
|
|
381
|
-
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 = q(e);
|
|
382
399
|
const i = () => {
|
|
383
400
|
const o = t.classList.toggle("expanded");
|
|
384
401
|
s.setAttribute("aria-expanded", String(o)), s.setAttribute(
|
|
@@ -414,13 +431,13 @@ class Z {
|
|
|
414
431
|
}
|
|
415
432
|
updateTimestampVisibility() {
|
|
416
433
|
for (let e = 0; e < this.renderedMessages.length; e += 1) {
|
|
417
|
-
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 <= V && s.message.ts >= t.message.ts;
|
|
418
435
|
t.timeEl.toggleAttribute("hidden", i), t.timeEl.textContent = this.formatMessageTimestamp(t.message.ts);
|
|
419
436
|
}
|
|
420
437
|
}
|
|
421
438
|
formatMessageTimestamp(e) {
|
|
422
439
|
const s = Date.now() - e;
|
|
423
|
-
if (s <
|
|
440
|
+
if (s < j) {
|
|
424
441
|
const i = Math.max(1, Math.round(s / 6e4));
|
|
425
442
|
if (i < 60)
|
|
426
443
|
return this.relativeTimeFormat.format(-i, "minute");
|
|
@@ -431,7 +448,7 @@ class Z {
|
|
|
431
448
|
}
|
|
432
449
|
formatDateSeparator(e) {
|
|
433
450
|
const t = new Date(e), s = this.startOfDay(Date.now()), i = this.startOfDay(e);
|
|
434
|
-
return i === s ? "Today" : i === s -
|
|
451
|
+
return i === s ? "Today" : i === s - j ? "Yesterday" : this.dateSeparatorFormat.format(t);
|
|
435
452
|
}
|
|
436
453
|
isSameDay(e, t) {
|
|
437
454
|
return this.startOfDay(e) === this.startOfDay(t);
|
|
@@ -441,7 +458,7 @@ class Z {
|
|
|
441
458
|
return new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime();
|
|
442
459
|
}
|
|
443
460
|
isScrolledUp() {
|
|
444
|
-
return this.distanceFromBottom() >
|
|
461
|
+
return this.distanceFromBottom() > J;
|
|
445
462
|
}
|
|
446
463
|
distanceFromBottom() {
|
|
447
464
|
return this.messagesEl.scrollHeight - this.messagesEl.scrollTop - this.messagesEl.clientHeight;
|
|
@@ -516,10 +533,10 @@ class Z {
|
|
|
516
533
|
e.shiftKey && i === t ? (e.preventDefault(), s.focus()) : !e.shiftKey && i === s && (e.preventDefault(), t.focus());
|
|
517
534
|
}
|
|
518
535
|
}
|
|
519
|
-
const
|
|
536
|
+
const y = 1500, D = 8e3;
|
|
520
537
|
class Q {
|
|
521
538
|
constructor(e, t) {
|
|
522
|
-
this.sessionId = null, this.currentKind = null, this.stopped = !1, this.backoff =
|
|
539
|
+
this.sessionId = null, this.currentKind = null, this.stopped = !1, this.backoff = y, this.connectPromise = null, this.options = e, this.handlers = t;
|
|
523
540
|
}
|
|
524
541
|
setAccessToken(e) {
|
|
525
542
|
this.options.accessToken = e;
|
|
@@ -561,7 +578,7 @@ class Q {
|
|
|
561
578
|
if (!i.ok)
|
|
562
579
|
throw new Error(`SpilkiWidget: connect failed (${i.status})`);
|
|
563
580
|
const o = await i.json();
|
|
564
|
-
return this.sessionId = o.sessionId, this.options.sessionId = o.sessionId, this.backoff =
|
|
581
|
+
return this.sessionId = o.sessionId, this.options.sessionId = o.sessionId, this.backoff = y, await this.startTransport(o), o;
|
|
565
582
|
}
|
|
566
583
|
async send(e, t) {
|
|
567
584
|
var a, n;
|
|
@@ -589,7 +606,7 @@ class Q {
|
|
|
589
606
|
}
|
|
590
607
|
// #1: accept resetBackoff param; #8 #9: clear retryTimer
|
|
591
608
|
stop(e = !0) {
|
|
592
|
-
this.stopped = !0, e && (this.backoff =
|
|
609
|
+
this.stopped = !0, e && (this.backoff = y), 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;
|
|
593
610
|
}
|
|
594
611
|
async startTransport(e) {
|
|
595
612
|
if (this.stopped) return;
|
|
@@ -614,7 +631,7 @@ class Q {
|
|
|
614
631
|
i.close();
|
|
615
632
|
return;
|
|
616
633
|
}
|
|
617
|
-
this.currentKind = "ws", this.handlers.onOpen("ws"), this.backoff =
|
|
634
|
+
this.currentKind = "ws", this.handlers.onOpen("ws"), this.backoff = y, t();
|
|
618
635
|
}, this.wsOnMessage = (o) => this.handleIncoming(o.data), this.wsOnClose = () => {
|
|
619
636
|
this.stopped || this.retryFallback("ws");
|
|
620
637
|
}, this.wsOnError = () => {
|
|
@@ -644,31 +661,31 @@ class Q {
|
|
|
644
661
|
i.abort();
|
|
645
662
|
return;
|
|
646
663
|
}
|
|
647
|
-
this.currentKind = "sse", this.handlers.onOpen("sse"), this.backoff =
|
|
664
|
+
this.currentKind = "sse", this.handlers.onOpen("sse"), this.backoff = y, t();
|
|
648
665
|
const a = o.body.getReader(), n = new TextDecoder();
|
|
649
666
|
let l = "";
|
|
650
|
-
const
|
|
651
|
-
a.read().then(({ done:
|
|
667
|
+
const m = () => {
|
|
668
|
+
a.read().then(({ done: g, value: h }) => {
|
|
652
669
|
var f;
|
|
653
|
-
if (
|
|
670
|
+
if (g || this.stopped) {
|
|
654
671
|
this.stopped || (this.handlers.onError(new Error("SpilkiWidget: SSE stream ended")), this.retryFallback("sse"));
|
|
655
672
|
return;
|
|
656
673
|
}
|
|
657
|
-
l += n.decode(
|
|
658
|
-
const
|
|
674
|
+
l += n.decode(h, { stream: !0 });
|
|
675
|
+
const d = l.split(`
|
|
659
676
|
|
|
660
677
|
`);
|
|
661
|
-
l = (f =
|
|
662
|
-
for (const b of
|
|
678
|
+
l = (f = d.pop()) != null ? f : "";
|
|
679
|
+
for (const b of d)
|
|
663
680
|
for (const p of b.split(`
|
|
664
681
|
`))
|
|
665
682
|
p.startsWith("data:") && this.handleIncoming(p.slice(5).trim());
|
|
666
|
-
|
|
667
|
-
}).catch((
|
|
668
|
-
i.signal.aborted || (this.handlers.onError(
|
|
683
|
+
m();
|
|
684
|
+
}).catch((g) => {
|
|
685
|
+
i.signal.aborted || (this.handlers.onError(g), this.stopped || this.retryFallback("sse"));
|
|
669
686
|
});
|
|
670
687
|
};
|
|
671
|
-
|
|
688
|
+
m();
|
|
672
689
|
}).catch((o) => {
|
|
673
690
|
i.signal.aborted || s(o);
|
|
674
691
|
});
|
|
@@ -676,7 +693,7 @@ class Q {
|
|
|
676
693
|
}
|
|
677
694
|
// #15: add auth header to poll fetch
|
|
678
695
|
async startPoll(e) {
|
|
679
|
-
this.currentKind = "poll", this.handlers.onOpen("poll"), this.backoff =
|
|
696
|
+
this.currentKind = "poll", this.handlers.onOpen("poll"), this.backoff = y;
|
|
680
697
|
const t = async () => {
|
|
681
698
|
if (!this.stopped)
|
|
682
699
|
try {
|
|
@@ -687,7 +704,7 @@ class Q {
|
|
|
687
704
|
});
|
|
688
705
|
if (!s.ok) throw new Error(`Poll failed ${s.status}`);
|
|
689
706
|
const i = await s.json();
|
|
690
|
-
|
|
707
|
+
E(i).forEach((o) => this.handlers.onMessage(o)), this.backoff = y;
|
|
691
708
|
} catch (s) {
|
|
692
709
|
this.handlers.onError(s), this.backoff = Math.min(this.backoff * 1.5, D);
|
|
693
710
|
} finally {
|
|
@@ -718,18 +735,24 @@ class Q {
|
|
|
718
735
|
dispatchIncoming(e) {
|
|
719
736
|
var t;
|
|
720
737
|
if ("type" in e) {
|
|
721
|
-
e.type === "message" ? this.handlers.onMessage(e.payload) : e.type === "typing"
|
|
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" && te(e.payload) && this.handlers.onAgentEvent(e.payload);
|
|
722
739
|
return;
|
|
723
740
|
}
|
|
724
741
|
this.handlers.onMessage(e);
|
|
725
742
|
}
|
|
726
743
|
}
|
|
727
|
-
const
|
|
728
|
-
|
|
744
|
+
const ee = /* @__PURE__ */ new Set(["TYPING", "THINKING", "SEARCHING", "EXECUTING_TOOL"]);
|
|
745
|
+
function te(r) {
|
|
746
|
+
if (typeof r != "object" || r === null) return !1;
|
|
747
|
+
const e = r;
|
|
748
|
+
return ee.has(e.eventType) && typeof e.active == "boolean";
|
|
749
|
+
}
|
|
750
|
+
const L = 30 * 60 * 1e3, se = 3e4, S = 30;
|
|
751
|
+
class ie {
|
|
729
752
|
constructor(e, t) {
|
|
730
|
-
this.org = e, this.listeners = /* @__PURE__ */ new Set(), this.state = {
|
|
753
|
+
this.org = e, this.listeners = /* @__PURE__ */ new Set(), this.activityTimer = null, this.activeEvents = /* @__PURE__ */ new Set(), this.state = {
|
|
731
754
|
isOpen: !1,
|
|
732
|
-
|
|
755
|
+
agentActivity: null,
|
|
733
756
|
isConnected: !1,
|
|
734
757
|
messages: []
|
|
735
758
|
}, this.historyKey = `spilki-history:${e}`, this.sessionKey = `spilki-session:${e}`, this.tokenKey = `spilki-token:${e}`, this.activityKey = `spilki-activity:${e}`, this.lastReadKey = `spilki-lastread:${e}`, this.persist = t.persist, this.state.messages = this.loadMessages();
|
|
@@ -737,7 +760,7 @@ class ee {
|
|
|
737
760
|
get snapshot() {
|
|
738
761
|
return {
|
|
739
762
|
isOpen: this.state.isOpen,
|
|
740
|
-
|
|
763
|
+
agentActivity: this.state.agentActivity,
|
|
741
764
|
isConnected: this.state.isConnected,
|
|
742
765
|
messages: this.state.messages
|
|
743
766
|
};
|
|
@@ -751,8 +774,27 @@ class ee {
|
|
|
751
774
|
close() {
|
|
752
775
|
this.state.isOpen && (this.state.isOpen = !1, this.emit());
|
|
753
776
|
}
|
|
777
|
+
handleAgentEvent(e, t) {
|
|
778
|
+
t ? this.activeEvents.add(e) : this.activeEvents.delete(e), this.updateDisplayedActivity();
|
|
779
|
+
}
|
|
754
780
|
setTyping(e) {
|
|
755
|
-
this.
|
|
781
|
+
this.handleAgentEvent("TYPING", e);
|
|
782
|
+
}
|
|
783
|
+
updateDisplayedActivity() {
|
|
784
|
+
this.activityTimer && (clearTimeout(this.activityTimer), this.activityTimer = null), this.activeEvents.size > 0 && (this.activityTimer = setTimeout(() => {
|
|
785
|
+
this.activeEvents.clear(), this.state.agentActivity = null, this.activityTimer = null, this.emit();
|
|
786
|
+
}, se));
|
|
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;
|
|
756
798
|
}
|
|
757
799
|
setConnected(e) {
|
|
758
800
|
this.state.isConnected !== e && (this.state.isConnected = e, this.emit());
|
|
@@ -765,10 +807,10 @@ class ee {
|
|
|
765
807
|
author: e.author,
|
|
766
808
|
text: e.text
|
|
767
809
|
};
|
|
768
|
-
return this.state.messages.some((o) => o.id === t.id) ? null : (this.state.messages =
|
|
810
|
+
return this.state.messages.some((o) => o.id === t.id) ? null : (this.state.messages = E([...this.state.messages, t], S), this.persistMessages(), this.touchActivity(), this.emit(), t);
|
|
769
811
|
}
|
|
770
812
|
setMessages(e) {
|
|
771
|
-
this.state.messages =
|
|
813
|
+
this.state.messages = E(e, S), this.persistMessages(), this.emit();
|
|
772
814
|
}
|
|
773
815
|
clearMessages() {
|
|
774
816
|
this.state.messages = [], this.persistMessages(), this.emit();
|
|
@@ -888,13 +930,13 @@ class ee {
|
|
|
888
930
|
const e = localStorage.getItem(this.historyKey);
|
|
889
931
|
if (!e) return [];
|
|
890
932
|
const t = JSON.parse(e);
|
|
891
|
-
return Array.isArray(t) ?
|
|
933
|
+
return Array.isArray(t) ? E(t, S) : [];
|
|
892
934
|
} catch (e) {
|
|
893
935
|
return console.error("SpilkiWidget: unable to load messages", e), [];
|
|
894
936
|
}
|
|
895
937
|
}
|
|
896
938
|
}
|
|
897
|
-
function
|
|
939
|
+
function re(r) {
|
|
898
940
|
const e = r.replace(/-/g, "+").replace(/_/g, "/"), t = e.padEnd(e.length + (4 - e.length % 4) % 4, "=");
|
|
899
941
|
if (typeof atob == "function")
|
|
900
942
|
return decodeURIComponent(
|
|
@@ -905,24 +947,24 @@ function te(r) {
|
|
|
905
947
|
return s.from(t, "base64").toString("utf8");
|
|
906
948
|
throw new Error("SpilkiWidget: no base64 decoder available");
|
|
907
949
|
}
|
|
908
|
-
function
|
|
950
|
+
function oe(r) {
|
|
909
951
|
if (!r) return null;
|
|
910
952
|
const e = r.split(".");
|
|
911
953
|
if (e.length < 2) return null;
|
|
912
954
|
try {
|
|
913
|
-
const t =
|
|
955
|
+
const t = re(e[1]);
|
|
914
956
|
return JSON.parse(t);
|
|
915
957
|
} catch (t) {
|
|
916
958
|
return console.error("SpilkiWidget: unable to parse JWT", t), null;
|
|
917
959
|
}
|
|
918
960
|
}
|
|
919
|
-
function
|
|
920
|
-
const e =
|
|
961
|
+
function ne(r) {
|
|
962
|
+
const e = oe(r);
|
|
921
963
|
if (!(e != null && e.exp) || typeof e.exp != "number") return !0;
|
|
922
964
|
const t = Math.floor(Date.now() / 1e3);
|
|
923
965
|
return e.exp < t + 60;
|
|
924
966
|
}
|
|
925
|
-
const
|
|
967
|
+
const ae = {
|
|
926
968
|
onOpen() {
|
|
927
969
|
},
|
|
928
970
|
onClose() {
|
|
@@ -934,7 +976,7 @@ const re = {
|
|
|
934
976
|
onTransportChange() {
|
|
935
977
|
}
|
|
936
978
|
};
|
|
937
|
-
async function
|
|
979
|
+
async function le(r, e, t) {
|
|
938
980
|
const s = `${r.replace(/\/$/, "")}/widget/install`, i = await fetch(s, {
|
|
939
981
|
method: "POST",
|
|
940
982
|
headers: { "Content-Type": "application/json", Origin: window.location.origin },
|
|
@@ -943,7 +985,7 @@ async function oe(r, e, t) {
|
|
|
943
985
|
if (!i.ok) throw new Error(`SpilkiWidget: install failed (${i.status})`);
|
|
944
986
|
return (await i.json()).accessToken;
|
|
945
987
|
}
|
|
946
|
-
async function
|
|
988
|
+
async function ce(r, e) {
|
|
947
989
|
const t = `${r.replace(/\/$/, "")}/widget/refresh`, s = await fetch(t, {
|
|
948
990
|
method: "POST",
|
|
949
991
|
headers: { "X-Authorization": `Bearer ${e}`, Origin: window.location.origin }
|
|
@@ -951,7 +993,7 @@ async function ne(r, e) {
|
|
|
951
993
|
if (!s.ok) throw new Error(`SpilkiWidget: refresh failed (${s.status})`);
|
|
952
994
|
return (await s.json()).accessToken;
|
|
953
995
|
}
|
|
954
|
-
function
|
|
996
|
+
function he(r) {
|
|
955
997
|
let e = !1, t = null;
|
|
956
998
|
const s = [], i = () => {
|
|
957
999
|
var n;
|
|
@@ -987,11 +1029,11 @@ function ae(r) {
|
|
|
987
1029
|
if (!n || n.state !== "running") return;
|
|
988
1030
|
const l = n.createGain();
|
|
989
1031
|
l.gain.value = 0.15, l.connect(n.destination);
|
|
990
|
-
const
|
|
1032
|
+
const m = (h, d, f) => {
|
|
991
1033
|
const b = n.createOscillator(), p = n.createGain();
|
|
992
|
-
b.type = "sine", b.frequency.setValueAtTime(
|
|
993
|
-
},
|
|
994
|
-
|
|
1034
|
+
b.type = "sine", b.frequency.setValueAtTime(h, d), p.gain.setValueAtTime(1e-4, d), p.gain.exponentialRampToValueAtTime(1, d + 0.012), p.gain.exponentialRampToValueAtTime(1e-4, d + f), b.connect(p), p.connect(l), b.start(d), b.stop(d + f + 0.02);
|
|
1035
|
+
}, g = n.currentTime;
|
|
1036
|
+
m(880, g, 0.08), m(1175, g + 0.09, 0.08);
|
|
995
1037
|
},
|
|
996
1038
|
destroy() {
|
|
997
1039
|
s.forEach(({ type: n, listener: l }) => {
|
|
@@ -1002,22 +1044,22 @@ function ae(r) {
|
|
|
1002
1044
|
};
|
|
1003
1045
|
}
|
|
1004
1046
|
function U(r) {
|
|
1005
|
-
var
|
|
1047
|
+
var A, I, O, M;
|
|
1006
1048
|
if (!r.org)
|
|
1007
1049
|
throw new Error("SpilkiWidget: org is required");
|
|
1008
|
-
const e =
|
|
1009
|
-
|
|
1010
|
-
const t = { ...
|
|
1011
|
-
let o = (
|
|
1050
|
+
const e = K(r);
|
|
1051
|
+
_(e.allowedOriginsHint);
|
|
1052
|
+
const t = { ...ae, ...(A = e.hooks) != null ? A : {} }, s = new ie(e.org, { persist: e.persist }), i = he(e.sound);
|
|
1053
|
+
let o = (I = s.accessToken) != null ? I : void 0, a = null;
|
|
1012
1054
|
const n = () => {
|
|
1013
|
-
|
|
1055
|
+
g.setBadge(s.countUnread());
|
|
1014
1056
|
}, l = () => {
|
|
1015
|
-
s.markRead(),
|
|
1016
|
-
},
|
|
1057
|
+
s.markRead(), g.setBadge(0);
|
|
1058
|
+
}, m = async () => a || (a = (async () => {
|
|
1017
1059
|
try {
|
|
1018
|
-
if (o &&
|
|
1060
|
+
if (o && ne(o))
|
|
1019
1061
|
try {
|
|
1020
|
-
o = await
|
|
1062
|
+
o = await ce(e.apiBase, o), s.persistAccessToken(o), d.setAccessToken(o);
|
|
1021
1063
|
return;
|
|
1022
1064
|
} catch {
|
|
1023
1065
|
o = void 0, s.clearAccessToken();
|
|
@@ -1025,32 +1067,32 @@ function U(r) {
|
|
|
1025
1067
|
if (!o) {
|
|
1026
1068
|
if (!r.installationToken) throw new Error("SpilkiWidget: missing installationToken");
|
|
1027
1069
|
if (!r.org) throw new Error("SpilkiWidget: missing org");
|
|
1028
|
-
o = await
|
|
1070
|
+
o = await le(e.apiBase, r.installationToken, r.org), s.persistAccessToken(o), d.setAccessToken(o);
|
|
1029
1071
|
}
|
|
1030
1072
|
} finally {
|
|
1031
1073
|
a = null;
|
|
1032
1074
|
}
|
|
1033
|
-
})(), a),
|
|
1075
|
+
})(), a), g = F({
|
|
1034
1076
|
color: e.color,
|
|
1035
|
-
position: (
|
|
1077
|
+
position: (O = e.position) != null ? O : "bottom-right",
|
|
1036
1078
|
onClick: () => {
|
|
1037
1079
|
s.snapshot.isOpen ? (s.close(), t.onClose()) : (i.markUserInteraction(), s.open(), l(), t.onOpen());
|
|
1038
1080
|
}
|
|
1039
|
-
}),
|
|
1081
|
+
}), h = new Z({
|
|
1040
1082
|
color: e.color,
|
|
1041
|
-
theme:
|
|
1042
|
-
position: (
|
|
1083
|
+
theme: P(e.theme),
|
|
1084
|
+
position: (M = e.position) != null ? M : "bottom-right",
|
|
1043
1085
|
i18n: e.i18n,
|
|
1044
1086
|
onClose: () => {
|
|
1045
1087
|
s.close(), t.onClose();
|
|
1046
1088
|
},
|
|
1047
1089
|
onSend: (c) => {
|
|
1048
1090
|
const u = s.addMessage({ author: "user", text: c });
|
|
1049
|
-
u && (
|
|
1050
|
-
t.onError(
|
|
1091
|
+
u && (h.appendMessage(u), m().then(() => d.send(c, u.id)).catch((w) => {
|
|
1092
|
+
t.onError(w), s.setConnected(!1), h.setOffline(!0);
|
|
1051
1093
|
}));
|
|
1052
1094
|
}
|
|
1053
|
-
}),
|
|
1095
|
+
}), d = new Q(
|
|
1054
1096
|
{
|
|
1055
1097
|
apiBase: e.apiBase,
|
|
1056
1098
|
accessToken: o,
|
|
@@ -1059,21 +1101,24 @@ function U(r) {
|
|
|
1059
1101
|
},
|
|
1060
1102
|
{
|
|
1061
1103
|
onOpen(c) {
|
|
1062
|
-
C.transport = c, t.onTransportChange(c), s.setConnected(!0),
|
|
1104
|
+
C.transport = c, t.onTransportChange(c), s.setConnected(!0), h.setOffline(!1);
|
|
1063
1105
|
},
|
|
1064
1106
|
onMessage(c) {
|
|
1065
1107
|
const u = s.addMessage(c);
|
|
1066
|
-
u && (
|
|
1108
|
+
u && (h.appendMessage(u), !s.snapshot.isOpen && u.author === "bot" && (n(), i.play()), t.onMessage(u));
|
|
1067
1109
|
},
|
|
1068
1110
|
onTyping(c) {
|
|
1069
1111
|
s.setTyping(c);
|
|
1070
1112
|
},
|
|
1113
|
+
onAgentEvent(c) {
|
|
1114
|
+
s.handleAgentEvent(c.eventType, c.active);
|
|
1115
|
+
},
|
|
1071
1116
|
onError(c) {
|
|
1072
|
-
t.onError(c), s.setConnected(!1), s.snapshot.isOpen &&
|
|
1117
|
+
t.onError(c), s.setConnected(!1), s.snapshot.isOpen && h.setOffline(!0);
|
|
1073
1118
|
}
|
|
1074
1119
|
}
|
|
1075
1120
|
);
|
|
1076
|
-
|
|
1121
|
+
g.mount(), h.mount();
|
|
1077
1122
|
const f = s.snapshot.messages, b = s.isSessionExpired(), p = s.getConversationGroups();
|
|
1078
1123
|
if (f.length === 0 && e.welcome) {
|
|
1079
1124
|
const c = {
|
|
@@ -1082,29 +1127,29 @@ function U(r) {
|
|
|
1082
1127
|
text: e.welcome,
|
|
1083
1128
|
ts: Date.now()
|
|
1084
1129
|
};
|
|
1085
|
-
s.addMessage(c),
|
|
1086
|
-
} else b && f.length > 0 ?
|
|
1087
|
-
let
|
|
1088
|
-
const
|
|
1130
|
+
s.addMessage(c), h.appendMessage(c);
|
|
1131
|
+
} else b && f.length > 0 ? h.renderWithConversations(p, []) : p.length > 1 ? h.renderWithConversations(p.slice(0, -1), p[p.length - 1].messages) : h.updateMessages(f);
|
|
1132
|
+
let x = !1;
|
|
1133
|
+
const N = s.subscribe(() => {
|
|
1089
1134
|
const c = s.snapshot;
|
|
1090
|
-
if (
|
|
1091
|
-
if (!
|
|
1092
|
-
const u = s.countUnread() > 0,
|
|
1093
|
-
l(), u &&
|
|
1135
|
+
if (g.setOpen(c.isOpen), h.setAgentActivity(c.agentActivity, e.i18n), h.setOffline(!c.isConnected), h.updateTheme(P(e.theme)), c.isOpen) {
|
|
1136
|
+
if (!x) {
|
|
1137
|
+
const u = s.countUnread() > 0, w = s.lastReadTs;
|
|
1138
|
+
l(), u && h.scrollToFirstUnread(w);
|
|
1094
1139
|
}
|
|
1095
|
-
|
|
1140
|
+
x = !0, h.show();
|
|
1096
1141
|
} else
|
|
1097
|
-
|
|
1098
|
-
}),
|
|
1099
|
-
n(),
|
|
1100
|
-
() =>
|
|
1101
|
-
var
|
|
1102
|
-
e.persist && s.persistSession(c.sessionId), s.setConnected(!0), t.onTransportChange((
|
|
1142
|
+
x = !1, h.hide();
|
|
1143
|
+
}), $ = f.length === 0 || b;
|
|
1144
|
+
n(), m().then(
|
|
1145
|
+
() => d.connect().then((c) => {
|
|
1146
|
+
var w, B;
|
|
1147
|
+
e.persist && s.persistSession(c.sessionId), s.setConnected(!0), t.onTransportChange((w = d.kind) != null ? w : "ws");
|
|
1103
1148
|
const u = (B = c.suggestedReplies) != null ? B : [];
|
|
1104
|
-
u.length > 0 &&
|
|
1149
|
+
u.length > 0 && $ && h.setSuggestedReplies(u);
|
|
1105
1150
|
})
|
|
1106
1151
|
).catch((c) => {
|
|
1107
|
-
t.onError(c), s.setConnected(!1),
|
|
1152
|
+
t.onError(c), s.setConnected(!1), h.setOffline(!0);
|
|
1108
1153
|
});
|
|
1109
1154
|
const C = {
|
|
1110
1155
|
transport: null,
|
|
@@ -1115,12 +1160,12 @@ function U(r) {
|
|
|
1115
1160
|
s.close(), t.onClose();
|
|
1116
1161
|
},
|
|
1117
1162
|
destroy() {
|
|
1118
|
-
|
|
1163
|
+
N(), d.stop(), i.destroy(), g.destroy(), h.destroy();
|
|
1119
1164
|
}
|
|
1120
1165
|
};
|
|
1121
1166
|
return C;
|
|
1122
1167
|
}
|
|
1123
|
-
function
|
|
1168
|
+
function de() {
|
|
1124
1169
|
var s, i;
|
|
1125
1170
|
if (typeof document == "undefined") return;
|
|
1126
1171
|
const r = document.currentScript;
|
|
@@ -1141,9 +1186,9 @@ function le() {
|
|
|
1141
1186
|
});
|
|
1142
1187
|
}
|
|
1143
1188
|
typeof window != "undefined" && (window.SpilkiWidget = window.SpilkiWidget || {}, window.SpilkiWidget.init = (r) => U(r));
|
|
1144
|
-
|
|
1189
|
+
de();
|
|
1145
1190
|
export {
|
|
1146
|
-
|
|
1191
|
+
de as autoInit,
|
|
1147
1192
|
U as initSpilkiWidget
|
|
1148
1193
|
};
|
|
1149
1194
|
//# sourceMappingURL=widget.es.js.map
|