@spilki/widget 0.1.0 → 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.
@@ -1,4 +1,4 @@
1
- const I = `
1
+ const M = `
2
2
  <style>
3
3
  :host {
4
4
  all: initial;
@@ -44,11 +44,11 @@ const I = `
44
44
  </span>
45
45
  </button>
46
46
  `;
47
- function T(r) {
47
+ function A(r) {
48
48
  const e = document.createElement("div");
49
49
  e.setAttribute("part", "bubble-root"), e.style.setProperty("--spilki-accent", r.color), e.style.position = "fixed", e.style.bottom = "24px", e.style[r.position === "bottom-right" ? "right" : "left"] = "24px";
50
50
  const t = e.attachShadow({ mode: "open" });
51
- t.innerHTML = I;
51
+ t.innerHTML = M;
52
52
  const s = t.querySelector("button");
53
53
  return s.addEventListener("click", () => r.onClick()), {
54
54
  element: e,
@@ -58,16 +58,16 @@ function T(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
- const O = ':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 M {
66
+ const C = ':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 W {
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
- <style>${O}</style>
70
+ <style>${C}</style>
71
71
  <div class="wrapper" role="dialog" aria-modal="true" aria-label="${e.i18n.title}">
72
72
  <header>
73
73
  <h1><span class="status-dot" aria-hidden="true"></span>${e.i18n.title}</h1>
@@ -149,15 +149,15 @@ class M {
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 $ = "https://api.spilki.ai", g = {
153
153
  welcome: "Hi! I'm your assistant.",
154
154
  placeholder: "Type a message…",
155
155
  sendLabel: "Send",
156
156
  typing: "Assistant is typing…",
157
157
  offline: "Unable to connect. Please try again later.",
158
158
  title: "Spilki Assistant"
159
- }, c = {
160
- apiBase: C,
159
+ }, p = {
160
+ apiBase: $,
161
161
  position: "bottom-right",
162
162
  theme: "auto",
163
163
  color: "#6366f1",
@@ -165,43 +165,43 @@ const C = "https://api.spilki.ai", g = {
165
165
  persist: !0,
166
166
  i18n: g
167
167
  };
168
- function A(r) {
169
- var t, s, i, o, a, l, p;
168
+ function B(r) {
169
+ var t, s, i, n, l, a, h;
170
170
  const e = { ...g, ...(t = r.i18n) != null ? t : {} };
171
171
  return {
172
- ...c,
172
+ ...p,
173
173
  ...r,
174
- apiBase: (s = r.apiBase) != null ? s : c.apiBase,
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 : c.position,
178
- theme: (a = r.theme) != null ? a : c.theme,
179
- color: (l = r.color) != null ? l : c.color,
180
- persist: (p = r.persist) != null ? p : c.persist
177
+ position: (n = r.position) != null ? n : p.position,
178
+ theme: (l = r.theme) != null ? l : p.theme,
179
+ color: (a = r.color) != null ? a : p.color,
180
+ persist: (h = r.persist) != null ? h : p.persist
181
181
  };
182
182
  }
183
- function $(r = "msg") {
183
+ function L(r = "msg") {
184
184
  return typeof crypto != "undefined" && crypto.randomUUID ? crypto.randomUUID() : `${r}-${Math.random().toString(16).slice(2)}`;
185
185
  }
186
- function W() {
186
+ function K() {
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 y(r) {
191
- return r === "light" || r === "dark" ? r : W() ? "dark" : "light";
190
+ function x(r) {
191
+ return r === "light" || r === "dark" ? r : K() ? "dark" : "light";
192
192
  }
193
193
  function u(r, e = 30) {
194
194
  return r.slice(-e);
195
195
  }
196
- function L(r) {
196
+ function P(r) {
197
197
  if (!r || r.length === 0) return;
198
198
  const e = window.location.origin;
199
199
  r.includes(e) || console.warn(
200
200
  `SpilkiWidget: current origin ${e} not in allowedOriginsHint: ${r.join(", ")}`
201
201
  );
202
202
  }
203
- const d = 1500, x = 8e3;
204
- class B {
203
+ const d = 1500, v = 8e3;
204
+ class U {
205
205
  constructor(e, t) {
206
206
  this.sessionId = null, this.currentKind = null, this.stopped = !1, this.backoff = d, this.options = e, this.handlers = t;
207
207
  }
@@ -213,11 +213,10 @@ class B {
213
213
  return (t = (e = this.sessionId) != null ? e : this.options.sessionId) != null ? t : null;
214
214
  }
215
215
  async connect() {
216
- var a, l;
216
+ var l, a;
217
217
  this.stopped = !1;
218
- const e = `${this.options.apiBase.replace(/\/$/, "")}/widget/connect`, t = (l = (a = this.sessionId) != null ? a : this.options.sessionId) != null ? l : 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 : "",
@@ -226,19 +225,19 @@ class B {
226
225
  method: "POST",
227
226
  headers: {
228
227
  "Content-Type": "application/json",
229
- ...this.options.token ? { Authorization: `Bearer ${this.options.token}` } : {}
228
+ ...this.options.accessToken ? { Authorization: `Bearer ${this.options.accessToken}` } : {}
230
229
  },
231
230
  body: JSON.stringify(s)
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, a;
238
+ var n, l;
240
239
  const t = {
241
- sessionId: (a = (o = this.sessionId) != null ? o : this.options.sessionId) != null ? a : "",
240
+ sessionId: (l = (n = this.sessionId) != null ? n : this.options.sessionId) != null ? l : "",
242
241
  text: e
243
242
  };
244
243
  if (!t.sessionId)
@@ -251,7 +250,7 @@ class B {
251
250
  method: "POST",
252
251
  headers: {
253
252
  "Content-Type": "application/json",
254
- ...this.options.token ? { Authorization: `Bearer ${this.options.token}` } : {}
253
+ ...this.options.accessToken ? { Authorization: `Bearer ${this.options.accessToken}` } : {}
255
254
  },
256
255
  body: JSON.stringify(t)
257
256
  });
@@ -284,7 +283,7 @@ class B {
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 B {
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
- }), i.addEventListener("message", (a) => this.handleIncoming(a.data)), i.addEventListener("error", () => {
313
- if (!o) {
311
+ }), i.addEventListener("message", (l) => this.handleIncoming(l.data)), i.addEventListener("error", () => {
312
+ if (!n) {
314
313
  s(new Error("SSE failed"));
315
314
  return;
316
315
  }
@@ -326,9 +325,9 @@ class B {
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
- this.handlers.onError(s), this.backoff = Math.min(this.backoff * 1.5, x);
330
+ this.handlers.onError(s), this.backoff = Math.min(this.backoff * 1.5, v);
332
331
  } finally {
333
332
  this.stopped || (this.pollTimer = window.setTimeout(t, this.backoff));
334
333
  }
@@ -336,7 +335,7 @@ class B {
336
335
  await t();
337
336
  }
338
337
  retryFallback(e) {
339
- this.stopped || (this.stop(), this.backoff = Math.min(this.backoff * 1.5, x), setTimeout(() => {
338
+ this.stopped || (this.stop(), this.backoff = Math.min(this.backoff * 1.5, v), setTimeout(() => {
340
339
  this.handlers.onError(new Error(`SpilkiWidget: retrying after ${e}`)), this.connect().catch((t) => this.handlers.onError(t));
341
340
  }, this.backoff));
342
341
  }
@@ -368,14 +367,14 @@ class B {
368
367
  }
369
368
  }
370
369
  const f = 30;
371
- class U {
372
- constructor(e, t, s) {
373
- this.org = e, this.assistant = t, this.listeners = /* @__PURE__ */ new Set(), this.state = {
370
+ class N {
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.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] };
@@ -398,7 +397,7 @@ class U {
398
397
  addMessage(e) {
399
398
  var s, i;
400
399
  const t = {
401
- id: (s = e.id) != null ? s : $("msg"),
400
+ id: (s = e.id) != null ? s : L("msg"),
402
401
  ts: (i = e.ts) != null ? i : Date.now(),
403
402
  author: e.author,
404
403
  text: e.text
@@ -415,8 +414,8 @@ class U {
415
414
  if (!this.persist) return null;
416
415
  try {
417
416
  return localStorage.getItem(this.sessionKey);
418
- } catch {
419
- return null;
417
+ } catch (e) {
418
+ return console.error("SpilkiWidget: unable to get item", e), null;
420
419
  }
421
420
  }
422
421
  persistSession(e) {
@@ -424,7 +423,7 @@ class U {
424
423
  try {
425
424
  localStorage.setItem(this.sessionKey, e);
426
425
  } catch (t) {
427
- console.warn("SpilkiWidget: Unable to persist session", t);
426
+ console.error("SpilkiWidget: unable to set item", t);
428
427
  }
429
428
  }
430
429
  clearSession() {
@@ -432,7 +431,31 @@ class U {
432
431
  try {
433
432
  localStorage.removeItem(this.sessionKey);
434
433
  } catch (e) {
435
- console.warn("SpilkiWidget: Unable to clear session", e);
434
+ console.error("SpilkiWidget: unable to remove item", e);
435
+ }
436
+ }
437
+ get accessToken() {
438
+ if (!this.persist) return null;
439
+ try {
440
+ return localStorage.getItem(this.tokenKey);
441
+ } catch (e) {
442
+ return console.error("SpilkiWidget: unable to get item", e), null;
443
+ }
444
+ }
445
+ persistAccessToken(e) {
446
+ if (this.persist)
447
+ try {
448
+ localStorage.setItem(this.tokenKey, e);
449
+ } catch (t) {
450
+ console.error("SpilkiWidget: unable to set item", t);
451
+ }
452
+ }
453
+ clearAccessToken() {
454
+ if (this.persist)
455
+ try {
456
+ localStorage.removeItem(this.tokenKey);
457
+ } catch (e) {
458
+ console.error("SpilkiWidget: unable to remove item", e);
436
459
  }
437
460
  }
438
461
  emit() {
@@ -443,7 +466,7 @@ class U {
443
466
  try {
444
467
  localStorage.setItem(this.historyKey, JSON.stringify(this.state.messages));
445
468
  } catch (e) {
446
- console.warn("SpilkiWidget: Unable to persist messages", e);
469
+ console.error("SpilkiWidget: unable to set item", e);
447
470
  }
448
471
  }
449
472
  loadMessages() {
@@ -453,12 +476,12 @@ class U {
453
476
  if (!e) return [];
454
477
  const t = JSON.parse(e);
455
478
  return Array.isArray(t) ? u(t, f) : [];
456
- } catch {
457
- return [];
479
+ } catch (e) {
480
+ return console.error("SpilkiWidget: unable to load messages", e), [];
458
481
  }
459
482
  }
460
483
  }
461
- function K(r) {
484
+ function D(r) {
462
485
  const e = r.replace(/-/g, "+").replace(/_/g, "/"), t = e.padEnd(e.length + (4 - e.length % 4) % 4, "=");
463
486
  if (typeof atob == "function")
464
487
  return decodeURIComponent(
@@ -469,24 +492,24 @@ function K(r) {
469
492
  return s.from(t, "base64").toString("utf8");
470
493
  throw new Error("SpilkiWidget: no base64 decoder available");
471
494
  }
472
- function P(r) {
495
+ function F(r) {
473
496
  if (!r) return null;
474
497
  const e = r.split(".");
475
498
  if (e.length < 2) return null;
476
499
  try {
477
- const t = K(e[1]);
500
+ const t = D(e[1]);
478
501
  return JSON.parse(t);
479
502
  } catch (t) {
480
503
  return console.error("SpilkiWidget: unable to parse JWT", t), null;
481
504
  }
482
505
  }
483
- function D(r) {
484
- const e = P(r);
506
+ function z(r) {
507
+ const e = F(r);
485
508
  if (!(e != null && e.exp)) return !1;
486
509
  const t = Math.floor(Date.now() / 1e3);
487
510
  return e.exp < t;
488
511
  }
489
- const N = {
512
+ const H = {
490
513
  onOpen() {
491
514
  },
492
515
  onClose() {
@@ -498,81 +521,107 @@ const N = {
498
521
  onTransportChange() {
499
522
  }
500
523
  };
501
- function v(r) {
502
- var m, k, w;
503
- if (!r.org || !r.assistant)
504
- throw new Error("SpilkiWidget: org and assistant are required");
505
- const e = A(r);
506
- if (e.token && D(e.token))
507
- throw new Error("SpilkiWidget: JWT token has expired");
508
- L(e.allowedOriginsHint);
509
- const t = { ...N, ...(m = e.hooks) != null ? m : {} }, s = new U(e.org, e.assistant, { persist: e.persist }), i = T({
524
+ async function q(r, e, t) {
525
+ const s = `${r.replace(/\/$/, "")}/widget/install`, i = await fetch(s, {
526
+ method: "POST",
527
+ headers: { "Content-Type": "application/json", Origin: window.location.origin },
528
+ body: JSON.stringify({ token: e, organisationId: t })
529
+ });
530
+ if (!i.ok) throw new Error(`SpilkiWidget: install failed (${i.status})`);
531
+ return (await i.json()).accessToken;
532
+ }
533
+ async function J(r, e) {
534
+ const t = `${r.replace(/\/$/, "")}/widget/refresh`, s = await fetch(t, {
535
+ method: "POST",
536
+ headers: { Authorization: `Bearer ${e}`, Origin: window.location.origin }
537
+ });
538
+ if (!s.ok) throw new Error(`SpilkiWidget: refresh failed (${s.status})`);
539
+ return (await s.json()).accessToken;
540
+ }
541
+ function E(r) {
542
+ var k, w, y, S;
543
+ if (!r.org)
544
+ throw new Error("SpilkiWidget: org is required");
545
+ const e = B(r);
546
+ P(e.allowedOriginsHint);
547
+ const t = { ...H, ...(k = e.hooks) != null ? k : {} }, s = new N(e.org, { persist: e.persist });
548
+ let i = (w = s.accessToken) != null ? w : void 0;
549
+ const n = async () => {
550
+ if (!i) {
551
+ if (!r.installationToken) throw new Error("SpilkiWidget: missing installationToken");
552
+ if (!r.org) throw new Error("SpilkiWidget: missing org");
553
+ i = await q(e.apiBase, r.installationToken, r.org), s.persistAccessToken(i);
554
+ return;
555
+ }
556
+ z(i) && (i = await J(e.apiBase, i), s.persistAccessToken(i));
557
+ }, l = A({
510
558
  color: e.color,
511
- position: (k = e.position) != null ? k : "bottom-right",
559
+ position: (y = e.position) != null ? y : "bottom-right",
512
560
  onClick: () => {
513
561
  s.snapshot.isOpen ? (s.close(), t.onClose()) : (s.open(), t.onOpen());
514
562
  }
515
- }), o = new M({
563
+ }), a = new W({
516
564
  color: e.color,
517
- theme: y(e.theme),
518
- position: (w = e.position) != null ? w : "bottom-right",
565
+ theme: x(e.theme),
566
+ position: (S = e.position) != null ? S : "bottom-right",
519
567
  i18n: e.i18n,
520
568
  onClose: () => {
521
569
  s.close(), t.onClose();
522
570
  },
523
- onSend: (n) => {
524
- const h = s.addMessage({ author: "user", text: n });
525
- o.appendMessage(h), a.send(n).catch((S) => {
526
- t.onError(S), s.setConnected(!1), o.setOffline(!0);
571
+ onSend: (o) => {
572
+ const c = s.addMessage({ author: "user", text: o });
573
+ a.appendMessage(c), n().then(() => h.send(o)).catch((O) => {
574
+ t.onError(O), s.setConnected(!1), a.setOffline(!0);
527
575
  });
528
576
  }
529
- }), a = new B(
577
+ }), h = new U(
530
578
  {
531
579
  apiBase: e.apiBase,
532
- token: e.token,
580
+ accessToken: i,
533
581
  org: e.org,
534
- assistant: e.assistant,
535
582
  sessionId: s.sessionId
536
583
  },
537
584
  {
538
- onOpen(n) {
539
- b.transport = n, t.onTransportChange(n), s.setConnected(!0), o.setOffline(!1);
585
+ onOpen(o) {
586
+ m.transport = o, t.onTransportChange(o), s.setConnected(!0), a.setOffline(!1);
540
587
  },
541
- onMessage(n) {
542
- const h = s.addMessage(n);
543
- o.appendMessage(h), t.onMessage(h);
588
+ onMessage(o) {
589
+ const c = s.addMessage(o);
590
+ a.appendMessage(c), t.onMessage(c);
544
591
  },
545
- onTyping(n) {
546
- s.setTyping(n);
592
+ onTyping(o) {
593
+ s.setTyping(o);
547
594
  },
548
- onError(n) {
549
- t.onError(n), s.setConnected(!1), s.snapshot.isOpen && o.setOffline(!0);
595
+ onError(o) {
596
+ t.onError(o), s.setConnected(!1), s.snapshot.isOpen && a.setOffline(!0);
550
597
  }
551
598
  }
552
599
  );
553
- i.mount(), o.mount();
554
- const l = s.snapshot.messages;
555
- if (l.length === 0 && e.welcome) {
556
- const n = {
600
+ l.mount(), a.mount();
601
+ const b = s.snapshot.messages;
602
+ if (b.length === 0 && e.welcome) {
603
+ const o = {
557
604
  id: "welcome",
558
605
  author: "bot",
559
606
  text: e.welcome,
560
607
  ts: Date.now()
561
608
  };
562
- s.addMessage(n), o.appendMessage(n);
609
+ s.addMessage(o), a.appendMessage(o);
563
610
  } else
564
- o.updateMessages(l);
565
- const p = s.subscribe(() => {
566
- const n = s.snapshot;
567
- i.setOpen(n.isOpen), o.setTyping(n.isTyping), o.setOffline(!n.isConnected), o.updateTheme(y(e.theme)), n.isOpen ? o.show() : o.hide();
611
+ a.updateMessages(b);
612
+ const I = s.subscribe(() => {
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();
568
615
  });
569
- a.connect().then((n) => {
570
- var h;
571
- e.persist && s.persistSession(n.sessionId), s.setConnected(!0), t.onTransportChange((h = a.kind) != null ? h : "ws");
572
- }).catch((n) => {
573
- t.onError(n), s.setConnected(!1), o.setOffline(!0);
616
+ n().then(
617
+ () => h.connect().then((o) => {
618
+ var c;
619
+ e.persist && s.persistSession(o.sessionId), s.setConnected(!0), t.onTransportChange((c = h.kind) != null ? c : "ws");
620
+ })
621
+ ).catch((o) => {
622
+ t.onError(o), s.setConnected(!1), a.setOffline(!0);
574
623
  });
575
- const b = {
624
+ const m = {
576
625
  transport: null,
577
626
  open() {
578
627
  s.open(), t.onOpen();
@@ -581,36 +630,35 @@ function v(r) {
581
630
  s.close(), t.onClose();
582
631
  },
583
632
  destroy() {
584
- p(), a.stop(), i.destroy(), o.destroy();
633
+ I(), h.stop(), l.destroy(), a.destroy();
585
634
  }
586
635
  };
587
- return b;
636
+ return m;
588
637
  }
589
- function E() {
590
- var i, o;
638
+ function T() {
639
+ var s, i;
591
640
  if (typeof document == "undefined") return;
592
641
  const r = document.currentScript;
593
642
  if (!r) return;
594
643
  const e = r.dataset;
595
644
  if (e.autoinit === "false") return;
596
- const t = e.org, s = e.assistant;
597
- if (!t || !s) {
598
- 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");
599
648
  return;
600
649
  }
601
- v({
650
+ E({
602
651
  org: t,
603
- assistant: s,
604
- token: e.token,
652
+ installationToken: e.installationToken,
605
653
  apiBase: e.apiBase,
606
- position: (i = e.position) != null ? i : void 0,
607
- 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
608
656
  });
609
657
  }
610
658
  if (typeof window != "undefined") {
611
659
  const r = window;
612
- r.SpilkiWidget = r.SpilkiWidget || {}, r.SpilkiWidget.init = (e) => v(e);
660
+ r.SpilkiWidget = r.SpilkiWidget || {}, r.SpilkiWidget.init = (e) => E(e);
613
661
  }
614
- E();
615
- E();
662
+ T();
663
+ T();
616
664
  //# sourceMappingURL=bootstrap.es.js.map