@cognitiondesk/widget 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1 -268
- package/dist/react.es.js +222 -124
- package/dist/react.umd.cjs +4 -4
- package/dist/widget.es.js +135 -45
- package/dist/widget.umd.cjs +4 -4
- package/package.json +1 -1
- package/src/react.jsx +25 -2
- package/src/widget.js +187 -34
package/dist/react.es.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { forwardRef as
|
|
3
|
-
const
|
|
1
|
+
import { jsx as P } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as I, useRef as E, useImperativeHandle as N, useEffect as x } from "react";
|
|
3
|
+
const j = "https://mounaji-backendv3.onrender.com", z = `
|
|
4
4
|
:host {
|
|
5
5
|
all: initial;
|
|
6
6
|
font-family: system-ui, sans-serif;
|
|
@@ -246,84 +246,174 @@ const P = "https://mounaji-backendv3.onrender.com", B = `
|
|
|
246
246
|
font-size: 16px;
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
|
-
`,
|
|
249
|
+
`, w = {
|
|
250
250
|
chat: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',
|
|
251
251
|
close: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',
|
|
252
252
|
send: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>'
|
|
253
253
|
};
|
|
254
|
-
function
|
|
254
|
+
function B() {
|
|
255
255
|
return "cd_" + Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
256
256
|
}
|
|
257
257
|
let D = class {
|
|
258
|
+
/**
|
|
259
|
+
* @param {Object} config
|
|
260
|
+
* @param {string} config.apiKey - Required. Your CognitionDesk API key.
|
|
261
|
+
* @param {string} [config.widgetId] - Widget ID from the dashboard. Enables remote config.
|
|
262
|
+
* @param {string} [config.assistantId] - Assistant ID (overrides server value if set).
|
|
263
|
+
* @param {string} [config.backendUrl] - Custom backend URL.
|
|
264
|
+
* @param {string} [config.theme] - 'light' | 'dark' | 'auto'
|
|
265
|
+
* @param {string} [config.primaryColor] - Hex color for buttons / header.
|
|
266
|
+
* @param {string} [config.botName] - Display name shown in the header.
|
|
267
|
+
* @param {string} [config.botEmoji] - Emoji shown as avatar.
|
|
268
|
+
* @param {string} [config.welcomeMessage] - First message shown to the user.
|
|
269
|
+
* @param {string} [config.placeholder] - Textarea placeholder text.
|
|
270
|
+
* @param {string} [config.position] - 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
|
|
271
|
+
* @param {boolean} [config.streaming] - Enable streaming responses (default: true).
|
|
272
|
+
* @param {Object} [config.overrideSettings]
|
|
273
|
+
* Explicit code-level overrides. Any key listed here takes precedence over
|
|
274
|
+
* the server-side dashboard config. Use this when you want to manage
|
|
275
|
+
* specific settings from code rather than the CognitionDesk dashboard.
|
|
276
|
+
*
|
|
277
|
+
* Example — let the dashboard control everything except color:
|
|
278
|
+
* overrideSettings: { primaryColor: '#e11d48' }
|
|
279
|
+
*
|
|
280
|
+
* Example — full code control (dashboard settings ignored):
|
|
281
|
+
* overrideSettings: {
|
|
282
|
+
* primaryColor: '#e11d48', botName: 'Aria', welcomeMessage: 'Hi!'
|
|
283
|
+
* }
|
|
284
|
+
*
|
|
285
|
+
* When omitted (default), ALL settings come from the dashboard.
|
|
286
|
+
*/
|
|
258
287
|
constructor(t = {}) {
|
|
259
|
-
var e,
|
|
288
|
+
var e, i, s, a, n;
|
|
260
289
|
if (!t.apiKey) throw new Error("[CognitionDesk] apiKey is required");
|
|
261
|
-
this.
|
|
290
|
+
this._overrides = new Set(
|
|
291
|
+
t.overrideSettings ? Object.keys(t.overrideSettings) : []
|
|
292
|
+
), this._cfg = {
|
|
262
293
|
apiKey: t.apiKey,
|
|
263
294
|
widgetId: t.widgetId || null,
|
|
264
295
|
assistantId: t.assistantId || null,
|
|
265
|
-
backendUrl: t.backendUrl ||
|
|
296
|
+
backendUrl: t.backendUrl || j,
|
|
266
297
|
primaryColor: t.primaryColor || "#2563eb",
|
|
267
298
|
theme: t.theme || "light",
|
|
268
|
-
// 'light' | 'dark' | 'auto'
|
|
269
299
|
botName: t.botName || "AI Assistant",
|
|
270
300
|
botEmoji: t.botEmoji || "🤖",
|
|
271
301
|
welcomeMessage: t.welcomeMessage || "Hello! How can I help you today?",
|
|
272
302
|
placeholder: t.placeholder || "Type a message…",
|
|
273
303
|
position: t.position || "bottom-right",
|
|
274
304
|
streaming: t.streaming !== !1,
|
|
275
|
-
// default: true
|
|
276
|
-
// Rate limiting — can be overridden by inline config or merged from server config
|
|
277
305
|
rateLimiting: {
|
|
278
306
|
enabled: ((e = t.rateLimiting) == null ? void 0 : e.enabled) !== !1,
|
|
279
|
-
maxMessagesPerSession: ((
|
|
307
|
+
maxMessagesPerSession: ((i = t.rateLimiting) == null ? void 0 : i.maxMessagesPerSession) ?? 0,
|
|
280
308
|
maxMessagesPerMinute: ((s = t.rateLimiting) == null ? void 0 : s.maxMessagesPerMinute) ?? 0,
|
|
281
|
-
limitReachedMessage: ((
|
|
309
|
+
limitReachedMessage: ((a = t.rateLimiting) == null ? void 0 : a.limitReachedMessage) || "You've reached the message limit for this session.",
|
|
282
310
|
rateLimitMessage: ((n = t.rateLimiting) == null ? void 0 : n.rateLimitMessage) || "You're sending messages too quickly. Please wait a moment."
|
|
283
|
-
}
|
|
284
|
-
|
|
311
|
+
},
|
|
312
|
+
// Store overrides for re-application after each config refresh
|
|
313
|
+
overrideSettings: t.overrideSettings || null
|
|
314
|
+
}, t.overrideSettings && this._applyOverrides(t.overrideSettings), this._sessionId = B(), this._messageCount = 0, this._minuteCount = 0, this._minuteStart = Date.now(), this._messages = [], this._open = !1, this._loading = !1, this._container = null, this._shadow = null, this._panel = null, this._messagesEl = null, this._textarea = null, this._sendBtn = null, this._viewportHandler = null, this._refreshPending = !1;
|
|
285
315
|
}
|
|
286
316
|
// ── Public API ──────────────────────────────────────────────────────────────
|
|
287
317
|
/**
|
|
288
318
|
* Mount the widget.
|
|
289
|
-
* If `widgetId`
|
|
290
|
-
* Returns a Promise so callers can await
|
|
319
|
+
* If `widgetId` is set, fetches server config first (async).
|
|
320
|
+
* Returns a Promise so callers can `await widget.mount()`.
|
|
291
321
|
*/
|
|
292
322
|
mount(t) {
|
|
293
323
|
const e = () => {
|
|
294
|
-
const
|
|
295
|
-
this._container = document.createElement("div"), this._container.setAttribute("data-cognitiondesk", ""),
|
|
324
|
+
const i = t || document.body;
|
|
325
|
+
this._container = document.createElement("div"), this._container.setAttribute("data-cognitiondesk", ""), i.appendChild(this._container), this._shadow = this._container.attachShadow({ mode: "open" });
|
|
296
326
|
const s = document.createElement("style");
|
|
297
|
-
s.textContent =
|
|
327
|
+
s.textContent = z, this._shadow.appendChild(s), this._buildDOM(), this._applyConfig(), this._syncViewportMetrics(), this._bindViewportMetrics(), this._bindEvents(), this._cfg.welcomeMessage && this._appendMessage("assistant", this._cfg.welcomeMessage, !1);
|
|
298
328
|
};
|
|
299
329
|
return this._cfg.widgetId ? this._fetchWidgetConfig().then(() => e()).catch(() => e()) : (e(), Promise.resolve(this));
|
|
300
330
|
}
|
|
331
|
+
/**
|
|
332
|
+
* Programmatically update settings at runtime.
|
|
333
|
+
* Merges `newSettings` into `overrideSettings` and re-applies to the live DOM.
|
|
334
|
+
* Use this to change colors, bot name, etc. without remounting.
|
|
335
|
+
*
|
|
336
|
+
* widget.updateSettings({ primaryColor: '#dc2626', botName: 'Support Bot' });
|
|
337
|
+
*/
|
|
338
|
+
updateSettings(t) {
|
|
339
|
+
if (!t || typeof t != "object") return;
|
|
340
|
+
const e = { ...this._cfg.overrideSettings || {}, ...t };
|
|
341
|
+
this._cfg.overrideSettings = e, this._overrides = new Set(Object.keys(e)), this._applyOverrides(e), this._applyConfig();
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Fetch fresh config from the dashboard right now and apply it.
|
|
345
|
+
* Useful after the user changes settings in the CognitionDesk dashboard
|
|
346
|
+
* and wants them reflected immediately without reloading the page.
|
|
347
|
+
*/
|
|
348
|
+
async refreshConfig() {
|
|
349
|
+
this._cfg.widgetId && (await this._fetchWidgetConfig(), this._applyConfig());
|
|
350
|
+
}
|
|
351
|
+
// ── Config internals ────────────────────────────────────────────────────────
|
|
352
|
+
/**
|
|
353
|
+
* Returns true if `key` is explicitly controlled by `overrideSettings`.
|
|
354
|
+
* Those keys are immune to server config overwrites.
|
|
355
|
+
*/
|
|
356
|
+
_userSet(t) {
|
|
357
|
+
return this._overrides.has(t);
|
|
358
|
+
}
|
|
301
359
|
/**
|
|
302
360
|
* Fetch public widget config from the platform and merge into this._cfg.
|
|
303
|
-
*
|
|
361
|
+
* Server values apply to any key NOT present in `overrideSettings`.
|
|
362
|
+
* After merging, overrides are re-applied so they always win.
|
|
304
363
|
*/
|
|
305
364
|
async _fetchWidgetConfig() {
|
|
306
365
|
var e;
|
|
307
366
|
const t = `${this._cfg.backendUrl}/platforms/web-widget/public/${this._cfg.widgetId}`;
|
|
308
367
|
try {
|
|
309
|
-
const
|
|
310
|
-
if (!
|
|
311
|
-
const { config: s } = await
|
|
368
|
+
const i = await fetch(t);
|
|
369
|
+
if (!i.ok) return;
|
|
370
|
+
const { config: s } = await i.json();
|
|
312
371
|
if (!s) return;
|
|
313
|
-
|
|
372
|
+
const a = (n, o) => {
|
|
373
|
+
o != null && !this._userSet(n) && (this._cfg[n] = o);
|
|
374
|
+
};
|
|
375
|
+
a("botName", s.botName), a("welcomeMessage", s.welcomeMessage), a("primaryColor", s.primaryColor), a("secondaryColor", s.secondaryColor), a("placeholder", s.placeholder), a("theme", s.theme), a("position", s.position), a("style", s.style), a("size", s.size), s.assistantId && !this._cfg.assistantId && (this._cfg.assistantId = s.assistantId), (e = s.avatar) != null && e.value && !this._userSet("botEmoji") && (this._cfg.botEmoji = s.avatar.value), s.rateLimiting && (this._cfg.rateLimiting = { ...this._cfg.rateLimiting, ...s.rateLimiting }), this._cfg.overrideSettings && this._applyOverrides(this._cfg.overrideSettings);
|
|
314
376
|
} catch {
|
|
315
377
|
}
|
|
316
378
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
379
|
+
/**
|
|
380
|
+
* Write override values into this._cfg (flat fields only; rateLimiting is merged).
|
|
381
|
+
*/
|
|
382
|
+
_applyOverrides(t) {
|
|
383
|
+
for (const [e, i] of Object.entries(t))
|
|
384
|
+
e === "rateLimiting" && typeof i == "object" ? this._cfg.rateLimiting = { ...this._cfg.rateLimiting, ...i } : this._cfg[e] = i;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Update live DOM elements to reflect the current this._cfg.
|
|
388
|
+
* Safe to call before or after mounting.
|
|
389
|
+
*/
|
|
390
|
+
_applyConfig() {
|
|
391
|
+
var s, a, n, o, d, c, l;
|
|
392
|
+
const t = this._cfg.theme === "dark" || this._cfg.theme === "auto" && ((s = window.matchMedia) == null ? void 0 : s.call(window, "(prefers-color-scheme: dark)").matches);
|
|
393
|
+
(a = this._root) == null || a.classList.toggle("cd-dark", t), (n = this._root) == null || n.style.setProperty("--cd-primary", this._cfg.primaryColor), (o = this._panel) == null || o.style.setProperty("--cd-primary", this._cfg.primaryColor), (d = this._toggleBtn) == null || d.style.setProperty("--cd-primary", this._cfg.primaryColor);
|
|
394
|
+
const e = (c = this._shadow) == null ? void 0 : c.querySelector(".cd-header-avatar");
|
|
395
|
+
e && (e.textContent = this._cfg.botEmoji);
|
|
396
|
+
const i = (l = this._shadow) == null ? void 0 : l.querySelector(".cd-header-name");
|
|
397
|
+
i && (i.textContent = this._cfg.botName), this._textarea && (this._textarea.placeholder = this._cfg.placeholder);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Silently refresh config from server in the background.
|
|
401
|
+
* Called each time the panel opens so dashboard changes
|
|
402
|
+
* are reflected without reloading the page.
|
|
403
|
+
* Uses a debounce flag to avoid concurrent fetches.
|
|
404
|
+
*/
|
|
405
|
+
_silentRefresh() {
|
|
406
|
+
!this._cfg.widgetId || this._refreshPending || (this._refreshPending = !0, this._fetchWidgetConfig().then(() => this._applyConfig()).catch(() => {
|
|
407
|
+
}).finally(() => {
|
|
408
|
+
this._refreshPending = !1;
|
|
409
|
+
}));
|
|
320
410
|
}
|
|
321
411
|
unmount() {
|
|
322
412
|
this._unbindViewportMetrics(), this._container && (this._container.remove(), this._container = null);
|
|
323
413
|
}
|
|
324
414
|
open() {
|
|
325
415
|
var t, e;
|
|
326
|
-
this._open = !0, this._syncViewportMetrics(), (t = this._panel) == null || t.classList.add("open"), (e = this._textarea) == null || e.focus();
|
|
416
|
+
this._open = !0, this._syncViewportMetrics(), (t = this._panel) == null || t.classList.add("open"), (e = this._textarea) == null || e.focus(), this._silentRefresh();
|
|
327
417
|
}
|
|
328
418
|
close() {
|
|
329
419
|
var t;
|
|
@@ -340,9 +430,9 @@ let D = class {
|
|
|
340
430
|
const t = document.createElement("div");
|
|
341
431
|
t.className = "cd-root";
|
|
342
432
|
const e = document.createElement("button");
|
|
343
|
-
e.className = "cd-widget-btn", e.innerHTML =
|
|
344
|
-
const
|
|
345
|
-
|
|
433
|
+
e.className = "cd-widget-btn", e.innerHTML = w.chat, e.setAttribute("aria-label", "Open chat"), e.style.setProperty("--cd-primary", this._cfg.primaryColor), this._toggleBtn = e;
|
|
434
|
+
const i = document.createElement("div");
|
|
435
|
+
i.className = "cd-panel", this._panel = i;
|
|
346
436
|
const s = document.createElement("div");
|
|
347
437
|
s.className = "cd-header", s.innerHTML = `
|
|
348
438
|
<div class="cd-header-avatar">${this._cfg.botEmoji}</div>
|
|
@@ -353,22 +443,22 @@ let D = class {
|
|
|
353
443
|
</div>
|
|
354
444
|
</div>
|
|
355
445
|
`;
|
|
356
|
-
const
|
|
357
|
-
|
|
446
|
+
const a = document.createElement("button");
|
|
447
|
+
a.className = "cd-close-btn", a.innerHTML = w.close, a.setAttribute("aria-label", "Close chat"), s.appendChild(a), this._closeBtn = a;
|
|
358
448
|
const n = document.createElement("div");
|
|
359
449
|
n.className = "cd-messages", n.setAttribute("role", "log"), n.setAttribute("aria-live", "polite"), this._messagesEl = n;
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
const
|
|
363
|
-
|
|
450
|
+
const o = document.createElement("div");
|
|
451
|
+
o.className = "cd-input-area";
|
|
452
|
+
const d = document.createElement("textarea");
|
|
453
|
+
d.className = "cd-textarea", d.rows = 1, d.placeholder = this._cfg.placeholder, this._textarea = d;
|
|
364
454
|
const c = document.createElement("button");
|
|
365
|
-
c.className = "cd-send-btn", c.innerHTML =
|
|
455
|
+
c.className = "cd-send-btn", c.innerHTML = w.send, c.setAttribute("aria-label", "Send"), this._sendBtn = c, o.appendChild(d), o.appendChild(c);
|
|
366
456
|
const l = document.createElement("div");
|
|
367
|
-
l.className = "cd-powered", l.innerHTML = 'Powered by <a href="https://cognitiondesk.com" target="_blank" rel="noopener">CognitionDesk</a>',
|
|
457
|
+
l.className = "cd-powered", l.innerHTML = 'Powered by <a href="https://cognitiondesk.com" target="_blank" rel="noopener">CognitionDesk</a>', i.appendChild(s), i.appendChild(n), i.appendChild(o), i.appendChild(l), t.appendChild(e), t.appendChild(i), this._shadow.appendChild(t), this._root = t;
|
|
368
458
|
}
|
|
369
459
|
_applyTheme() {
|
|
370
|
-
var e,
|
|
371
|
-
(this._cfg.theme === "auto" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : this._cfg.theme) === "dark" && ((e = this._root) == null || e.classList.add("cd-dark")), (
|
|
460
|
+
var e, i, s;
|
|
461
|
+
(this._cfg.theme === "auto" ? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" : this._cfg.theme) === "dark" && ((e = this._root) == null || e.classList.add("cd-dark")), (i = this._root) == null || i.style.setProperty("--cd-primary", this._cfg.primaryColor), (s = this._panel) == null || s.style.setProperty("--cd-primary", this._cfg.primaryColor);
|
|
372
462
|
}
|
|
373
463
|
// ── Events ──────────────────────────────────────────────────────────────────
|
|
374
464
|
_bindEvents() {
|
|
@@ -389,12 +479,12 @@ let D = class {
|
|
|
389
479
|
_syncViewportMetrics() {
|
|
390
480
|
const t = this._root || this._container;
|
|
391
481
|
if (!t) return;
|
|
392
|
-
const e = window.visualViewport,
|
|
393
|
-
t.style.setProperty("--cd-viewport-height", `${Math.round(
|
|
482
|
+
const e = window.visualViewport, i = e ? e.height : window.innerHeight;
|
|
483
|
+
t.style.setProperty("--cd-viewport-height", `${Math.round(i)}px`);
|
|
394
484
|
}
|
|
395
485
|
// ── Chat ────────────────────────────────────────────────────────────────────
|
|
396
486
|
async _sendMessage() {
|
|
397
|
-
var
|
|
487
|
+
var i;
|
|
398
488
|
const t = this._textarea.value.trim();
|
|
399
489
|
if (!t || this._loading) return;
|
|
400
490
|
const e = this._cfg.rateLimiting;
|
|
@@ -414,13 +504,13 @@ let D = class {
|
|
|
414
504
|
if (this._cfg.streaming)
|
|
415
505
|
await this._callApiStream();
|
|
416
506
|
else {
|
|
417
|
-
const s = this._showTyping(),
|
|
418
|
-
this._removeTyping(s), this._messages.push({ role: "assistant", content:
|
|
507
|
+
const s = this._showTyping(), a = await this._callApi();
|
|
508
|
+
this._removeTyping(s), this._messages.push({ role: "assistant", content: a }), this._appendMessage("assistant", a, !0);
|
|
419
509
|
}
|
|
420
510
|
} catch (s) {
|
|
421
|
-
if (s.status === 429 || (
|
|
422
|
-
const
|
|
423
|
-
this._appendMessage("error",
|
|
511
|
+
if (s.status === 429 || (i = s.message) != null && i.includes("429")) {
|
|
512
|
+
const a = s.rateLimitMessage || (e == null ? void 0 : e.rateLimitMessage) || "You're sending messages too quickly. Please wait a moment.";
|
|
513
|
+
this._appendMessage("error", a, !1);
|
|
424
514
|
} else
|
|
425
515
|
this._appendMessage("error", "Sorry, something went wrong. Please try again.", !1);
|
|
426
516
|
console.error("[CognitionDesk]", s);
|
|
@@ -448,56 +538,56 @@ let D = class {
|
|
|
448
538
|
body: JSON.stringify({ ...this._buildRequestBody(), stream: !0 })
|
|
449
539
|
});
|
|
450
540
|
if (!e.ok) {
|
|
451
|
-
const
|
|
452
|
-
throw c.status = e.status, c.rateLimitMessage =
|
|
541
|
+
const d = await e.json().catch(() => ({})), c = new Error(d.message || `HTTP ${e.status}`);
|
|
542
|
+
throw c.status = e.status, c.rateLimitMessage = d.message, c;
|
|
453
543
|
}
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
const s = e.body.getReader(),
|
|
457
|
-
let n = "",
|
|
544
|
+
const i = document.createElement("div");
|
|
545
|
+
i.className = "cd-msg assistant", i.innerHTML = '<div class="cd-typing"><span></span><span></span><span></span></div>', this._messagesEl.appendChild(i), this._scrollToBottom();
|
|
546
|
+
const s = e.body.getReader(), a = new TextDecoder();
|
|
547
|
+
let n = "", o = !1;
|
|
458
548
|
try {
|
|
459
549
|
for (; ; ) {
|
|
460
|
-
const { done:
|
|
461
|
-
if (
|
|
462
|
-
const l =
|
|
463
|
-
for (const
|
|
550
|
+
const { done: d, value: c } = await s.read();
|
|
551
|
+
if (d) break;
|
|
552
|
+
const l = a.decode(c, { stream: !0 });
|
|
553
|
+
for (const f of l.split(`
|
|
464
554
|
`)) {
|
|
465
|
-
if (!
|
|
466
|
-
const m =
|
|
555
|
+
if (!f.startsWith("data: ")) continue;
|
|
556
|
+
const m = f.slice(6).trim();
|
|
467
557
|
if (m === "[DONE]") break;
|
|
468
|
-
let
|
|
558
|
+
let p;
|
|
469
559
|
try {
|
|
470
|
-
|
|
560
|
+
p = JSON.parse(m);
|
|
471
561
|
} catch {
|
|
472
562
|
continue;
|
|
473
563
|
}
|
|
474
|
-
|
|
564
|
+
p.type === "content" && p.data && (o || (i.innerHTML = "", o = !0), n += p.data, i.innerHTML = this._renderMarkdown(n), this._scrollToBottom());
|
|
475
565
|
}
|
|
476
566
|
}
|
|
477
567
|
} finally {
|
|
478
568
|
s.releaseLock();
|
|
479
569
|
}
|
|
480
|
-
|
|
570
|
+
o || (i.innerHTML = this._renderMarkdown("No response")), n && this._messages.push({ role: "assistant", content: n });
|
|
481
571
|
}
|
|
482
572
|
/** Non-streaming fallback path */
|
|
483
573
|
async _callApi() {
|
|
484
|
-
var s,
|
|
574
|
+
var s, a, n;
|
|
485
575
|
const t = `${this._cfg.backendUrl}/chat-apiKeyAuth/chat`, e = await fetch(t, {
|
|
486
576
|
method: "POST",
|
|
487
577
|
headers: { "Content-Type": "application/json", "x-api-key": this._cfg.apiKey },
|
|
488
578
|
body: JSON.stringify(this._buildRequestBody())
|
|
489
579
|
});
|
|
490
580
|
if (!e.ok) {
|
|
491
|
-
const
|
|
492
|
-
throw
|
|
581
|
+
const o = await e.json().catch(() => ({})), d = new Error(o.message || `HTTP ${e.status}`);
|
|
582
|
+
throw d.status = e.status, d.rateLimitMessage = o.message, d;
|
|
493
583
|
}
|
|
494
|
-
const
|
|
495
|
-
return
|
|
584
|
+
const i = await e.json();
|
|
585
|
+
return i.response || i.message || i.content || ((n = (a = (s = i.choices) == null ? void 0 : s[0]) == null ? void 0 : a.message) == null ? void 0 : n.content) || "No response";
|
|
496
586
|
}
|
|
497
587
|
// ── DOM helpers ─────────────────────────────────────────────────────────────
|
|
498
|
-
_appendMessage(t, e,
|
|
588
|
+
_appendMessage(t, e, i = !0) {
|
|
499
589
|
const s = document.createElement("div");
|
|
500
|
-
s.className = `cd-msg ${t}`,
|
|
590
|
+
s.className = `cd-msg ${t}`, i && t !== "user" ? s.innerHTML = this._renderMarkdown(e) : s.textContent = e, this._messagesEl.appendChild(s), this._scrollToBottom();
|
|
501
591
|
}
|
|
502
592
|
/** Minimal, safe markdown → HTML renderer (no dependencies). */
|
|
503
593
|
_renderMarkdown(t) {
|
|
@@ -505,7 +595,7 @@ let D = class {
|
|
|
505
595
|
let e = this._escHtml(t);
|
|
506
596
|
return e = e.replace(
|
|
507
597
|
/```[\w]*\n?([\s\S]*?)```/g,
|
|
508
|
-
(
|
|
598
|
+
(i, s) => `<pre style="background:#0f172a;color:#e2e8f0;padding:10px;border-radius:6px;font-size:12px;overflow-x:auto;margin:6px 0;white-space:pre-wrap">${s.trim()}</pre>`
|
|
509
599
|
), e = e.replace(/`([^`]+)`/g, '<code style="background:rgba(0,0,0,.08);padding:1px 5px;border-radius:4px;font-size:.9em">$1</code>'), e = e.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>"), e = e.replace(/__([^_]+)__/g, "<strong>$1</strong>"), e = e.replace(/\*([^*]+)\*/g, "<em>$1</em>"), e = e.replace(/_([^_]+)_/g, "<em>$1</em>"), e = e.replace(
|
|
510
600
|
/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g,
|
|
511
601
|
'<a href="$2" target="_blank" rel="noopener" style="color:var(--cd-primary,#2563eb)">$1</a>'
|
|
@@ -525,88 +615,96 @@ let D = class {
|
|
|
525
615
|
return String(t).replace(/[&<>"']/g, (e) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[e]);
|
|
526
616
|
}
|
|
527
617
|
};
|
|
528
|
-
const V =
|
|
618
|
+
const V = I(function(t, e) {
|
|
529
619
|
const {
|
|
530
|
-
apiKey:
|
|
620
|
+
apiKey: i,
|
|
531
621
|
widgetId: s,
|
|
532
|
-
assistantId:
|
|
622
|
+
assistantId: a,
|
|
533
623
|
theme: n = "light",
|
|
534
|
-
primaryColor:
|
|
535
|
-
botName:
|
|
624
|
+
primaryColor: o = "#2563eb",
|
|
625
|
+
botName: d = "AI Assistant",
|
|
536
626
|
botEmoji: c = "🤖",
|
|
537
627
|
welcomeMessage: l = "Hello! How can I help you today?",
|
|
538
|
-
placeholder:
|
|
628
|
+
placeholder: f = "Type a message…",
|
|
539
629
|
defaultOpen: m = !1,
|
|
540
|
-
streaming:
|
|
541
|
-
backendUrl:
|
|
630
|
+
streaming: p = !0,
|
|
631
|
+
backendUrl: y,
|
|
542
632
|
// Rate limiting — 0 means unlimited
|
|
543
|
-
maxMessagesPerSession:
|
|
633
|
+
maxMessagesPerSession: S = 0,
|
|
544
634
|
maxMessagesPerMinute: H = 0,
|
|
545
|
-
limitReachedMessage:
|
|
546
|
-
rateLimitMessage:
|
|
547
|
-
onOpen:
|
|
548
|
-
onClose:
|
|
549
|
-
|
|
550
|
-
|
|
635
|
+
limitReachedMessage: k,
|
|
636
|
+
rateLimitMessage: M,
|
|
637
|
+
onOpen: u,
|
|
638
|
+
onClose: _,
|
|
639
|
+
// Fields listed here are owned by code and won't be overwritten by
|
|
640
|
+
// dashboard config refreshes. Pass an object whose keys match widget
|
|
641
|
+
// config fields, e.g. { primaryColor: '#7c3aed', botName: 'Aria' }.
|
|
642
|
+
overrideSettings: g
|
|
643
|
+
} = t, h = E(null), C = E(null);
|
|
644
|
+
return N(e, () => ({
|
|
551
645
|
open: () => {
|
|
552
|
-
var
|
|
553
|
-
return (
|
|
646
|
+
var r;
|
|
647
|
+
return (r = h.current) == null ? void 0 : r.open();
|
|
554
648
|
},
|
|
555
649
|
close: () => {
|
|
556
|
-
var
|
|
557
|
-
return (
|
|
650
|
+
var r;
|
|
651
|
+
return (r = h.current) == null ? void 0 : r.close();
|
|
558
652
|
},
|
|
559
653
|
toggle: () => {
|
|
560
|
-
var
|
|
561
|
-
return (
|
|
654
|
+
var r;
|
|
655
|
+
return (r = h.current) == null ? void 0 : r.toggle();
|
|
562
656
|
},
|
|
563
657
|
clearHistory: () => {
|
|
564
|
-
var
|
|
565
|
-
return (
|
|
658
|
+
var r;
|
|
659
|
+
return (r = h.current) == null ? void 0 : r.clearHistory();
|
|
566
660
|
}
|
|
567
|
-
}), []),
|
|
568
|
-
if (!
|
|
661
|
+
}), []), x(() => {
|
|
662
|
+
if (!i) {
|
|
569
663
|
console.error("[CognitionDesk] apiKey prop is required");
|
|
570
664
|
return;
|
|
571
665
|
}
|
|
572
|
-
const
|
|
573
|
-
apiKey:
|
|
666
|
+
const r = new D({
|
|
667
|
+
apiKey: i,
|
|
574
668
|
widgetId: s,
|
|
575
|
-
assistantId:
|
|
669
|
+
assistantId: a,
|
|
576
670
|
theme: n,
|
|
577
|
-
primaryColor:
|
|
578
|
-
botName:
|
|
671
|
+
primaryColor: o,
|
|
672
|
+
botName: d,
|
|
579
673
|
botEmoji: c,
|
|
580
674
|
welcomeMessage: l,
|
|
581
|
-
placeholder:
|
|
582
|
-
streaming:
|
|
583
|
-
...
|
|
675
|
+
placeholder: f,
|
|
676
|
+
streaming: p,
|
|
677
|
+
...y ? { backendUrl: y } : {},
|
|
678
|
+
...g ? { overrideSettings: g } : {},
|
|
584
679
|
rateLimiting: {
|
|
585
680
|
enabled: !0,
|
|
586
|
-
maxMessagesPerSession:
|
|
681
|
+
maxMessagesPerSession: S,
|
|
587
682
|
maxMessagesPerMinute: H,
|
|
588
|
-
...
|
|
589
|
-
...
|
|
683
|
+
...k ? { limitReachedMessage: k } : {},
|
|
684
|
+
...M ? { rateLimitMessage: M } : {}
|
|
590
685
|
}
|
|
591
686
|
});
|
|
592
|
-
if (
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
},
|
|
597
|
-
T(...
|
|
687
|
+
if (u || _) {
|
|
688
|
+
const b = r.open.bind(r), T = r.close.bind(r);
|
|
689
|
+
r.open = (...v) => {
|
|
690
|
+
b(...v), u == null || u();
|
|
691
|
+
}, r.close = (...v) => {
|
|
692
|
+
T(...v), _ == null || _();
|
|
598
693
|
};
|
|
599
694
|
}
|
|
600
|
-
return Promise.resolve(
|
|
601
|
-
|
|
695
|
+
return Promise.resolve(r.mount(C.current)).then(() => {
|
|
696
|
+
h.current = r, m && r.open();
|
|
602
697
|
}), () => {
|
|
603
|
-
|
|
698
|
+
r.unmount(), h.current = null;
|
|
604
699
|
};
|
|
605
|
-
}, [
|
|
606
|
-
var
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
}, [n,
|
|
700
|
+
}, [i, s, a]), x(() => {
|
|
701
|
+
var b;
|
|
702
|
+
const r = h.current;
|
|
703
|
+
r && (r._cfg.theme = n, r._cfg.primaryColor = o, (b = r._applyConfig) == null || b.call(r));
|
|
704
|
+
}, [n, o]), x(() => {
|
|
705
|
+
const r = h.current;
|
|
706
|
+
!r || !g || r.updateSettings(g);
|
|
707
|
+
}, [g]), /* @__PURE__ */ P("div", { ref: C, "data-cognitiondesk-root": "" });
|
|
610
708
|
});
|
|
611
709
|
export {
|
|
612
710
|
V as CognitionDeskWidget,
|