@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/dist/widget.es.js CHANGED
@@ -58,13 +58,13 @@ function M(r) {
58
58
  destroy() {
59
59
  e.remove();
60
60
  },
61
- setOpen(o) {
62
- s.setAttribute("aria-expanded", String(o));
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 C = "https://api.spilki.ai", g = {
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: C,
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 W(r) {
169
- var t, s, i, o, l, a, h;
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: (o = r.position) != null ? o : p.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 S(r) {
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/connect`, t = (a = (l = this.sessionId) != null ? l : this.options.sessionId) != null ? a : void 0, s = {
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 o = await i.json();
236
- return this.sessionId = o.sessionId, this.options.sessionId = o.sessionId, this.backoff = d, await this.startTransport(o), o;
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 o, l;
238
+ var n, l;
240
239
  const t = {
241
- sessionId: (l = (o = this.sessionId) != null ? o : this.options.sessionId) != null ? 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", (o) => this.handleIncoming(o.data)), i.addEventListener("close", () => {
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 o = !1;
304
+ let n = !1;
306
305
  i.addEventListener("open", () => {
307
- if (o = !0, this.stopped) {
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 (!o) {
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((o) => this.handlers.onMessage(o)), this.backoff = d;
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, s) {
373
- this.org = e, this.assistant = t, this.listeners = /* @__PURE__ */ new Set(), this.state = {
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}:${t}`, this.sessionKey = `spilki-session:${e}:${t}`, this.tokenKey = `spilki-token:${e}:${t}`, this.persist = s.persist, this.state.messages = this.loadMessages();
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 t = `${r.replace(/\/$/, "")}/widget/install`, s = await fetch(t, {
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 (!s.ok) throw new Error(`SpilkiWidget: install failed (${s.status})`);
532
- return (await s.json()).accessToken;
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, x;
544
- if (!r.org || !r.assistant)
545
- throw new Error("SpilkiWidget: org and assistant are required");
546
- const e = W(r);
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, e.assistant, { persist: e.persist });
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 o = async () => {
549
+ const n = async () => {
551
550
  if (!i) {
552
551
  if (!r.installationToken) throw new Error("SpilkiWidget: missing installationToken");
553
- i = await H(e.apiBase, r.installationToken), s.persistAccessToken(i);
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: S(e.theme),
566
- position: (x = e.position) != null ? x : "bottom-right",
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: (n) => {
572
- const c = s.addMessage({ author: "user", text: n });
573
- a.appendMessage(c), o().then(() => h.send(n)).catch((I) => {
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(n) {
587
- m.transport = n, t.onTransportChange(n), s.setConnected(!0), a.setOffline(!1);
585
+ onOpen(o) {
586
+ m.transport = o, t.onTransportChange(o), s.setConnected(!0), a.setOffline(!1);
588
587
  },
589
- onMessage(n) {
590
- const c = s.addMessage(n);
588
+ onMessage(o) {
589
+ const c = s.addMessage(o);
591
590
  a.appendMessage(c), t.onMessage(c);
592
591
  },
593
- onTyping(n) {
594
- s.setTyping(n);
592
+ onTyping(o) {
593
+ s.setTyping(o);
595
594
  },
596
- onError(n) {
597
- t.onError(n), s.setConnected(!1), s.snapshot.isOpen && a.setOffline(!0);
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 n = {
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(n), a.appendMessage(n);
609
+ s.addMessage(o), a.appendMessage(o);
611
610
  } else
612
611
  a.updateMessages(b);
613
612
  const T = s.subscribe(() => {
614
- const n = s.snapshot;
615
- l.setOpen(n.isOpen), a.setTyping(n.isTyping), a.setOffline(!n.isConnected), a.updateTheme(S(e.theme)), n.isOpen ? a.show() : a.hide();
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
- o().then(
618
- () => h.connect().then((n) => {
616
+ n().then(
617
+ () => h.connect().then((o) => {
619
618
  var c;
620
- e.persist && s.persistSession(n.sessionId), s.setConnected(!0), t.onTransportChange((c = h.kind) != null ? c : "ws");
619
+ e.persist && s.persistSession(o.sessionId), s.setConnected(!0), t.onTransportChange((c = h.kind) != null ? c : "ws");
621
620
  })
622
- ).catch((n) => {
623
- t.onError(n), s.setConnected(!1), a.setOffline(!0);
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 i, o;
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, s = e.assistant;
647
- if (!t || !s) {
648
- console.error("SpilkiWidget: data-org and data-assistant are required for auto init");
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: (i = e.position) != null ? i : void 0,
657
- theme: (o = e.theme) != null ? o : void 0
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") {
@@ -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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"}