@spilki/widget 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,8 @@
3
3
  [![npm version](https://img.shields.io/npm/v/%40spilki/widget.svg)](https://www.npmjs.com/package/@spilki/widget)
4
4
  [![bundle size](https://img.shields.io/badge/gzip%20%3C=35kB-success)](#size-budget)
5
5
 
6
- Embeddable chat widget that connects your website visitors with the Spilki assistant backend via a secure Web Widget channel.
6
+ Embeddable chat widget that connects your website visitors with the Spilki assistant backend via a secure Web Widget
7
+ channel.
7
8
 
8
9
  ## Features
9
10
 
@@ -24,40 +25,38 @@ npm install @spilki/widget
24
25
  ### CDN (UMD)
25
26
 
26
27
  ```html
28
+
27
29
  <script src="https://cdn.jsdelivr.net/npm/@spilki/widget/dist/widget.umd.js"
28
30
  data-org="ori-bar"
29
- data-assistant="main-bot"
30
31
  data-token="<your-jwt>"></script>
31
32
  ```
32
33
 
33
34
  ### ESM
34
35
 
35
36
  ```ts
36
- import { initSpilkiWidget } from "@spilki/widget";
37
+ import {initSpilkiWidget} from "@spilki/widget";
37
38
 
38
39
  initSpilkiWidget({
39
- org: "ori-bar",
40
- assistant: "main-bot",
41
- token: "<your-jwt>"
40
+ org: "ori-bar",
41
+ token: "<your-jwt>"
42
42
  });
43
43
  ```
44
44
 
45
45
  ## Options
46
46
 
47
- | Option | Type | Default | Description |
48
- | --- | --- | --- | --- |
49
- | `org` | `string` | – | Spilki organisation identifier. |
50
- | `assistant` | `string` | – | Assistant identifier. |
51
- | `token` | `string?` | | Signed JWT obtained from the admin UI or backend. |
52
- | `apiBase` | `string?` | `https://api.spilki.ai` | Override API endpoint (useful for staging/local). |
53
- | `position` | `"bottom-right" \| "bottom-left"` | `"bottom-right"` | Corner to anchor the bubble + panel. |
54
- | `theme` | `"auto" \| "light" \| "dark"` | `"auto"` | Force light/dark or respect OS preference. |
55
- | `color` | `string?` | `#6366f1` | Accent color for bubble + primary CTA. |
56
- | `welcome` | `string?` | "Hi! I'm your assistant." | Greeting shown when no conversation exists. |
57
- | `persist` | `boolean?` | `true` | Persist session + history in localStorage. |
58
- | `allowedOriginsHint` | `string[]?` | – | List of origins expected to be in JWT allowlist. Logs warnings during misconfiguration. |
59
- | `i18n` | `Partial<WidgetI18n>?` | – | Override UI strings (welcome, placeholder, sendLabel, typing, offline, title). |
60
- | `hooks` | `Partial<WidgetHooks>?` | – | Telemetry callbacks for open/close/message/error/transport change. |
47
+ | Option | Type | Default | Description |
48
+ |----------------------|-----------------------------------|---------------------------|-----------------------------------------------------------------------------------------|
49
+ | `org` | `string` | – | Spilki organisation identifier. |
50
+ | `token` | `string?` | – | Signed JWT obtained from the admin UI or backend. |
51
+ | `apiBase` | `string?` | `https://api.spilki.ai` | Override API endpoint (useful for staging/local). |
52
+ | `position` | `"bottom-right" \| "bottom-left"` | `"bottom-right"` | Corner to anchor the bubble + panel. |
53
+ | `theme` | `"auto" \| "light" \| "dark"` | `"auto"` | Force light/dark or respect OS preference. |
54
+ | `color` | `string?` | `#6366f1` | Accent color for bubble + primary CTA. |
55
+ | `welcome` | `string?` | "Hi! I'm your assistant." | Greeting shown when no conversation exists. |
56
+ | `persist` | `boolean?` | `true` | Persist session + history in localStorage. |
57
+ | `allowedOriginsHint` | `string[]?` | | List of origins expected to be in JWT allowlist. Logs warnings during misconfiguration. |
58
+ | `i18n` | `Partial<WidgetI18n>?` | – | Override UI strings (welcome, placeholder, sendLabel, typing, offline, title). |
59
+ | `hooks` | `Partial<WidgetHooks>?` | – | Telemetry callbacks for open/close/message/error/transport change. |
61
60
 
62
61
  ## Security
63
62
 
@@ -66,13 +65,16 @@ The widget never stores credentials. Provide a short-lived JWT (HS256) issued se
66
65
  ```json
67
66
  {
68
67
  "organisation_id": "ori-bar",
69
- "assistant_id": "main-bot",
70
- "allowed_origins": ["https://yourdomain.com"],
68
+ "allowed_origins": [
69
+ "https://yourdomain.com"
70
+ ],
71
71
  "exp": 1760000000
72
72
  }
73
73
  ```
74
74
 
75
- During `POST /widget/connect` the widget sends `Origin` and the JWT for verification. Expired tokens are rejected client-side before any network call. Rotate tokens frequently and limit the allowed origins array to trusted domains only.
75
+ During `POST /widget/session` the widget sends `Origin` and the JWT for verification. Expired tokens are rejected
76
+ client-side before any network call. Rotate tokens frequently and limit the allowed origins array to trusted domains
77
+ only.
76
78
 
77
79
  See [`apps/mock-server/openapi.yaml`](../apps/mock-server/openapi.yaml) for the full handshake specification.
78
80
 
@@ -92,8 +94,10 @@ pnpm install
92
94
  pnpm -w dev # runs mock server + demo site
93
95
  ```
94
96
 
95
- Open [http://localhost:5174](http://localhost:5174) and use **Issue token** to obtain a development JWT. Messages are relayed via websocket by default; stop the websocket server to see SSE fallback.
97
+ Open [http://localhost:5174](http://localhost:5174) and use **Issue token** to obtain a development JWT. Messages are
98
+ relayed via websocket by default; stop the websocket server to see SSE fallback.
96
99
 
97
100
  ## Publishing
98
101
 
99
- The GitHub Actions workflow publishes on tags that match `v*`. Ensure `NPM_TOKEN` is configured in the repository secrets before tagging `v0.1.1` or later.
102
+ The GitHub Actions workflow publishes on tags that match `v*`. Ensure `NPM_TOKEN` is configured in the repository
103
+ secrets before tagging `v0.1.3` or later.
@@ -1,4 +1,4 @@
1
- const M = `
1
+ const A = `
2
2
  <style>
3
3
  :host {
4
4
  all: initial;
@@ -44,11 +44,11 @@ const M = `
44
44
  </span>
45
45
  </button>
46
46
  `;
47
- function A(r) {
47
+ function M(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 = M;
51
+ t.innerHTML = A;
52
52
  const s = t.querySelector("button");
53
53
  return s.addEventListener("click", () => r.onClick()), {
54
54
  element: e,
@@ -58,16 +58,16 @@ function A(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 $ = ':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 C {
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>${$}</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,7 +149,7 @@ class C {
149
149
  e.shiftKey && i === t ? (e.preventDefault(), s.focus()) : !e.shiftKey && i === s && (e.preventDefault(), t.focus());
150
150
  }
151
151
  }
152
- const W = "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",
@@ -157,7 +157,7 @@ const W = "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: W,
160
+ apiBase: $,
161
161
  position: "bottom-right",
162
162
  theme: "auto",
163
163
  color: "#6366f1",
@@ -166,7 +166,7 @@ const W = "https://api.spilki.ai", g = {
166
166
  i18n: g
167
167
  };
168
168
  function B(r) {
169
- var t, s, i, o, l, a, h;
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 B(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
@@ -205,6 +205,9 @@ 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
  }
208
+ setAccessToken(e) {
209
+ this.options.accessToken = e;
210
+ }
208
211
  get kind() {
209
212
  return this.currentKind;
210
213
  }
@@ -215,9 +218,8 @@ class U {
215
218
  async connect() {
216
219
  var l, a;
217
220
  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 = {
221
+ const e = `${this.options.apiBase.replace(/\/$/, "")}/widget/session`, t = (a = (l = this.sessionId) != null ? l : this.options.sessionId) != null ? a : void 0, s = {
219
222
  organisationId: this.options.org,
220
- assistantId: this.options.assistant,
221
223
  sessionId: t,
222
224
  userAgent: typeof navigator != "undefined" ? navigator.userAgent : "",
223
225
  referrer: typeof document != "undefined" ? document.referrer : "",
@@ -232,13 +234,13 @@ class U {
232
234
  });
233
235
  if (!i.ok)
234
236
  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;
237
+ const n = await i.json();
238
+ return this.sessionId = n.sessionId, this.options.sessionId = n.sessionId, this.backoff = d, await this.startTransport(n), n;
237
239
  }
238
240
  async send(e) {
239
- var o, l;
241
+ var n, l;
240
242
  const t = {
241
- sessionId: (l = (o = this.sessionId) != null ? o : this.options.sessionId) != null ? l : "",
243
+ sessionId: (l = (n = this.sessionId) != null ? n : this.options.sessionId) != null ? l : "",
242
244
  text: e
243
245
  };
244
246
  if (!t.sessionId)
@@ -284,7 +286,7 @@ class U {
284
286
  return;
285
287
  }
286
288
  this.currentKind = "ws", this.handlers.onOpen("ws"), this.backoff = d, t();
287
- }), i.addEventListener("message", (o) => this.handleIncoming(o.data)), i.addEventListener("close", () => {
289
+ }), i.addEventListener("message", (n) => this.handleIncoming(n.data)), i.addEventListener("close", () => {
288
290
  this.stopped || this.retryFallback("ws");
289
291
  }), i.addEventListener("error", () => {
290
292
  this.handlers.onError(new Error("SpilkiWidget: websocket error")), i.readyState !== WebSocket.OPEN && s(new Error("WebSocket failed"));
@@ -302,15 +304,15 @@ class U {
302
304
  }
303
305
  const i = new EventSource(e);
304
306
  this.sse = i;
305
- let o = !1;
307
+ let n = !1;
306
308
  i.addEventListener("open", () => {
307
- if (o = !0, this.stopped) {
309
+ if (n = !0, this.stopped) {
308
310
  i.close();
309
311
  return;
310
312
  }
311
313
  this.currentKind = "sse", this.handlers.onOpen("sse"), this.backoff = d, t();
312
314
  }), i.addEventListener("message", (l) => this.handleIncoming(l.data)), i.addEventListener("error", () => {
313
- if (!o) {
315
+ if (!n) {
314
316
  s(new Error("SSE failed"));
315
317
  return;
316
318
  }
@@ -326,7 +328,7 @@ class U {
326
328
  const s = await fetch(e);
327
329
  if (!s.ok) throw new Error(`Poll failed ${s.status}`);
328
330
  const i = await s.json();
329
- u(i).forEach((o) => this.handlers.onMessage(o)), this.backoff = d;
331
+ u(i).forEach((n) => this.handlers.onMessage(n)), this.backoff = d;
330
332
  } catch (s) {
331
333
  this.handlers.onError(s), this.backoff = Math.min(this.backoff * 1.5, v);
332
334
  } finally {
@@ -369,13 +371,13 @@ class U {
369
371
  }
370
372
  const f = 30;
371
373
  class N {
372
- constructor(e, t, s) {
373
- this.org = e, this.assistant = t, this.listeners = /* @__PURE__ */ new Set(), this.state = {
374
+ constructor(e, t) {
375
+ this.org = e, this.listeners = /* @__PURE__ */ new Set(), this.state = {
374
376
  isOpen: !1,
375
377
  isTyping: !1,
376
378
  isConnected: !1,
377
379
  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();
380
+ }, 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
381
  }
380
382
  get snapshot() {
381
383
  return { ...this.state, messages: [...this.state.messages] };
@@ -522,14 +524,14 @@ const H = {
522
524
  onTransportChange() {
523
525
  }
524
526
  };
525
- async function q(r, e) {
526
- const t = `${r.replace(/\/$/, "")}/widget/install`, s = await fetch(t, {
527
+ async function q(r, e, t) {
528
+ const s = `${r.replace(/\/$/, "")}/widget/install`, i = await fetch(s, {
527
529
  method: "POST",
528
530
  headers: { "Content-Type": "application/json", Origin: window.location.origin },
529
- body: JSON.stringify({ token: e })
531
+ body: JSON.stringify({ token: e, organisationId: t })
530
532
  });
531
- if (!s.ok) throw new Error(`SpilkiWidget: install failed (${s.status})`);
532
- return (await s.json()).accessToken;
533
+ if (!i.ok) throw new Error(`SpilkiWidget: install failed (${i.status})`);
534
+ return (await i.json()).accessToken;
533
535
  }
534
536
  async function J(r, e) {
535
537
  const t = `${r.replace(/\/$/, "")}/widget/refresh`, s = await fetch(t, {
@@ -541,26 +543,27 @@ async function J(r, e) {
541
543
  }
542
544
  function E(r) {
543
545
  var k, w, y, S;
544
- if (!r.org || !r.assistant)
545
- throw new Error("SpilkiWidget: org and assistant are required");
546
+ if (!r.org)
547
+ throw new Error("SpilkiWidget: org is required");
546
548
  const e = B(r);
547
549
  P(e.allowedOriginsHint);
548
- const t = { ...H, ...(k = e.hooks) != null ? k : {} }, s = new N(e.org, e.assistant, { persist: e.persist });
550
+ const t = { ...H, ...(k = e.hooks) != null ? k : {} }, s = new N(e.org, { persist: e.persist });
549
551
  let i = (w = s.accessToken) != null ? w : void 0;
550
- const o = async () => {
552
+ const n = async () => {
551
553
  if (!i) {
552
554
  if (!r.installationToken) throw new Error("SpilkiWidget: missing installationToken");
553
- i = await q(e.apiBase, r.installationToken), s.persistAccessToken(i);
555
+ if (!r.org) throw new Error("SpilkiWidget: missing org");
556
+ i = await q(e.apiBase, r.installationToken, r.org), s.persistAccessToken(i), h.setAccessToken(i);
554
557
  return;
555
558
  }
556
- z(i) && (i = await J(e.apiBase, i), s.persistAccessToken(i));
557
- }, l = A({
559
+ z(i) && (i = await J(e.apiBase, i), s.persistAccessToken(i), h.setAccessToken(i));
560
+ }, l = M({
558
561
  color: e.color,
559
562
  position: (y = e.position) != null ? y : "bottom-right",
560
563
  onClick: () => {
561
564
  s.snapshot.isOpen ? (s.close(), t.onClose()) : (s.open(), t.onOpen());
562
565
  }
563
- }), a = new C({
566
+ }), a = new W({
564
567
  color: e.color,
565
568
  theme: x(e.theme),
566
569
  position: (S = e.position) != null ? S : "bottom-right",
@@ -568,9 +571,9 @@ function E(r) {
568
571
  onClose: () => {
569
572
  s.close(), t.onClose();
570
573
  },
571
- onSend: (n) => {
572
- const c = s.addMessage({ author: "user", text: n });
573
- a.appendMessage(c), o().then(() => h.send(n)).catch((O) => {
574
+ onSend: (o) => {
575
+ const c = s.addMessage({ author: "user", text: o });
576
+ a.appendMessage(c), n().then(() => h.send(o)).catch((O) => {
574
577
  t.onError(O), s.setConnected(!1), a.setOffline(!0);
575
578
  });
576
579
  }
@@ -579,48 +582,47 @@ function E(r) {
579
582
  apiBase: e.apiBase,
580
583
  accessToken: i,
581
584
  org: e.org,
582
- assistant: e.assistant,
583
585
  sessionId: s.sessionId
584
586
  },
585
587
  {
586
- onOpen(n) {
587
- m.transport = n, t.onTransportChange(n), s.setConnected(!0), a.setOffline(!1);
588
+ onOpen(o) {
589
+ m.transport = o, t.onTransportChange(o), s.setConnected(!0), a.setOffline(!1);
588
590
  },
589
- onMessage(n) {
590
- const c = s.addMessage(n);
591
+ onMessage(o) {
592
+ const c = s.addMessage(o);
591
593
  a.appendMessage(c), t.onMessage(c);
592
594
  },
593
- onTyping(n) {
594
- s.setTyping(n);
595
+ onTyping(o) {
596
+ s.setTyping(o);
595
597
  },
596
- onError(n) {
597
- t.onError(n), s.setConnected(!1), s.snapshot.isOpen && a.setOffline(!0);
598
+ onError(o) {
599
+ t.onError(o), s.setConnected(!1), s.snapshot.isOpen && a.setOffline(!0);
598
600
  }
599
601
  }
600
602
  );
601
603
  l.mount(), a.mount();
602
604
  const b = s.snapshot.messages;
603
605
  if (b.length === 0 && e.welcome) {
604
- const n = {
606
+ const o = {
605
607
  id: "welcome",
606
608
  author: "bot",
607
609
  text: e.welcome,
608
610
  ts: Date.now()
609
611
  };
610
- s.addMessage(n), a.appendMessage(n);
612
+ s.addMessage(o), a.appendMessage(o);
611
613
  } else
612
614
  a.updateMessages(b);
613
615
  const I = s.subscribe(() => {
614
- const n = s.snapshot;
615
- l.setOpen(n.isOpen), a.setTyping(n.isTyping), a.setOffline(!n.isConnected), a.updateTheme(x(e.theme)), n.isOpen ? a.show() : a.hide();
616
+ const o = s.snapshot;
617
+ l.setOpen(o.isOpen), a.setTyping(o.isTyping), a.setOffline(!o.isConnected), a.updateTheme(x(e.theme)), o.isOpen ? a.show() : a.hide();
616
618
  });
617
- o().then(
618
- () => h.connect().then((n) => {
619
+ n().then(
620
+ () => h.connect().then((o) => {
619
621
  var c;
620
- e.persist && s.persistSession(n.sessionId), s.setConnected(!0), t.onTransportChange((c = h.kind) != null ? c : "ws");
622
+ e.persist && s.persistSession(o.sessionId), s.setConnected(!0), t.onTransportChange((c = h.kind) != null ? c : "ws");
621
623
  })
622
- ).catch((n) => {
623
- t.onError(n), s.setConnected(!1), a.setOffline(!0);
624
+ ).catch((o) => {
625
+ t.onError(o), s.setConnected(!1), a.setOffline(!0);
624
626
  });
625
627
  const m = {
626
628
  transport: null,
@@ -637,24 +639,23 @@ function E(r) {
637
639
  return m;
638
640
  }
639
641
  function T() {
640
- var i, o;
642
+ var s, i;
641
643
  if (typeof document == "undefined") return;
642
644
  const r = document.currentScript;
643
645
  if (!r) return;
644
646
  const e = r.dataset;
645
647
  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");
648
+ const t = e.org;
649
+ if (!t) {
650
+ console.error("SpilkiWidget: data-org and is required for auto init");
649
651
  return;
650
652
  }
651
653
  E({
652
654
  org: t,
653
- assistant: s,
654
655
  installationToken: e.installationToken,
655
656
  apiBase: e.apiBase,
656
- position: (i = e.position) != null ? i : void 0,
657
- theme: (o = e.theme) != null ? o : void 0
657
+ position: (s = e.position) != null ? s : void 0,
658
+ theme: (i = e.theme) != null ? i : void 0
658
659
  });
659
660
  }
660
661
  if (typeof window != "undefined") {