@locdo.tech/botiq-chat-sdk 0.3.3 → 0.4.0

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/sdk/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as e } from "./npm-DfSKhYCq.js";
1
+ import { t as e } from "./npm-DV43YS-n.js";
2
2
  export { e as init };
@@ -1,30 +1,31 @@
1
1
  //#region src/core/config.ts
2
2
  var e = "https://bot-q-backend.vercel.app", t = {
3
- name: "BotIQ",
4
- design: {
5
- colors: {
6
- primary: "#F97316",
7
- header: "#F97316",
8
- userBubble: "#F97316",
9
- botBubble: "#1A1A1A",
10
- background: "#000000",
11
- text: "#FFFFFF"
12
- },
13
- layout: {
14
- position: "bottom-right",
15
- buttonShape: "circle",
16
- width: 360,
17
- height: 520
18
- },
19
- content: {
20
- greeting: "",
21
- suggestionChips: [],
22
- placeholder: ""
23
- },
24
- font: "inter"
3
+ colors: {
4
+ primary: "#F97316",
5
+ header: "#F97316",
6
+ userBubble: "#F97316",
7
+ botBubble: "#1A1A1A",
8
+ background: "#000000",
9
+ text: "#FFFFFF",
10
+ inputBackground: "#1A1A1A"
11
+ },
12
+ layout: {
13
+ position: "bottom-right",
14
+ buttonShape: "circle",
15
+ width: 360,
16
+ height: 520
17
+ },
18
+ content: {
19
+ greeting: "",
20
+ suggestionChips: [],
21
+ placeholder: ""
25
22
  },
23
+ font: "inter"
24
+ }, n = {
25
+ name: "BotIQ",
26
+ design: t,
26
27
  widgetLanguage: "vi"
27
- }, n = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/, r = new Set(["bottom-right", "bottom-left"]), i = new Set(["circle", "square"]), a = new Set([
28
+ }, r = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/, i = new Set(["bottom-right", "bottom-left"]), a = new Set(["circle", "square"]), o = new Set([
28
29
  "inter",
29
30
  "plus-jakarta",
30
31
  "poppins",
@@ -33,56 +34,74 @@ var e = "https://bot-q-backend.vercel.app", t = {
33
34
  "raleway",
34
35
  "lato",
35
36
  "playfair"
36
- ]), o = new Set([
37
+ ]), s = new Set([
37
38
  "none",
38
39
  "fade",
39
40
  "slide-up",
40
41
  "bounce"
41
- ]), s = new Set([
42
+ ]), c = new Set([
42
43
  "dots-bounce",
43
44
  "dots-pulse",
44
45
  "bar"
45
46
  ]);
46
- function c(e) {
47
+ function l(e) {
47
48
  let t = e.colors;
48
- if (![
49
+ if (t.inputBackground ||= "#1A1A1A", ![
49
50
  t.primary,
50
51
  t.header,
51
52
  t.userBubble,
52
53
  t.botBubble,
53
54
  t.background,
54
- t.text
55
- ].every((e) => typeof e == "string" && n.test(e)) || !r.has(e.layout.position) || !i.has(e.layout.buttonShape) || !a.has(e.font)) return !1;
56
- let { width: c, height: l } = e.layout;
57
- if (!Number.isFinite(c) || c < 280 || c > 800 || !Number.isFinite(l) || l < 200 || l > 900) return !1;
55
+ t.text,
56
+ t.inputBackground
57
+ ].every((e) => typeof e == "string" && r.test(e)) || !i.has(e.layout.position) || !a.has(e.layout.buttonShape) || !o.has(e.font)) return !1;
58
+ let { width: n, height: l } = e.layout;
59
+ if (!Number.isFinite(n) || n < 280 || n > 800 || !Number.isFinite(l) || l < 200 || l > 900) return !1;
58
60
  if (e.gradient) {
59
61
  let t = e.gradient;
60
- if (t.type !== "linear" && t.type !== "radial" || !n.test(t.from) || !n.test(t.to) || t.angle !== void 0 && (!Number.isFinite(t.angle) || t.angle < 0 || t.angle > 360)) return !1;
62
+ if (t.type !== "linear" && t.type !== "radial" || !r.test(t.from) || !r.test(t.to) || t.angle !== void 0 && (!Number.isFinite(t.angle) || t.angle < 0 || t.angle > 360)) return !1;
61
63
  }
62
- return !(e.animation && (!o.has(e.animation.bubbleOpen) || !s.has(e.animation.typingIndicator)) || e.customCSS !== void 0 && (typeof e.customCSS != "string" || e.customCSS.length > 8e3));
64
+ return !(e.animation && (!s.has(e.animation.bubbleOpen) || !c.has(e.animation.typingIndicator)) || e.customCSS !== void 0 && (typeof e.customCSS != "string" || e.customCSS.length > 8e3));
65
+ }
66
+ var u = 8e3;
67
+ function d(e, t) {
68
+ return fetch(`${t}/widget/meta`, {
69
+ headers: { "X-Api-Key": e },
70
+ referrerPolicy: "no-referrer-when-downgrade",
71
+ signal: AbortSignal.timeout(u)
72
+ });
63
73
  }
64
- async function l(e, n) {
74
+ async function f(e, r) {
75
+ let i;
65
76
  try {
66
- let r = await fetch(`${n}/widget/meta`, {
67
- headers: { "X-Api-Key": e },
68
- referrerPolicy: "no-referrer-when-downgrade",
69
- signal: AbortSignal.timeout(5e3)
70
- });
71
- if (r.status === 401 || r.status === 403) return null;
72
- if (!r.ok) return t;
73
- let i = await r.json();
74
- if (!i?.design?.colors || !i?.design?.layout || !i?.design?.content || !c(i.design)) return t;
75
- let a = typeof i.name == "string" && i.name.length > 0 ? i.name : "BotIQ", o = i.widgetLanguage === "en" ? "en" : "vi";
76
- return {
77
- name: a,
78
- design: i.design,
79
- widgetLanguage: o
80
- };
77
+ i = await d(e, r);
81
78
  } catch {
82
- return t;
79
+ try {
80
+ i = await d(e, r);
81
+ } catch {
82
+ return n;
83
+ }
83
84
  }
85
+ if (i.status === 401 || i.status === 403) return null;
86
+ if (!i.ok) return n;
87
+ let a;
88
+ try {
89
+ a = await i.json();
90
+ } catch {
91
+ return n;
92
+ }
93
+ let o = typeof a.name == "string" && a.name.length > 0 ? a.name : n.name, s = a.widgetLanguage === "en" ? "en" : "vi";
94
+ return !a.design?.colors || !a.design?.layout || !a.design?.content || !l(a.design) ? {
95
+ name: o,
96
+ design: t,
97
+ widgetLanguage: s
98
+ } : {
99
+ name: o,
100
+ design: a.design,
101
+ widgetLanguage: s
102
+ };
84
103
  }
85
- function u(t) {
104
+ function p(t) {
86
105
  return {
87
106
  apiKey: t.apiKey,
88
107
  apiUrl: e
@@ -90,32 +109,38 @@ function u(t) {
90
109
  }
91
110
  //#endregion
92
111
  //#region src/core/session.ts
93
- var d = "botiq:sessionId", f = "botiq:history:", p = 10;
94
- function m() {
112
+ var m = "botiq:sessionId", h = "botiq:sessionId:", g = "botiq:history:", _ = 10;
113
+ function v() {
114
+ try {
115
+ let e = localStorage.getItem(m);
116
+ localStorage.removeItem(m), e && localStorage.removeItem(g + e);
117
+ } catch {}
118
+ }
119
+ function y(e) {
95
120
  try {
96
- let e = localStorage.getItem(d);
97
- return e || (e = crypto.randomUUID(), localStorage.setItem(d, e)), e;
121
+ let t = h + e, n = localStorage.getItem(t);
122
+ return n || (n = crypto.randomUUID(), localStorage.setItem(t, n)), n;
98
123
  } catch {
99
124
  return crypto.randomUUID();
100
125
  }
101
126
  }
102
- function h(e) {
127
+ function b(e, t) {
103
128
  try {
104
- let t = localStorage.getItem(f + e);
105
- return t ? JSON.parse(t) : [];
129
+ let n = localStorage.getItem(`${g}${e}:${t}`);
130
+ return n ? JSON.parse(n) : [];
106
131
  } catch {
107
132
  return [];
108
133
  }
109
134
  }
110
- function g(e, t) {
135
+ function x(e, t, n) {
111
136
  try {
112
- let n = [...h(e), ...t].slice(-p);
113
- localStorage.setItem(f + e, JSON.stringify(n));
137
+ let r = [...b(e, t), ...n].slice(-_);
138
+ localStorage.setItem(`${g}${e}:${t}`, JSON.stringify(r));
114
139
  } catch {}
115
140
  }
116
141
  //#endregion
117
142
  //#region src/core/api.ts
118
- async function _(e, t, n, r, i, a) {
143
+ async function S(e, t, n, r, i, a) {
119
144
  try {
120
145
  let o = await fetch(`${e}/widget/chat`, {
121
146
  method: "POST",
@@ -135,30 +160,68 @@ async function _(e, t, n, r, i, a) {
135
160
  return a.errorMessage;
136
161
  }
137
162
  }
163
+ var C = {
164
+ messages: [],
165
+ hasMore: !1
166
+ };
167
+ function w(e) {
168
+ if (!e || typeof e != "object") return !1;
169
+ let t = e;
170
+ return typeof t.id == "string" && (t.role === "user" || t.role === "assistant") && typeof t.content == "string";
171
+ }
172
+ async function T(e, t, n, r, i) {
173
+ try {
174
+ let a = new URLSearchParams({
175
+ sessionId: n,
176
+ limit: String(i)
177
+ });
178
+ r && a.set("before", r);
179
+ let o = await fetch(`${e}/widget/messages?${a.toString()}`, {
180
+ method: "GET",
181
+ headers: { "X-Api-Key": t },
182
+ referrerPolicy: "no-referrer-when-downgrade"
183
+ });
184
+ if (!o.ok) return C;
185
+ let s = await o.json();
186
+ return {
187
+ messages: Array.isArray(s.messages) ? s.messages.filter(w) : [],
188
+ hasMore: s.hasMore === !0
189
+ };
190
+ } catch {
191
+ return C;
192
+ }
193
+ }
194
+ function ee(e, t, n, r) {
195
+ return T(e, t, n, void 0, r);
196
+ }
197
+ function te(e, t, n, r, i) {
198
+ return T(e, t, n, r, i);
199
+ }
138
200
  //#endregion
139
201
  //#region src/core/state.ts
140
- var v = {
202
+ var E = {
141
203
  messages: [],
142
204
  isLoading: !1,
143
- isOpen: !1
144
- }, y = /* @__PURE__ */ new Set();
145
- function b() {
146
- return v;
147
- }
148
- function x(e) {
149
- Object.assign(v, e);
205
+ isOpen: !1,
206
+ loadingOlder: !1
207
+ }, D = /* @__PURE__ */ new Set();
208
+ function O() {
209
+ return E;
210
+ }
211
+ function k(e) {
212
+ Object.assign(E, e);
150
213
  let t = {
151
- ...v,
152
- messages: [...v.messages]
214
+ ...E,
215
+ messages: [...E.messages]
153
216
  };
154
- y.forEach((e) => e(t));
217
+ D.forEach((e) => e(t));
155
218
  }
156
- function S(e) {
157
- return y.add(e), () => y.delete(e);
219
+ function A(e) {
220
+ return D.add(e), () => D.delete(e);
158
221
  }
159
222
  //#endregion
160
223
  //#region src/core/styles.ts
161
- var C = {
224
+ var j = {
162
225
  inter: {
163
226
  url: "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap",
164
227
  family: "'Inter', system-ui, -apple-system, sans-serif"
@@ -167,45 +230,33 @@ var C = {
167
230
  url: "https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600&display=swap",
168
231
  family: "'Plus Jakarta Sans', system-ui, -apple-system, sans-serif"
169
232
  },
170
- poppins: {
171
- url: "https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap",
172
- family: "'Poppins', system-ui, -apple-system, sans-serif"
173
- },
174
233
  nunito: {
175
234
  url: "https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600&display=swap",
176
235
  family: "'Nunito', system-ui, -apple-system, sans-serif"
177
236
  },
178
- "dm-sans": {
179
- url: "https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600&display=swap",
180
- family: "'DM Sans', system-ui, -apple-system, sans-serif"
181
- },
182
237
  raleway: {
183
238
  url: "https://fonts.googleapis.com/css2?family=Raleway:wght@400;500;600&display=swap",
184
239
  family: "'Raleway', system-ui, -apple-system, sans-serif"
185
240
  },
186
- lato: {
187
- url: "https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap",
188
- family: "'Lato', system-ui, -apple-system, sans-serif"
189
- },
190
241
  playfair: {
191
242
  url: "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600&display=swap",
192
243
  family: "'Playfair Display', Georgia, serif"
193
244
  }
194
245
  };
195
- function w(e, t) {
246
+ function M(e, t) {
196
247
  if (!t) return e;
197
248
  let n = t.angle ?? 135;
198
249
  return t.type === "linear" ? `linear-gradient(${n}deg, ${t.from}, ${t.to})` : `radial-gradient(circle, ${t.from}, ${t.to})`;
199
250
  }
200
- function T(e) {
251
+ function ne(e) {
201
252
  return e.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\\[0-9a-fA-F]{1,6}\s?/g, "x").replace(/@import\b[^;]*;?/gi, "").replace(/url\s*\(\s*["']?\s*(?!data:)[^)]*["']?\s*\)/gi, "url(\"\")").replace(/expression\s*\(/gi, "expression_(").replace(/javascript\s*:/gi, "blocked:").replace(/-moz-binding\s*:/gi, "").replace(/\bbehavior\s*:/gi, "");
202
253
  }
203
- function E(e) {
254
+ function N(e) {
204
255
  let t = e?.bubbleOpen ?? "none", n = e?.typingIndicator ?? "dots-bounce";
205
256
  return [t === "fade" ? "@keyframes biq-open-fade { from { opacity: 0; } to { opacity: 1; } }\n.chat-window.open { animation: biq-open-fade .22s ease forwards; }" : t === "slide-up" ? "@keyframes biq-open-slide { from { opacity: 0; transform: scale(1) translateY(20px); } to { opacity: 1; transform: scale(1) translateY(0); } }\n.chat-window.open { animation: biq-open-slide .25s cubic-bezier(.22,1,.36,1) forwards; }" : t === "bounce" ? "@keyframes biq-open-bounce { 0% { opacity: 0; transform: scale(.85) translateY(8px); } 60% { transform: scale(1.03) translateY(-3px); } 100% { opacity: 1; transform: scale(1) translateY(0); } }\n.chat-window.open { animation: biq-open-bounce .35s cubic-bezier(.34,1.56,.64,1) forwards; }" : "", n === "dots-pulse" ? "@keyframes biq-pulse { 0%, 100% { opacity: 0.3; transform: scale(1); } 50% { opacity: 1; transform: scale(1.3); } }\n.typing span { animation: biq-pulse 1.2s infinite ease-in-out; }" : n === "bar" ? ".typing { gap: 3px; align-items: flex-end; }\n.typing span { width: 3px; height: 14px; border-radius: 2px; animation: biq-bar 1s infinite ease-in-out; }\n.typing span:nth-child(1) { animation-delay: 0s; }\n.typing span:nth-child(2) { animation-delay: .15s; height: 20px; }\n.typing span:nth-child(3) { animation-delay: .3s; }\n@keyframes biq-bar { 0%, 100% { transform: scaleY(.4); opacity: .5; } 50% { transform: scaleY(1); opacity: 1; } }" : ""].filter(Boolean).join("\n");
206
257
  }
207
- function D(e) {
208
- let { colors: t, layout: n, font: r, gradient: i, animation: a, customCSS: o, whiteLabel: s } = e, c = C[r] ?? C.inter, l = n.buttonShape === "square" ? "14px" : "50%", u = n.position === "bottom-left" ? "right: auto; left: 24px;" : "right: 24px;", d = n.position === "bottom-left" ? "bottom left" : "bottom right", f = n.position === "bottom-left" ? "right: auto; left: 0;" : "right: 0;", p = w(t.primary, i), m = w(t.header, i), h = w(t.userBubble, i), g = s ? ".botiq-badge { display: none !important; }" : "";
258
+ function P(e) {
259
+ let { colors: t, layout: n, font: r, gradient: i, animation: a, customCSS: o, whiteLabel: s } = e, c = j[r] ?? j.inter, l = n.buttonShape === "square" ? "14px" : "50%", u = n.position === "bottom-left" ? "right: auto; left: 24px;" : "right: 24px;", d = n.position === "bottom-left" ? "bottom left" : "bottom right", f = n.position === "bottom-left" ? "right: auto; left: 0;" : "right: 0;", p = M(t.primary, i), m = M(t.header, i), h = M(t.userBubble, i), g = s ? ".botiq-badge { display: none !important; }" : "";
209
260
  return `
210
261
  @import url('${c.url}');
211
262
 
@@ -222,6 +273,7 @@ function D(e) {
222
273
  --color-bot: ${t.botBubble};
223
274
  --color-bg: ${t.background};
224
275
  --color-text: ${t.text};
276
+ --color-input-bg: ${t.inputBackground};
225
277
  --gray-50: #1A1A1A;
226
278
  --gray-100: #222222;
227
279
  --gray-200: #2D2D2D;
@@ -381,6 +433,37 @@ function D(e) {
381
433
  background: rgba(255,255,255,.1);
382
434
  white-space: pre-wrap;
383
435
  }
436
+ .message-bubble del { text-decoration: line-through; opacity: .7; }
437
+
438
+ /* ── Markdown headings ───────────────────────────────── */
439
+ /* Kept modest — the chat bubble is small, so headings are only slightly
440
+ larger than body text, never document-sized. */
441
+ .message-bubble h1,
442
+ .message-bubble h2,
443
+ .message-bubble h3,
444
+ .message-bubble h4,
445
+ .message-bubble h5,
446
+ .message-bubble h6 {
447
+ margin: 8px 0 4px;
448
+ font-weight: 600;
449
+ line-height: 1.3;
450
+ color: #fff;
451
+ }
452
+ .message-bubble h1 { font-size: 16px; }
453
+ .message-bubble h2 { font-size: 15px; }
454
+ .message-bubble h3 { font-size: 14px; }
455
+ .message-bubble h4,
456
+ .message-bubble h5,
457
+ .message-bubble h6 { font-size: 13px; }
458
+ .message-bubble :first-child { margin-top: 0; }
459
+
460
+ /* ── Markdown horizontal rule ────────────────────────── */
461
+ .message-bubble hr {
462
+ border: 0;
463
+ height: 1px;
464
+ background: rgba(255,255,255,.15);
465
+ margin: 8px 0;
466
+ }
384
467
 
385
468
  /* ── Markdown tables ─────────────────────────────────── */
386
469
  .message-bubble table {
@@ -531,13 +614,13 @@ function D(e) {
531
614
  color: var(--color-text);
532
615
  resize: none;
533
616
  outline: none;
534
- background: var(--gray-50);
617
+ background: var(--color-input-bg);
535
618
  line-height: 1.4;
536
619
  overflow-y: auto;
537
620
  transition: border-color .15s;
538
621
  }
539
622
 
540
- .input:focus { border-color: var(--color-primary); background: var(--gray-100); }
623
+ .input:focus { border-color: var(--color-primary); background: var(--color-input-bg); }
541
624
  .input::placeholder { color: var(--gray-400); }
542
625
 
543
626
  .send-btn {
@@ -560,144 +643,192 @@ function D(e) {
560
643
  .send-btn svg { width: 18px; height: 18px; fill: #fff; }
561
644
 
562
645
  ${g}
563
- ${E(a)}
564
- ${o ? T(o) : ""}
646
+ ${N(a)}
647
+ ${o ? ne(o) : ""}
565
648
  `;
566
649
  }
567
650
  //#endregion
651
+ //#region src/core/assets.ts
652
+ var F = "data:image/png;base64,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";
653
+ //#endregion
654
+ //#region src/core/history-pager.ts
655
+ function I() {
656
+ return {
657
+ oldestCursor: null,
658
+ hasMore: !1,
659
+ cursorReady: !1
660
+ };
661
+ }
662
+ function L(e) {
663
+ return {
664
+ oldestCursor: e.messages[0]?.id ?? null,
665
+ hasMore: e.hasMore,
666
+ cursorReady: e.messages.length > 0
667
+ };
668
+ }
669
+ function R(e, t) {
670
+ return {
671
+ oldestCursor: t.messages[0]?.id ?? e.oldestCursor,
672
+ hasMore: t.hasMore,
673
+ cursorReady: e.cursorReady
674
+ };
675
+ }
676
+ function z(e, t) {
677
+ return e.cursorReady && e.hasMore && !t && e.oldestCursor !== null;
678
+ }
679
+ function B(e, t, n) {
680
+ return e + (n - t);
681
+ }
682
+ //#endregion
568
683
  //#region src/core/ui.ts
569
- var O = "https://bot-q-frontend.vercel.app/", k = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M20 2H4a2 2 0 00-2 2v18l4-4h14a2 2 0 002-2V4a2 2 0 00-2-2z\"/>\n</svg>", A = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\n</svg>", j = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 2a2 2 0 012 2c0 .74-.4 1.38-1 1.72V7h3a3 3 0 013 3v8a3 3 0 01-3 3H8a3 3 0 01-3-3v-8a3 3 0 013-3h3V5.72A2 2 0 0110 4a2 2 0 012-2zm-2 9a1.5 1.5 0 100 3 1.5 1.5 0 000-3zm4 0a1.5 1.5 0 100 3 1.5 1.5 0 000-3z\"/>\n</svg>", M = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\"/>\n</svg>", N = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M20 2H4a2 2 0 00-2 2v18l4-4h14a2 2 0 002-2V4a2 2 0 00-2-2zm-2 10H6v-2h12v2zm0-3H6V7h12v2z\"/>\n</svg>";
570
- function P(e) {
571
- if (!e || e.type === "icon") return j;
572
- if (e.type === "emoji") return `<span style="font-size:22px;line-height:1;display:flex;align-items:center;justify-content:center;width:100%;height:100%">${F(e.value)}</span>`;
684
+ var V = "https://bot-q-frontend.vercel.app/", H = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M20 2H4a2 2 0 00-2 2v18l4-4h14a2 2 0 002-2V4a2 2 0 00-2-2z\"/>\n</svg>", U = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\n</svg>", W = `<img src="${F}" alt="" style="width:100%;height:100%;object-fit:cover;border-radius:50%" />`, G = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\"/>\n</svg>", K = "<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M20 2H4a2 2 0 00-2 2v18l4-4h14a2 2 0 002-2V4a2 2 0 00-2-2zm-2 10H6v-2h12v2zm0-3H6V7h12v2z\"/>\n</svg>";
685
+ function q(e) {
686
+ if (!e || e.type === "icon") return W;
687
+ if (e.type === "emoji") return `<span style="font-size:22px;line-height:1;display:flex;align-items:center;justify-content:center;width:100%;height:100%">${J(e.value)}</span>`;
573
688
  if (e.type === "initials") {
574
689
  let t = e.bgColor ?? "#F97316";
575
- return `<div style="width:100%;height:100%;border-radius:50%;background:${/^#[0-9A-Fa-f]{3,6}$/.test(t) ? t : "#F97316"};display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:#fff">${F(e.value.slice(0, 2).toUpperCase())}</div>`;
690
+ return `<div style="width:100%;height:100%;border-radius:50%;background:${/^#[0-9A-Fa-f]{3,6}$/.test(t) ? t : "#F97316"};display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;color:#fff">${J(e.value.slice(0, 2).toUpperCase())}</div>`;
576
691
  }
577
- return e.type === "image" ? `<img src="${F(e.value)}" style="width:100%;height:100%;object-fit:cover;border-radius:50%" alt="" />` : j;
692
+ return e.type === "image" ? `<img src="${J(e.value)}" style="width:100%;height:100%;object-fit:cover;border-radius:50%" alt="" />` : W;
578
693
  }
579
- function F(e) {
694
+ function J(e) {
580
695
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;");
581
696
  }
582
- function I(e) {
697
+ function Y(e) {
583
698
  let t = [];
584
- return e = e.replace(/`([^`]+)`/g, (e, n) => (t.push(`<code>${n}</code>`), `\x00CODE${t.length - 1}\x00`)), e = e.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>"), e = e.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>"), e = e.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<em>$1</em>"), e = e.replace(/\[([^\]]+)\]\(([^()]*(?:\([^()]*\))*[^()]*)\)/g, (e, t, n) => /^https?:\/\//.test(n) ? `<a href="${n}" target="_blank" rel="noopener noreferrer">${t}</a>` : t), e = e.replace(/\x00CODE(\d+)\x00/g, (e, n) => t[Number(n)]), e;
699
+ return e = e.replace(/`([^`]+)`/g, (e, n) => (t.push(`<code>${n}</code>`), `\x00CODE${t.length - 1}\x00`)), e = e.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>"), e = e.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>"), e = e.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<em>$1</em>"), e = e.replace(/~~(.+?)~~/g, "<del>$1</del>"), e = e.replace(/__(.+?)__/g, "<strong>$1</strong>"), e = e.replace(/(^|\s)_(?!_)(.+?)_(?!_)(?=\s|$)/g, "$1<em>$2</em>"), e = e.replace(/\[([^\]]+)\]\(([^()]*(?:\([^()]*\))*[^()]*)\)/g, (e, t, n) => /^https?:\/\//.test(n) ? `<a href="${n}" target="_blank" rel="noopener noreferrer">${t}</a>` : t), e = e.replace(/\x00CODE(\d+)\x00/g, (e, n) => t[Number(n)]), e;
585
700
  }
586
- function L(e) {
701
+ function X(e) {
587
702
  return /^\|[\s\-:|]+\|$/.test(e);
588
703
  }
589
- function R(e) {
704
+ function Z(e) {
590
705
  return e.replace(/^\|/, "").replace(/\|$/, "").split("|").map((e) => e.trim());
591
706
  }
592
- function z(e) {
593
- let t = F(e).replace(/\x00/g, "").split("\n"), n = [], r = 0;
707
+ function re(e) {
708
+ let t = J(e).replace(/\x00/g, "").split("\n"), n = [], r = 0;
594
709
  for (; r < t.length;) {
595
710
  let e = t[r].trim();
596
711
  if (e.startsWith("|") && e.endsWith("|")) {
597
712
  let e = [];
598
713
  for (; r < t.length && t[r].trim().startsWith("|") && t[r].trim().endsWith("|");) e.push(t[r].trim()), r++;
599
- let i = e.findIndex(L), a = i > 0 ? e.slice(0, i) : [], o = i >= 0 ? e.slice(i + 1) : e, s = "<table>";
600
- a.length > 0 && (s += "<thead>" + a.map((e) => "<tr>" + R(e).map((e) => `<th>${I(e)}</th>`).join("") + "</tr>").join("") + "</thead>"), o.length > 0 && (s += "<tbody>" + o.map((e) => "<tr>" + R(e).map((e) => `<td>${I(e)}</td>`).join("") + "</tr>").join("") + "</tbody>"), s += "</table>", n.push(s);
714
+ let i = e.findIndex(X), a = i > 0 ? e.slice(0, i) : [], o = i >= 0 ? e.slice(i + 1) : e, s = "<table>";
715
+ a.length > 0 && (s += "<thead>" + a.map((e) => "<tr>" + Z(e).map((e) => `<th>${Y(e)}</th>`).join("") + "</tr>").join("") + "</thead>"), o.length > 0 && (s += "<tbody>" + o.map((e) => "<tr>" + Z(e).map((e) => `<td>${Y(e)}</td>`).join("") + "</tr>").join("") + "</tbody>"), s += "</table>", n.push(s);
716
+ continue;
717
+ }
718
+ if (/^-{3,}$/.test(e)) {
719
+ n.push("<hr>"), r++;
720
+ continue;
721
+ }
722
+ let i = e.match(/^(#{1,6})\s+(.*)$/);
723
+ if (i) {
724
+ let e = i[1].length;
725
+ n.push(`<h${e}>${Y(i[2])}</h${e}>`), r++;
601
726
  continue;
602
727
  }
603
728
  if (/^[-*]\s/.test(e)) {
604
729
  let e = [];
605
730
  for (; r < t.length && /^\s*[-*]\s/.test(t[r]);) e.push(t[r].trim().replace(/^[-*]\s+/, "")), r++;
606
- n.push("<ul>" + e.map((e) => `<li>${I(e)}</li>`).join("") + "</ul>");
731
+ n.push("<ul>" + e.map((e) => `<li>${Y(e)}</li>`).join("") + "</ul>");
607
732
  continue;
608
733
  }
609
734
  if (/^\d+\.\s/.test(e)) {
610
735
  let e = [];
611
736
  for (; r < t.length && /^\s*\d+\.\s/.test(t[r]);) e.push(t[r].trim().replace(/^\d+\.\s+/, "")), r++;
612
- n.push("<ol>" + e.map((e) => `<li>${I(e)}</li>`).join("") + "</ol>");
737
+ n.push("<ol>" + e.map((e) => `<li>${Y(e)}</li>`).join("") + "</ol>");
613
738
  continue;
614
739
  }
615
740
  if (e === "") {
616
741
  n.push("<br>"), r++;
617
742
  continue;
618
743
  }
619
- n.push(I(e)), n.push("<br>"), r++;
744
+ n.push(Y(e)), n.push("<br>"), r++;
620
745
  }
621
746
  for (; n.length > 0 && n[n.length - 1] === "<br>";) n.pop();
622
747
  return n.join("");
623
748
  }
624
- function B(e, t, n, r, i) {
625
- let { name: a, design: o } = t, s, c, l, u, d, f, { content: p } = o;
626
- function m(e) {
627
- e.setAttribute("data-position", o.layout.position), s = e.attachShadow({ mode: "closed" });
749
+ function ie(e, t, n, r, i, a) {
750
+ let { name: o, design: s } = t, c, l, u, d, f, p, { content: m } = s;
751
+ function h(e) {
752
+ e.setAttribute("data-position", s.layout.position), c = e.attachShadow({ mode: "closed" });
628
753
  let t = document.createElement("style");
629
- t.textContent = D(o), s.appendChild(t), c = document.createElement("button"), c.className = "bubble", c.setAttribute("aria-label", n.ariaOpenChat), c.innerHTML = `
630
- <span class="icon-chat">${k}</span>
631
- <span class="icon-close">${A}</span>
632
- `, c.addEventListener("click", i), s.appendChild(c), l = document.createElement("div"), l.className = "chat-window", l.setAttribute("role", "dialog"), l.setAttribute("aria-label", `${a} chat`), l.innerHTML = `
754
+ t.textContent = P(s), c.appendChild(t), l = document.createElement("button"), l.className = "bubble", l.setAttribute("aria-label", n.ariaOpenChat), l.innerHTML = `
755
+ <span class="icon-chat">${H}</span>
756
+ <span class="icon-close">${U}</span>
757
+ `, l.addEventListener("click", i), c.appendChild(l), u = document.createElement("div"), u.className = "chat-window", u.setAttribute("role", "dialog"), u.setAttribute("aria-label", `${o} chat`), u.innerHTML = `
633
758
  <div class="chat-header">
634
- <div class="avatar">${P(o.avatar)}</div>
759
+ <div class="avatar">${q(s.avatar)}</div>
635
760
  <div class="header-text">
636
- <span class="bot-name">${F(a)}</span>
637
- <span class="bot-status">${F(n.statusOnline)}</span>
761
+ <span class="bot-name">${J(o)}</span>
762
+ <span class="bot-status">${J(n.statusOnline)}</span>
638
763
  </div>
639
- <button class="close-btn" aria-label="${F(n.ariaCloseChat)}">×</button>
764
+ <button class="close-btn" aria-label="${J(n.ariaCloseChat)}">×</button>
640
765
  </div>
641
766
  <div class="messages" id="messages-container" role="log" aria-live="polite" aria-atomic="false"></div>
642
767
  <div class="chat-footer">
643
768
  <div class="input-row">
644
769
  <textarea
645
770
  class="input"
646
- placeholder="${F(p.placeholder || n.inputPlaceholder)}"
771
+ placeholder="${J(m.placeholder || n.inputPlaceholder)}"
647
772
  rows="1"
648
773
  maxlength="2000"
649
774
  aria-label="Message input"
650
775
  ></textarea>
651
- <button class="send-btn" aria-label="${F(n.ariaSendMessage)}">
652
- ${M}
776
+ <button class="send-btn" aria-label="${J(n.ariaSendMessage)}">
777
+ ${G}
653
778
  </button>
654
779
  </div>
655
- <a class="botiq-badge" href="${O}" target="_blank" rel="noopener noreferrer">
656
- ${F(n.poweredBy)} <span class="botiq-badge-name">BotIQ</span>
780
+ <a class="botiq-badge" href="${V}" target="_blank" rel="noopener noreferrer">
781
+ ${J(n.poweredBy)} <span class="botiq-badge-name">BotIQ</span>
657
782
  </a>
658
783
  </div>
659
- `, l.querySelector(".close-btn").addEventListener("click", i), u = l.querySelector("#messages-container"), d = l.querySelector(".input"), f = l.querySelector(".send-btn"), d.addEventListener("input", () => {
660
- d.style.height = "auto", d.style.height = Math.min(d.scrollHeight, 100) + "px";
661
- }), d.addEventListener("keydown", (e) => {
662
- e.key === "Enter" && !e.shiftKey && (e.preventDefault(), h());
663
- }), f.addEventListener("click", h), s.appendChild(l);
784
+ `, u.querySelector(".close-btn").addEventListener("click", i), d = u.querySelector("#messages-container");
785
+ let r = null;
786
+ d.addEventListener("scroll", () => {
787
+ d.scrollTop <= 48 && !r && (r = setTimeout(() => {
788
+ r = null;
789
+ }, 150), a());
790
+ }), f = u.querySelector(".input"), p = u.querySelector(".send-btn"), f.addEventListener("input", () => {
791
+ f.style.height = "auto", f.style.height = Math.min(f.scrollHeight, 100) + "px";
792
+ }), f.addEventListener("keydown", (e) => {
793
+ e.key === "Enter" && !e.shiftKey && (e.preventDefault(), g());
794
+ }), p.addEventListener("click", g), c.appendChild(u);
664
795
  }
665
- function h() {
666
- let e = d.value.trim();
667
- !e || f.disabled || (d.value = "", d.style.height = "auto", r(e));
796
+ function g() {
797
+ let e = f.value.trim();
798
+ !e || p.disabled || (f.value = "", f.style.height = "auto", r(e));
668
799
  }
669
- function g(e) {
800
+ function _(e) {
670
801
  if (e.messages.length === 0 && !e.isLoading) {
671
- let e = p.suggestionChips.length > 0 ? `<div class="chips">${p.suggestionChips.map((e) => `<button class="chip">${F(e)}</button>`).join("")}</div>` : "";
672
- u.innerHTML = `
802
+ let e = m.suggestionChips.length > 0 ? `<div class="chips">${m.suggestionChips.map((e) => `<button class="chip">${J(e)}</button>`).join("")}</div>` : "";
803
+ d.innerHTML = `
673
804
  <div class="empty-state">
674
- ${N}
675
- <span class="greeting">${F(p.greeting || n.defaultGreeting)}</span>
805
+ ${K}
806
+ <span class="greeting">${J(m.greeting || n.defaultGreeting)}</span>
676
807
  ${e}
677
808
  </div>
678
- `, u.querySelectorAll(".chip").forEach((e) => {
809
+ `, d.querySelectorAll(".chip").forEach((e) => {
679
810
  e.addEventListener("click", () => r(e.textContent ?? ""));
680
811
  });
681
812
  return;
682
813
  }
683
814
  let t = e.messages.map((e) => `
684
815
  <div class="message ${e.role}">
685
- <div class="message-bubble">${e.role === "assistant" ? z(e.content) : F(e.content)}</div>
816
+ <div class="message-bubble">${e.role === "assistant" ? re(e.content) : J(e.content)}</div>
686
817
  </div>
687
- `).join(""), i = e.isLoading ? "<div class=\"typing\"><span></span><span></span><span></span></div>" : "";
688
- u.innerHTML = t + i, u.scrollTop = u.scrollHeight;
818
+ `).join(""), i = e.loadingOlder ? "<div class=\"typing\"><span></span><span></span><span></span></div>" : "", a = e.isLoading ? "<div class=\"typing\"><span></span><span></span><span></span></div>" : "", o = d.scrollHeight - d.scrollTop - d.clientHeight < 80, s = d.scrollTop, c = d.scrollHeight;
819
+ d.innerHTML = i + t + a, o ? d.scrollTop = d.scrollHeight : d.scrollTop = B(s, c, d.scrollHeight);
689
820
  }
690
- function _(e) {
691
- e.isOpen ? (l.classList.add("open"), c.classList.add("open"), c.setAttribute("aria-label", n.ariaCloseChat), requestAnimationFrame(() => d.focus())) : (l.classList.remove("open"), c.classList.remove("open"), c.setAttribute("aria-label", n.ariaOpenChat)), f.disabled = e.isLoading, g(e);
821
+ function v(e) {
822
+ e.isOpen ? (u.classList.add("open"), l.classList.add("open"), l.setAttribute("aria-label", n.ariaCloseChat), requestAnimationFrame(() => f.focus())) : (u.classList.remove("open"), l.classList.remove("open"), l.setAttribute("aria-label", n.ariaOpenChat)), p.disabled = e.isLoading, _(e);
692
823
  }
693
824
  return {
694
- mount: m,
695
- update: _
825
+ mount: h,
826
+ update: v
696
827
  };
697
828
  }
698
829
  //#endregion
699
830
  //#region src/i18n/vi.ts
700
- var V = {
831
+ var ae = {
701
832
  statusOnline: "Trực tuyến",
702
833
  inputPlaceholder: "Nhắn tin...",
703
834
  defaultGreeting: "Xin chào! Tôi có thể giúp gì cho bạn?",
@@ -713,7 +844,7 @@ var V = {
713
844
  ariaOpenChat: "Mở khung chat",
714
845
  ariaCloseChat: "Đóng khung chat",
715
846
  ariaSendMessage: "Gửi tin nhắn"
716
- }, H = {
847
+ }, oe = {
717
848
  statusOnline: "Online",
718
849
  inputPlaceholder: "Type a message...",
719
850
  defaultGreeting: "Hello! How can I help you?",
@@ -732,57 +863,81 @@ var V = {
732
863
  };
733
864
  //#endregion
734
865
  //#region src/i18n/index.ts
735
- function U(e) {
736
- return e === "en" ? H : V;
866
+ function Q(e) {
867
+ return e === "en" ? oe : ae;
737
868
  }
738
869
  //#endregion
739
870
  //#region src/builds/npm/index.ts
740
- function W(e) {
871
+ var $ = 10;
872
+ function se(e) {
741
873
  if (!e.apiKey) return console.warn("[BotIQ] apiKey is required"), () => void 0;
742
- let t = u(e), n = m();
743
- x({ messages: h(n) });
744
- let r = document.createElement("div");
745
- document.body.appendChild(r);
746
- let i = () => void 0, a = !1, o = U(void 0);
747
- l(t.apiKey, t.apiUrl).then((e) => {
748
- if (a) return;
874
+ let t = p(e);
875
+ v();
876
+ let n = t.apiKey.slice(-16), r = y(n), i = b(n, r);
877
+ k({ messages: i });
878
+ let a = I(), o = document.createElement("div");
879
+ document.body.appendChild(o);
880
+ let s = () => void 0, c = !1, l = Q(void 0);
881
+ f(t.apiKey, t.apiUrl).then((e) => {
882
+ if (c) return;
749
883
  if (e === null) {
750
- console.warn("[BotIQ] Widget not authorised on this origin — skipped mount"), r.remove();
884
+ console.warn("[BotIQ] Widget not authorised on this origin — skipped mount"), o.remove();
751
885
  return;
752
886
  }
753
- o = U(e.widgetLanguage);
754
- let n = B(t, e, o, s, c);
755
- n.mount(r), i = S((e) => n.update(e)), n.update(b());
887
+ l = Q(e.widgetLanguage);
888
+ let n = ie(t, e, l, h, g, m);
889
+ n.mount(o), s = A((e) => n.update(e)), n.update(O()), i.length > 0 && d();
756
890
  });
757
- function s(e) {
758
- let r = b();
759
- if (r.isLoading) return;
760
- let i = {
891
+ function u(e) {
892
+ return {
893
+ role: e.role,
894
+ content: e.content
895
+ };
896
+ }
897
+ async function d() {
898
+ let e = await ee(t.apiUrl, t.apiKey, r, $);
899
+ e.messages.length > 0 && (a = L(e), k({ messages: e.messages.map(u) }));
900
+ }
901
+ async function m() {
902
+ if (z(a, O().loadingOlder)) {
903
+ k({ loadingOlder: !0 });
904
+ try {
905
+ let e = await te(t.apiUrl, t.apiKey, r, a.oldestCursor, $);
906
+ e.messages.length > 0 && k({ messages: [...e.messages.map(u), ...O().messages] }), a = R(a, e);
907
+ } finally {
908
+ k({ loadingOlder: !1 });
909
+ }
910
+ }
911
+ }
912
+ function h(e) {
913
+ let i = O();
914
+ if (i.isLoading) return;
915
+ let a = {
761
916
  role: "user",
762
917
  content: e
763
918
  };
764
- x({
765
- messages: [...r.messages, i],
919
+ k({
920
+ messages: [...i.messages, a],
766
921
  isLoading: !0
767
- }), _(t.apiUrl, t.apiKey, n, e, r.messages, o).then((e) => {
922
+ }), S(t.apiUrl, t.apiKey, r, e, i.messages, l).then((e) => {
768
923
  let t = {
769
924
  role: "assistant",
770
925
  content: e
771
926
  };
772
- x({
773
- messages: [...b().messages, t],
927
+ k({
928
+ messages: [...O().messages, t],
774
929
  isLoading: !1
775
- }), g(n, [i, t]);
930
+ }), x(n, r, [a, t]);
776
931
  }).catch(() => {
777
- x({ isLoading: !1 });
932
+ k({ isLoading: !1 });
778
933
  });
779
934
  }
780
- function c() {
781
- x({ isOpen: !b().isOpen });
935
+ function g() {
936
+ k({ isOpen: !O().isOpen });
782
937
  }
783
938
  return () => {
784
- a = !0, i(), r.remove();
939
+ c = !0, s(), o.remove();
785
940
  };
786
941
  }
787
942
  //#endregion
788
- export { W as t };
943
+ export { se as t };
package/dist/sdk/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as e } from "./npm-DfSKhYCq.js";
1
+ import { t as e } from "./npm-DV43YS-n.js";
2
2
  import { useEffect as t } from "react";
3
3
  //#region src/builds/npm/react.tsx
4
4
  function n(n) {
package/dist/sdk/vue.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as e } from "./npm-DfSKhYCq.js";
1
+ import { t as e } from "./npm-DV43YS-n.js";
2
2
  import { defineComponent as t, onMounted as n, onUnmounted as r } from "vue";
3
3
  //#region src/builds/npm/vue.ts
4
4
  var i = t({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locdo.tech/botiq-chat-sdk",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "BotIQ chat widget SDK — embed AI chatbot into any website with vanilla JS, React, or Vue.",
5
5
  "keywords": [
6
6
  "botiq",