@spilki/widget 0.1.1 → 0.1.2
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/README.md +29 -25
- package/dist/bootstrap.es.js +60 -62
- package/dist/bootstrap.es.js.map +1 -1
- package/dist/bootstrap.umd.js +2 -2
- package/dist/bootstrap.umd.js.map +1 -1
- package/dist/core/state.d.ts +1 -2
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/transport.d.ts +0 -1
- package/dist/core/transport.d.ts.map +1 -1
- package/dist/core/utils.d.ts +4 -4
- package/dist/core/utils.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/widget.es.js +64 -66
- package/dist/widget.es.js.map +1 -1
- package/dist/widget.umd.js +2 -2
- package/dist/widget.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/widget.es.js
CHANGED
|
@@ -58,13 +58,13 @@ function M(r) {
|
|
|
58
58
|
destroy() {
|
|
59
59
|
e.remove();
|
|
60
60
|
},
|
|
61
|
-
setOpen(
|
|
62
|
-
s.setAttribute("aria-expanded", String(
|
|
61
|
+
setOpen(n) {
|
|
62
|
+
s.setAttribute("aria-expanded", String(n));
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
const A = ':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-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{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 .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}.message{display:flex;flex-direction:column;gap:.25rem;max-width:85%;line-height:1.4;word-wrap:break-word;overflow-wrap:anywhere;white-space:pre-wrap}.message.user{align-self:flex-end;text-align:right}.message .bubble{padding:.6rem .8rem;border-radius:1rem;background:#6366f126}.message.user .bubble{background:var(--spilki-accent);color:#fff}.message.bot .bubble{background:#94a3b826}.input-area{display:flex;align-items:flex-end;gap:.5rem;padding:.75rem 1rem;border-top:1px solid var(--spilki-border)}.input-area textarea{flex:1;resize:none;min-height:2.5rem;max-height:6rem;border-radius:.75rem;border:1px solid var(--spilki-border);padding:.6rem .75rem;font-family:inherit;font-size:.95rem;background:var(--spilki-surface);color:var(--spilki-text)}.input-area button{border:none;border-radius:999px;padding:.6rem 1.1rem;background:var(--spilki-accent);color:#fff;font-weight:600;cursor:pointer}.typing{font-size:.75rem;color:#94a3b8e6;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)}:host([data-theme="light"]){--spilki-surface: var(--spilki-bg-light);--spilki-text: var(--spilki-text-light);--spilki-border: var(--spilki-border-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:#0f172ad9}.messages::-webkit-scrollbar,.input-area textarea::-webkit-scrollbar{width:6px}.messages::-webkit-scrollbar-track,.input-area textarea::-webkit-scrollbar-track{background:transparent}.messages::-webkit-scrollbar-thumb,.input-area textarea::-webkit-scrollbar-thumb{background:#94a3b84d;border-radius:999px}.messages::-webkit-scrollbar-thumb:hover,.input-area textarea::-webkit-scrollbar-thumb:hover{background:#94a3b880}:host([data-theme="dark"]) .messages::-webkit-scrollbar-thumb,:host([data-theme="dark"]) .input-area textarea::-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{background:#ffffff59}.messages{scroll-behavior:smooth}';
|
|
67
|
-
class
|
|
67
|
+
class C {
|
|
68
68
|
constructor(e) {
|
|
69
69
|
this.options = e, this.focusable = [], 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" }), this.shadow.innerHTML = `
|
|
70
70
|
<style>${A}</style>
|
|
@@ -149,7 +149,7 @@ class $ {
|
|
|
149
149
|
e.shiftKey && i === t ? (e.preventDefault(), s.focus()) : !e.shiftKey && i === s && (e.preventDefault(), t.focus());
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
-
const
|
|
152
|
+
const W = "https://api.spilki.ai", g = {
|
|
153
153
|
welcome: "Hi! I'm your assistant.",
|
|
154
154
|
placeholder: "Type a message…",
|
|
155
155
|
sendLabel: "Send",
|
|
@@ -157,7 +157,7 @@ const C = "https://api.spilki.ai", g = {
|
|
|
157
157
|
offline: "Unable to connect. Please try again later.",
|
|
158
158
|
title: "Spilki Assistant"
|
|
159
159
|
}, p = {
|
|
160
|
-
apiBase:
|
|
160
|
+
apiBase: W,
|
|
161
161
|
position: "bottom-right",
|
|
162
162
|
theme: "auto",
|
|
163
163
|
color: "#6366f1",
|
|
@@ -165,8 +165,8 @@ const C = "https://api.spilki.ai", g = {
|
|
|
165
165
|
persist: !0,
|
|
166
166
|
i18n: g
|
|
167
167
|
};
|
|
168
|
-
function
|
|
169
|
-
var t, s, i,
|
|
168
|
+
function $(r) {
|
|
169
|
+
var t, s, i, n, l, a, h;
|
|
170
170
|
const e = { ...g, ...(t = r.i18n) != null ? t : {} };
|
|
171
171
|
return {
|
|
172
172
|
...p,
|
|
@@ -174,7 +174,7 @@ function W(r) {
|
|
|
174
174
|
apiBase: (s = r.apiBase) != null ? s : p.apiBase,
|
|
175
175
|
i18n: e,
|
|
176
176
|
welcome: (i = r.welcome) != null ? i : e.welcome,
|
|
177
|
-
position: (
|
|
177
|
+
position: (n = r.position) != null ? n : p.position,
|
|
178
178
|
theme: (l = r.theme) != null ? l : p.theme,
|
|
179
179
|
color: (a = r.color) != null ? a : p.color,
|
|
180
180
|
persist: (h = r.persist) != null ? h : p.persist
|
|
@@ -187,7 +187,7 @@ function L() {
|
|
|
187
187
|
var r, e;
|
|
188
188
|
return (e = (r = window.matchMedia) == null ? void 0 : r.call(window, "(prefers-color-scheme: dark)").matches) != null ? e : !1;
|
|
189
189
|
}
|
|
190
|
-
function
|
|
190
|
+
function x(r) {
|
|
191
191
|
return r === "light" || r === "dark" ? r : L() ? "dark" : "light";
|
|
192
192
|
}
|
|
193
193
|
function u(r, e = 30) {
|
|
@@ -215,9 +215,8 @@ class P {
|
|
|
215
215
|
async connect() {
|
|
216
216
|
var l, a;
|
|
217
217
|
this.stopped = !1;
|
|
218
|
-
const e = `${this.options.apiBase.replace(/\/$/, "")}/widget/
|
|
218
|
+
const e = `${this.options.apiBase.replace(/\/$/, "")}/widget/session`, t = (a = (l = this.sessionId) != null ? l : this.options.sessionId) != null ? a : void 0, s = {
|
|
219
219
|
organisationId: this.options.org,
|
|
220
|
-
assistantId: this.options.assistant,
|
|
221
220
|
sessionId: t,
|
|
222
221
|
userAgent: typeof navigator != "undefined" ? navigator.userAgent : "",
|
|
223
222
|
referrer: typeof document != "undefined" ? document.referrer : "",
|
|
@@ -232,13 +231,13 @@ class P {
|
|
|
232
231
|
});
|
|
233
232
|
if (!i.ok)
|
|
234
233
|
throw new Error(`SpilkiWidget: connect failed (${i.status})`);
|
|
235
|
-
const
|
|
236
|
-
return this.sessionId =
|
|
234
|
+
const n = await i.json();
|
|
235
|
+
return this.sessionId = n.sessionId, this.options.sessionId = n.sessionId, this.backoff = d, await this.startTransport(n), n;
|
|
237
236
|
}
|
|
238
237
|
async send(e) {
|
|
239
|
-
var
|
|
238
|
+
var n, l;
|
|
240
239
|
const t = {
|
|
241
|
-
sessionId: (l = (
|
|
240
|
+
sessionId: (l = (n = this.sessionId) != null ? n : this.options.sessionId) != null ? l : "",
|
|
242
241
|
text: e
|
|
243
242
|
};
|
|
244
243
|
if (!t.sessionId)
|
|
@@ -284,7 +283,7 @@ class P {
|
|
|
284
283
|
return;
|
|
285
284
|
}
|
|
286
285
|
this.currentKind = "ws", this.handlers.onOpen("ws"), this.backoff = d, t();
|
|
287
|
-
}), i.addEventListener("message", (
|
|
286
|
+
}), i.addEventListener("message", (n) => this.handleIncoming(n.data)), i.addEventListener("close", () => {
|
|
288
287
|
this.stopped || this.retryFallback("ws");
|
|
289
288
|
}), i.addEventListener("error", () => {
|
|
290
289
|
this.handlers.onError(new Error("SpilkiWidget: websocket error")), i.readyState !== WebSocket.OPEN && s(new Error("WebSocket failed"));
|
|
@@ -302,15 +301,15 @@ class P {
|
|
|
302
301
|
}
|
|
303
302
|
const i = new EventSource(e);
|
|
304
303
|
this.sse = i;
|
|
305
|
-
let
|
|
304
|
+
let n = !1;
|
|
306
305
|
i.addEventListener("open", () => {
|
|
307
|
-
if (
|
|
306
|
+
if (n = !0, this.stopped) {
|
|
308
307
|
i.close();
|
|
309
308
|
return;
|
|
310
309
|
}
|
|
311
310
|
this.currentKind = "sse", this.handlers.onOpen("sse"), this.backoff = d, t();
|
|
312
311
|
}), i.addEventListener("message", (l) => this.handleIncoming(l.data)), i.addEventListener("error", () => {
|
|
313
|
-
if (!
|
|
312
|
+
if (!n) {
|
|
314
313
|
s(new Error("SSE failed"));
|
|
315
314
|
return;
|
|
316
315
|
}
|
|
@@ -326,7 +325,7 @@ class P {
|
|
|
326
325
|
const s = await fetch(e);
|
|
327
326
|
if (!s.ok) throw new Error(`Poll failed ${s.status}`);
|
|
328
327
|
const i = await s.json();
|
|
329
|
-
u(i).forEach((
|
|
328
|
+
u(i).forEach((n) => this.handlers.onMessage(n)), this.backoff = d;
|
|
330
329
|
} catch (s) {
|
|
331
330
|
this.handlers.onError(s), this.backoff = Math.min(this.backoff * 1.5, v);
|
|
332
331
|
} finally {
|
|
@@ -369,13 +368,13 @@ class P {
|
|
|
369
368
|
}
|
|
370
369
|
const f = 30;
|
|
371
370
|
class U {
|
|
372
|
-
constructor(e, t
|
|
373
|
-
this.org = e, this.
|
|
371
|
+
constructor(e, t) {
|
|
372
|
+
this.org = e, this.listeners = /* @__PURE__ */ new Set(), this.state = {
|
|
374
373
|
isOpen: !1,
|
|
375
374
|
isTyping: !1,
|
|
376
375
|
isConnected: !1,
|
|
377
376
|
messages: []
|
|
378
|
-
}, this.historyKey = `spilki-history:${e}
|
|
377
|
+
}, this.historyKey = `spilki-history:${e}`, this.sessionKey = `spilki-session:${e}`, this.tokenKey = `spilki-token:${e}`, this.persist = t.persist, this.state.messages = this.loadMessages();
|
|
379
378
|
}
|
|
380
379
|
get snapshot() {
|
|
381
380
|
return { ...this.state, messages: [...this.state.messages] };
|
|
@@ -522,14 +521,14 @@ const z = {
|
|
|
522
521
|
onTransportChange() {
|
|
523
522
|
}
|
|
524
523
|
};
|
|
525
|
-
async function H(r, e) {
|
|
526
|
-
const
|
|
524
|
+
async function H(r, e, t) {
|
|
525
|
+
const s = `${r.replace(/\/$/, "")}/widget/install`, i = await fetch(s, {
|
|
527
526
|
method: "POST",
|
|
528
527
|
headers: { "Content-Type": "application/json", Origin: window.location.origin },
|
|
529
|
-
body: JSON.stringify({ token: e })
|
|
528
|
+
body: JSON.stringify({ token: e, organisationId: t })
|
|
530
529
|
});
|
|
531
|
-
if (!
|
|
532
|
-
return (await
|
|
530
|
+
if (!i.ok) throw new Error(`SpilkiWidget: install failed (${i.status})`);
|
|
531
|
+
return (await i.json()).accessToken;
|
|
533
532
|
}
|
|
534
533
|
async function q(r, e) {
|
|
535
534
|
const t = `${r.replace(/\/$/, "")}/widget/refresh`, s = await fetch(t, {
|
|
@@ -540,17 +539,18 @@ async function q(r, e) {
|
|
|
540
539
|
return (await s.json()).accessToken;
|
|
541
540
|
}
|
|
542
541
|
function E(r) {
|
|
543
|
-
var k, w, y,
|
|
544
|
-
if (!r.org
|
|
545
|
-
throw new Error("SpilkiWidget: org
|
|
546
|
-
const e =
|
|
542
|
+
var k, w, y, S;
|
|
543
|
+
if (!r.org)
|
|
544
|
+
throw new Error("SpilkiWidget: org is required");
|
|
545
|
+
const e = $(r);
|
|
547
546
|
K(e.allowedOriginsHint);
|
|
548
|
-
const t = { ...z, ...(k = e.hooks) != null ? k : {} }, s = new U(e.org,
|
|
547
|
+
const t = { ...z, ...(k = e.hooks) != null ? k : {} }, s = new U(e.org, { persist: e.persist });
|
|
549
548
|
let i = (w = s.accessToken) != null ? w : void 0;
|
|
550
|
-
const
|
|
549
|
+
const n = async () => {
|
|
551
550
|
if (!i) {
|
|
552
551
|
if (!r.installationToken) throw new Error("SpilkiWidget: missing installationToken");
|
|
553
|
-
|
|
552
|
+
if (!r.org) throw new Error("SpilkiWidget: missing org");
|
|
553
|
+
i = await H(e.apiBase, r.installationToken, r.org), s.persistAccessToken(i);
|
|
554
554
|
return;
|
|
555
555
|
}
|
|
556
556
|
F(i) && (i = await q(e.apiBase, i), s.persistAccessToken(i));
|
|
@@ -560,17 +560,17 @@ function E(r) {
|
|
|
560
560
|
onClick: () => {
|
|
561
561
|
s.snapshot.isOpen ? (s.close(), t.onClose()) : (s.open(), t.onOpen());
|
|
562
562
|
}
|
|
563
|
-
}), a = new
|
|
563
|
+
}), a = new C({
|
|
564
564
|
color: e.color,
|
|
565
|
-
theme:
|
|
566
|
-
position: (
|
|
565
|
+
theme: x(e.theme),
|
|
566
|
+
position: (S = e.position) != null ? S : "bottom-right",
|
|
567
567
|
i18n: e.i18n,
|
|
568
568
|
onClose: () => {
|
|
569
569
|
s.close(), t.onClose();
|
|
570
570
|
},
|
|
571
|
-
onSend: (
|
|
572
|
-
const c = s.addMessage({ author: "user", text:
|
|
573
|
-
a.appendMessage(c),
|
|
571
|
+
onSend: (o) => {
|
|
572
|
+
const c = s.addMessage({ author: "user", text: o });
|
|
573
|
+
a.appendMessage(c), n().then(() => h.send(o)).catch((I) => {
|
|
574
574
|
t.onError(I), s.setConnected(!1), a.setOffline(!0);
|
|
575
575
|
});
|
|
576
576
|
}
|
|
@@ -579,48 +579,47 @@ function E(r) {
|
|
|
579
579
|
apiBase: e.apiBase,
|
|
580
580
|
accessToken: i,
|
|
581
581
|
org: e.org,
|
|
582
|
-
assistant: e.assistant,
|
|
583
582
|
sessionId: s.sessionId
|
|
584
583
|
},
|
|
585
584
|
{
|
|
586
|
-
onOpen(
|
|
587
|
-
m.transport =
|
|
585
|
+
onOpen(o) {
|
|
586
|
+
m.transport = o, t.onTransportChange(o), s.setConnected(!0), a.setOffline(!1);
|
|
588
587
|
},
|
|
589
|
-
onMessage(
|
|
590
|
-
const c = s.addMessage(
|
|
588
|
+
onMessage(o) {
|
|
589
|
+
const c = s.addMessage(o);
|
|
591
590
|
a.appendMessage(c), t.onMessage(c);
|
|
592
591
|
},
|
|
593
|
-
onTyping(
|
|
594
|
-
s.setTyping(
|
|
592
|
+
onTyping(o) {
|
|
593
|
+
s.setTyping(o);
|
|
595
594
|
},
|
|
596
|
-
onError(
|
|
597
|
-
t.onError(
|
|
595
|
+
onError(o) {
|
|
596
|
+
t.onError(o), s.setConnected(!1), s.snapshot.isOpen && a.setOffline(!0);
|
|
598
597
|
}
|
|
599
598
|
}
|
|
600
599
|
);
|
|
601
600
|
l.mount(), a.mount();
|
|
602
601
|
const b = s.snapshot.messages;
|
|
603
602
|
if (b.length === 0 && e.welcome) {
|
|
604
|
-
const
|
|
603
|
+
const o = {
|
|
605
604
|
id: "welcome",
|
|
606
605
|
author: "bot",
|
|
607
606
|
text: e.welcome,
|
|
608
607
|
ts: Date.now()
|
|
609
608
|
};
|
|
610
|
-
s.addMessage(
|
|
609
|
+
s.addMessage(o), a.appendMessage(o);
|
|
611
610
|
} else
|
|
612
611
|
a.updateMessages(b);
|
|
613
612
|
const T = s.subscribe(() => {
|
|
614
|
-
const
|
|
615
|
-
l.setOpen(
|
|
613
|
+
const o = s.snapshot;
|
|
614
|
+
l.setOpen(o.isOpen), a.setTyping(o.isTyping), a.setOffline(!o.isConnected), a.updateTheme(x(e.theme)), o.isOpen ? a.show() : a.hide();
|
|
616
615
|
});
|
|
617
|
-
|
|
618
|
-
() => h.connect().then((
|
|
616
|
+
n().then(
|
|
617
|
+
() => h.connect().then((o) => {
|
|
619
618
|
var c;
|
|
620
|
-
e.persist && s.persistSession(
|
|
619
|
+
e.persist && s.persistSession(o.sessionId), s.setConnected(!0), t.onTransportChange((c = h.kind) != null ? c : "ws");
|
|
621
620
|
})
|
|
622
|
-
).catch((
|
|
623
|
-
t.onError(
|
|
621
|
+
).catch((o) => {
|
|
622
|
+
t.onError(o), s.setConnected(!1), a.setOffline(!0);
|
|
624
623
|
});
|
|
625
624
|
const m = {
|
|
626
625
|
transport: null,
|
|
@@ -637,24 +636,23 @@ function E(r) {
|
|
|
637
636
|
return m;
|
|
638
637
|
}
|
|
639
638
|
function J() {
|
|
640
|
-
var
|
|
639
|
+
var s, i;
|
|
641
640
|
if (typeof document == "undefined") return;
|
|
642
641
|
const r = document.currentScript;
|
|
643
642
|
if (!r) return;
|
|
644
643
|
const e = r.dataset;
|
|
645
644
|
if (e.autoinit === "false") return;
|
|
646
|
-
const t = e.org
|
|
647
|
-
if (!t
|
|
648
|
-
console.error("SpilkiWidget: data-org and
|
|
645
|
+
const t = e.org;
|
|
646
|
+
if (!t) {
|
|
647
|
+
console.error("SpilkiWidget: data-org and is required for auto init");
|
|
649
648
|
return;
|
|
650
649
|
}
|
|
651
650
|
E({
|
|
652
651
|
org: t,
|
|
653
|
-
assistant: s,
|
|
654
652
|
installationToken: e.installationToken,
|
|
655
653
|
apiBase: e.apiBase,
|
|
656
|
-
position: (
|
|
657
|
-
theme: (
|
|
654
|
+
position: (s = e.position) != null ? s : void 0,
|
|
655
|
+
theme: (i = e.theme) != null ? i : void 0
|
|
658
656
|
});
|
|
659
657
|
}
|
|
660
658
|
if (typeof window != "undefined") {
|
package/dist/widget.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget.es.js","sources":["../src/ui/bubble.ts","../src/ui/panel.ts","../src/core/utils.ts","../src/core/transport.ts","../src/core/state.ts","../src/core/jwt.ts","../src/index.ts"],"sourcesContent":["import type { PositionOption } from \"../types\";\n\nexport interface BubbleController {\n mount(): void;\n destroy(): void;\n setOpen(open: boolean): void;\n element: HTMLDivElement;\n}\n\ninterface BubbleOptions {\n color: string;\n position: PositionOption;\n onClick(): void;\n}\n\nconst TEMPLATE = `\n <style>\n :host {\n all: initial;\n position: fixed;\n z-index: 2147483000;\n }\n button {\n all: unset;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 56px;\n height: 56px;\n border-radius: 999px;\n cursor: pointer;\n background: var(--spilki-accent);\n color: #fff;\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);\n transition: transform 0.18s ease, box-shadow 0.18s ease;\n }\n button:focus-visible {\n outline: 2px solid #fff;\n outline-offset: 3px;\n }\n button:hover {\n transform: translateY(-1px);\n box-shadow: 0 12px 30px rgba(0, 0, 0, 0.25);\n }\n .icon {\n width: 28px;\n height: 28px;\n }\n .icon svg {\n width: 100%;\n height: 100%;\n }\n </style>\n <button type=\"button\" aria-label=\"Open chat\">\n <span class=\"icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5 6a3 3 0 0 1 3-3h16a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H14l-5 6v-6H8a3 3 0 0 1-3-3V6Z\" fill=\"currentColor\"/>\n </svg>\n </span>\n </button>\n`;\n\nexport function createBubble(options: BubbleOptions): BubbleController {\n const host = document.createElement(\"div\");\n host.setAttribute(\"part\", \"bubble-root\");\n host.style.setProperty(\"--spilki-accent\", options.color);\n host.style.position = \"fixed\";\n host.style.bottom = \"24px\";\n host.style[options.position === \"bottom-right\" ? \"right\" : \"left\"] = \"24px\";\n\n const shadow = host.attachShadow({ mode: \"open\" });\n shadow.innerHTML = TEMPLATE;\n const button = shadow.querySelector(\"button\")!;\n button.addEventListener(\"click\", () => options.onClick());\n\n const controller: BubbleController = {\n element: host,\n mount() {\n document.body.appendChild(host);\n },\n destroy() {\n host.remove();\n },\n setOpen(open: boolean) {\n button.setAttribute(\"aria-expanded\", String(open));\n }\n };\n return controller;\n}\n","import type { Message, WidgetI18n } from \"../types\";\nimport styles from \"./styles.css?inline\";\n\ninterface PanelOptions {\n color: string;\n theme: \"light\" | \"dark\";\n position: \"bottom-right\" | \"bottom-left\";\n i18n: WidgetI18n;\n onClose(): void;\n onSend(text: string): void;\n}\n\nexport class Panel {\n private readonly host: HTMLDivElement;\n private readonly shadow: ShadowRoot;\n private readonly messagesEl: HTMLDivElement;\n private readonly typingEl: HTMLDivElement;\n private readonly input: HTMLTextAreaElement;\n private readonly offlineEl: HTMLDivElement;\n private readonly sendButton: HTMLButtonElement;\n private readonly focusable: HTMLElement[] = [];\n private open = false;\n\n constructor(private readonly options: PanelOptions) {\n this.host = document.createElement(\"div\");\n this.host.setAttribute(\"part\", \"panel-root\");\n this.host.style.position = \"fixed\";\n this.host.style.bottom = \"96px\";\n this.host.style[options.position === \"bottom-right\" ? \"right\" : \"left\"] = \"24px\";\n this.host.style.width = \"360px\";\n this.host.style.maxWidth = \"calc(100vw - 32px)\";\n this.host.style.height = \"520px\";\n this.host.style.display = \"none\";\n this.host.style.zIndex = \"2147483001\";\n\n this.shadow = this.host.attachShadow({ mode: \"open\" });\n this.shadow.innerHTML = `\n <style>${styles}</style>\n <div class=\"wrapper\" role=\"dialog\" aria-modal=\"true\" aria-label=\"${options.i18n.title}\">\n <header>\n <h1><span class=\"status-dot\" aria-hidden=\"true\"></span>${options.i18n.title}</h1>\n <button class=\"close\" type=\"button\" aria-label=\"Close\">×</button>\n </header>\n <div class=\"messages\" part=\"messages\"></div>\n <div class=\"typing\" hidden>${options.i18n.typing}</div>\n <div class=\"offline\" hidden>${options.i18n.offline}</div>\n <div class=\"input-area\">\n <textarea rows=\"2\" placeholder=\"${options.i18n.placeholder}\" aria-label=\"${options.i18n.placeholder}\"></textarea>\n <button type=\"button\">${options.i18n.sendLabel}</button>\n </div>\n </div>\n `;\n\n this.host.dataset.theme = options.theme;\n this.host.style.setProperty(\"--spilki-accent\", options.color);\n\n this.messagesEl = this.shadow.querySelector(\".messages\") as HTMLDivElement;\n this.typingEl = this.shadow.querySelector(\".typing\") as HTMLDivElement;\n this.input = this.shadow.querySelector(\"textarea\") as HTMLTextAreaElement;\n this.offlineEl = this.shadow.querySelector(\".offline\") as HTMLDivElement;\n this.sendButton = this.shadow.querySelector(\".input-area button\") as HTMLButtonElement;\n\n const closeButton = this.shadow.querySelector(\"header .close\") as HTMLButtonElement;\n closeButton.addEventListener(\"click\", () => this.options.onClose());\n this.sendButton.addEventListener(\"click\", () => this.send());\n\n this.input.addEventListener(\"keydown\", (event: KeyboardEvent) => {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n this.send();\n } else if (event.key === \"Escape\") {\n this.options.onClose();\n }\n });\n\n this.shadow.addEventListener(\"keydown\", (event) => {\n const keyboard = event as KeyboardEvent;\n if (keyboard.key === \"Escape\") {\n this.options.onClose();\n }\n if (keyboard.key === \"Tab\") {\n this.trapFocus(keyboard);\n }\n });\n\n this.shadow.addEventListener(\"focusin\", () => this.collectFocusable());\n this.collectFocusable();\n }\n\n mount(): void {\n document.body.appendChild(this.host);\n }\n\n destroy(): void {\n this.host.remove();\n }\n\n show(): void {\n if (this.open) return;\n this.open = true;\n this.host.style.display = \"block\";\n this.focusInput();\n }\n\n hide(): void {\n if (!this.open) return;\n this.open = false;\n this.host.style.display = \"none\";\n }\n\n focusInput(): void {\n queueMicrotask(() => {\n this.input.focus();\n });\n }\n\n updateTheme(theme: \"light\" | \"dark\"): void {\n this.host.dataset.theme = theme;\n }\n\n updateMessages(messages: Message[]): void {\n this.messagesEl.innerHTML = \"\";\n messages.forEach((message) => {\n const item = document.createElement(\"div\");\n item.className = `message ${message.author}`;\n item.setAttribute(\"data-author\", message.author);\n const bubble = document.createElement(\"div\");\n bubble.className = \"bubble\";\n bubble.textContent = message.text;\n item.appendChild(bubble);\n this.messagesEl.appendChild(item);\n });\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight;\n }\n\n appendMessage(message: Message): void {\n const item = document.createElement(\"div\");\n item.className = `message ${message.author}`;\n item.setAttribute(\"data-author\", message.author);\n const bubble = document.createElement(\"div\");\n bubble.className = \"bubble\";\n bubble.textContent = message.text;\n item.appendChild(bubble);\n this.messagesEl.appendChild(item);\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight;\n }\n\n setTyping(active: boolean): void {\n this.typingEl.toggleAttribute(\"hidden\", !active);\n }\n\n setOffline(active: boolean): void {\n this.offlineEl.toggleAttribute(\"hidden\", !active);\n }\n\n clearInput(): void {\n this.input.value = \"\";\n this.input.dispatchEvent(new Event(\"input\"));\n }\n\n private send(): void {\n const text = this.input.value.trim();\n if (!text) return;\n this.options.onSend(text);\n this.clearInput();\n }\n\n private collectFocusable(): void {\n const items = this.shadow.querySelectorAll<HTMLElement>(\n 'button, textarea, [href], [tabindex]:not([tabindex=\"-1\"])'\n );\n this.focusable.length = 0;\n items.forEach((el) => {\n if (!el.hasAttribute(\"disabled\")) {\n this.focusable.push(el);\n }\n });\n }\n\n private trapFocus(event: KeyboardEvent): void {\n if (this.focusable.length === 0) return;\n const first = this.focusable[0];\n const last = this.focusable[this.focusable.length - 1];\n const active = this.shadow.activeElement as HTMLElement;\n if (event.shiftKey && active === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && active === last) {\n event.preventDefault();\n first.focus();\n }\n }\n}\n","import type {InitOptions, WidgetI18n} from \"../types\";\n\nexport const DEFAULT_API_BASE = \"https://api.spilki.ai\";\nexport const SESSION_PREFIX = \"spilki-widget\";\n\nconst DEFAULT_I18N: WidgetI18n = {\n welcome: \"Hi! I'm your assistant.\",\n placeholder: \"Type a message…\",\n sendLabel: \"Send\",\n typing: \"Assistant is typing…\",\n offline: \"Unable to connect. Please try again later.\",\n title: \"Spilki Assistant\"\n};\n\nexport const DEFAULT_OPTIONS: Required<\n Pick<InitOptions, \"position\" | \"theme\" | \"color\" | \"welcome\" | \"persist\">\n> & { apiBase: string; i18n: WidgetI18n } = {\n apiBase: DEFAULT_API_BASE,\n position: \"bottom-right\",\n theme: \"auto\",\n color: \"#6366f1\",\n welcome: DEFAULT_I18N.welcome,\n persist: true,\n i18n: DEFAULT_I18N\n};\n\nexport type NormalizedOptions = InitOptions & {\n apiBase: string;\n position: InitOptions[\"position\"];\n theme: InitOptions[\"theme\"];\n color: string;\n welcome: string;\n persist: boolean;\n i18n: WidgetI18n;\n};\n\nexport function mergeOptions(options: InitOptions): NormalizedOptions {\n const mergedI18n = {...DEFAULT_I18N, ...(options.i18n ?? {})};\n return {\n ...DEFAULT_OPTIONS,\n ...options,\n apiBase: options.apiBase ?? DEFAULT_OPTIONS.apiBase,\n i18n: mergedI18n,\n welcome: options.welcome ?? mergedI18n.welcome,\n position: options.position ?? DEFAULT_OPTIONS.position,\n theme: options.theme ?? DEFAULT_OPTIONS.theme,\n color: options.color ?? DEFAULT_OPTIONS.color,\n persist: options.persist ?? DEFAULT_OPTIONS.persist\n } as NormalizedOptions;\n}\n\nexport function storageKey(org: string, assistant: string): string {\n return `${SESSION_PREFIX}:${org}:${assistant}`;\n}\n\nexport function getPersistedSession(\n org: string,\n assistant: string\n): string | null {\n try {\n return localStorage.getItem(storageKey(org, assistant));\n } catch (error) {\n console.warn(\"SpilkiWidget: Unable to read localStorage\", error);\n return null;\n }\n}\n\nexport function persistSession(\n org: string,\n assistant: string,\n sessionId: string\n): void {\n try {\n localStorage.setItem(storageKey(org, assistant), sessionId);\n } catch (error) {\n console.warn(\"SpilkiWidget: Unable to persist session\", error);\n }\n}\n\nexport function clearSession(org: string, assistant: string): void {\n try {\n localStorage.removeItem(storageKey(org, assistant));\n } catch (error) {\n console.warn(\"SpilkiWidget: Unable to clear session\", error);\n }\n}\n\nexport function createId(prefix = \"msg\"): string {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `${prefix}-${Math.random().toString(16).slice(2)}`;\n}\n\nexport function prefersDark(): boolean {\n return window.matchMedia?.(\"(prefers-color-scheme: dark)\").matches ?? false;\n}\n\nexport function getTheme(theme: string | undefined): \"light\" | \"dark\" {\n if (theme === \"light\" || theme === \"dark\") return theme;\n return prefersDark() ? \"dark\" : \"light\";\n}\n\nexport function clampMessages<T>(messages: T[], limit = 30): T[] {\n return messages.slice(-limit);\n}\n\nexport function warnAllowedOrigins(hint: string[] | undefined): void {\n if (!hint || hint.length === 0) return;\n const origin = window.location.origin;\n if (!hint.includes(origin)) {\n console.warn(\n `SpilkiWidget: current origin ${origin} not in allowedOriginsHint: ${hint.join(\", \")}`\n );\n }\n}\n","import type {ConnectResponse, Message, SendPayload, TransportKind} from \"../types\";\nimport {clampMessages} from \"./utils\";\n\ninterface TransportHandlers {\n onOpen(kind: TransportKind): void;\n\n onMessage(message: Message): void;\n\n onTyping(typing: boolean): void;\n\n onError(error: Error): void;\n}\n\ninterface TransportOptions {\n apiBase: string;\n accessToken?: string;\n org: string;\n assistant: string;\n sessionId?: string | null;\n}\n\ntype IncomingPayload =\n | { type: \"message\"; payload: Message }\n | { type: \"typing\"; payload: { active: boolean } }\n | Message;\n\nconst RETRY_BASE = 1500;\nconst RETRY_MAX = 8000;\n\nexport class TransportManager {\n private sessionId: string | null = null;\n private currentKind: TransportKind | null = null;\n private ws?: WebSocket;\n private sse?: EventSource;\n private pollTimer?: number;\n private stopped = false;\n private backoff = RETRY_BASE;\n private readonly handlers: TransportHandlers;\n private readonly options: TransportOptions;\n\n constructor(options: TransportOptions, handlers: TransportHandlers) {\n this.options = options;\n this.handlers = handlers;\n }\n\n get kind(): TransportKind | null {\n return this.currentKind;\n }\n\n get activeSession(): string | null {\n return this.sessionId ?? this.options.sessionId ?? null;\n }\n\n async connect(): Promise<ConnectResponse> {\n this.stopped = false;\n const connectUrl = `${this.options.apiBase.replace(/\\/$/, \"\")}/widget/connect`;\n const currentSession = this.sessionId ?? this.options.sessionId ?? undefined;\n const body = {\n organisationId: this.options.org,\n assistantId: this.options.assistant,\n sessionId: currentSession,\n userAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : \"\",\n referrer: typeof document !== \"undefined\" ? document.referrer : \"\",\n origin: typeof window !== \"undefined\" ? window.location.origin : \"\"\n };\n\n const res = await fetch(connectUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(this.options.accessToken ? {Authorization: `Bearer ${this.options.accessToken}`} : {})\n },\n body: JSON.stringify(body)\n });\n\n if (!res.ok) {\n throw new Error(`SpilkiWidget: connect failed (${res.status})`);\n }\n\n const data = (await res.json()) as ConnectResponse;\n this.sessionId = data.sessionId;\n this.options.sessionId = data.sessionId;\n this.backoff = RETRY_BASE;\n await this.startTransport(data);\n return data;\n }\n\n async send(text: string): Promise<void> {\n const payload: SendPayload = {\n sessionId: this.sessionId ?? this.options.sessionId ?? \"\",\n text\n };\n\n if (!payload.sessionId) {\n throw new Error(\"SpilkiWidget: missing session id\");\n }\n\n if (this.currentKind === \"ws\" && this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify({type: \"message\", payload}));\n return;\n }\n\n const url = `${this.options.apiBase.replace(/\\/$/, \"\")}/widget/message`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(this.options.accessToken ? {Authorization: `Bearer ${this.options.accessToken}`} : {})\n },\n body: JSON.stringify(payload)\n });\n\n if (!res.ok) {\n throw new Error(`SpilkiWidget: send failed (${res.status})`);\n }\n }\n\n stop(): void {\n this.stopped = true;\n this.backoff = RETRY_BASE;\n if (this.ws) {\n this.ws.close();\n this.ws = undefined;\n }\n if (this.sse) {\n this.sse.close();\n this.sse = undefined;\n }\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = undefined;\n }\n this.currentKind = null;\n }\n\n private async startTransport(connect: ConnectResponse): Promise<void> {\n if (this.stopped) return;\n const attempts: Array<() => Promise<void>> = [];\n if (connect.wsUrl) attempts.push(() => this.startWs(connect.wsUrl!));\n if (connect.sseUrl) attempts.push(() => this.startSse(connect.sseUrl!));\n if (connect.pollUrl) attempts.push(() => this.startPoll(connect.pollUrl!));\n\n for (const attempt of attempts) {\n try {\n await attempt();\n return;\n } catch (error) {\n this.handlers.onError(error as Error);\n }\n }\n throw new Error(\"SpilkiWidget: unable to establish transport\");\n }\n\n private startWs(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const ws = new WebSocket(url);\n this.ws = ws;\n ws.addEventListener(\"open\", () => {\n if (this.stopped) {\n ws.close();\n return;\n }\n this.currentKind = \"ws\";\n this.handlers.onOpen(\"ws\");\n this.backoff = RETRY_BASE;\n resolve();\n });\n ws.addEventListener(\"message\", (event) => this.handleIncoming(event.data));\n ws.addEventListener(\"close\", () => {\n if (this.stopped) return;\n this.retryFallback(\"ws\");\n });\n ws.addEventListener(\"error\", () => {\n this.handlers.onError(new Error(\"SpilkiWidget: websocket error\"));\n if (ws.readyState !== WebSocket.OPEN) {\n reject(new Error(\"WebSocket failed\"));\n }\n });\n } catch (error) {\n reject(error as Error);\n }\n });\n }\n\n private startSse(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (typeof EventSource === \"undefined\") {\n reject(new Error(\"SSE not supported\"));\n return;\n }\n const sse = new EventSource(url);\n this.sse = sse;\n let opened = false;\n sse.addEventListener(\"open\", () => {\n opened = true;\n if (this.stopped) {\n sse.close();\n return;\n }\n this.currentKind = \"sse\";\n this.handlers.onOpen(\"sse\");\n this.backoff = RETRY_BASE;\n resolve();\n });\n sse.addEventListener(\"message\", (event) => this.handleIncoming(event.data));\n sse.addEventListener(\"error\", () => {\n if (!opened) {\n reject(new Error(\"SSE failed\"));\n return;\n }\n this.handlers.onError(new Error(\"SpilkiWidget: SSE error\"));\n if (this.stopped) return;\n this.retryFallback(\"sse\");\n });\n });\n }\n\n private async startPoll(url: string): Promise<void> {\n this.currentKind = \"poll\";\n this.handlers.onOpen(\"poll\");\n this.backoff = RETRY_BASE;\n const poll = async () => {\n if (this.stopped) return;\n try {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Poll failed ${res.status}`);\n const messages = (await res.json()) as Message[];\n clampMessages(messages).forEach((message) => this.handlers.onMessage(message));\n this.backoff = RETRY_BASE;\n } catch (error) {\n this.handlers.onError(error as Error);\n this.backoff = Math.min(this.backoff * 1.5, RETRY_MAX);\n } finally {\n if (!this.stopped) {\n this.pollTimer = window.setTimeout(poll, this.backoff);\n }\n }\n };\n await poll();\n }\n\n private retryFallback(failed: TransportKind): void {\n if (this.stopped) return;\n this.stop();\n this.backoff = Math.min(this.backoff * 1.5, RETRY_MAX);\n setTimeout(() => {\n this.handlers.onError(new Error(`SpilkiWidget: retrying after ${failed}`));\n this.connect().catch((error) => this.handlers.onError(error));\n }, this.backoff);\n }\n\n private handleIncoming(raw: string): void {\n try {\n const data = JSON.parse(raw) as IncomingPayload;\n if (Array.isArray(data)) {\n data.forEach((item) => this.dispatchIncoming(item));\n return;\n }\n this.dispatchIncoming(data);\n } catch {\n const message: Message = {\n id: `${Date.now()}`,\n author: \"bot\",\n text: raw,\n ts: Date.now()\n };\n this.handlers.onMessage(message);\n }\n }\n\n private dispatchIncoming(data: IncomingPayload): void {\n if (\"type\" in data) {\n if (data.type === \"message\") {\n this.handlers.onMessage(data.payload);\n } else if (data.type === \"typing\") {\n this.handlers.onTyping(Boolean(data.payload?.active));\n }\n return;\n }\n this.handlers.onMessage(data as Message);\n }\n}\n","import {clampMessages, createId} from \"./utils\";\nimport type {Message} from \"../types\";\n\ntype Listener = () => void;\n\nexport interface WidgetStateSnapshot {\n isOpen: boolean;\n isTyping: boolean;\n isConnected: boolean;\n messages: Message[];\n}\n\nconst HISTORY_LIMIT = 30;\n\nexport class WidgetState {\n private listeners = new Set<Listener>();\n private historyKey: string;\n private sessionKey: string;\n private tokenKey: string;\n private readonly persist: boolean;\n private state: WidgetStateSnapshot = {\n isOpen: false,\n isTyping: false,\n isConnected: false,\n messages: []\n };\n\n constructor(\n private readonly org: string,\n private readonly assistant: string,\n options: { persist: boolean }\n ) {\n this.historyKey = `spilki-history:${org}:${assistant}`;\n this.sessionKey = `spilki-session:${org}:${assistant}`;\n this.tokenKey = `spilki-token:${org}:${assistant}`;\n this.persist = options.persist;\n this.state.messages = this.loadMessages();\n }\n\n get snapshot(): WidgetStateSnapshot {\n return {...this.state, messages: [...this.state.messages]};\n }\n\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n open(): void {\n if (!this.state.isOpen) {\n this.state.isOpen = true;\n this.emit();\n }\n }\n\n close(): void {\n if (this.state.isOpen) {\n this.state.isOpen = false;\n this.emit();\n }\n }\n\n setTyping(value: boolean): void {\n if (this.state.isTyping !== value) {\n this.state.isTyping = value;\n this.emit();\n }\n }\n\n setConnected(value: boolean): void {\n if (this.state.isConnected !== value) {\n this.state.isConnected = value;\n this.emit();\n }\n }\n\n addMessage(message: Omit<Message, \"id\" | \"ts\"> & Partial<Pick<Message, \"id\" | \"ts\">>): Message {\n const full: Message = {\n id: message.id ?? createId(\"msg\"),\n ts: message.ts ?? Date.now(),\n author: message.author,\n text: message.text\n };\n this.state.messages = clampMessages([...this.state.messages, full], HISTORY_LIMIT);\n this.persistMessages();\n this.emit();\n return full;\n }\n\n setMessages(messages: Message[]): void {\n this.state.messages = clampMessages(messages, HISTORY_LIMIT);\n this.persistMessages();\n this.emit();\n }\n\n clearMessages(): void {\n this.state.messages = [];\n this.persistMessages();\n this.emit();\n }\n\n get sessionId(): string | null {\n if (!this.persist) return null;\n try {\n return localStorage.getItem(this.sessionKey);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to get item\", error);\n return null;\n }\n }\n\n persistSession(sessionId: string): void {\n if (!this.persist) return;\n try {\n localStorage.setItem(this.sessionKey, sessionId);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to set item\", error);\n }\n }\n\n clearSession(): void {\n if (!this.persist) return;\n try {\n localStorage.removeItem(this.sessionKey);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to remove item\", error);\n }\n }\n\n get accessToken(): string | null {\n if (!this.persist) return null;\n try {\n return localStorage.getItem(this.tokenKey);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to get item\", error);\n return null;\n }\n }\n\n persistAccessToken(token: string): void {\n if (!this.persist) return;\n try {\n localStorage.setItem(this.tokenKey, token);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to set item\", error);\n }\n }\n\n clearAccessToken(): void {\n if (!this.persist) return;\n try {\n localStorage.removeItem(this.tokenKey);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to remove item\", error);\n }\n }\n\n private emit(): void {\n this.listeners.forEach((listener) => listener());\n }\n\n private persistMessages(): void {\n if (!this.persist) return;\n try {\n localStorage.setItem(this.historyKey, JSON.stringify(this.state.messages));\n } catch (error) {\n console.error(\"SpilkiWidget: unable to set item\", error);\n }\n }\n\n private loadMessages(): Message[] {\n if (!this.persist) return [];\n try {\n const raw = localStorage.getItem(this.historyKey);\n if (!raw) return [];\n const parsed = JSON.parse(raw) as Message[];\n return Array.isArray(parsed) ? clampMessages(parsed, HISTORY_LIMIT) : [];\n } catch (error) {\n console.error(\"SpilkiWidget: unable to load messages\", error);\n return [];\n }\n }\n}\n","interface JwtPayload {\n exp?: number;\n\n [key: string]: unknown;\n}\n\nfunction decodePart(part: string): string {\n const normalized = part.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized.padEnd(normalized.length + ((4 - (normalized.length % 4)) % 4), \"=\");\n if (typeof atob === \"function\") {\n return decodeURIComponent(\n Array.prototype.map\n .call(atob(padded), (c: string) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`)\n .join(\"\")\n );\n }\n const buffer = (globalThis as {\n Buffer?: { from(input: string, encoding: string): { toString(enc: string): string } }\n }).Buffer;\n if (buffer) {\n return buffer.from(padded, \"base64\").toString(\"utf8\");\n }\n throw new Error(\"SpilkiWidget: no base64 decoder available\");\n}\n\nexport function parseJwt<T extends JwtPayload = JwtPayload>(token: string): T | null {\n if (!token) return null;\n const parts = token.split(\".\");\n if (parts.length < 2) return null;\n try {\n const payload = decodePart(parts[1]);\n return JSON.parse(payload) as T;\n } catch (error) {\n console.error(\"SpilkiWidget: unable to parse JWT\", error);\n return null;\n }\n}\n\nexport function isExpired(token: string): boolean {\n const payload = parseJwt(token);\n if (!payload?.exp) return false;\n const now = Math.floor(Date.now() / 1000);\n return payload.exp < now;\n}\n","import {createBubble} from \"./ui/bubble\";\nimport {Panel} from \"./ui/panel\";\nimport {TransportManager} from \"./core/transport\";\nimport {WidgetState} from \"./core/state\";\nimport type {NormalizedOptions} from \"./core/utils\";\nimport {getTheme, mergeOptions, warnAllowedOrigins} from \"./core/utils\";\nimport {isExpired} from \"./core/jwt\";\nimport type {InitOptions, Message, TransportKind, WidgetAccessTokenResponse, WidgetHooks} from \"./types\";\n\nexport interface SpilkiWidgetInstance {\n open(): void;\n\n close(): void;\n\n destroy(): void;\n\n transport?: TransportKind | null;\n}\n\nconst DEFAULT_HOOKS: WidgetHooks = {\n onOpen() {\n },\n onClose() {\n },\n onMessage() {\n },\n onError() {\n },\n onTransportChange() {\n }\n};\n\nasync function installAndGetAccessToken(apiBase: string, installationToken: string): Promise<string> {\n const url = `${apiBase.replace(/\\/$/, \"\")}/widget/install`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\"Content-Type\": \"application/json\", Origin: window.location.origin},\n body: JSON.stringify({token: installationToken})\n });\n if (!res.ok) throw new Error(`SpilkiWidget: install failed (${res.status})`);\n const data = (await res.json()) as WidgetAccessTokenResponse;\n return data.accessToken;\n}\n\nasync function refreshAccessToken(apiBase: string, oldToken: string): Promise<string> {\n const url = `${apiBase.replace(/\\/$/, \"\")}/widget/refresh`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {Authorization: `Bearer ${oldToken}`, Origin: window.location.origin}\n });\n if (!res.ok) throw new Error(`SpilkiWidget: refresh failed (${res.status})`);\n const data = (await res.json()) as WidgetAccessTokenResponse;\n return data.accessToken;\n}\n\nexport function initSpilkiWidget(rawOptions: InitOptions): SpilkiWidgetInstance {\n if (!rawOptions.org || !rawOptions.assistant) {\n throw new Error(\"SpilkiWidget: org and assistant are required\");\n }\n\n const options: NormalizedOptions = mergeOptions(rawOptions);\n warnAllowedOrigins(options.allowedOriginsHint);\n\n const hooks: WidgetHooks = {...DEFAULT_HOOKS, ...(options.hooks ?? {})};\n const state = new WidgetState(options.org, options.assistant, {persist: options.persist});\n\n let accessToken = state.accessToken ?? undefined;\n\n const ensureAccessToken = async () => {\n if (!accessToken) {\n if (!rawOptions.installationToken) throw new Error(\"SpilkiWidget: missing installationToken\");\n accessToken = await installAndGetAccessToken(options.apiBase, rawOptions.installationToken);\n state.persistAccessToken(accessToken);\n return;\n }\n if (isExpired(accessToken)) {\n accessToken = await refreshAccessToken(options.apiBase, accessToken);\n state.persistAccessToken(accessToken);\n }\n };\n\n const bubble = createBubble({\n color: options.color!,\n position: options.position ?? \"bottom-right\",\n onClick: () => {\n const snap = state.snapshot;\n if (snap.isOpen) {\n state.close();\n hooks.onClose();\n } else {\n state.open();\n hooks.onOpen();\n }\n }\n });\n\n const panel = new Panel({\n color: options.color!,\n theme: getTheme(options.theme),\n position: options.position ?? \"bottom-right\",\n i18n: options.i18n,\n onClose: () => {\n state.close();\n hooks.onClose();\n },\n onSend: (text) => {\n const message = state.addMessage({author: \"user\", text});\n panel.appendMessage(message);\n ensureAccessToken()\n .then(() => transport.send(text))\n .catch((error) => {\n hooks.onError(error as Error);\n state.setConnected(false);\n panel.setOffline(true);\n });\n }\n });\n\n const transport = new TransportManager(\n {\n apiBase: options.apiBase,\n accessToken,\n org: options.org,\n assistant: options.assistant,\n sessionId: state.sessionId\n },\n {\n onOpen(kind) {\n instance.transport = kind;\n hooks.onTransportChange(kind);\n state.setConnected(true);\n panel.setOffline(false);\n },\n onMessage(message) {\n const stored = state.addMessage(message);\n panel.appendMessage(stored);\n hooks.onMessage(stored);\n },\n onTyping(active) {\n state.setTyping(active);\n },\n onError(error) {\n hooks.onError(error);\n state.setConnected(false);\n if (state.snapshot.isOpen) {\n panel.setOffline(true);\n }\n }\n }\n );\n\n bubble.mount();\n panel.mount();\n\n const initialMessages = state.snapshot.messages;\n if (initialMessages.length === 0 && options.welcome) {\n const welcome: Message = {\n id: \"welcome\",\n author: \"bot\",\n text: options.welcome,\n ts: Date.now()\n };\n state.addMessage(welcome);\n panel.appendMessage(welcome);\n } else {\n panel.updateMessages(initialMessages);\n }\n\n const unsubscribe = state.subscribe(() => {\n const snap = state.snapshot;\n bubble.setOpen(snap.isOpen);\n panel.setTyping(snap.isTyping);\n panel.setOffline(!snap.isConnected);\n panel.updateTheme(getTheme(options.theme));\n if (snap.isOpen) {\n panel.show();\n } else {\n panel.hide();\n }\n });\n\n ensureAccessToken()\n .then(() =>\n transport.connect().then((response) => {\n if (options.persist) {\n state.persistSession(response.sessionId);\n }\n state.setConnected(true);\n hooks.onTransportChange(transport.kind ?? \"ws\");\n })\n )\n .catch((error) => {\n hooks.onError(error);\n state.setConnected(false);\n panel.setOffline(true);\n });\n\n const instance: SpilkiWidgetInstance = {\n transport: null,\n open() {\n state.open();\n hooks.onOpen();\n },\n close() {\n state.close();\n hooks.onClose();\n },\n destroy() {\n unsubscribe();\n transport.stop();\n bubble.destroy();\n panel.destroy();\n }\n };\n\n return instance;\n}\n\n/* ✅ RESTORED — UNCHANGED */\nexport function autoInit(): void {\n if (typeof document === \"undefined\") return;\n const script = document.currentScript as HTMLScriptElement | null;\n if (!script) return;\n const dataset = script.dataset;\n if (dataset.autoinit === \"false\") return;\n const org = dataset.org;\n const assistant = dataset.assistant;\n if (!org || !assistant) {\n console.error(\"SpilkiWidget: data-org and data-assistant are required for auto init\");\n return;\n }\n initSpilkiWidget({\n org,\n assistant,\n installationToken: dataset.installationToken,\n apiBase: dataset.apiBase,\n position: (dataset.position as InitOptions[\"position\"]) ?? undefined,\n theme: (dataset.theme as InitOptions[\"theme\"]) ?? undefined\n });\n}\n\nif (typeof window !== \"undefined\") {\n const globalAny = window as any;\n globalAny.SpilkiWidget = globalAny.SpilkiWidget || {};\n globalAny.SpilkiWidget.init = (options: InitOptions) => initSpilkiWidget(options);\n}\n\nautoInit();\n\nexport type {InitOptions, Message} from \"./types\";\n"],"names":["TEMPLATE","createBubble","options","host","shadow","button","open","Panel","styles","event","keyboard","theme","messages","message","item","bubble","active","text","items","el","first","last","DEFAULT_API_BASE","DEFAULT_I18N","DEFAULT_OPTIONS","mergeOptions","_a","_b","_c","_d","_e","_f","_g","mergedI18n","createId","prefix","prefersDark","getTheme","clampMessages","limit","warnAllowedOrigins","hint","origin","RETRY_BASE","RETRY_MAX","TransportManager","handlers","connectUrl","currentSession","body","res","data","payload","url","connect","attempts","attempt","error","resolve","reject","ws","sse","opened","poll","failed","raw","HISTORY_LIMIT","WidgetState","org","assistant","listener","value","full","sessionId","token","parsed","decodePart","part","normalized","padded","c","buffer","parseJwt","parts","isExpired","now","DEFAULT_HOOKS","installAndGetAccessToken","apiBase","installationToken","refreshAccessToken","oldToken","initSpilkiWidget","rawOptions","hooks","state","accessToken","ensureAccessToken","panel","transport","kind","instance","stored","initialMessages","welcome","unsubscribe","snap","response","autoInit","script","dataset","globalAny"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"widget.es.js","sources":["../src/ui/bubble.ts","../src/ui/panel.ts","../src/core/utils.ts","../src/core/transport.ts","../src/core/state.ts","../src/core/jwt.ts","../src/index.ts"],"sourcesContent":["import type { PositionOption } from \"../types\";\n\nexport interface BubbleController {\n mount(): void;\n destroy(): void;\n setOpen(open: boolean): void;\n element: HTMLDivElement;\n}\n\ninterface BubbleOptions {\n color: string;\n position: PositionOption;\n onClick(): void;\n}\n\nconst TEMPLATE = `\n <style>\n :host {\n all: initial;\n position: fixed;\n z-index: 2147483000;\n }\n button {\n all: unset;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 56px;\n height: 56px;\n border-radius: 999px;\n cursor: pointer;\n background: var(--spilki-accent);\n color: #fff;\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);\n transition: transform 0.18s ease, box-shadow 0.18s ease;\n }\n button:focus-visible {\n outline: 2px solid #fff;\n outline-offset: 3px;\n }\n button:hover {\n transform: translateY(-1px);\n box-shadow: 0 12px 30px rgba(0, 0, 0, 0.25);\n }\n .icon {\n width: 28px;\n height: 28px;\n }\n .icon svg {\n width: 100%;\n height: 100%;\n }\n </style>\n <button type=\"button\" aria-label=\"Open chat\">\n <span class=\"icon\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 32 32\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M5 6a3 3 0 0 1 3-3h16a3 3 0 0 1 3 3v12a3 3 0 0 1-3 3H14l-5 6v-6H8a3 3 0 0 1-3-3V6Z\" fill=\"currentColor\"/>\n </svg>\n </span>\n </button>\n`;\n\nexport function createBubble(options: BubbleOptions): BubbleController {\n const host = document.createElement(\"div\");\n host.setAttribute(\"part\", \"bubble-root\");\n host.style.setProperty(\"--spilki-accent\", options.color);\n host.style.position = \"fixed\";\n host.style.bottom = \"24px\";\n host.style[options.position === \"bottom-right\" ? \"right\" : \"left\"] = \"24px\";\n\n const shadow = host.attachShadow({ mode: \"open\" });\n shadow.innerHTML = TEMPLATE;\n const button = shadow.querySelector(\"button\")!;\n button.addEventListener(\"click\", () => options.onClick());\n\n const controller: BubbleController = {\n element: host,\n mount() {\n document.body.appendChild(host);\n },\n destroy() {\n host.remove();\n },\n setOpen(open: boolean) {\n button.setAttribute(\"aria-expanded\", String(open));\n }\n };\n return controller;\n}\n","import type { Message, WidgetI18n } from \"../types\";\nimport styles from \"./styles.css?inline\";\n\ninterface PanelOptions {\n color: string;\n theme: \"light\" | \"dark\";\n position: \"bottom-right\" | \"bottom-left\";\n i18n: WidgetI18n;\n onClose(): void;\n onSend(text: string): void;\n}\n\nexport class Panel {\n private readonly host: HTMLDivElement;\n private readonly shadow: ShadowRoot;\n private readonly messagesEl: HTMLDivElement;\n private readonly typingEl: HTMLDivElement;\n private readonly input: HTMLTextAreaElement;\n private readonly offlineEl: HTMLDivElement;\n private readonly sendButton: HTMLButtonElement;\n private readonly focusable: HTMLElement[] = [];\n private open = false;\n\n constructor(private readonly options: PanelOptions) {\n this.host = document.createElement(\"div\");\n this.host.setAttribute(\"part\", \"panel-root\");\n this.host.style.position = \"fixed\";\n this.host.style.bottom = \"96px\";\n this.host.style[options.position === \"bottom-right\" ? \"right\" : \"left\"] = \"24px\";\n this.host.style.width = \"360px\";\n this.host.style.maxWidth = \"calc(100vw - 32px)\";\n this.host.style.height = \"520px\";\n this.host.style.display = \"none\";\n this.host.style.zIndex = \"2147483001\";\n\n this.shadow = this.host.attachShadow({ mode: \"open\" });\n this.shadow.innerHTML = `\n <style>${styles}</style>\n <div class=\"wrapper\" role=\"dialog\" aria-modal=\"true\" aria-label=\"${options.i18n.title}\">\n <header>\n <h1><span class=\"status-dot\" aria-hidden=\"true\"></span>${options.i18n.title}</h1>\n <button class=\"close\" type=\"button\" aria-label=\"Close\">×</button>\n </header>\n <div class=\"messages\" part=\"messages\"></div>\n <div class=\"typing\" hidden>${options.i18n.typing}</div>\n <div class=\"offline\" hidden>${options.i18n.offline}</div>\n <div class=\"input-area\">\n <textarea rows=\"2\" placeholder=\"${options.i18n.placeholder}\" aria-label=\"${options.i18n.placeholder}\"></textarea>\n <button type=\"button\">${options.i18n.sendLabel}</button>\n </div>\n </div>\n `;\n\n this.host.dataset.theme = options.theme;\n this.host.style.setProperty(\"--spilki-accent\", options.color);\n\n this.messagesEl = this.shadow.querySelector(\".messages\") as HTMLDivElement;\n this.typingEl = this.shadow.querySelector(\".typing\") as HTMLDivElement;\n this.input = this.shadow.querySelector(\"textarea\") as HTMLTextAreaElement;\n this.offlineEl = this.shadow.querySelector(\".offline\") as HTMLDivElement;\n this.sendButton = this.shadow.querySelector(\".input-area button\") as HTMLButtonElement;\n\n const closeButton = this.shadow.querySelector(\"header .close\") as HTMLButtonElement;\n closeButton.addEventListener(\"click\", () => this.options.onClose());\n this.sendButton.addEventListener(\"click\", () => this.send());\n\n this.input.addEventListener(\"keydown\", (event: KeyboardEvent) => {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n this.send();\n } else if (event.key === \"Escape\") {\n this.options.onClose();\n }\n });\n\n this.shadow.addEventListener(\"keydown\", (event) => {\n const keyboard = event as KeyboardEvent;\n if (keyboard.key === \"Escape\") {\n this.options.onClose();\n }\n if (keyboard.key === \"Tab\") {\n this.trapFocus(keyboard);\n }\n });\n\n this.shadow.addEventListener(\"focusin\", () => this.collectFocusable());\n this.collectFocusable();\n }\n\n mount(): void {\n document.body.appendChild(this.host);\n }\n\n destroy(): void {\n this.host.remove();\n }\n\n show(): void {\n if (this.open) return;\n this.open = true;\n this.host.style.display = \"block\";\n this.focusInput();\n }\n\n hide(): void {\n if (!this.open) return;\n this.open = false;\n this.host.style.display = \"none\";\n }\n\n focusInput(): void {\n queueMicrotask(() => {\n this.input.focus();\n });\n }\n\n updateTheme(theme: \"light\" | \"dark\"): void {\n this.host.dataset.theme = theme;\n }\n\n updateMessages(messages: Message[]): void {\n this.messagesEl.innerHTML = \"\";\n messages.forEach((message) => {\n const item = document.createElement(\"div\");\n item.className = `message ${message.author}`;\n item.setAttribute(\"data-author\", message.author);\n const bubble = document.createElement(\"div\");\n bubble.className = \"bubble\";\n bubble.textContent = message.text;\n item.appendChild(bubble);\n this.messagesEl.appendChild(item);\n });\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight;\n }\n\n appendMessage(message: Message): void {\n const item = document.createElement(\"div\");\n item.className = `message ${message.author}`;\n item.setAttribute(\"data-author\", message.author);\n const bubble = document.createElement(\"div\");\n bubble.className = \"bubble\";\n bubble.textContent = message.text;\n item.appendChild(bubble);\n this.messagesEl.appendChild(item);\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight;\n }\n\n setTyping(active: boolean): void {\n this.typingEl.toggleAttribute(\"hidden\", !active);\n }\n\n setOffline(active: boolean): void {\n this.offlineEl.toggleAttribute(\"hidden\", !active);\n }\n\n clearInput(): void {\n this.input.value = \"\";\n this.input.dispatchEvent(new Event(\"input\"));\n }\n\n private send(): void {\n const text = this.input.value.trim();\n if (!text) return;\n this.options.onSend(text);\n this.clearInput();\n }\n\n private collectFocusable(): void {\n const items = this.shadow.querySelectorAll<HTMLElement>(\n 'button, textarea, [href], [tabindex]:not([tabindex=\"-1\"])'\n );\n this.focusable.length = 0;\n items.forEach((el) => {\n if (!el.hasAttribute(\"disabled\")) {\n this.focusable.push(el);\n }\n });\n }\n\n private trapFocus(event: KeyboardEvent): void {\n if (this.focusable.length === 0) return;\n const first = this.focusable[0];\n const last = this.focusable[this.focusable.length - 1];\n const active = this.shadow.activeElement as HTMLElement;\n if (event.shiftKey && active === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && active === last) {\n event.preventDefault();\n first.focus();\n }\n }\n}\n","import type {InitOptions, WidgetI18n} from \"../types\";\n\nexport const DEFAULT_API_BASE = \"https://api.spilki.ai\";\nexport const SESSION_PREFIX = \"spilki-widget\";\n\nconst DEFAULT_I18N: WidgetI18n = {\n welcome: \"Hi! I'm your assistant.\",\n placeholder: \"Type a message…\",\n sendLabel: \"Send\",\n typing: \"Assistant is typing…\",\n offline: \"Unable to connect. Please try again later.\",\n title: \"Spilki Assistant\"\n};\n\nexport const DEFAULT_OPTIONS: Required<\n Pick<InitOptions, \"position\" | \"theme\" | \"color\" | \"welcome\" | \"persist\">\n> & { apiBase: string; i18n: WidgetI18n } = {\n apiBase: DEFAULT_API_BASE,\n position: \"bottom-right\",\n theme: \"auto\",\n color: \"#6366f1\",\n welcome: DEFAULT_I18N.welcome,\n persist: true,\n i18n: DEFAULT_I18N\n};\n\nexport type NormalizedOptions = InitOptions & {\n apiBase: string;\n position: InitOptions[\"position\"];\n theme: InitOptions[\"theme\"];\n color: string;\n welcome: string;\n persist: boolean;\n i18n: WidgetI18n;\n};\n\nexport function mergeOptions(options: InitOptions): NormalizedOptions {\n const mergedI18n = {...DEFAULT_I18N, ...(options.i18n ?? {})};\n return {\n ...DEFAULT_OPTIONS,\n ...options,\n apiBase: options.apiBase ?? DEFAULT_OPTIONS.apiBase,\n i18n: mergedI18n,\n welcome: options.welcome ?? mergedI18n.welcome,\n position: options.position ?? DEFAULT_OPTIONS.position,\n theme: options.theme ?? DEFAULT_OPTIONS.theme,\n color: options.color ?? DEFAULT_OPTIONS.color,\n persist: options.persist ?? DEFAULT_OPTIONS.persist\n } as NormalizedOptions;\n}\n\nexport function storageKey(org: string): string {\n return `${SESSION_PREFIX}:${org}`;\n}\n\nexport function getPersistedSession(\n org: string,\n): string | null {\n try {\n return localStorage.getItem(storageKey(org));\n } catch (error) {\n console.warn(\"SpilkiWidget: Unable to read localStorage\", error);\n return null;\n }\n}\n\nexport function persistSession(\n org: string,\n sessionId: string\n): void {\n try {\n localStorage.setItem(storageKey(org), sessionId);\n } catch (error) {\n console.warn(\"SpilkiWidget: Unable to persist session\", error);\n }\n}\n\nexport function clearSession(org: string): void {\n try {\n localStorage.removeItem(storageKey(org));\n } catch (error) {\n console.warn(\"SpilkiWidget: Unable to clear session\", error);\n }\n}\n\nexport function createId(prefix = \"msg\"): string {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `${prefix}-${Math.random().toString(16).slice(2)}`;\n}\n\nexport function prefersDark(): boolean {\n return window.matchMedia?.(\"(prefers-color-scheme: dark)\").matches ?? false;\n}\n\nexport function getTheme(theme: string | undefined): \"light\" | \"dark\" {\n if (theme === \"light\" || theme === \"dark\") return theme;\n return prefersDark() ? \"dark\" : \"light\";\n}\n\nexport function clampMessages<T>(messages: T[], limit = 30): T[] {\n return messages.slice(-limit);\n}\n\nexport function warnAllowedOrigins(hint: string[] | undefined): void {\n if (!hint || hint.length === 0) return;\n const origin = window.location.origin;\n if (!hint.includes(origin)) {\n console.warn(\n `SpilkiWidget: current origin ${origin} not in allowedOriginsHint: ${hint.join(\", \")}`\n );\n }\n}\n","import type {ConnectResponse, Message, SendPayload, TransportKind} from \"../types\";\nimport {clampMessages} from \"./utils\";\n\ninterface TransportHandlers {\n onOpen(kind: TransportKind): void;\n\n onMessage(message: Message): void;\n\n onTyping(typing: boolean): void;\n\n onError(error: Error): void;\n}\n\ninterface TransportOptions {\n apiBase: string;\n accessToken?: string;\n org: string;\n sessionId?: string | null;\n}\n\ntype IncomingPayload =\n | { type: \"message\"; payload: Message }\n | { type: \"typing\"; payload: { active: boolean } }\n | Message;\n\nconst RETRY_BASE = 1500;\nconst RETRY_MAX = 8000;\n\nexport class TransportManager {\n private sessionId: string | null = null;\n private currentKind: TransportKind | null = null;\n private ws?: WebSocket;\n private sse?: EventSource;\n private pollTimer?: number;\n private stopped = false;\n private backoff = RETRY_BASE;\n private readonly handlers: TransportHandlers;\n private readonly options: TransportOptions;\n\n constructor(options: TransportOptions, handlers: TransportHandlers) {\n this.options = options;\n this.handlers = handlers;\n }\n\n get kind(): TransportKind | null {\n return this.currentKind;\n }\n\n get activeSession(): string | null {\n return this.sessionId ?? this.options.sessionId ?? null;\n }\n\n async connect(): Promise<ConnectResponse> {\n this.stopped = false;\n const connectUrl = `${this.options.apiBase.replace(/\\/$/, \"\")}/widget/session`;\n const currentSession = this.sessionId ?? this.options.sessionId ?? undefined;\n const body = {\n organisationId: this.options.org,\n sessionId: currentSession,\n userAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : \"\",\n referrer: typeof document !== \"undefined\" ? document.referrer : \"\",\n origin: typeof window !== \"undefined\" ? window.location.origin : \"\"\n };\n\n const res = await fetch(connectUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(this.options.accessToken ? {Authorization: `Bearer ${this.options.accessToken}`} : {})\n },\n body: JSON.stringify(body)\n });\n\n if (!res.ok) {\n throw new Error(`SpilkiWidget: connect failed (${res.status})`);\n }\n\n const data = (await res.json()) as ConnectResponse;\n this.sessionId = data.sessionId;\n this.options.sessionId = data.sessionId;\n this.backoff = RETRY_BASE;\n await this.startTransport(data);\n return data;\n }\n\n async send(text: string): Promise<void> {\n const payload: SendPayload = {\n sessionId: this.sessionId ?? this.options.sessionId ?? \"\",\n text\n };\n\n if (!payload.sessionId) {\n throw new Error(\"SpilkiWidget: missing session id\");\n }\n\n if (this.currentKind === \"ws\" && this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify({type: \"message\", payload}));\n return;\n }\n\n const url = `${this.options.apiBase.replace(/\\/$/, \"\")}/widget/message`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(this.options.accessToken ? {Authorization: `Bearer ${this.options.accessToken}`} : {})\n },\n body: JSON.stringify(payload)\n });\n\n if (!res.ok) {\n throw new Error(`SpilkiWidget: send failed (${res.status})`);\n }\n }\n\n stop(): void {\n this.stopped = true;\n this.backoff = RETRY_BASE;\n if (this.ws) {\n this.ws.close();\n this.ws = undefined;\n }\n if (this.sse) {\n this.sse.close();\n this.sse = undefined;\n }\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = undefined;\n }\n this.currentKind = null;\n }\n\n private async startTransport(connect: ConnectResponse): Promise<void> {\n if (this.stopped) return;\n const attempts: Array<() => Promise<void>> = [];\n if (connect.wsUrl) attempts.push(() => this.startWs(connect.wsUrl!));\n if (connect.sseUrl) attempts.push(() => this.startSse(connect.sseUrl!));\n if (connect.pollUrl) attempts.push(() => this.startPoll(connect.pollUrl!));\n\n for (const attempt of attempts) {\n try {\n await attempt();\n return;\n } catch (error) {\n this.handlers.onError(error as Error);\n }\n }\n throw new Error(\"SpilkiWidget: unable to establish transport\");\n }\n\n private startWs(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const ws = new WebSocket(url);\n this.ws = ws;\n ws.addEventListener(\"open\", () => {\n if (this.stopped) {\n ws.close();\n return;\n }\n this.currentKind = \"ws\";\n this.handlers.onOpen(\"ws\");\n this.backoff = RETRY_BASE;\n resolve();\n });\n ws.addEventListener(\"message\", (event) => this.handleIncoming(event.data));\n ws.addEventListener(\"close\", () => {\n if (this.stopped) return;\n this.retryFallback(\"ws\");\n });\n ws.addEventListener(\"error\", () => {\n this.handlers.onError(new Error(\"SpilkiWidget: websocket error\"));\n if (ws.readyState !== WebSocket.OPEN) {\n reject(new Error(\"WebSocket failed\"));\n }\n });\n } catch (error) {\n reject(error as Error);\n }\n });\n }\n\n private startSse(url: string): Promise<void> {\n return new Promise((resolve, reject) => {\n if (typeof EventSource === \"undefined\") {\n reject(new Error(\"SSE not supported\"));\n return;\n }\n const sse = new EventSource(url);\n this.sse = sse;\n let opened = false;\n sse.addEventListener(\"open\", () => {\n opened = true;\n if (this.stopped) {\n sse.close();\n return;\n }\n this.currentKind = \"sse\";\n this.handlers.onOpen(\"sse\");\n this.backoff = RETRY_BASE;\n resolve();\n });\n sse.addEventListener(\"message\", (event) => this.handleIncoming(event.data));\n sse.addEventListener(\"error\", () => {\n if (!opened) {\n reject(new Error(\"SSE failed\"));\n return;\n }\n this.handlers.onError(new Error(\"SpilkiWidget: SSE error\"));\n if (this.stopped) return;\n this.retryFallback(\"sse\");\n });\n });\n }\n\n private async startPoll(url: string): Promise<void> {\n this.currentKind = \"poll\";\n this.handlers.onOpen(\"poll\");\n this.backoff = RETRY_BASE;\n const poll = async () => {\n if (this.stopped) return;\n try {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`Poll failed ${res.status}`);\n const messages = (await res.json()) as Message[];\n clampMessages(messages).forEach((message) => this.handlers.onMessage(message));\n this.backoff = RETRY_BASE;\n } catch (error) {\n this.handlers.onError(error as Error);\n this.backoff = Math.min(this.backoff * 1.5, RETRY_MAX);\n } finally {\n if (!this.stopped) {\n this.pollTimer = window.setTimeout(poll, this.backoff);\n }\n }\n };\n await poll();\n }\n\n private retryFallback(failed: TransportKind): void {\n if (this.stopped) return;\n this.stop();\n this.backoff = Math.min(this.backoff * 1.5, RETRY_MAX);\n setTimeout(() => {\n this.handlers.onError(new Error(`SpilkiWidget: retrying after ${failed}`));\n this.connect().catch((error) => this.handlers.onError(error));\n }, this.backoff);\n }\n\n private handleIncoming(raw: string): void {\n try {\n const data = JSON.parse(raw) as IncomingPayload;\n if (Array.isArray(data)) {\n data.forEach((item) => this.dispatchIncoming(item));\n return;\n }\n this.dispatchIncoming(data);\n } catch {\n const message: Message = {\n id: `${Date.now()}`,\n author: \"bot\",\n text: raw,\n ts: Date.now()\n };\n this.handlers.onMessage(message);\n }\n }\n\n private dispatchIncoming(data: IncomingPayload): void {\n if (\"type\" in data) {\n if (data.type === \"message\") {\n this.handlers.onMessage(data.payload);\n } else if (data.type === \"typing\") {\n this.handlers.onTyping(Boolean(data.payload?.active));\n }\n return;\n }\n this.handlers.onMessage(data as Message);\n }\n}\n","import {clampMessages, createId} from \"./utils\";\nimport type {Message} from \"../types\";\n\ntype Listener = () => void;\n\nexport interface WidgetStateSnapshot {\n isOpen: boolean;\n isTyping: boolean;\n isConnected: boolean;\n messages: Message[];\n}\n\nconst HISTORY_LIMIT = 30;\n\nexport class WidgetState {\n private listeners = new Set<Listener>();\n private historyKey: string;\n private sessionKey: string;\n private tokenKey: string;\n private readonly persist: boolean;\n private state: WidgetStateSnapshot = {\n isOpen: false,\n isTyping: false,\n isConnected: false,\n messages: []\n };\n\n constructor(\n private readonly org: string,\n options: { persist: boolean }\n ) {\n this.historyKey = `spilki-history:${org}`;\n this.sessionKey = `spilki-session:${org}`;\n this.tokenKey = `spilki-token:${org}`;\n this.persist = options.persist;\n this.state.messages = this.loadMessages();\n }\n\n get snapshot(): WidgetStateSnapshot {\n return {...this.state, messages: [...this.state.messages]};\n }\n\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n open(): void {\n if (!this.state.isOpen) {\n this.state.isOpen = true;\n this.emit();\n }\n }\n\n close(): void {\n if (this.state.isOpen) {\n this.state.isOpen = false;\n this.emit();\n }\n }\n\n setTyping(value: boolean): void {\n if (this.state.isTyping !== value) {\n this.state.isTyping = value;\n this.emit();\n }\n }\n\n setConnected(value: boolean): void {\n if (this.state.isConnected !== value) {\n this.state.isConnected = value;\n this.emit();\n }\n }\n\n addMessage(message: Omit<Message, \"id\" | \"ts\"> & Partial<Pick<Message, \"id\" | \"ts\">>): Message {\n const full: Message = {\n id: message.id ?? createId(\"msg\"),\n ts: message.ts ?? Date.now(),\n author: message.author,\n text: message.text\n };\n this.state.messages = clampMessages([...this.state.messages, full], HISTORY_LIMIT);\n this.persistMessages();\n this.emit();\n return full;\n }\n\n setMessages(messages: Message[]): void {\n this.state.messages = clampMessages(messages, HISTORY_LIMIT);\n this.persistMessages();\n this.emit();\n }\n\n clearMessages(): void {\n this.state.messages = [];\n this.persistMessages();\n this.emit();\n }\n\n get sessionId(): string | null {\n if (!this.persist) return null;\n try {\n return localStorage.getItem(this.sessionKey);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to get item\", error);\n return null;\n }\n }\n\n persistSession(sessionId: string): void {\n if (!this.persist) return;\n try {\n localStorage.setItem(this.sessionKey, sessionId);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to set item\", error);\n }\n }\n\n clearSession(): void {\n if (!this.persist) return;\n try {\n localStorage.removeItem(this.sessionKey);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to remove item\", error);\n }\n }\n\n get accessToken(): string | null {\n if (!this.persist) return null;\n try {\n return localStorage.getItem(this.tokenKey);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to get item\", error);\n return null;\n }\n }\n\n persistAccessToken(token: string): void {\n if (!this.persist) return;\n try {\n localStorage.setItem(this.tokenKey, token);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to set item\", error);\n }\n }\n\n clearAccessToken(): void {\n if (!this.persist) return;\n try {\n localStorage.removeItem(this.tokenKey);\n } catch (error) {\n console.error(\"SpilkiWidget: unable to remove item\", error);\n }\n }\n\n private emit(): void {\n this.listeners.forEach((listener) => listener());\n }\n\n private persistMessages(): void {\n if (!this.persist) return;\n try {\n localStorage.setItem(this.historyKey, JSON.stringify(this.state.messages));\n } catch (error) {\n console.error(\"SpilkiWidget: unable to set item\", error);\n }\n }\n\n private loadMessages(): Message[] {\n if (!this.persist) return [];\n try {\n const raw = localStorage.getItem(this.historyKey);\n if (!raw) return [];\n const parsed = JSON.parse(raw) as Message[];\n return Array.isArray(parsed) ? clampMessages(parsed, HISTORY_LIMIT) : [];\n } catch (error) {\n console.error(\"SpilkiWidget: unable to load messages\", error);\n return [];\n }\n }\n}\n","interface JwtPayload {\n exp?: number;\n\n [key: string]: unknown;\n}\n\nfunction decodePart(part: string): string {\n const normalized = part.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const padded = normalized.padEnd(normalized.length + ((4 - (normalized.length % 4)) % 4), \"=\");\n if (typeof atob === \"function\") {\n return decodeURIComponent(\n Array.prototype.map\n .call(atob(padded), (c: string) => `%${`00${c.charCodeAt(0).toString(16)}`.slice(-2)}`)\n .join(\"\")\n );\n }\n const buffer = (globalThis as {\n Buffer?: { from(input: string, encoding: string): { toString(enc: string): string } }\n }).Buffer;\n if (buffer) {\n return buffer.from(padded, \"base64\").toString(\"utf8\");\n }\n throw new Error(\"SpilkiWidget: no base64 decoder available\");\n}\n\nexport function parseJwt<T extends JwtPayload = JwtPayload>(token: string): T | null {\n if (!token) return null;\n const parts = token.split(\".\");\n if (parts.length < 2) return null;\n try {\n const payload = decodePart(parts[1]);\n return JSON.parse(payload) as T;\n } catch (error) {\n console.error(\"SpilkiWidget: unable to parse JWT\", error);\n return null;\n }\n}\n\nexport function isExpired(token: string): boolean {\n const payload = parseJwt(token);\n if (!payload?.exp) return false;\n const now = Math.floor(Date.now() / 1000);\n return payload.exp < now;\n}\n","import {createBubble} from \"./ui/bubble\";\nimport {Panel} from \"./ui/panel\";\nimport {TransportManager} from \"./core/transport\";\nimport {WidgetState} from \"./core/state\";\nimport type {NormalizedOptions} from \"./core/utils\";\nimport {getTheme, mergeOptions, warnAllowedOrigins} from \"./core/utils\";\nimport {isExpired} from \"./core/jwt\";\nimport type {InitOptions, Message, TransportKind, WidgetAccessTokenResponse, WidgetHooks} from \"./types\";\n\nexport interface SpilkiWidgetInstance {\n open(): void;\n\n close(): void;\n\n destroy(): void;\n\n transport?: TransportKind | null;\n}\n\nconst DEFAULT_HOOKS: WidgetHooks = {\n onOpen() {\n },\n onClose() {\n },\n onMessage() {\n },\n onError() {\n },\n onTransportChange() {\n }\n};\n\nasync function installAndGetAccessToken(apiBase: string, installationToken: string, organisationId: string): Promise<string> {\n const url = `${apiBase.replace(/\\/$/, \"\")}/widget/install`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\"Content-Type\": \"application/json\", Origin: window.location.origin},\n body: JSON.stringify({token: installationToken, organisationId: organisationId}),\n });\n if (!res.ok) throw new Error(`SpilkiWidget: install failed (${res.status})`);\n const data = (await res.json()) as WidgetAccessTokenResponse;\n return data.accessToken;\n}\n\nasync function refreshAccessToken(apiBase: string, oldToken: string): Promise<string> {\n const url = `${apiBase.replace(/\\/$/, \"\")}/widget/refresh`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: {Authorization: `Bearer ${oldToken}`, Origin: window.location.origin}\n });\n if (!res.ok) throw new Error(`SpilkiWidget: refresh failed (${res.status})`);\n const data = (await res.json()) as WidgetAccessTokenResponse;\n return data.accessToken;\n}\n\nexport function initSpilkiWidget(rawOptions: InitOptions): SpilkiWidgetInstance {\n if (!rawOptions.org) {\n throw new Error(\"SpilkiWidget: org is required\");\n }\n\n const options: NormalizedOptions = mergeOptions(rawOptions);\n warnAllowedOrigins(options.allowedOriginsHint);\n\n const hooks: WidgetHooks = {...DEFAULT_HOOKS, ...(options.hooks ?? {})};\n const state = new WidgetState(options.org, {persist: options.persist});\n\n let accessToken = state.accessToken ?? undefined;\n\n const ensureAccessToken = async () => {\n if (!accessToken) {\n if (!rawOptions.installationToken) throw new Error(\"SpilkiWidget: missing installationToken\");\n if (!rawOptions.org) throw new Error(\"SpilkiWidget: missing org\");\n accessToken = await installAndGetAccessToken(options.apiBase, rawOptions.installationToken, rawOptions.org);\n state.persistAccessToken(accessToken);\n return;\n }\n if (isExpired(accessToken)) {\n accessToken = await refreshAccessToken(options.apiBase, accessToken);\n state.persistAccessToken(accessToken);\n }\n };\n\n const bubble = createBubble({\n color: options.color!,\n position: options.position ?? \"bottom-right\",\n onClick: () => {\n const snap = state.snapshot;\n if (snap.isOpen) {\n state.close();\n hooks.onClose();\n } else {\n state.open();\n hooks.onOpen();\n }\n }\n });\n\n const panel = new Panel({\n color: options.color!,\n theme: getTheme(options.theme),\n position: options.position ?? \"bottom-right\",\n i18n: options.i18n,\n onClose: () => {\n state.close();\n hooks.onClose();\n },\n onSend: (text) => {\n const message = state.addMessage({author: \"user\", text});\n panel.appendMessage(message);\n ensureAccessToken()\n .then(() => transport.send(text))\n .catch((error) => {\n hooks.onError(error as Error);\n state.setConnected(false);\n panel.setOffline(true);\n });\n }\n });\n\n const transport = new TransportManager(\n {\n apiBase: options.apiBase,\n accessToken,\n org: options.org,\n sessionId: state.sessionId\n },\n {\n onOpen(kind) {\n instance.transport = kind;\n hooks.onTransportChange(kind);\n state.setConnected(true);\n panel.setOffline(false);\n },\n onMessage(message) {\n const stored = state.addMessage(message);\n panel.appendMessage(stored);\n hooks.onMessage(stored);\n },\n onTyping(active) {\n state.setTyping(active);\n },\n onError(error) {\n hooks.onError(error);\n state.setConnected(false);\n if (state.snapshot.isOpen) {\n panel.setOffline(true);\n }\n }\n }\n );\n\n bubble.mount();\n panel.mount();\n\n const initialMessages = state.snapshot.messages;\n if (initialMessages.length === 0 && options.welcome) {\n const welcome: Message = {\n id: \"welcome\",\n author: \"bot\",\n text: options.welcome,\n ts: Date.now()\n };\n state.addMessage(welcome);\n panel.appendMessage(welcome);\n } else {\n panel.updateMessages(initialMessages);\n }\n\n const unsubscribe = state.subscribe(() => {\n const snap = state.snapshot;\n bubble.setOpen(snap.isOpen);\n panel.setTyping(snap.isTyping);\n panel.setOffline(!snap.isConnected);\n panel.updateTheme(getTheme(options.theme));\n if (snap.isOpen) {\n panel.show();\n } else {\n panel.hide();\n }\n });\n\n ensureAccessToken()\n .then(() =>\n transport.connect().then((response) => {\n if (options.persist) {\n state.persistSession(response.sessionId);\n }\n state.setConnected(true);\n hooks.onTransportChange(transport.kind ?? \"ws\");\n })\n )\n .catch((error) => {\n hooks.onError(error);\n state.setConnected(false);\n panel.setOffline(true);\n });\n\n const instance: SpilkiWidgetInstance = {\n transport: null,\n open() {\n state.open();\n hooks.onOpen();\n },\n close() {\n state.close();\n hooks.onClose();\n },\n destroy() {\n unsubscribe();\n transport.stop();\n bubble.destroy();\n panel.destroy();\n }\n };\n\n return instance;\n}\n\n/* ✅ RESTORED — UNCHANGED */\nexport function autoInit(): void {\n if (typeof document === \"undefined\") return;\n const script = document.currentScript as HTMLScriptElement | null;\n if (!script) return;\n const dataset = script.dataset;\n if (dataset.autoinit === \"false\") return;\n const org = dataset.org;\n if (!org) {\n console.error(\"SpilkiWidget: data-org and is required for auto init\");\n return;\n }\n initSpilkiWidget({\n org,\n installationToken: dataset.installationToken,\n apiBase: dataset.apiBase,\n position: (dataset.position as InitOptions[\"position\"]) ?? undefined,\n theme: (dataset.theme as InitOptions[\"theme\"]) ?? undefined\n });\n}\n\nif (typeof window !== \"undefined\") {\n const globalAny = window as any;\n globalAny.SpilkiWidget = globalAny.SpilkiWidget || {};\n globalAny.SpilkiWidget.init = (options: InitOptions) => initSpilkiWidget(options);\n}\n\nautoInit();\n\nexport type {InitOptions, Message} from \"./types\";\n"],"names":["TEMPLATE","createBubble","options","host","shadow","button","open","Panel","styles","event","keyboard","theme","messages","message","item","bubble","active","text","items","el","first","last","DEFAULT_API_BASE","DEFAULT_I18N","DEFAULT_OPTIONS","mergeOptions","_a","_b","_c","_d","_e","_f","_g","mergedI18n","createId","prefix","prefersDark","getTheme","clampMessages","limit","warnAllowedOrigins","hint","origin","RETRY_BASE","RETRY_MAX","TransportManager","handlers","connectUrl","currentSession","body","res","data","payload","url","connect","attempts","attempt","error","resolve","reject","ws","sse","opened","poll","failed","raw","HISTORY_LIMIT","WidgetState","org","listener","value","full","sessionId","token","parsed","decodePart","part","normalized","padded","c","buffer","parseJwt","parts","isExpired","now","DEFAULT_HOOKS","installAndGetAccessToken","apiBase","installationToken","organisationId","refreshAccessToken","oldToken","initSpilkiWidget","rawOptions","hooks","state","accessToken","ensureAccessToken","panel","transport","kind","instance","stored","initialMessages","welcome","unsubscribe","snap","response","autoInit","script","dataset","globalAny"],"mappings":"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"}
|