@helpai/elements 0.30.0 → 0.30.1
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/elements-web-component.esm.js +27 -27
- package/elements-web-component.esm.js.map +4 -4
- package/elements.cjs.js +18 -18
- package/elements.cjs.js.map +4 -4
- package/elements.esm.js +18 -18
- package/elements.esm.js.map +4 -4
- package/elements.js +19 -19
- package/elements.js.map +4 -4
- package/index.d.ts +47 -26
- package/index.mjs +554 -524
- package/package.json +1 -1
- package/schema.d.ts +1 -1
- package/web-component.d.ts +11 -5
- package/web-component.mjs +335 -333
package/index.mjs
CHANGED
|
@@ -3,11 +3,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
|
|
5
5
|
// src/index.ts
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
// src/ui/app.tsx
|
|
9
|
-
import { useCallback as useCallback6, useEffect as useEffect17, useMemo as useMemo3, useRef as useRef9, useState as useState13 } from "preact/hooks";
|
|
10
|
-
import { useComputed as useComputed7, useSignal as useSignal2 } from "@preact/signals";
|
|
6
|
+
import { render } from "preact";
|
|
11
7
|
|
|
12
8
|
// src/core/brand.ts
|
|
13
9
|
var BRAND = {
|
|
@@ -935,20 +931,6 @@ var REACTIVE_ATTRS = [
|
|
|
935
931
|
...SPECIAL_REACTIVE_ATTRS
|
|
936
932
|
];
|
|
937
933
|
|
|
938
|
-
// src/core/handshake-shape.ts
|
|
939
|
-
function isPlainObject(raw) {
|
|
940
|
-
return !!raw && typeof raw === "object" && !Array.isArray(raw);
|
|
941
|
-
}
|
|
942
|
-
function isSiteConfigShape(raw) {
|
|
943
|
-
return isPlainObject(raw);
|
|
944
|
-
}
|
|
945
|
-
function isBlocksConfigShape(raw) {
|
|
946
|
-
if (!isPlainObject(raw)) return false;
|
|
947
|
-
if (raw.navigation !== void 0 && !Array.isArray(raw.navigation)) return false;
|
|
948
|
-
if (raw.linkCards !== void 0 && !Array.isArray(raw.linkCards)) return false;
|
|
949
|
-
return true;
|
|
950
|
-
}
|
|
951
|
-
|
|
952
934
|
// src/core/host-commands.ts
|
|
953
935
|
function commandEventName(cmd) {
|
|
954
936
|
return `${BRAND.cssPrefix}:${cmd}`;
|
|
@@ -969,6 +951,155 @@ function bindHostCommands(host, handlers) {
|
|
|
969
951
|
};
|
|
970
952
|
}
|
|
971
953
|
|
|
954
|
+
// src/core/ids.ts
|
|
955
|
+
function uuid7() {
|
|
956
|
+
const ts = Date.now();
|
|
957
|
+
const bytes = new Uint8Array(16);
|
|
958
|
+
bytes[0] = Math.floor(ts / 2 ** 40) & 255;
|
|
959
|
+
bytes[1] = Math.floor(ts / 2 ** 32) & 255;
|
|
960
|
+
bytes[2] = ts >>> 24 & 255;
|
|
961
|
+
bytes[3] = ts >>> 16 & 255;
|
|
962
|
+
bytes[4] = ts >>> 8 & 255;
|
|
963
|
+
bytes[5] = ts & 255;
|
|
964
|
+
fillRandom(bytes.subarray(6));
|
|
965
|
+
bytes[6] = bytes[6] & 15 | 112;
|
|
966
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
967
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
968
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
969
|
+
}
|
|
970
|
+
function fillRandom(view) {
|
|
971
|
+
if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
|
|
972
|
+
crypto.getRandomValues(view);
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
for (let i = 0; i < view.length; i++) view[i] = Math.floor(Math.random() * 256);
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// src/core/persistence.ts
|
|
979
|
+
var log2 = logger.scope("persistence");
|
|
980
|
+
function createPersistence(widgetId, storage = defaultStorage) {
|
|
981
|
+
const prefix = `${BRAND.cssPrefix}.${widgetId}`;
|
|
982
|
+
const KEY_VISITOR = `${prefix}.visitorId`;
|
|
983
|
+
const KEY_CONVERSATION = `${prefix}.conversationId`;
|
|
984
|
+
const KEY_USER_PREFS = `${prefix}.userPrefs`;
|
|
985
|
+
const KEY_PANEL_OPEN = `${prefix}.panelOpen`;
|
|
986
|
+
const KEY_PANEL_SIZE = `${prefix}.panelSize`;
|
|
987
|
+
const KEY_CALLOUT_DISMISSED = `${prefix}.calloutDismissed`;
|
|
988
|
+
const KEY_SIDEBAR_COLLAPSED = `${prefix}.sidebarCollapsed`;
|
|
989
|
+
const KEY_ACTIVE_MODULE = `${prefix}.activeModule`;
|
|
990
|
+
const KEY_FORMS_DONE = `${prefix}.formsDone`;
|
|
991
|
+
const persistence = {
|
|
992
|
+
getVisitorId() {
|
|
993
|
+
const existing = storage.get(KEY_VISITOR);
|
|
994
|
+
if (existing) return existing;
|
|
995
|
+
const minted = uuid7();
|
|
996
|
+
storage.set(KEY_VISITOR, minted);
|
|
997
|
+
return minted;
|
|
998
|
+
},
|
|
999
|
+
setVisitorId(id) {
|
|
1000
|
+
log2.debug("setVisitorId (rebind)", { id, widgetId });
|
|
1001
|
+
storage.set(KEY_VISITOR, id);
|
|
1002
|
+
},
|
|
1003
|
+
loadConversationId() {
|
|
1004
|
+
return storage.get(KEY_CONVERSATION) ?? void 0;
|
|
1005
|
+
},
|
|
1006
|
+
saveConversationId(id) {
|
|
1007
|
+
log2.trace("saveConversationId", { id, widgetId });
|
|
1008
|
+
if (id) storage.set(KEY_CONVERSATION, id);
|
|
1009
|
+
else storage.remove(KEY_CONVERSATION);
|
|
1010
|
+
},
|
|
1011
|
+
loadUserPrefs() {
|
|
1012
|
+
const raw = storage.get(KEY_USER_PREFS);
|
|
1013
|
+
if (!raw) return {};
|
|
1014
|
+
try {
|
|
1015
|
+
const parsed = JSON.parse(raw);
|
|
1016
|
+
return isPlainObject(parsed) ? parsed : {};
|
|
1017
|
+
} catch (error) {
|
|
1018
|
+
log2.warn("loadUserPrefs parse failed", { error });
|
|
1019
|
+
return {};
|
|
1020
|
+
}
|
|
1021
|
+
},
|
|
1022
|
+
saveUserPrefs(s) {
|
|
1023
|
+
try {
|
|
1024
|
+
storage.set(KEY_USER_PREFS, JSON.stringify(s));
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
log2.warn("saveUserPrefs serialise failed", { error });
|
|
1027
|
+
}
|
|
1028
|
+
},
|
|
1029
|
+
patchUserPrefs(patch) {
|
|
1030
|
+
const current = persistence.loadUserPrefs();
|
|
1031
|
+
persistence.saveUserPrefs({ ...current, ...patch });
|
|
1032
|
+
},
|
|
1033
|
+
loadPanelOpen() {
|
|
1034
|
+
const raw = storage.get(KEY_PANEL_OPEN);
|
|
1035
|
+
if (raw === "1") return true;
|
|
1036
|
+
if (raw === "0") return false;
|
|
1037
|
+
return null;
|
|
1038
|
+
},
|
|
1039
|
+
savePanelOpen(open) {
|
|
1040
|
+
storage.set(KEY_PANEL_OPEN, open ? "1" : "0");
|
|
1041
|
+
},
|
|
1042
|
+
loadPanelSize() {
|
|
1043
|
+
const raw = storage.get(KEY_PANEL_SIZE);
|
|
1044
|
+
return raw === "normal" || raw === "expanded" || raw === "fullscreen" ? raw : null;
|
|
1045
|
+
},
|
|
1046
|
+
savePanelSize(size) {
|
|
1047
|
+
storage.set(KEY_PANEL_SIZE, size);
|
|
1048
|
+
},
|
|
1049
|
+
loadCalloutDismissed(currentText) {
|
|
1050
|
+
if (!currentText) return false;
|
|
1051
|
+
const dismissedText = storage.get(KEY_CALLOUT_DISMISSED);
|
|
1052
|
+
return !!dismissedText && dismissedText === currentText;
|
|
1053
|
+
},
|
|
1054
|
+
saveCalloutDismissed(currentText) {
|
|
1055
|
+
if (currentText) storage.set(KEY_CALLOUT_DISMISSED, currentText);
|
|
1056
|
+
else storage.remove(KEY_CALLOUT_DISMISSED);
|
|
1057
|
+
},
|
|
1058
|
+
loadSidebarCollapsed() {
|
|
1059
|
+
const raw = storage.get(KEY_SIDEBAR_COLLAPSED);
|
|
1060
|
+
if (raw === "1") return true;
|
|
1061
|
+
if (raw === "0") return false;
|
|
1062
|
+
return null;
|
|
1063
|
+
},
|
|
1064
|
+
saveSidebarCollapsed(collapsed) {
|
|
1065
|
+
storage.set(KEY_SIDEBAR_COLLAPSED, collapsed ? "1" : "0");
|
|
1066
|
+
},
|
|
1067
|
+
loadActiveModule() {
|
|
1068
|
+
return storage.get(KEY_ACTIVE_MODULE) || null;
|
|
1069
|
+
},
|
|
1070
|
+
saveActiveModule(id) {
|
|
1071
|
+
storage.set(KEY_ACTIVE_MODULE, id);
|
|
1072
|
+
},
|
|
1073
|
+
loadFormsDone() {
|
|
1074
|
+
const raw = storage.get(KEY_FORMS_DONE);
|
|
1075
|
+
if (!raw) return {};
|
|
1076
|
+
try {
|
|
1077
|
+
const parsed = JSON.parse(raw);
|
|
1078
|
+
return isPlainObject(parsed) ? parsed : {};
|
|
1079
|
+
} catch (error) {
|
|
1080
|
+
log2.warn("loadFormsDone parse failed", { error });
|
|
1081
|
+
return {};
|
|
1082
|
+
}
|
|
1083
|
+
},
|
|
1084
|
+
saveFormDone(id) {
|
|
1085
|
+
try {
|
|
1086
|
+
const done = persistence.loadFormsDone();
|
|
1087
|
+
done[id] = Date.now();
|
|
1088
|
+
storage.set(KEY_FORMS_DONE, JSON.stringify(done));
|
|
1089
|
+
} catch (error) {
|
|
1090
|
+
log2.warn("saveFormDone serialise failed", { error });
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
clearConversation() {
|
|
1094
|
+
storage.remove(KEY_CONVERSATION);
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
return persistence;
|
|
1098
|
+
}
|
|
1099
|
+
function isPlainObject(v) {
|
|
1100
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
972
1103
|
// src/styles/tokens.css
|
|
973
1104
|
var tokens_default = ':host{--__P__-accent-user: __BRAND_ACCENT__;--__P__-accent: var(--__P__-accent-user);--__P__-accent-text-user: __BRAND_ACCENT_TEXT__;--__P__-accent-text: var(--__P__-accent-text-user);--__P__-radius: __BRAND_RADIUS__;--__P__-radius-sm: 8px;--__P__-radius-md: 10px;--__P__-radius-lg: 16px;--__P__-font: __BRAND_FONT__;--__P__-font-display: var(--__P__-font);--__P__-font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;--__P__-bg: oklch(1 0 0);--__P__-bg-elevated: oklch(.9789 .0029 278.3);--__P__-surface: var(--__P__-bg-elevated);--__P__-muted: var(--__P__-fg-muted);--__P__-hover: oklch(.1686 .011 278.3 / .06);--__P__-fg: oklch(.1686 .011 278.3);--__P__-fg-muted: oklch(.4932 .0301 278.3);--__P__-border: oklch(.9312 .0084 278.3);--__P__-border-strong: oklch(.8757 .0131 278.3);--__P__-bubble-user: var(--__P__-accent);--__P__-bubble-user-text: var(--__P__-accent-text);--__P__-bubble-assistant: oklch(.9638 .0058 278.3);--__P__-bubble-assistant-text: var(--__P__-fg);--__P__-on-accent: var(--__P__-accent-text);--__P__-success: oklch(.6456 .1654 151.53);--__P__-warning: oklch(.7135 .1494 74.05);--__P__-danger: oklch(.5966 .1818 24.51);--__P__-danger-text: oklch(.5054 .1905 27.52);--__P__-danger-bg: oklch(.5966 .1818 24.51 / .1);--__P__-neutral: oklch(.7137 .0192 278.3);--__P__-focus: var(--__P__-accent);--__P__-shadow-panel: 0 8px 24px -8px rgba(13, 15, 20, .18), 0 24px 64px -24px rgba(13, 15, 20, .24);--__P__-shadow-card: 0 1px 2px rgba(13, 15, 20, .06), 0 4px 12px -6px rgba(13, 15, 20, .12);--__P__-backdrop: oklch(.1686 .011 278.3 / .55);--__P__-shadow-fab: 0 6px 16px -4px color-mix(in oklch, var(--__P__-accent) 45%, transparent), 0 12px 32px -12px rgba(13, 15, 20, .25);--__P__-z-fab: 2147483600;--__P__-z-panel: 2147483601;--__P__-panel-w: 380px;--__P__-panel-h: 600px;--__P__-fab-size: 56px;--__P__-space-1: 4px;--__P__-space-2: 8px;--__P__-space-3: 12px;--__P__-space-4: 16px;--__P__-space-5: 20px;--__P__-space-6: 24px;--__P__-space-8: 32px;--__P__-text-scale: 1;--__P__-text-xs: calc(12px * var(--__P__-text-scale));--__P__-text-sm: calc(13px * var(--__P__-text-scale));--__P__-text-base: calc(15px * var(--__P__-text-scale));--__P__-text-md: calc(16px * var(--__P__-text-scale));--__P__-text-lg: calc(18px * var(--__P__-text-scale));--__P__-text-xl: calc(22px * var(--__P__-text-scale));--__P__-text-2xl: calc(30px * var(--__P__-text-scale))}:host([data-text-size="small"]){--__P__-text-scale: .9}:host([data-text-size="large"]){--__P__-text-scale: 1.15}:host{--__P__-ease: cubic-bezier(.2, .7, .2, 1);--__P__-ease-out: cubic-bezier(.2, .7, .2, 1);--__P__-ease-in: cubic-bezier(.4, 0, 1, 1);--__P__-ease-in-out: cubic-bezier(.65, 0, .35, 1);--__P__-dur-quick: .12s;--__P__-dur-base: .22s;--__P__-dur-slow: .32s;font-family:var(--__P__-font);color:var(--__P__-fg);color-scheme:light;--__P__-color-scheme: light}:host([data-theme="dark"]){--__P__-bg: oklch(.1783 .0128 278.3);--__P__-bg-elevated: oklch(.2232 .0182 278.3);--__P__-fg: oklch(.9368 .01 278.3);--__P__-fg-muted: oklch(.7048 .0296 278.3);--__P__-border: oklch(.2752 .0266 278.3);--__P__-border-strong: oklch(.335 .0291 278.3);--__P__-hover: oklch(.9368 .01 278.3 / .08);--__P__-bubble-assistant: oklch(.2474 .0311 278.3);--__P__-bubble-assistant-text: var(--__P__-fg);--__P__-danger-text: oklch(.8077 .1035 19.57);--__P__-danger-bg: oklch(.5966 .1818 24.51 / .18);--__P__-shadow-panel: 0 8px 24px -8px rgba(0, 0, 0, .6), 0 24px 64px -24px rgba(0, 0, 0, .7);--__P__-shadow-card: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 12px -6px rgba(0, 0, 0, .5);--__P__-backdrop: rgba(0, 0, 0, .65);color-scheme:dark;--__P__-color-scheme: dark}@media(prefers-color-scheme:dark){:host([data-theme="auto"]){--__P__-bg: oklch(.1783 .0128 278.3);--__P__-bg-elevated: oklch(.2232 .0182 278.3);--__P__-fg: oklch(.9368 .01 278.3);--__P__-fg-muted: oklch(.7048 .0296 278.3);--__P__-border: oklch(.2752 .0266 278.3);--__P__-border-strong: oklch(.335 .0291 278.3);--__P__-hover: oklch(.9368 .01 278.3 / .08);--__P__-bubble-assistant: oklch(.2474 .0311 278.3);--__P__-bubble-assistant-text: var(--__P__-fg);--__P__-shadow-panel: 0 8px 24px -8px rgba(0, 0, 0, .6), 0 24px 64px -24px rgba(0, 0, 0, .7);color-scheme:dark;--__P__-color-scheme: dark}}@supports (color: oklch(from red l c h)){:host{--__P__-accent: oklch(from var(--__P__-accent-user) clamp(.3, l, .62) c h);--__P__-accent-text: oklch(from var(--__P__-accent) clamp(0, (l / .623 - 1) * -infinity, 1) 0 h)}:host([data-theme="dark"]){--__P__-accent: oklch(from var(--__P__-accent-user) clamp(.65, l, .85) c h)}@media(prefers-color-scheme:dark){:host([data-theme="auto"]){--__P__-accent: oklch(from var(--__P__-accent-user) clamp(.65, l, .85) c h)}}}@media(prefers-reduced-motion:reduce){:host{--__P__-dur-quick: 1ms;--__P__-dur-base: 1ms;--__P__-dur-slow: 1ms}}\n';
|
|
974
1105
|
|
|
@@ -993,7 +1124,7 @@ var FONT = true ? "Inter, system-ui, -apple-system, 'Segoe UI', sans-serif" : "I
|
|
|
993
1124
|
var CSS_TEXT = [tokens_default, reset_default, panel_default, standalone_default, page_default].join("\n").replace(/__P__/g, PREFIX).replaceAll("__BRAND_ACCENT_TEXT__", ACCENT_TEXT).replaceAll("__BRAND_ACCENT__", ACCENT).replaceAll("__BRAND_RADIUS__", RADIUS).replaceAll("__BRAND_FONT__", FONT);
|
|
994
1125
|
|
|
995
1126
|
// src/shadow/mount.ts
|
|
996
|
-
var
|
|
1127
|
+
var log3 = logger.scope("mount");
|
|
997
1128
|
var sheetsByDocument = /* @__PURE__ */ new WeakMap();
|
|
998
1129
|
var HOST_CSS = {
|
|
999
1130
|
floating: "all: initial; position: fixed; z-index: 2147483600;",
|
|
@@ -1010,7 +1141,7 @@ function hostPositionForMode(mode) {
|
|
|
1010
1141
|
}
|
|
1011
1142
|
function createShadowMount(opts = {}) {
|
|
1012
1143
|
const position = opts.position ?? "flow";
|
|
1013
|
-
|
|
1144
|
+
log3.debug("createShadowMount", { position, hasTarget: !!opts.target, hasHost: !!opts.existingHost });
|
|
1014
1145
|
const tagName = `${BRAND.cssPrefix}-chat-host`;
|
|
1015
1146
|
if (typeof customElements !== "undefined" && !customElements.get(tagName)) {
|
|
1016
1147
|
customElements.define(tagName, class extends HTMLElement {
|
|
@@ -1094,6 +1225,123 @@ function applyHostAttributes(host, resolved) {
|
|
|
1094
1225
|
applySize(host, resolved.size);
|
|
1095
1226
|
}
|
|
1096
1227
|
|
|
1228
|
+
// src/shadow/iframe-mount.ts
|
|
1229
|
+
var log4 = logger.scope("iframe");
|
|
1230
|
+
var IFRAME_SRCDOC = '<!doctype html><html><head><meta charset="utf-8"><style>html,body{margin:0;padding:0;background:transparent;overflow:hidden}</style></head><body></body></html>';
|
|
1231
|
+
function createIframeMount(opts, position, initialMode = "closed", layoutMode = "floating", target = null) {
|
|
1232
|
+
log4.debug("createIframeMount", { position, initialMode, layoutMode, hasTarget: !!target });
|
|
1233
|
+
const iframe = document.createElement("iframe");
|
|
1234
|
+
iframe.title = `${BRAND.name} chat`;
|
|
1235
|
+
iframe.setAttribute("allow", "microphone; clipboard-write");
|
|
1236
|
+
sizeIframe(iframe, position, initialMode, layoutMode);
|
|
1237
|
+
const parent = layoutMode === "inline" && target ? target : document.body;
|
|
1238
|
+
parent.appendChild(iframe);
|
|
1239
|
+
const doc = iframe.contentDocument;
|
|
1240
|
+
if (!doc) throw new Error("iframe contentDocument unavailable (cross-origin?)");
|
|
1241
|
+
doc.open();
|
|
1242
|
+
doc.write(IFRAME_SRCDOC);
|
|
1243
|
+
doc.close();
|
|
1244
|
+
const mount2 = createShadowMount({ ...opts, target: doc.body });
|
|
1245
|
+
const mo = new MutationObserver(() => {
|
|
1246
|
+
sizeIframe(iframe, position, mount2.hostElement.dataset.mode ?? "closed", layoutMode);
|
|
1247
|
+
});
|
|
1248
|
+
mo.observe(mount2.hostElement, { attributes: true, attributeFilter: ["data-mode"] });
|
|
1249
|
+
return {
|
|
1250
|
+
...mount2,
|
|
1251
|
+
iframeElement: iframe,
|
|
1252
|
+
destroy() {
|
|
1253
|
+
mo.disconnect();
|
|
1254
|
+
mount2.destroy();
|
|
1255
|
+
iframe.remove();
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
var BASE_CSS = "border:0;background:transparent;z-index:2147483647;pointer-events:auto;";
|
|
1260
|
+
var FLOATING_SIZE_BY_MODE = {
|
|
1261
|
+
closed: { w: "88px", h: "88px" },
|
|
1262
|
+
expanded: { w: "min(calc(100vw - 32px), 680px)", h: "min(calc(100vh - 32px), 860px)" },
|
|
1263
|
+
// `open` (normal) — also the fallback for any other non-fullscreen state.
|
|
1264
|
+
open: { w: "min(calc(100vw - 32px), 440px)", h: "min(calc(100vh - 32px), 700px)" }
|
|
1265
|
+
};
|
|
1266
|
+
function sizeIframe(iframe, position, mode, layoutMode) {
|
|
1267
|
+
if (mode === "fullscreen" || layoutMode === "standalone") {
|
|
1268
|
+
iframe.style.cssText = `${BASE_CSS}position:fixed;inset:0;width:100vw;height:100vh;`;
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
if (layoutMode === "inline") {
|
|
1272
|
+
iframe.style.cssText = `${BASE_CSS}position:static;display:block;width:100%;height:100%;`;
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
const compact = typeof matchMedia === "function" && matchMedia("(max-width: 640px)").matches;
|
|
1276
|
+
if (compact && (mode === "open" || mode === "expanded")) {
|
|
1277
|
+
iframe.style.cssText = `${BASE_CSS}position:fixed;inset:0;width:100vw;height:100vh;`;
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1280
|
+
const vKey = position.startsWith("top-") ? "top" : "bottom";
|
|
1281
|
+
const hKey = position.endsWith("-left") ? "left" : "right";
|
|
1282
|
+
const { w, h: h2 } = FLOATING_SIZE_BY_MODE[mode] ?? FLOATING_SIZE_BY_MODE.open;
|
|
1283
|
+
iframe.style.cssText = `${BASE_CSS}position:fixed;${vKey}:16px;${hKey}:16px;width:${w};height:${h2};`;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// src/core/events.ts
|
|
1287
|
+
var EventBus = class {
|
|
1288
|
+
constructor() {
|
|
1289
|
+
__publicField(this, "handlers", /* @__PURE__ */ new Map());
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Register a listener for `name`.
|
|
1293
|
+
* @returns an `off` function that removes this listener.
|
|
1294
|
+
*/
|
|
1295
|
+
on(name, fn) {
|
|
1296
|
+
let set = this.handlers.get(name);
|
|
1297
|
+
if (!set) {
|
|
1298
|
+
set = /* @__PURE__ */ new Set();
|
|
1299
|
+
this.handlers.set(name, set);
|
|
1300
|
+
}
|
|
1301
|
+
set.add(fn);
|
|
1302
|
+
return () => this.handlers.get(name)?.delete(fn);
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Dispatch an event synchronously to all listeners.
|
|
1306
|
+
* Listener errors are swallowed — the widget must not crash on user callbacks.
|
|
1307
|
+
*/
|
|
1308
|
+
emit(name, payload) {
|
|
1309
|
+
const set = this.handlers.get(name);
|
|
1310
|
+
if (!set) return;
|
|
1311
|
+
for (const fn of set) {
|
|
1312
|
+
try {
|
|
1313
|
+
fn(payload);
|
|
1314
|
+
} catch {
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
/** Remove every listener. Called by the instance `destroy()`. */
|
|
1319
|
+
clear() {
|
|
1320
|
+
this.handlers.clear();
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
|
|
1324
|
+
// src/core/boot.ts
|
|
1325
|
+
import { h, render as renderPreact } from "preact";
|
|
1326
|
+
|
|
1327
|
+
// src/ui/app.tsx
|
|
1328
|
+
import { useCallback as useCallback6, useEffect as useEffect17, useMemo as useMemo3, useRef as useRef9, useState as useState13 } from "preact/hooks";
|
|
1329
|
+
import { useComputed as useComputed7, useSignal as useSignal2 } from "@preact/signals";
|
|
1330
|
+
|
|
1331
|
+
// src/core/handshake-shape.ts
|
|
1332
|
+
function isPlainObject2(raw) {
|
|
1333
|
+
return !!raw && typeof raw === "object" && !Array.isArray(raw);
|
|
1334
|
+
}
|
|
1335
|
+
function isSiteConfigShape(raw) {
|
|
1336
|
+
return isPlainObject2(raw);
|
|
1337
|
+
}
|
|
1338
|
+
function isBlocksConfigShape(raw) {
|
|
1339
|
+
if (!isPlainObject2(raw)) return false;
|
|
1340
|
+
if (raw.navigation !== void 0 && !Array.isArray(raw.navigation)) return false;
|
|
1341
|
+
if (raw.linkCards !== void 0 && !Array.isArray(raw.linkCards)) return false;
|
|
1342
|
+
return true;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1097
1345
|
// src/ui/host-mode.ts
|
|
1098
1346
|
function computeHostMode(configured, panelSize, isOpen) {
|
|
1099
1347
|
if (configured === "page") return "page";
|
|
@@ -1144,30 +1392,6 @@ function createAuth(opts) {
|
|
|
1144
1392
|
};
|
|
1145
1393
|
}
|
|
1146
1394
|
|
|
1147
|
-
// src/core/ids.ts
|
|
1148
|
-
function uuid7() {
|
|
1149
|
-
const ts = Date.now();
|
|
1150
|
-
const bytes = new Uint8Array(16);
|
|
1151
|
-
bytes[0] = Math.floor(ts / 2 ** 40) & 255;
|
|
1152
|
-
bytes[1] = Math.floor(ts / 2 ** 32) & 255;
|
|
1153
|
-
bytes[2] = ts >>> 24 & 255;
|
|
1154
|
-
bytes[3] = ts >>> 16 & 255;
|
|
1155
|
-
bytes[4] = ts >>> 8 & 255;
|
|
1156
|
-
bytes[5] = ts & 255;
|
|
1157
|
-
fillRandom(bytes.subarray(6));
|
|
1158
|
-
bytes[6] = bytes[6] & 15 | 112;
|
|
1159
|
-
bytes[8] = bytes[8] & 63 | 128;
|
|
1160
|
-
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
1161
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
1162
|
-
}
|
|
1163
|
-
function fillRandom(view) {
|
|
1164
|
-
if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
|
|
1165
|
-
crypto.getRandomValues(view);
|
|
1166
|
-
return;
|
|
1167
|
-
}
|
|
1168
|
-
for (let i = 0; i < view.length; i++) view[i] = Math.floor(Math.random() * 256);
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
1395
|
// src/stream/types.ts
|
|
1172
1396
|
var StreamError = class extends Error {
|
|
1173
1397
|
constructor(message, code, status, cause) {
|
|
@@ -1180,7 +1404,7 @@ var StreamError = class extends Error {
|
|
|
1180
1404
|
};
|
|
1181
1405
|
|
|
1182
1406
|
// src/stream/parser.ts
|
|
1183
|
-
var
|
|
1407
|
+
var log5 = logger.scope("parser");
|
|
1184
1408
|
async function* parseChatStream(response, signal7) {
|
|
1185
1409
|
if (!response.ok) {
|
|
1186
1410
|
const text = await response.text().catch(() => "");
|
|
@@ -1232,10 +1456,10 @@ ${part}` : part;
|
|
|
1232
1456
|
if (!dataPayload || dataPayload === "[DONE]") return null;
|
|
1233
1457
|
try {
|
|
1234
1458
|
const chunk = JSON.parse(dataPayload);
|
|
1235
|
-
|
|
1459
|
+
log5.trace("chunk", { type: chunk.type, eventId });
|
|
1236
1460
|
return { chunk, eventId };
|
|
1237
1461
|
} catch (err) {
|
|
1238
|
-
|
|
1462
|
+
log5.trace("frame parse failed", { err, payload: dataPayload.slice(0, 200) });
|
|
1239
1463
|
return null;
|
|
1240
1464
|
}
|
|
1241
1465
|
}
|
|
@@ -1390,7 +1614,7 @@ function messageToWireParts(m) {
|
|
|
1390
1614
|
}
|
|
1391
1615
|
|
|
1392
1616
|
// src/stream/transport.ts
|
|
1393
|
-
var
|
|
1617
|
+
var log6 = logger.scope("transport");
|
|
1394
1618
|
var MAX_RESUME_ATTEMPTS = 3;
|
|
1395
1619
|
var RESUME_BACKOFF_MS = 400;
|
|
1396
1620
|
var CONTENT_CACHE_TTL_MS = 6e4;
|
|
@@ -1516,13 +1740,13 @@ var AgentTransport = class {
|
|
|
1516
1740
|
}
|
|
1517
1741
|
/** One-shot runtime bootstrap. Called once after the widget mounts. */
|
|
1518
1742
|
async handshake(body) {
|
|
1519
|
-
|
|
1743
|
+
log6.debug("handshake \u2192", {
|
|
1520
1744
|
visitorId: body.visitorId,
|
|
1521
1745
|
conversationId: body.conversationId,
|
|
1522
1746
|
locale: body.locale
|
|
1523
1747
|
});
|
|
1524
1748
|
const res = await this.postJson(DEFAULT_PATHS.handshake, body, "handshake");
|
|
1525
|
-
|
|
1749
|
+
log6.debug("handshake \u2190", {
|
|
1526
1750
|
visitorId: res.visitorId,
|
|
1527
1751
|
conversationId: res.conversationId,
|
|
1528
1752
|
hasWelcome: !!res.welcome,
|
|
@@ -1530,7 +1754,7 @@ var AgentTransport = class {
|
|
|
1530
1754
|
rebind: res.rebind
|
|
1531
1755
|
});
|
|
1532
1756
|
if (!isHandshakeResponseShape(res)) {
|
|
1533
|
-
|
|
1757
|
+
log6.warn("handshake response did not match expected shape; using raw response", { response: res });
|
|
1534
1758
|
}
|
|
1535
1759
|
this.visitorId = res.visitorId ?? body.visitorId;
|
|
1536
1760
|
this.conversationId = res.conversationId;
|
|
@@ -1538,11 +1762,11 @@ var AgentTransport = class {
|
|
|
1538
1762
|
}
|
|
1539
1763
|
/** Upload a file attachment. Returns the `{id, url}` the backend assigns. */
|
|
1540
1764
|
async uploadFile(file) {
|
|
1541
|
-
|
|
1765
|
+
log6.debug("uploadFile \u2192", { name: file.name, size: file.size, type: file.type });
|
|
1542
1766
|
const fd = new FormData();
|
|
1543
1767
|
fd.append("file", file, file.name);
|
|
1544
1768
|
const res = await this.postForm(this.uploadPath, fd, "upload");
|
|
1545
|
-
|
|
1769
|
+
log6.debug("uploadFile \u2190", { id: res.id, url: res.url });
|
|
1546
1770
|
return res;
|
|
1547
1771
|
}
|
|
1548
1772
|
/**
|
|
@@ -1550,12 +1774,12 @@ var AgentTransport = class {
|
|
|
1550
1774
|
* Only used when `features.voice === 'server'`.
|
|
1551
1775
|
*/
|
|
1552
1776
|
async transcribe(audio, mimeType = "audio/webm") {
|
|
1553
|
-
|
|
1777
|
+
log6.debug("transcribe \u2192", { size: audio.size, mimeType });
|
|
1554
1778
|
const fd = new FormData();
|
|
1555
1779
|
fd.append("audio", audio, `voice.${extensionFor(mimeType)}`);
|
|
1556
1780
|
fd.append("mimeType", mimeType);
|
|
1557
1781
|
const res = await this.postForm(this.transcribePath, fd, "transcribe");
|
|
1558
|
-
|
|
1782
|
+
log6.debug("transcribe \u2190", { textLen: res.text.length });
|
|
1559
1783
|
return res;
|
|
1560
1784
|
}
|
|
1561
1785
|
async listConversations(params = {}) {
|
|
@@ -1563,14 +1787,14 @@ var AgentTransport = class {
|
|
|
1563
1787
|
if (params.visitorId) url.searchParams.set("visitorId", params.visitorId);
|
|
1564
1788
|
if (params.limit) url.searchParams.set("limit", String(params.limit));
|
|
1565
1789
|
if (params.cursor) url.searchParams.set("cursor", params.cursor);
|
|
1566
|
-
|
|
1790
|
+
log6.debug("listConversations \u2192", {
|
|
1567
1791
|
visitorId: params.visitorId ?? this.visitorId,
|
|
1568
1792
|
limit: params.limit,
|
|
1569
1793
|
cursor: params.cursor
|
|
1570
1794
|
});
|
|
1571
1795
|
const res = await this.getJson(url.toString(), "listConversations");
|
|
1572
1796
|
const conversations = res.conversations ?? [];
|
|
1573
|
-
|
|
1797
|
+
log6.debug("listConversations \u2190", { count: conversations.length, nextCursor: res.nextCursor });
|
|
1574
1798
|
return {
|
|
1575
1799
|
conversations: conversations.map((conversation) => ({
|
|
1576
1800
|
conversationId: conversation.conversationId,
|
|
@@ -1586,10 +1810,10 @@ var AgentTransport = class {
|
|
|
1586
1810
|
async loadConversation(conversationId) {
|
|
1587
1811
|
const url = new URL(this.url(DEFAULT_PATHS.listMessages));
|
|
1588
1812
|
url.searchParams.set("conversationId", conversationId);
|
|
1589
|
-
|
|
1813
|
+
log6.debug("loadConversation \u2192", { conversationId, visitorId: this.visitorId });
|
|
1590
1814
|
const res = await this.getJson(url.toString(), "loadConversation");
|
|
1591
1815
|
const messages = res.messages ?? [];
|
|
1592
|
-
|
|
1816
|
+
log6.debug("loadConversation \u2190", {
|
|
1593
1817
|
conversationId: res.conversationId,
|
|
1594
1818
|
canContinue: res.canContinue,
|
|
1595
1819
|
messageCount: messages.length,
|
|
@@ -1611,11 +1835,11 @@ var AgentTransport = class {
|
|
|
1611
1835
|
*/
|
|
1612
1836
|
async markRead(conversationId) {
|
|
1613
1837
|
if (!this.visitorId || !conversationId) return;
|
|
1614
|
-
|
|
1838
|
+
log6.debug("markRead \u2192", { conversationId, visitorId: this.visitorId });
|
|
1615
1839
|
try {
|
|
1616
1840
|
await this.postJson(DEFAULT_PATHS.markRead, { conversationId }, "markRead");
|
|
1617
1841
|
} catch (err) {
|
|
1618
|
-
|
|
1842
|
+
log6.debug("markRead failed (non-fatal)", { err });
|
|
1619
1843
|
}
|
|
1620
1844
|
}
|
|
1621
1845
|
/** Fetch content rows by filter. `GET /pai/content` (data-API), TTL-cached. */
|
|
@@ -1623,7 +1847,7 @@ var AgentTransport = class {
|
|
|
1623
1847
|
const key = JSON.stringify(query, Object.keys(query).toSorted());
|
|
1624
1848
|
const cached = this.contentCache.get(key);
|
|
1625
1849
|
if (cached && Date.now() - cached.at < CONTENT_CACHE_TTL_MS) {
|
|
1626
|
-
|
|
1850
|
+
log6.debug("listContent \u2192 cache", query);
|
|
1627
1851
|
return cached.result;
|
|
1628
1852
|
}
|
|
1629
1853
|
const result = this.fetchContent(query).catch((err) => {
|
|
@@ -1639,10 +1863,10 @@ var AgentTransport = class {
|
|
|
1639
1863
|
if (value === void 0) continue;
|
|
1640
1864
|
url.searchParams.set(key, Array.isArray(value) ? value.join(",") : String(value));
|
|
1641
1865
|
}
|
|
1642
|
-
|
|
1866
|
+
log6.debug("listContent \u2192", query);
|
|
1643
1867
|
const res = await this.getJson(url.toString(), "listContent");
|
|
1644
1868
|
const items = res.items ?? [];
|
|
1645
|
-
|
|
1869
|
+
log6.debug("listContent \u2190", { count: items.length, total: res.pagination?.total });
|
|
1646
1870
|
return { ...res, items };
|
|
1647
1871
|
}
|
|
1648
1872
|
/**
|
|
@@ -1660,21 +1884,21 @@ var AgentTransport = class {
|
|
|
1660
1884
|
async bootstrap(conversationId) {
|
|
1661
1885
|
const url = new URL(this.dataUrl(DEFAULT_PATHS.bootstrap));
|
|
1662
1886
|
if (conversationId) url.searchParams.set("conversationId", conversationId);
|
|
1663
|
-
|
|
1887
|
+
log6.debug("bootstrap \u2192", { conversationId: conversationId ?? this.conversationId });
|
|
1664
1888
|
const res = await this.getJson(url.toString(), "bootstrap");
|
|
1665
1889
|
const forms = res.forms ?? [];
|
|
1666
1890
|
const formSubmissions = res.formSubmissions ?? [];
|
|
1667
|
-
|
|
1891
|
+
log6.debug("bootstrap \u2190", { forms: forms.length, formSubmissions: formSubmissions.length });
|
|
1668
1892
|
return { forms, formSubmissions };
|
|
1669
1893
|
}
|
|
1670
1894
|
async saveUserPrefs(userPrefs) {
|
|
1671
|
-
|
|
1895
|
+
log6.debug("saveUserPrefs \u2192", {
|
|
1672
1896
|
visitorId: this.visitorId,
|
|
1673
1897
|
conversationId: this.conversationId,
|
|
1674
1898
|
settingsKeys: Object.keys(userPrefs)
|
|
1675
1899
|
});
|
|
1676
1900
|
const res = await this.postJson(DEFAULT_PATHS.updateSettings, { userPrefs }, "saveUserPrefs");
|
|
1677
|
-
|
|
1901
|
+
log6.debug("saveUserPrefs \u2190", { ok: res.ok });
|
|
1678
1902
|
return res;
|
|
1679
1903
|
}
|
|
1680
1904
|
get uploadPath() {
|
|
@@ -1695,15 +1919,15 @@ var AgentTransport = class {
|
|
|
1695
1919
|
* that doesn't implement the endpoint) is non-fatal, so callers don't await.
|
|
1696
1920
|
*/
|
|
1697
1921
|
async submitForm(body) {
|
|
1698
|
-
|
|
1922
|
+
log6.debug("submitForm \u2192", { formId: body.formId, trigger: body.trigger, fields: Object.keys(body.values).length });
|
|
1699
1923
|
try {
|
|
1700
1924
|
await this.postJson(this.dataUrl(this.submitFormPath), body, "submitForm");
|
|
1701
1925
|
} catch (err) {
|
|
1702
|
-
|
|
1926
|
+
log6.debug("submitForm failed (non-fatal)", { err });
|
|
1703
1927
|
}
|
|
1704
1928
|
}
|
|
1705
1929
|
sendMessage(body) {
|
|
1706
|
-
|
|
1930
|
+
log6.debug("message \u2192", {
|
|
1707
1931
|
conversationId: body.conversationId,
|
|
1708
1932
|
visitorId: body.visitorId,
|
|
1709
1933
|
messageCount: body.messages.length,
|
|
@@ -1783,17 +2007,17 @@ var AgentTransport = class {
|
|
|
1783
2007
|
});
|
|
1784
2008
|
} catch (err) {
|
|
1785
2009
|
if (ctrl.signal.aborted) return;
|
|
1786
|
-
|
|
2010
|
+
log6.debug("resume fetch failed \u2014 retrying", { attempt, err });
|
|
1787
2011
|
continue;
|
|
1788
2012
|
}
|
|
1789
2013
|
if (res.status === 204 || !res.ok) {
|
|
1790
|
-
|
|
2014
|
+
log6.debug("resume \u2192 no in-flight stream", { status: res.status });
|
|
1791
2015
|
return;
|
|
1792
2016
|
}
|
|
1793
2017
|
const before = seenIds.size;
|
|
1794
2018
|
if (yield* this.drain(parseChatStream(res, ctrl.signal), seenIds, ctrl)) return;
|
|
1795
2019
|
if (seenIds.size === before) {
|
|
1796
|
-
|
|
2020
|
+
log6.debug("resume \u2192 stream closed with no new events; nothing to resume");
|
|
1797
2021
|
return;
|
|
1798
2022
|
}
|
|
1799
2023
|
}
|
|
@@ -1820,14 +2044,14 @@ var AgentTransport = class {
|
|
|
1820
2044
|
} catch (err) {
|
|
1821
2045
|
if (ctrl.signal.aborted) return true;
|
|
1822
2046
|
if (err instanceof StreamError && err.status !== void 0) throw err;
|
|
1823
|
-
|
|
2047
|
+
log6.debug("stream segment dropped", { err });
|
|
1824
2048
|
}
|
|
1825
2049
|
return false;
|
|
1826
2050
|
}
|
|
1827
2051
|
/** Abort + fire-and-forget POST to `/pai/cancel-stream`. Idempotent. */
|
|
1828
2052
|
cancelStream(ctrl, conversationId) {
|
|
1829
2053
|
if (ctrl.signal.aborted) return;
|
|
1830
|
-
|
|
2054
|
+
log6.debug("cancel stream", { conversationId, visitorId: this.visitorId });
|
|
1831
2055
|
ctrl.abort();
|
|
1832
2056
|
if (!this.visitorId || !conversationId) return;
|
|
1833
2057
|
this.fetchImpl(this.url(DEFAULT_PATHS.cancelStream), {
|
|
@@ -1836,7 +2060,7 @@ var AgentTransport = class {
|
|
|
1836
2060
|
headers: { "content-type": "application/json", ...this.opts.auth.headers() },
|
|
1837
2061
|
body: JSON.stringify(this.withEnvelope({})),
|
|
1838
2062
|
keepalive: true
|
|
1839
|
-
}).catch((err) =>
|
|
2063
|
+
}).catch((err) => log6.debug("cancel POST failed (non-fatal)", { err }));
|
|
1840
2064
|
}
|
|
1841
2065
|
// ---- Low-level fetch helpers ------------------------------------------
|
|
1842
2066
|
async *openMessageStream(body, signal7) {
|
|
@@ -1918,13 +2142,13 @@ var AgentTransport = class {
|
|
|
1918
2142
|
if (attempt >= MAX_REQUEST_RETRIES) {
|
|
1919
2143
|
throw new StreamError(`${label} failed: network error`, "network", void 0, err);
|
|
1920
2144
|
}
|
|
1921
|
-
|
|
2145
|
+
log6.debug("request network error \u2014 retrying", { label, attempt });
|
|
1922
2146
|
await sleep(backoffMs(attempt));
|
|
1923
2147
|
continue;
|
|
1924
2148
|
}
|
|
1925
2149
|
if (res.ok || !RETRYABLE_STATUS.has(res.status) || attempt >= MAX_REQUEST_RETRIES) return res;
|
|
1926
2150
|
const wait = retryAfterMs(res.headers) ?? backoffMs(attempt);
|
|
1927
|
-
|
|
2151
|
+
log6.debug("request retryable status \u2014 retrying", { label, status: res.status, attempt, wait });
|
|
1928
2152
|
await sleep(wait);
|
|
1929
2153
|
}
|
|
1930
2154
|
}
|
|
@@ -2119,7 +2343,7 @@ var TRIGGER = {
|
|
|
2119
2343
|
};
|
|
2120
2344
|
|
|
2121
2345
|
// src/stream/reducer.ts
|
|
2122
|
-
var
|
|
2346
|
+
var log7 = logger.scope("reducer");
|
|
2123
2347
|
var StreamReducer = class {
|
|
2124
2348
|
constructor(messagesSig) {
|
|
2125
2349
|
__publicField(this, "messagesSig", messagesSig);
|
|
@@ -2141,13 +2365,13 @@ var StreamReducer = class {
|
|
|
2141
2365
|
case "finish-step":
|
|
2142
2366
|
return;
|
|
2143
2367
|
case "finish":
|
|
2144
|
-
|
|
2368
|
+
log7.debug("finish", { reason: chunk.finishReason, canContinue: chunk.canContinue });
|
|
2145
2369
|
m.status = "complete";
|
|
2146
2370
|
if (chunk.finishReason) m.finishReason = chunk.finishReason;
|
|
2147
2371
|
this.bumpDone(m);
|
|
2148
2372
|
return;
|
|
2149
2373
|
case "error":
|
|
2150
|
-
|
|
2374
|
+
log7.warn("stream error chunk", { errorText: chunk.errorText });
|
|
2151
2375
|
m.status = "error";
|
|
2152
2376
|
m.errorText = chunk.errorText;
|
|
2153
2377
|
this.bumpDone(m);
|
|
@@ -2177,235 +2401,110 @@ var StreamReducer = class {
|
|
|
2177
2401
|
case "tool-input-start":
|
|
2178
2402
|
case "tool-input-delta":
|
|
2179
2403
|
case "tool-input-available":
|
|
2180
|
-
case "tool-output-available":
|
|
2181
|
-
case "tool-output-error":
|
|
2182
|
-
case "tool-approval-request":
|
|
2183
|
-
applyTool(m, chunk);
|
|
2184
|
-
return;
|
|
2185
|
-
case "file":
|
|
2186
|
-
appendPart(m, { kind: "file", url: chunk.url, mediaType: chunk.mediaType });
|
|
2187
|
-
return;
|
|
2188
|
-
case "source-url": {
|
|
2189
|
-
const parts = m.partsSig.value;
|
|
2190
|
-
if (parts.some((p33) => p33.kind === "source" && p33.sourceId === chunk.sourceId)) return;
|
|
2191
|
-
appendPart(m, { kind: "source", sourceId: chunk.sourceId, url: chunk.url, title: chunk.title });
|
|
2192
|
-
return;
|
|
2193
|
-
}
|
|
2194
|
-
case "data-notification":
|
|
2195
|
-
return;
|
|
2196
|
-
default: {
|
|
2197
|
-
const _exhaustive = chunk;
|
|
2198
|
-
void _exhaustive;
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
}
|
|
2202
|
-
/**
|
|
2203
|
-
* Terminal-state bump (`finish`/`error`). Touches the message's own `partsSig`
|
|
2204
|
-
* AND the list so subscribers re-render: a buffered bubble (subscribed to its
|
|
2205
|
-
* parts) flips out of the loading indicator into the finished reply, and the
|
|
2206
|
-
* list reflects the new `status`.
|
|
2207
|
-
*/
|
|
2208
|
-
bumpDone(m) {
|
|
2209
|
-
m.partsSig.value = [...m.partsSig.value];
|
|
2210
|
-
this.messagesSig.value = [...this.messagesSig.value];
|
|
2211
|
-
}
|
|
2212
|
-
};
|
|
2213
|
-
function ensureTextPart(m, kind, id) {
|
|
2214
|
-
const existing = m.partsSig.value.find((p33) => p33.kind === kind && p33.id === id);
|
|
2215
|
-
if (existing) return existing;
|
|
2216
|
-
const part = { kind, id, textSig: signal2(""), doneSig: signal2(false) };
|
|
2217
|
-
appendPart(m, part);
|
|
2218
|
-
return part;
|
|
2219
|
-
}
|
|
2220
|
-
function ensureToolPart(m, toolCallId, toolName) {
|
|
2221
|
-
const existing = m.partsSig.value.find((p33) => p33.kind === "tool" && p33.toolCallId === toolCallId);
|
|
2222
|
-
if (existing) return existing;
|
|
2223
|
-
const part = {
|
|
2224
|
-
kind: "tool",
|
|
2225
|
-
toolCallId,
|
|
2226
|
-
toolName: toolName ?? "tool",
|
|
2227
|
-
inputPartialSig: signal2(""),
|
|
2228
|
-
inputSig: signal2(void 0),
|
|
2229
|
-
outputSig: signal2(void 0),
|
|
2230
|
-
errorSig: signal2(void 0),
|
|
2231
|
-
stateSig: signal2("input"),
|
|
2232
|
-
approvalSig: signal2(void 0)
|
|
2233
|
-
};
|
|
2234
|
-
appendPart(m, part);
|
|
2235
|
-
return part;
|
|
2236
|
-
}
|
|
2237
|
-
function appendPart(m, part) {
|
|
2238
|
-
m.partsSig.value = [...m.partsSig.value, part];
|
|
2239
|
-
}
|
|
2240
|
-
function applyTool(m, chunk) {
|
|
2241
|
-
switch (chunk.type) {
|
|
2242
|
-
case "tool-input-start":
|
|
2243
|
-
ensureToolPart(m, chunk.toolCallId, chunk.toolName);
|
|
2244
|
-
return;
|
|
2245
|
-
case "tool-input-delta": {
|
|
2246
|
-
const p33 = ensureToolPart(m, chunk.toolCallId);
|
|
2247
|
-
p33.inputPartialSig.value += chunk.delta;
|
|
2248
|
-
return;
|
|
2249
|
-
}
|
|
2250
|
-
case "tool-input-available": {
|
|
2251
|
-
const p33 = ensureToolPart(m, chunk.toolCallId, chunk.toolName);
|
|
2252
|
-
p33.inputSig.value = chunk.input;
|
|
2253
|
-
p33.stateSig.value = isAskUserInputTool(p33.toolName) ? "awaiting-input" : "awaiting";
|
|
2254
|
-
return;
|
|
2255
|
-
}
|
|
2256
|
-
case "tool-approval-request": {
|
|
2257
|
-
const p33 = ensureToolPart(m, chunk.toolCallId, chunk.toolName);
|
|
2258
|
-
p33.approvalSig.value = { id: chunk.approvalId };
|
|
2259
|
-
p33.stateSig.value = "awaiting-approval";
|
|
2260
|
-
return;
|
|
2261
|
-
}
|
|
2262
|
-
case "tool-output-available": {
|
|
2263
|
-
const p33 = ensureToolPart(m, chunk.toolCallId);
|
|
2264
|
-
p33.outputSig.value = chunk.output;
|
|
2265
|
-
p33.stateSig.value = "output";
|
|
2266
|
-
return;
|
|
2267
|
-
}
|
|
2268
|
-
case "tool-output-error": {
|
|
2269
|
-
const p33 = ensureToolPart(m, chunk.toolCallId);
|
|
2270
|
-
p33.errorSig.value = chunk.errorText;
|
|
2271
|
-
p33.stateSig.value = "error";
|
|
2272
|
-
return;
|
|
2273
|
-
}
|
|
2274
|
-
default:
|
|
2275
|
-
return;
|
|
2276
|
-
}
|
|
2277
|
-
}
|
|
2278
|
-
|
|
2279
|
-
// src/core/persistence.ts
|
|
2280
|
-
var log6 = logger.scope("persistence");
|
|
2281
|
-
function createPersistence(widgetId, storage = defaultStorage) {
|
|
2282
|
-
const prefix = `${BRAND.cssPrefix}.${widgetId}`;
|
|
2283
|
-
const KEY_VISITOR = `${prefix}.visitorId`;
|
|
2284
|
-
const KEY_CONVERSATION = `${prefix}.conversationId`;
|
|
2285
|
-
const KEY_USER_PREFS = `${prefix}.userPrefs`;
|
|
2286
|
-
const KEY_PANEL_OPEN = `${prefix}.panelOpen`;
|
|
2287
|
-
const KEY_PANEL_SIZE = `${prefix}.panelSize`;
|
|
2288
|
-
const KEY_CALLOUT_DISMISSED = `${prefix}.calloutDismissed`;
|
|
2289
|
-
const KEY_SIDEBAR_COLLAPSED = `${prefix}.sidebarCollapsed`;
|
|
2290
|
-
const KEY_ACTIVE_MODULE = `${prefix}.activeModule`;
|
|
2291
|
-
const KEY_FORMS_DONE = `${prefix}.formsDone`;
|
|
2292
|
-
const persistence = {
|
|
2293
|
-
getVisitorId() {
|
|
2294
|
-
const existing = storage.get(KEY_VISITOR);
|
|
2295
|
-
if (existing) return existing;
|
|
2296
|
-
const minted = uuid7();
|
|
2297
|
-
storage.set(KEY_VISITOR, minted);
|
|
2298
|
-
return minted;
|
|
2299
|
-
},
|
|
2300
|
-
setVisitorId(id) {
|
|
2301
|
-
log6.debug("setVisitorId (rebind)", { id, widgetId });
|
|
2302
|
-
storage.set(KEY_VISITOR, id);
|
|
2303
|
-
},
|
|
2304
|
-
loadConversationId() {
|
|
2305
|
-
return storage.get(KEY_CONVERSATION) ?? void 0;
|
|
2306
|
-
},
|
|
2307
|
-
saveConversationId(id) {
|
|
2308
|
-
log6.trace("saveConversationId", { id, widgetId });
|
|
2309
|
-
if (id) storage.set(KEY_CONVERSATION, id);
|
|
2310
|
-
else storage.remove(KEY_CONVERSATION);
|
|
2311
|
-
},
|
|
2312
|
-
loadUserPrefs() {
|
|
2313
|
-
const raw = storage.get(KEY_USER_PREFS);
|
|
2314
|
-
if (!raw) return {};
|
|
2315
|
-
try {
|
|
2316
|
-
const parsed = JSON.parse(raw);
|
|
2317
|
-
return isPlainObject2(parsed) ? parsed : {};
|
|
2318
|
-
} catch (error) {
|
|
2319
|
-
log6.warn("loadUserPrefs parse failed", { error });
|
|
2320
|
-
return {};
|
|
2321
|
-
}
|
|
2322
|
-
},
|
|
2323
|
-
saveUserPrefs(s) {
|
|
2324
|
-
try {
|
|
2325
|
-
storage.set(KEY_USER_PREFS, JSON.stringify(s));
|
|
2326
|
-
} catch (error) {
|
|
2327
|
-
log6.warn("saveUserPrefs serialise failed", { error });
|
|
2328
|
-
}
|
|
2329
|
-
},
|
|
2330
|
-
patchUserPrefs(patch) {
|
|
2331
|
-
const current = persistence.loadUserPrefs();
|
|
2332
|
-
persistence.saveUserPrefs({ ...current, ...patch });
|
|
2333
|
-
},
|
|
2334
|
-
loadPanelOpen() {
|
|
2335
|
-
const raw = storage.get(KEY_PANEL_OPEN);
|
|
2336
|
-
if (raw === "1") return true;
|
|
2337
|
-
if (raw === "0") return false;
|
|
2338
|
-
return null;
|
|
2339
|
-
},
|
|
2340
|
-
savePanelOpen(open) {
|
|
2341
|
-
storage.set(KEY_PANEL_OPEN, open ? "1" : "0");
|
|
2342
|
-
},
|
|
2343
|
-
loadPanelSize() {
|
|
2344
|
-
const raw = storage.get(KEY_PANEL_SIZE);
|
|
2345
|
-
return raw === "normal" || raw === "expanded" || raw === "fullscreen" ? raw : null;
|
|
2346
|
-
},
|
|
2347
|
-
savePanelSize(size) {
|
|
2348
|
-
storage.set(KEY_PANEL_SIZE, size);
|
|
2349
|
-
},
|
|
2350
|
-
loadCalloutDismissed(currentText) {
|
|
2351
|
-
if (!currentText) return false;
|
|
2352
|
-
const dismissedText = storage.get(KEY_CALLOUT_DISMISSED);
|
|
2353
|
-
return !!dismissedText && dismissedText === currentText;
|
|
2354
|
-
},
|
|
2355
|
-
saveCalloutDismissed(currentText) {
|
|
2356
|
-
if (currentText) storage.set(KEY_CALLOUT_DISMISSED, currentText);
|
|
2357
|
-
else storage.remove(KEY_CALLOUT_DISMISSED);
|
|
2358
|
-
},
|
|
2359
|
-
loadSidebarCollapsed() {
|
|
2360
|
-
const raw = storage.get(KEY_SIDEBAR_COLLAPSED);
|
|
2361
|
-
if (raw === "1") return true;
|
|
2362
|
-
if (raw === "0") return false;
|
|
2363
|
-
return null;
|
|
2364
|
-
},
|
|
2365
|
-
saveSidebarCollapsed(collapsed) {
|
|
2366
|
-
storage.set(KEY_SIDEBAR_COLLAPSED, collapsed ? "1" : "0");
|
|
2367
|
-
},
|
|
2368
|
-
loadActiveModule() {
|
|
2369
|
-
return storage.get(KEY_ACTIVE_MODULE) || null;
|
|
2370
|
-
},
|
|
2371
|
-
saveActiveModule(id) {
|
|
2372
|
-
storage.set(KEY_ACTIVE_MODULE, id);
|
|
2373
|
-
},
|
|
2374
|
-
loadFormsDone() {
|
|
2375
|
-
const raw = storage.get(KEY_FORMS_DONE);
|
|
2376
|
-
if (!raw) return {};
|
|
2377
|
-
try {
|
|
2378
|
-
const parsed = JSON.parse(raw);
|
|
2379
|
-
return isPlainObject2(parsed) ? parsed : {};
|
|
2380
|
-
} catch (error) {
|
|
2381
|
-
log6.warn("loadFormsDone parse failed", { error });
|
|
2382
|
-
return {};
|
|
2404
|
+
case "tool-output-available":
|
|
2405
|
+
case "tool-output-error":
|
|
2406
|
+
case "tool-approval-request":
|
|
2407
|
+
applyTool(m, chunk);
|
|
2408
|
+
return;
|
|
2409
|
+
case "file":
|
|
2410
|
+
appendPart(m, { kind: "file", url: chunk.url, mediaType: chunk.mediaType });
|
|
2411
|
+
return;
|
|
2412
|
+
case "source-url": {
|
|
2413
|
+
const parts = m.partsSig.value;
|
|
2414
|
+
if (parts.some((p33) => p33.kind === "source" && p33.sourceId === chunk.sourceId)) return;
|
|
2415
|
+
appendPart(m, { kind: "source", sourceId: chunk.sourceId, url: chunk.url, title: chunk.title });
|
|
2416
|
+
return;
|
|
2383
2417
|
}
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
const
|
|
2388
|
-
|
|
2389
|
-
storage.set(KEY_FORMS_DONE, JSON.stringify(done));
|
|
2390
|
-
} catch (error) {
|
|
2391
|
-
log6.warn("saveFormDone serialise failed", { error });
|
|
2418
|
+
case "data-notification":
|
|
2419
|
+
return;
|
|
2420
|
+
default: {
|
|
2421
|
+
const _exhaustive = chunk;
|
|
2422
|
+
void _exhaustive;
|
|
2392
2423
|
}
|
|
2393
|
-
},
|
|
2394
|
-
clearConversation() {
|
|
2395
|
-
storage.remove(KEY_CONVERSATION);
|
|
2396
2424
|
}
|
|
2425
|
+
}
|
|
2426
|
+
/**
|
|
2427
|
+
* Terminal-state bump (`finish`/`error`). Touches the message's own `partsSig`
|
|
2428
|
+
* AND the list so subscribers re-render: a buffered bubble (subscribed to its
|
|
2429
|
+
* parts) flips out of the loading indicator into the finished reply, and the
|
|
2430
|
+
* list reflects the new `status`.
|
|
2431
|
+
*/
|
|
2432
|
+
bumpDone(m) {
|
|
2433
|
+
m.partsSig.value = [...m.partsSig.value];
|
|
2434
|
+
this.messagesSig.value = [...this.messagesSig.value];
|
|
2435
|
+
}
|
|
2436
|
+
};
|
|
2437
|
+
function ensureTextPart(m, kind, id) {
|
|
2438
|
+
const existing = m.partsSig.value.find((p33) => p33.kind === kind && p33.id === id);
|
|
2439
|
+
if (existing) return existing;
|
|
2440
|
+
const part = { kind, id, textSig: signal2(""), doneSig: signal2(false) };
|
|
2441
|
+
appendPart(m, part);
|
|
2442
|
+
return part;
|
|
2443
|
+
}
|
|
2444
|
+
function ensureToolPart(m, toolCallId, toolName) {
|
|
2445
|
+
const existing = m.partsSig.value.find((p33) => p33.kind === "tool" && p33.toolCallId === toolCallId);
|
|
2446
|
+
if (existing) return existing;
|
|
2447
|
+
const part = {
|
|
2448
|
+
kind: "tool",
|
|
2449
|
+
toolCallId,
|
|
2450
|
+
toolName: toolName ?? "tool",
|
|
2451
|
+
inputPartialSig: signal2(""),
|
|
2452
|
+
inputSig: signal2(void 0),
|
|
2453
|
+
outputSig: signal2(void 0),
|
|
2454
|
+
errorSig: signal2(void 0),
|
|
2455
|
+
stateSig: signal2("input"),
|
|
2456
|
+
approvalSig: signal2(void 0)
|
|
2397
2457
|
};
|
|
2398
|
-
|
|
2458
|
+
appendPart(m, part);
|
|
2459
|
+
return part;
|
|
2399
2460
|
}
|
|
2400
|
-
function
|
|
2401
|
-
|
|
2461
|
+
function appendPart(m, part) {
|
|
2462
|
+
m.partsSig.value = [...m.partsSig.value, part];
|
|
2463
|
+
}
|
|
2464
|
+
function applyTool(m, chunk) {
|
|
2465
|
+
switch (chunk.type) {
|
|
2466
|
+
case "tool-input-start":
|
|
2467
|
+
ensureToolPart(m, chunk.toolCallId, chunk.toolName);
|
|
2468
|
+
return;
|
|
2469
|
+
case "tool-input-delta": {
|
|
2470
|
+
const p33 = ensureToolPart(m, chunk.toolCallId);
|
|
2471
|
+
p33.inputPartialSig.value += chunk.delta;
|
|
2472
|
+
return;
|
|
2473
|
+
}
|
|
2474
|
+
case "tool-input-available": {
|
|
2475
|
+
const p33 = ensureToolPart(m, chunk.toolCallId, chunk.toolName);
|
|
2476
|
+
p33.inputSig.value = chunk.input;
|
|
2477
|
+
p33.stateSig.value = isAskUserInputTool(p33.toolName) ? "awaiting-input" : "awaiting";
|
|
2478
|
+
return;
|
|
2479
|
+
}
|
|
2480
|
+
case "tool-approval-request": {
|
|
2481
|
+
const p33 = ensureToolPart(m, chunk.toolCallId, chunk.toolName);
|
|
2482
|
+
p33.approvalSig.value = { id: chunk.approvalId };
|
|
2483
|
+
p33.stateSig.value = "awaiting-approval";
|
|
2484
|
+
return;
|
|
2485
|
+
}
|
|
2486
|
+
case "tool-output-available": {
|
|
2487
|
+
const p33 = ensureToolPart(m, chunk.toolCallId);
|
|
2488
|
+
p33.outputSig.value = chunk.output;
|
|
2489
|
+
p33.stateSig.value = "output";
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2492
|
+
case "tool-output-error": {
|
|
2493
|
+
const p33 = ensureToolPart(m, chunk.toolCallId);
|
|
2494
|
+
p33.errorSig.value = chunk.errorText;
|
|
2495
|
+
p33.stateSig.value = "error";
|
|
2496
|
+
return;
|
|
2497
|
+
}
|
|
2498
|
+
default:
|
|
2499
|
+
return;
|
|
2500
|
+
}
|
|
2402
2501
|
}
|
|
2403
2502
|
|
|
2404
2503
|
// src/core/feedback/index.ts
|
|
2405
2504
|
import { signal as signal3 } from "@preact/signals";
|
|
2406
2505
|
|
|
2407
2506
|
// src/core/feedback/audio.ts
|
|
2408
|
-
var
|
|
2507
|
+
var log8 = logger.scope("feedback:audio");
|
|
2409
2508
|
var AudioEngine = class {
|
|
2410
2509
|
constructor() {
|
|
2411
2510
|
__publicField(this, "ctx", null);
|
|
@@ -2426,7 +2525,7 @@ var AudioEngine = class {
|
|
|
2426
2525
|
this.master.gain.value = 1;
|
|
2427
2526
|
this.master.connect(this.ctx.destination);
|
|
2428
2527
|
} catch (err) {
|
|
2429
|
-
|
|
2528
|
+
log8.warn("AudioContext init failed", { err });
|
|
2430
2529
|
}
|
|
2431
2530
|
}
|
|
2432
2531
|
/** Route all sounds through this multiplier. Call on volume change. */
|
|
@@ -2483,7 +2582,7 @@ var AudioEngine = class {
|
|
|
2483
2582
|
this.buffers.set(url, buf);
|
|
2484
2583
|
return buf;
|
|
2485
2584
|
}).catch((err) => {
|
|
2486
|
-
|
|
2585
|
+
log8.warn("audio fetch/decode failed", { url, err });
|
|
2487
2586
|
this.buffers.delete(url);
|
|
2488
2587
|
return null;
|
|
2489
2588
|
});
|
|
@@ -2569,7 +2668,7 @@ function acquireHaptics() {
|
|
|
2569
2668
|
}
|
|
2570
2669
|
|
|
2571
2670
|
// src/core/feedback/index.ts
|
|
2572
|
-
var
|
|
2671
|
+
var log9 = logger.scope("feedback");
|
|
2573
2672
|
var DEDUP_WINDOW_MS = 100;
|
|
2574
2673
|
var FeedbackBus = class {
|
|
2575
2674
|
constructor(sound, haptics) {
|
|
@@ -2647,7 +2746,7 @@ var FeedbackBus = class {
|
|
|
2647
2746
|
const override = this.sound.events?.[event];
|
|
2648
2747
|
if (override === false) return;
|
|
2649
2748
|
if (typeof override === "string") {
|
|
2650
|
-
this.audio.playUrl(override).catch((err) =>
|
|
2749
|
+
this.audio.playUrl(override).catch((err) => log9.warn("audio play failed", { err, url: override }));
|
|
2651
2750
|
return;
|
|
2652
2751
|
}
|
|
2653
2752
|
const tone = DEFAULT_TONES[event];
|
|
@@ -3292,7 +3391,7 @@ function AgentBadge({ agent }) {
|
|
|
3292
3391
|
import { useEffect as useEffect4, useRef as useRef2, useState as useState2 } from "preact/hooks";
|
|
3293
3392
|
|
|
3294
3393
|
// src/core/attachments.ts
|
|
3295
|
-
var
|
|
3394
|
+
var log10 = logger.scope("attachments");
|
|
3296
3395
|
function ingest(source, existing, limits) {
|
|
3297
3396
|
const incoming = collectFiles(source);
|
|
3298
3397
|
const accepted = [];
|
|
@@ -3311,7 +3410,7 @@ function ingest(source, existing, limits) {
|
|
|
3311
3410
|
totalCount += 1;
|
|
3312
3411
|
}
|
|
3313
3412
|
if (accepted.length || rejected.length) {
|
|
3314
|
-
|
|
3413
|
+
log10.debug("ingest", {
|
|
3315
3414
|
accepted: accepted.length,
|
|
3316
3415
|
rejected: rejected.map((r) => ({ name: r.file.name, reason: r.reason }))
|
|
3317
3416
|
});
|
|
@@ -3322,7 +3421,7 @@ function revoke(att) {
|
|
|
3322
3421
|
try {
|
|
3323
3422
|
URL.revokeObjectURL(att.previewUrl);
|
|
3324
3423
|
} catch (error) {
|
|
3325
|
-
|
|
3424
|
+
log10.debug("revokeObjectURL failed", { error });
|
|
3326
3425
|
}
|
|
3327
3426
|
}
|
|
3328
3427
|
function reject(file, count, bytes, limits, accept) {
|
|
@@ -3498,7 +3597,7 @@ function pickSupportedMimeType() {
|
|
|
3498
3597
|
// src/ui/composer.tsx
|
|
3499
3598
|
import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
3500
3599
|
var p7 = BRAND.cssPrefix;
|
|
3501
|
-
var
|
|
3600
|
+
var log11 = logger.scope("composer");
|
|
3502
3601
|
function totalBytes(items) {
|
|
3503
3602
|
return items.reduce((acc, a) => acc + a.size, 0);
|
|
3504
3603
|
}
|
|
@@ -3551,7 +3650,7 @@ function Composer({ options, transport, feedback, bus, isStreaming, onSend, onSt
|
|
|
3551
3650
|
attachFromDrop: (items) => {
|
|
3552
3651
|
const result = ingest(items, attsRef.current, options.attachments);
|
|
3553
3652
|
if (result.accepted.length === 0) return;
|
|
3554
|
-
|
|
3653
|
+
log11.info("attach (drop)", { count: result.accepted.length, totalBytes: totalBytes(result.accepted) });
|
|
3555
3654
|
bus.emit("attach", { count: result.accepted.length, totalBytes: totalBytes(result.accepted) });
|
|
3556
3655
|
setAtts((prev) => [...prev, ...result.accepted]);
|
|
3557
3656
|
}
|
|
@@ -3572,7 +3671,7 @@ function Composer({ options, transport, feedback, bus, isStreaming, onSend, onSt
|
|
|
3572
3671
|
const result = ingest(data.items, attsRef.current, options.attachments);
|
|
3573
3672
|
if (result.accepted.length > 0) {
|
|
3574
3673
|
e.preventDefault();
|
|
3575
|
-
|
|
3674
|
+
log11.info("attach (paste)", { count: result.accepted.length, totalBytes: totalBytes(result.accepted) });
|
|
3576
3675
|
bus.emit("attach", { count: result.accepted.length, totalBytes: totalBytes(result.accepted) });
|
|
3577
3676
|
setAtts((prev) => [...prev, ...result.accepted]);
|
|
3578
3677
|
return;
|
|
@@ -3606,14 +3705,14 @@ function Composer({ options, transport, feedback, bus, isStreaming, onSend, onSt
|
|
|
3606
3705
|
const input = e.target;
|
|
3607
3706
|
const result = ingest(input.files, atts, options.attachments);
|
|
3608
3707
|
if (result.accepted.length > 0) {
|
|
3609
|
-
|
|
3708
|
+
log11.info("attach (file picker)", { count: result.accepted.length, totalBytes: totalBytes(result.accepted) });
|
|
3610
3709
|
bus.emit("attach", { count: result.accepted.length, totalBytes: totalBytes(result.accepted) });
|
|
3611
3710
|
setAtts((prev) => [...prev, ...result.accepted]);
|
|
3612
3711
|
}
|
|
3613
3712
|
input.value = "";
|
|
3614
3713
|
};
|
|
3615
3714
|
const removeAtt = (id) => {
|
|
3616
|
-
|
|
3715
|
+
log11.info("removeAttachment", { id });
|
|
3617
3716
|
bus.emit("removeAttachment", { id });
|
|
3618
3717
|
setAtts((prev) => {
|
|
3619
3718
|
const target = prev.find((a) => a.id === id);
|
|
@@ -3626,7 +3725,7 @@ function Composer({ options, transport, feedback, bus, isStreaming, onSend, onSt
|
|
|
3626
3725
|
if (!voice.isSupported) return;
|
|
3627
3726
|
if (voiceOn) {
|
|
3628
3727
|
const durationMs = voiceStartedAtRef.current ? Date.now() - voiceStartedAtRef.current : 0;
|
|
3629
|
-
|
|
3728
|
+
log11.info("voiceStop", { durationMs });
|
|
3630
3729
|
bus.emit("voiceStop", { durationMs });
|
|
3631
3730
|
voice.stop();
|
|
3632
3731
|
setVoiceOn(false);
|
|
@@ -3635,7 +3734,7 @@ function Composer({ options, transport, feedback, bus, isStreaming, onSend, onSt
|
|
|
3635
3734
|
return;
|
|
3636
3735
|
}
|
|
3637
3736
|
voiceStartedAtRef.current = Date.now();
|
|
3638
|
-
|
|
3737
|
+
log11.info("voiceStart");
|
|
3639
3738
|
bus.emit("voiceStart", void 0);
|
|
3640
3739
|
setVoiceOn(true);
|
|
3641
3740
|
feedback.play("voiceStart");
|
|
@@ -3645,7 +3744,7 @@ function Composer({ options, transport, feedback, bus, isStreaming, onSend, onSt
|
|
|
3645
3744
|
setVoiceOn(false);
|
|
3646
3745
|
if (voiceStartedAtRef.current) {
|
|
3647
3746
|
const durationMs = Date.now() - voiceStartedAtRef.current;
|
|
3648
|
-
|
|
3747
|
+
log11.debug("voiceStop (auto)", { durationMs });
|
|
3649
3748
|
bus.emit("voiceStop", { durationMs });
|
|
3650
3749
|
voiceStartedAtRef.current = null;
|
|
3651
3750
|
}
|
|
@@ -5206,7 +5305,7 @@ function startOfDay(ms) {
|
|
|
5206
5305
|
|
|
5207
5306
|
// src/ui/conversation-list.tsx
|
|
5208
5307
|
import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs15 } from "preact/jsx-runtime";
|
|
5209
|
-
var
|
|
5308
|
+
var log12 = logger.scope("history");
|
|
5210
5309
|
var BUCKET_TO_STRING = {
|
|
5211
5310
|
today: "dateToday",
|
|
5212
5311
|
yesterday: "dateYesterday",
|
|
@@ -5239,7 +5338,7 @@ function ConversationList({
|
|
|
5239
5338
|
setState("loaded");
|
|
5240
5339
|
}).catch((err) => {
|
|
5241
5340
|
if (cancelled) return;
|
|
5242
|
-
|
|
5341
|
+
log12.warn("listConversations failed", { err });
|
|
5243
5342
|
setState("error");
|
|
5244
5343
|
});
|
|
5245
5344
|
return () => {
|
|
@@ -5882,7 +5981,7 @@ function ModuleState({
|
|
|
5882
5981
|
// src/ui/modules/help.tsx
|
|
5883
5982
|
import { jsx as jsx27, jsxs as jsxs23 } from "preact/jsx-runtime";
|
|
5884
5983
|
var p23 = BRAND.cssPrefix;
|
|
5885
|
-
var
|
|
5984
|
+
var log13 = logger.scope("help");
|
|
5886
5985
|
var openArticle = (nav, a) => a.url ? nav.push({ kind: "iframe", url: a.url, title: a.title }) : nav.push({ kind: "content", id: a.id, title: a.title });
|
|
5887
5986
|
function groupByCategory(items) {
|
|
5888
5987
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -5936,7 +6035,7 @@ function HelpRoot({ transport, strings, config, nav, panelProps }) {
|
|
|
5936
6035
|
setState("loaded");
|
|
5937
6036
|
}).catch((err) => {
|
|
5938
6037
|
if (cancelled) return;
|
|
5939
|
-
|
|
6038
|
+
log13.warn("listContent (help) failed", { err });
|
|
5940
6039
|
setErrorMsg(errorMessageFor(err, strings));
|
|
5941
6040
|
setState("error");
|
|
5942
6041
|
});
|
|
@@ -5987,7 +6086,7 @@ function HomeCard({ onClick, children, testid }) {
|
|
|
5987
6086
|
// src/ui/modules/home.tsx
|
|
5988
6087
|
import { Fragment as Fragment6, jsx as jsx29, jsxs as jsxs24 } from "preact/jsx-runtime";
|
|
5989
6088
|
var p25 = BRAND.cssPrefix;
|
|
5990
|
-
var
|
|
6089
|
+
var log14 = logger.scope("home");
|
|
5991
6090
|
function resolveGreeting(props2) {
|
|
5992
6091
|
const name = props2.options.userContext?.name;
|
|
5993
6092
|
const fromConfig = props2.config.greetingText;
|
|
@@ -6006,7 +6105,7 @@ function HomeRoot(props2) {
|
|
|
6006
6105
|
useEffect12(() => {
|
|
6007
6106
|
if (!config.showRecentConversations) return;
|
|
6008
6107
|
let cancelled = false;
|
|
6009
|
-
transport.listConversations({ limit: 1 }).then((res) => !cancelled && setRecent(res.conversations?.[0] ?? null)).catch((err) => !cancelled &&
|
|
6108
|
+
transport.listConversations({ limit: 1 }).then((res) => !cancelled && setRecent(res.conversations?.[0] ?? null)).catch((err) => !cancelled && log14.warn("listConversations (home) failed", { err }));
|
|
6010
6109
|
return () => {
|
|
6011
6110
|
cancelled = true;
|
|
6012
6111
|
};
|
|
@@ -6014,7 +6113,7 @@ function HomeRoot(props2) {
|
|
|
6014
6113
|
useEffect12(() => {
|
|
6015
6114
|
if (!config.contentTags?.length) return;
|
|
6016
6115
|
let cancelled = false;
|
|
6017
|
-
transport.listContent({ tags: config.contentTags, limit: 6 }).then((res) => !cancelled && setContent(res.items ?? [])).catch((err) => !cancelled &&
|
|
6116
|
+
transport.listContent({ tags: config.contentTags, limit: 6 }).then((res) => !cancelled && setContent(res.items ?? [])).catch((err) => !cancelled && log14.warn("listContent (home) failed", { err }));
|
|
6018
6117
|
return () => {
|
|
6019
6118
|
cancelled = true;
|
|
6020
6119
|
};
|
|
@@ -6088,7 +6187,7 @@ var homeLayout = {
|
|
|
6088
6187
|
import { useEffect as useEffect13, useState as useState10 } from "preact/hooks";
|
|
6089
6188
|
import { jsx as jsx30, jsxs as jsxs25 } from "preact/jsx-runtime";
|
|
6090
6189
|
var p26 = BRAND.cssPrefix;
|
|
6091
|
-
var
|
|
6190
|
+
var log15 = logger.scope("news");
|
|
6092
6191
|
function NewsRoot({ transport, strings, config, nav, panelProps }) {
|
|
6093
6192
|
const tags = config.contentTags;
|
|
6094
6193
|
const [state, setState] = useState10("loading");
|
|
@@ -6104,7 +6203,7 @@ function NewsRoot({ transport, strings, config, nav, panelProps }) {
|
|
|
6104
6203
|
setState("loaded");
|
|
6105
6204
|
}).catch((err) => {
|
|
6106
6205
|
if (cancelled) return;
|
|
6107
|
-
|
|
6206
|
+
log15.warn("listContent (news) failed", { err });
|
|
6108
6207
|
setErrorMsg(errorMessageFor(err, strings));
|
|
6109
6208
|
setState("error");
|
|
6110
6209
|
});
|
|
@@ -6219,7 +6318,7 @@ function IframeView({ url, title, strings, onBack, actions }) {
|
|
|
6219
6318
|
import { useCallback as useCallback3, useEffect as useEffect14, useState as useState11 } from "preact/hooks";
|
|
6220
6319
|
import { jsx as jsx33, jsxs as jsxs28 } from "preact/jsx-runtime";
|
|
6221
6320
|
var p29 = BRAND.cssPrefix;
|
|
6222
|
-
var
|
|
6321
|
+
var log16 = logger.scope("content");
|
|
6223
6322
|
function ContentView({ id, title, transport, strings, onBack, actions }) {
|
|
6224
6323
|
const [item, setItem] = useState11(null);
|
|
6225
6324
|
const [failed, setFailed] = useState11(false);
|
|
@@ -6238,7 +6337,7 @@ function ContentView({ id, title, transport, strings, onBack, actions }) {
|
|
|
6238
6337
|
else setFailed(true);
|
|
6239
6338
|
}).catch((err) => {
|
|
6240
6339
|
if (cancelled) return;
|
|
6241
|
-
|
|
6340
|
+
log16.warn("listContent (reader) failed", { err });
|
|
6242
6341
|
setFailed(true);
|
|
6243
6342
|
});
|
|
6244
6343
|
return () => {
|
|
@@ -6458,7 +6557,7 @@ function useLauncherCallout({ callout, persistence }) {
|
|
|
6458
6557
|
|
|
6459
6558
|
// src/ui/app.tsx
|
|
6460
6559
|
import { jsx as jsx36, jsxs as jsxs31 } from "preact/jsx-runtime";
|
|
6461
|
-
var
|
|
6560
|
+
var log17 = logger.scope("app");
|
|
6462
6561
|
var p32 = BRAND.cssPrefix;
|
|
6463
6562
|
function App({ options, hostElement, bus }) {
|
|
6464
6563
|
const [persistence] = useState13(() => createPersistence(options.widgetId, options.storage));
|
|
@@ -6516,7 +6615,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6516
6615
|
});
|
|
6517
6616
|
const calloutPersistent = options.launcher.callout?.persistent ?? true;
|
|
6518
6617
|
const dismissCallout = useCallback6(() => {
|
|
6519
|
-
|
|
6618
|
+
log17.info("calloutDismiss");
|
|
6520
6619
|
bus.emit("calloutDismiss", void 0);
|
|
6521
6620
|
dismissCalloutRaw();
|
|
6522
6621
|
}, [bus, dismissCalloutRaw]);
|
|
@@ -6550,7 +6649,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6550
6649
|
(patch) => {
|
|
6551
6650
|
persistence.patchUserPrefs(patch);
|
|
6552
6651
|
transport.saveUserPrefs(persistence.loadUserPrefs()).catch((err) => {
|
|
6553
|
-
|
|
6652
|
+
log17.warn("saveUserPrefs failed", { err });
|
|
6554
6653
|
});
|
|
6555
6654
|
},
|
|
6556
6655
|
[persistence, transport]
|
|
@@ -6631,7 +6730,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6631
6730
|
values: rec.values
|
|
6632
6731
|
}));
|
|
6633
6732
|
} catch (err) {
|
|
6634
|
-
|
|
6733
|
+
log17.debug("bootstrap failed \u2014 no form markers (non-fatal)", { err });
|
|
6635
6734
|
return [];
|
|
6636
6735
|
}
|
|
6637
6736
|
},
|
|
@@ -6671,7 +6770,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6671
6770
|
}
|
|
6672
6771
|
} catch (err) {
|
|
6673
6772
|
if (isStale()) return;
|
|
6674
|
-
|
|
6773
|
+
log17.warn("loadThread failed; resetting conversationId", { err, conversationId });
|
|
6675
6774
|
conversationIdSig.value = void 0;
|
|
6676
6775
|
persistence.saveConversationId(void 0);
|
|
6677
6776
|
} finally {
|
|
@@ -6710,7 +6809,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6710
6809
|
}
|
|
6711
6810
|
if (isStale()) return;
|
|
6712
6811
|
if (res.visitorId && res.visitorId !== visitorId) {
|
|
6713
|
-
|
|
6812
|
+
log17.info("visitor rebound", { previous: visitorId, current: res.visitorId, reason: res.rebind?.visitorId });
|
|
6714
6813
|
persistence.setVisitorId(res.visitorId);
|
|
6715
6814
|
setVisitorId(res.visitorId);
|
|
6716
6815
|
bus.emit("visitorRebound", {
|
|
@@ -6720,7 +6819,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6720
6819
|
});
|
|
6721
6820
|
}
|
|
6722
6821
|
if (res.conversationId && res.conversationId !== conversationId) {
|
|
6723
|
-
|
|
6822
|
+
log17.info("conversation rebound", {
|
|
6724
6823
|
previous: conversationId,
|
|
6725
6824
|
current: res.conversationId,
|
|
6726
6825
|
reason: res.rebind?.conversationId
|
|
@@ -6735,9 +6834,9 @@ function App({ options, hostElement, bus }) {
|
|
|
6735
6834
|
if (res.welcome?.suggestions) setSuggestions(res.welcome.suggestions);
|
|
6736
6835
|
if (options.mode === "page") {
|
|
6737
6836
|
if (res.site && isSiteConfigShape(res.site)) setParsedSite(res.site);
|
|
6738
|
-
else if (res.site)
|
|
6837
|
+
else if (res.site) log17.warn("invalid site config, using fallback", { site: res.site });
|
|
6739
6838
|
if (res.blocks && isBlocksConfigShape(res.blocks)) setParsedBlocks(res.blocks);
|
|
6740
|
-
else if (res.blocks)
|
|
6839
|
+
else if (res.blocks) log17.warn("invalid blocks config, using fallback", { blocks: res.blocks });
|
|
6741
6840
|
}
|
|
6742
6841
|
if (res.userPrefs && !newConversation) {
|
|
6743
6842
|
persistence.saveUserPrefs(res.userPrefs);
|
|
@@ -6803,7 +6902,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6803
6902
|
resumeActiveRef.current = true;
|
|
6804
6903
|
const chatTab = chatTabIdRef.current;
|
|
6805
6904
|
if (chatTab) homeNav.switchTab(chatTab);
|
|
6806
|
-
|
|
6905
|
+
log17.info("resumed in-flight reply on mount");
|
|
6807
6906
|
}
|
|
6808
6907
|
reducer.apply(evt.chunk);
|
|
6809
6908
|
if (evt.chunk.type === "finish" && evt.chunk.canContinue === false) setCanSend(false);
|
|
@@ -6819,7 +6918,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6819
6918
|
bubble.errorText = errorMessageFor(err, options.strings);
|
|
6820
6919
|
feedback.play("error");
|
|
6821
6920
|
}
|
|
6822
|
-
|
|
6921
|
+
log17.debug("mount resume ended without completing", { err });
|
|
6823
6922
|
} finally {
|
|
6824
6923
|
resumeBubbleRef.current = null;
|
|
6825
6924
|
if (bubble) {
|
|
@@ -6850,7 +6949,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6850
6949
|
const res = await dataBootRef.current;
|
|
6851
6950
|
setRemoteForms(resolveForms((res ?? { forms: [] }).forms));
|
|
6852
6951
|
} catch (err) {
|
|
6853
|
-
|
|
6952
|
+
log17.debug("bootstrap failed \u2014 treating as no forms", { err });
|
|
6854
6953
|
} finally {
|
|
6855
6954
|
setFormsReady(true);
|
|
6856
6955
|
}
|
|
@@ -6950,7 +7049,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6950
7049
|
(pt) => pt.kind === "tool" && pt.toolCallId === toolCallId
|
|
6951
7050
|
);
|
|
6952
7051
|
if (!part) {
|
|
6953
|
-
|
|
7052
|
+
log17.warn("resolveTool: tool part not found", { toolCallId });
|
|
6954
7053
|
return;
|
|
6955
7054
|
}
|
|
6956
7055
|
mutate(part);
|
|
@@ -6964,7 +7063,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6964
7063
|
);
|
|
6965
7064
|
const handleToolResult = useCallback6(
|
|
6966
7065
|
(toolCallId, output) => {
|
|
6967
|
-
|
|
7066
|
+
log17.info("toolResult", { toolCallId });
|
|
6968
7067
|
bus.emit("toolResult", { toolCallId });
|
|
6969
7068
|
resolveTool(toolCallId, TRIGGER.toolResult, (part) => {
|
|
6970
7069
|
part.outputSig.value = output;
|
|
@@ -6975,7 +7074,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6975
7074
|
);
|
|
6976
7075
|
const handleToolDecision = useCallback6(
|
|
6977
7076
|
(toolCallId, approved, reason) => {
|
|
6978
|
-
|
|
7077
|
+
log17.info("toolDecision", { toolCallId, approved });
|
|
6979
7078
|
bus.emit("toolDecision", { toolCallId, approved });
|
|
6980
7079
|
resolveTool(toolCallId, TRIGGER.toolApproval, (part) => {
|
|
6981
7080
|
const id = part.approvalSig.value?.id ?? toolCallId;
|
|
@@ -6999,7 +7098,7 @@ function App({ options, hostElement, bus }) {
|
|
|
6999
7098
|
pageArea: () => options.pageContext?.area ? String(options.pageContext.area) : void 0,
|
|
7000
7099
|
conversationId: () => conversationIdSig.value,
|
|
7001
7100
|
onComplete: (form, trigger, values, skipped) => {
|
|
7002
|
-
|
|
7101
|
+
log17.info("formSubmit", { formId: form.id, trigger, skipped });
|
|
7003
7102
|
bus.emit("formSubmit", { formId: form.id, values, skipped });
|
|
7004
7103
|
setFormMarkers((prev) => [
|
|
7005
7104
|
...prev.filter((m) => !(m.formId === form.id && m.outcome === "skipped")),
|
|
@@ -7044,12 +7143,12 @@ function App({ options, hostElement, bus }) {
|
|
|
7044
7143
|
}, [idleMs, isOpen, forms, msgCount.value]);
|
|
7045
7144
|
const handleSend = useCallback6(
|
|
7046
7145
|
async (text, attachments) => {
|
|
7047
|
-
|
|
7146
|
+
log17.info("send", { textLen: text.length, attachments: attachments.length, streaming });
|
|
7048
7147
|
if (streaming) return;
|
|
7049
7148
|
bus.emit("send", { text, attachmentCount: attachments.length });
|
|
7050
7149
|
if (suggestions.length > 0) setSuggestions([]);
|
|
7051
7150
|
const uploaded = await uploadAttachments(transport, attachments, (err) => {
|
|
7052
|
-
|
|
7151
|
+
log17.warn("upload failed", { err });
|
|
7053
7152
|
bus.emit("error", err);
|
|
7054
7153
|
options.onError?.(err);
|
|
7055
7154
|
});
|
|
@@ -7066,24 +7165,24 @@ function App({ options, hostElement, bus }) {
|
|
|
7066
7165
|
[streaming, transport, bus, options, suggestions.length, messagesSig, reducer, streamAssistant, forms]
|
|
7067
7166
|
);
|
|
7068
7167
|
const handleStop = useCallback6(() => {
|
|
7069
|
-
|
|
7168
|
+
log17.info("stop");
|
|
7070
7169
|
bus.emit("stop", void 0);
|
|
7071
7170
|
activeCancel?.();
|
|
7072
7171
|
}, [activeCancel, bus]);
|
|
7073
7172
|
const handleSoundToggle = useCallback6(() => {
|
|
7074
7173
|
feedback.toggleMuted();
|
|
7075
7174
|
const muted = feedback.mutedSig.value;
|
|
7076
|
-
|
|
7175
|
+
log17.info("soundToggle", { muted });
|
|
7077
7176
|
bus.emit("soundToggle", { muted });
|
|
7078
7177
|
}, [feedback, bus]);
|
|
7079
7178
|
const handleClose = useCallback6(() => {
|
|
7080
7179
|
if (resolveCloseAction(options.mode, panelSize) === "exit-fullscreen") {
|
|
7081
|
-
|
|
7180
|
+
log17.info("close \u2192 exit-fullscreen", { mode: options.mode });
|
|
7082
7181
|
setPanelSize("normal");
|
|
7083
7182
|
bus.emit("fullscreen", false);
|
|
7084
7183
|
return;
|
|
7085
7184
|
}
|
|
7086
|
-
|
|
7185
|
+
log17.info("close \u2192 panel closed", { mode: options.mode });
|
|
7087
7186
|
forms.fire("panel-close");
|
|
7088
7187
|
setIsOpen(false);
|
|
7089
7188
|
persistence.savePanelOpen(false);
|
|
@@ -7094,7 +7193,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7094
7193
|
if (!options.modules.list.some((m) => m.layout === "chat")) return;
|
|
7095
7194
|
transport.listConversations({ limit: 50 }).then((res) => {
|
|
7096
7195
|
unreadCountSig.value = res.conversations.reduce((sum, c) => sum + (c.unreadCount ?? 0), 0);
|
|
7097
|
-
}).catch((err) =>
|
|
7196
|
+
}).catch((err) => log17.debug("refreshUnread failed (non-fatal)", { err }));
|
|
7098
7197
|
}, [transport, options.modules, unreadCountSig]);
|
|
7099
7198
|
const unreadSeeded = useRef9(false);
|
|
7100
7199
|
useEffect17(() => {
|
|
@@ -7103,7 +7202,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7103
7202
|
refreshUnread();
|
|
7104
7203
|
}, [activated, conversationReady, refreshUnread]);
|
|
7105
7204
|
const handleOpen = useCallback6(() => {
|
|
7106
|
-
|
|
7205
|
+
log17.info("open", { mode: options.mode });
|
|
7107
7206
|
feedback.unlock();
|
|
7108
7207
|
setLauncherLeaving(true);
|
|
7109
7208
|
setIsOpen(true);
|
|
@@ -7117,11 +7216,11 @@ function App({ options, hostElement, bus }) {
|
|
|
7117
7216
|
const handleClear = useCallback6(() => {
|
|
7118
7217
|
const hasUserMessages = messagesSig.value.some((m) => m.role === "user");
|
|
7119
7218
|
if (!hasUserMessages && canSend && conversationIdSig.value) {
|
|
7120
|
-
|
|
7219
|
+
log17.info("clear \u2192 reusing empty conversation", { conversationId: conversationIdSig.value });
|
|
7121
7220
|
if (messagesSig.value.length === 0) playWelcome(welcomeRef.current?.messages);
|
|
7122
7221
|
return;
|
|
7123
7222
|
}
|
|
7124
|
-
|
|
7223
|
+
log17.info("clear \u2192 new conversation", { wasStreaming: streaming });
|
|
7125
7224
|
bus.emit("clear", void 0);
|
|
7126
7225
|
if (streaming) activeCancel?.();
|
|
7127
7226
|
messagesSig.value = [];
|
|
@@ -7139,14 +7238,14 @@ function App({ options, hostElement, bus }) {
|
|
|
7139
7238
|
}, [handleClear, homeNav, options]);
|
|
7140
7239
|
const handleExpand = useCallback6(() => {
|
|
7141
7240
|
const nextSize = panelSize === "expanded" ? "normal" : "expanded";
|
|
7142
|
-
|
|
7241
|
+
log17.info("expand", { from: panelSize, expanded: nextSize === "expanded" });
|
|
7143
7242
|
setPanelSize(nextSize);
|
|
7144
7243
|
persistence.savePanelSize(nextSize);
|
|
7145
7244
|
bus.emit("expand", nextSize === "expanded");
|
|
7146
7245
|
}, [bus, panelSize, persistence]);
|
|
7147
7246
|
const handleFullscreen = useCallback6(() => {
|
|
7148
7247
|
const nextSize = panelSize === "fullscreen" ? "normal" : "fullscreen";
|
|
7149
|
-
|
|
7248
|
+
log17.info("fullscreen", { from: panelSize, fullscreen: nextSize === "fullscreen" });
|
|
7150
7249
|
setPanelSize(nextSize);
|
|
7151
7250
|
persistence.savePanelSize(nextSize);
|
|
7152
7251
|
bus.emit("fullscreen", nextSize === "fullscreen");
|
|
@@ -7156,21 +7255,21 @@ function App({ options, hostElement, bus }) {
|
|
|
7156
7255
|
const url = new URL(options.popOutUrl);
|
|
7157
7256
|
if (conversationIdSig.value) url.searchParams.set("conversation", conversationIdSig.value);
|
|
7158
7257
|
if (options.widgetId !== "default") url.searchParams.set("widgetId", options.widgetId);
|
|
7159
|
-
|
|
7258
|
+
log17.info("popOut", { url: url.toString() });
|
|
7160
7259
|
window.open(url.toString(), "_blank", "noopener,noreferrer");
|
|
7161
7260
|
bus.emit("popOut", void 0);
|
|
7162
7261
|
}, [bus, conversationIdSig, options.popOutUrl, options.widgetId]);
|
|
7163
7262
|
const handleToggleHistory = useCallback6(() => {
|
|
7164
7263
|
setView((v) => {
|
|
7165
7264
|
const next = v === "history" ? "chat" : "history";
|
|
7166
|
-
|
|
7265
|
+
log17.info("toggleHistory", { view: next });
|
|
7167
7266
|
bus.emit("toggleHistory", { view: next });
|
|
7168
7267
|
return next;
|
|
7169
7268
|
});
|
|
7170
7269
|
}, [bus]);
|
|
7171
7270
|
const handleLocaleChange = useCallback6(
|
|
7172
7271
|
(locale) => {
|
|
7173
|
-
|
|
7272
|
+
log17.info("localeChange", { locale });
|
|
7174
7273
|
setActiveLocale(locale);
|
|
7175
7274
|
patchAndSync({ locale });
|
|
7176
7275
|
bus.emit("localeChange", locale);
|
|
@@ -7179,7 +7278,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7179
7278
|
);
|
|
7180
7279
|
const handleThemeChange = useCallback6(
|
|
7181
7280
|
(mode) => {
|
|
7182
|
-
|
|
7281
|
+
log17.info("themeChange", { mode });
|
|
7183
7282
|
setActiveThemeMode(mode);
|
|
7184
7283
|
hostElement.dataset.theme = mode;
|
|
7185
7284
|
patchAndSync({ themeMode: mode });
|
|
@@ -7189,7 +7288,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7189
7288
|
);
|
|
7190
7289
|
const handleTextSizeChange = useCallback6(
|
|
7191
7290
|
(size) => {
|
|
7192
|
-
|
|
7291
|
+
log17.info("textSizeChange", { size });
|
|
7193
7292
|
setActiveTextSize(size);
|
|
7194
7293
|
hostElement.dataset.textSize = size;
|
|
7195
7294
|
patchAndSync({ textSize: size });
|
|
@@ -7200,7 +7299,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7200
7299
|
const handleToggleSidebarCollapsed = useCallback6(() => {
|
|
7201
7300
|
setSidebarCollapsed((prev) => {
|
|
7202
7301
|
const next = !prev;
|
|
7203
|
-
|
|
7302
|
+
log17.info("sidebarToggle", { collapsed: next });
|
|
7204
7303
|
persistence.saveSidebarCollapsed(next);
|
|
7205
7304
|
bus.emit("sidebarToggle", { collapsed: next });
|
|
7206
7305
|
return next;
|
|
@@ -7208,7 +7307,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7208
7307
|
}, [persistence, bus]);
|
|
7209
7308
|
const handleWidgetSizeChange = useCallback6(
|
|
7210
7309
|
(size) => {
|
|
7211
|
-
|
|
7310
|
+
log17.info("resize", size);
|
|
7212
7311
|
patchAndSync({ widgetSize: size });
|
|
7213
7312
|
bus.emit("resize", size);
|
|
7214
7313
|
},
|
|
@@ -7216,7 +7315,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7216
7315
|
);
|
|
7217
7316
|
const handleSelectHistoryConversation = useCallback6(
|
|
7218
7317
|
async (targetConversationId) => {
|
|
7219
|
-
|
|
7318
|
+
log17.info("selectConversation", { conversationId: targetConversationId });
|
|
7220
7319
|
bus.emit("selectConversation", { conversationId: targetConversationId });
|
|
7221
7320
|
try {
|
|
7222
7321
|
const [res, markers] = await Promise.all([
|
|
@@ -7318,7 +7417,7 @@ function App({ options, hostElement, bus }) {
|
|
|
7318
7417
|
onStop: handleStop,
|
|
7319
7418
|
onSuggestion: (s) => {
|
|
7320
7419
|
const text = s.text ?? s.label;
|
|
7321
|
-
|
|
7420
|
+
log17.info("suggestion", { text });
|
|
7322
7421
|
bus.emit("suggestion", { text });
|
|
7323
7422
|
void handleSend(text, []);
|
|
7324
7423
|
},
|
|
@@ -7440,14 +7539,14 @@ function emitMessage(bus, options, role, text) {
|
|
|
7440
7539
|
|
|
7441
7540
|
// src/ui/error-boundary.tsx
|
|
7442
7541
|
import { Component } from "preact";
|
|
7443
|
-
var
|
|
7542
|
+
var log18 = logger.scope("error-boundary");
|
|
7444
7543
|
var ErrorBoundary = class extends Component {
|
|
7445
7544
|
constructor() {
|
|
7446
7545
|
super(...arguments);
|
|
7447
7546
|
__publicField(this, "state", { crashed: false });
|
|
7448
7547
|
}
|
|
7449
7548
|
componentDidCatch(error, info) {
|
|
7450
|
-
|
|
7549
|
+
log18.error("widget render crashed", { error, componentStack: info?.componentStack });
|
|
7451
7550
|
this.setState({ crashed: true });
|
|
7452
7551
|
this.props.onError(error, info?.componentStack);
|
|
7453
7552
|
}
|
|
@@ -7456,102 +7555,6 @@ var ErrorBoundary = class extends Component {
|
|
|
7456
7555
|
}
|
|
7457
7556
|
};
|
|
7458
7557
|
|
|
7459
|
-
// src/shadow/iframe-mount.ts
|
|
7460
|
-
var log18 = logger.scope("iframe");
|
|
7461
|
-
var IFRAME_SRCDOC = '<!doctype html><html><head><meta charset="utf-8"><style>html,body{margin:0;padding:0;background:transparent;overflow:hidden}</style></head><body></body></html>';
|
|
7462
|
-
function createIframeMount(opts, position, initialMode = "closed", layoutMode = "floating", target = null) {
|
|
7463
|
-
log18.debug("createIframeMount", { position, initialMode, layoutMode, hasTarget: !!target });
|
|
7464
|
-
const iframe = document.createElement("iframe");
|
|
7465
|
-
iframe.title = `${BRAND.name} chat`;
|
|
7466
|
-
iframe.setAttribute("allow", "microphone; clipboard-write");
|
|
7467
|
-
sizeIframe(iframe, position, initialMode, layoutMode);
|
|
7468
|
-
const parent = layoutMode === "inline" && target ? target : document.body;
|
|
7469
|
-
parent.appendChild(iframe);
|
|
7470
|
-
const doc = iframe.contentDocument;
|
|
7471
|
-
if (!doc) throw new Error("iframe contentDocument unavailable (cross-origin?)");
|
|
7472
|
-
doc.open();
|
|
7473
|
-
doc.write(IFRAME_SRCDOC);
|
|
7474
|
-
doc.close();
|
|
7475
|
-
const mount2 = createShadowMount({ ...opts, target: doc.body });
|
|
7476
|
-
const mo = new MutationObserver(() => {
|
|
7477
|
-
sizeIframe(iframe, position, mount2.hostElement.dataset.mode ?? "closed", layoutMode);
|
|
7478
|
-
});
|
|
7479
|
-
mo.observe(mount2.hostElement, { attributes: true, attributeFilter: ["data-mode"] });
|
|
7480
|
-
return {
|
|
7481
|
-
...mount2,
|
|
7482
|
-
iframeElement: iframe,
|
|
7483
|
-
destroy() {
|
|
7484
|
-
mo.disconnect();
|
|
7485
|
-
mount2.destroy();
|
|
7486
|
-
iframe.remove();
|
|
7487
|
-
}
|
|
7488
|
-
};
|
|
7489
|
-
}
|
|
7490
|
-
var BASE_CSS = "border:0;background:transparent;z-index:2147483647;pointer-events:auto;";
|
|
7491
|
-
var FLOATING_SIZE_BY_MODE = {
|
|
7492
|
-
closed: { w: "88px", h: "88px" },
|
|
7493
|
-
expanded: { w: "min(calc(100vw - 32px), 680px)", h: "min(calc(100vh - 32px), 860px)" },
|
|
7494
|
-
// `open` (normal) — also the fallback for any other non-fullscreen state.
|
|
7495
|
-
open: { w: "min(calc(100vw - 32px), 440px)", h: "min(calc(100vh - 32px), 700px)" }
|
|
7496
|
-
};
|
|
7497
|
-
function sizeIframe(iframe, position, mode, layoutMode) {
|
|
7498
|
-
if (mode === "fullscreen" || layoutMode === "standalone") {
|
|
7499
|
-
iframe.style.cssText = `${BASE_CSS}position:fixed;inset:0;width:100vw;height:100vh;`;
|
|
7500
|
-
return;
|
|
7501
|
-
}
|
|
7502
|
-
if (layoutMode === "inline") {
|
|
7503
|
-
iframe.style.cssText = `${BASE_CSS}position:static;display:block;width:100%;height:100%;`;
|
|
7504
|
-
return;
|
|
7505
|
-
}
|
|
7506
|
-
const compact = typeof matchMedia === "function" && matchMedia("(max-width: 640px)").matches;
|
|
7507
|
-
if (compact && (mode === "open" || mode === "expanded")) {
|
|
7508
|
-
iframe.style.cssText = `${BASE_CSS}position:fixed;inset:0;width:100vw;height:100vh;`;
|
|
7509
|
-
return;
|
|
7510
|
-
}
|
|
7511
|
-
const vKey = position.startsWith("top-") ? "top" : "bottom";
|
|
7512
|
-
const hKey = position.endsWith("-left") ? "left" : "right";
|
|
7513
|
-
const { w, h: h2 } = FLOATING_SIZE_BY_MODE[mode] ?? FLOATING_SIZE_BY_MODE.open;
|
|
7514
|
-
iframe.style.cssText = `${BASE_CSS}position:fixed;${vKey}:16px;${hKey}:16px;width:${w};height:${h2};`;
|
|
7515
|
-
}
|
|
7516
|
-
|
|
7517
|
-
// src/core/events.ts
|
|
7518
|
-
var EventBus = class {
|
|
7519
|
-
constructor() {
|
|
7520
|
-
__publicField(this, "handlers", /* @__PURE__ */ new Map());
|
|
7521
|
-
}
|
|
7522
|
-
/**
|
|
7523
|
-
* Register a listener for `name`.
|
|
7524
|
-
* @returns an `off` function that removes this listener.
|
|
7525
|
-
*/
|
|
7526
|
-
on(name, fn) {
|
|
7527
|
-
let set = this.handlers.get(name);
|
|
7528
|
-
if (!set) {
|
|
7529
|
-
set = /* @__PURE__ */ new Set();
|
|
7530
|
-
this.handlers.set(name, set);
|
|
7531
|
-
}
|
|
7532
|
-
set.add(fn);
|
|
7533
|
-
return () => this.handlers.get(name)?.delete(fn);
|
|
7534
|
-
}
|
|
7535
|
-
/**
|
|
7536
|
-
* Dispatch an event synchronously to all listeners.
|
|
7537
|
-
* Listener errors are swallowed — the widget must not crash on user callbacks.
|
|
7538
|
-
*/
|
|
7539
|
-
emit(name, payload) {
|
|
7540
|
-
const set = this.handlers.get(name);
|
|
7541
|
-
if (!set) return;
|
|
7542
|
-
for (const fn of set) {
|
|
7543
|
-
try {
|
|
7544
|
-
fn(payload);
|
|
7545
|
-
} catch {
|
|
7546
|
-
}
|
|
7547
|
-
}
|
|
7548
|
-
}
|
|
7549
|
-
/** Remove every listener. Called by the instance `destroy()`. */
|
|
7550
|
-
clear() {
|
|
7551
|
-
this.handlers.clear();
|
|
7552
|
-
}
|
|
7553
|
-
};
|
|
7554
|
-
|
|
7555
7558
|
// src/core/tracking.ts
|
|
7556
7559
|
var PROTOCOL_VERSION = "1";
|
|
7557
7560
|
var MAX_HITS_PER_MINUTE = 60;
|
|
@@ -7667,6 +7670,73 @@ function createTracker(bus, deps) {
|
|
|
7667
7670
|
};
|
|
7668
7671
|
}
|
|
7669
7672
|
|
|
7673
|
+
// src/core/boot.ts
|
|
7674
|
+
function createWidgetRuntime(params) {
|
|
7675
|
+
const { bus, host, appRoot, persistence, reportError } = params;
|
|
7676
|
+
let userRaw = params.initialRaw;
|
|
7677
|
+
let serverConfig;
|
|
7678
|
+
let currentOptions = resolveOptions(userRaw);
|
|
7679
|
+
let firstRender = true;
|
|
7680
|
+
const recompute = () => {
|
|
7681
|
+
currentOptions = resolveOptions(serverConfig ? mergeServerConfig(userRaw, serverConfig) : userRaw);
|
|
7682
|
+
};
|
|
7683
|
+
const applyHostStyling = () => {
|
|
7684
|
+
applyHostPosition(host, hostPositionForMode(currentOptions.mode));
|
|
7685
|
+
const cachedThemeMode = persistence.loadUserPrefs().themeMode;
|
|
7686
|
+
applyHostAttributes(host, cachedThemeMode ? { ...currentOptions, themeMode: cachedThemeMode } : currentOptions);
|
|
7687
|
+
if (firstRender) {
|
|
7688
|
+
applyMode(host, resolveInitialHostMode(currentOptions));
|
|
7689
|
+
firstRender = false;
|
|
7690
|
+
}
|
|
7691
|
+
};
|
|
7692
|
+
const render2 = () => {
|
|
7693
|
+
applyHostStyling();
|
|
7694
|
+
renderPreact(
|
|
7695
|
+
h(ErrorBoundary, { onError: reportError }, h(App, { bus, hostElement: host, options: currentOptions })),
|
|
7696
|
+
appRoot
|
|
7697
|
+
);
|
|
7698
|
+
};
|
|
7699
|
+
bus.on("handshake", (response) => {
|
|
7700
|
+
if (!response.config) return;
|
|
7701
|
+
serverConfig = response.config;
|
|
7702
|
+
recompute();
|
|
7703
|
+
render2();
|
|
7704
|
+
});
|
|
7705
|
+
const untrack = createTracker(bus, {
|
|
7706
|
+
getOptions: () => currentOptions,
|
|
7707
|
+
getVisitorId: () => persistence.getVisitorId(),
|
|
7708
|
+
getConversationId: () => persistence.loadConversationId()
|
|
7709
|
+
});
|
|
7710
|
+
return {
|
|
7711
|
+
getOptions: () => currentOptions,
|
|
7712
|
+
getUserOptions: () => userRaw,
|
|
7713
|
+
render: render2,
|
|
7714
|
+
setUserOptions: (raw) => {
|
|
7715
|
+
userRaw = raw;
|
|
7716
|
+
recompute();
|
|
7717
|
+
render2();
|
|
7718
|
+
},
|
|
7719
|
+
patchUserOptions: (patch) => {
|
|
7720
|
+
userRaw = { ...userRaw, ...patch };
|
|
7721
|
+
recompute();
|
|
7722
|
+
render2();
|
|
7723
|
+
},
|
|
7724
|
+
destroy: () => untrack()
|
|
7725
|
+
};
|
|
7726
|
+
}
|
|
7727
|
+
function resolveInitialHostMode(options) {
|
|
7728
|
+
if (options.mode === "standalone") return "standalone";
|
|
7729
|
+
if (options.mode === "inline") return "inline";
|
|
7730
|
+
const persistence = createPersistence(options.widgetId, options.storage);
|
|
7731
|
+
const { panelOpen, panelSize } = resolveInitialPanelState(
|
|
7732
|
+
options,
|
|
7733
|
+
currentViewportWidth(),
|
|
7734
|
+
persistence.loadPanelOpen(),
|
|
7735
|
+
persistence.loadPanelSize()
|
|
7736
|
+
);
|
|
7737
|
+
return computeHostMode(options.mode, panelSize, panelOpen);
|
|
7738
|
+
}
|
|
7739
|
+
|
|
7670
7740
|
// src/core/hooks.ts
|
|
7671
7741
|
var log19 = logger.scope("hooks");
|
|
7672
7742
|
var HOOK_WILDCARD = "*";
|
|
@@ -7752,73 +7822,45 @@ function mount(opts) {
|
|
|
7752
7822
|
if (opts.debug !== void 0) setLogLevel(opts.debug);
|
|
7753
7823
|
const log20 = logger.scope("mount");
|
|
7754
7824
|
log20.info("mount", { widgetId: opts.widgetId, publicKey: opts.publicKey, mode: opts.presentation?.mode });
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
const widgetId = currentOptions.widgetId;
|
|
7825
|
+
const resolved = resolveOptions(opts);
|
|
7826
|
+
const widgetId = resolved.widgetId;
|
|
7758
7827
|
const existing = instances.get(widgetId);
|
|
7759
7828
|
if (existing) {
|
|
7760
7829
|
log20.debug("destroy existing instance at slot", { widgetId });
|
|
7761
7830
|
existing.destroy();
|
|
7762
7831
|
}
|
|
7763
|
-
const initialHostMode = resolveInitialHostMode(
|
|
7764
|
-
const mountResult =
|
|
7765
|
-
{ position: hostPositionForMode(
|
|
7766
|
-
|
|
7832
|
+
const initialHostMode = resolveInitialHostMode(resolved);
|
|
7833
|
+
const mountResult = resolved.iframe ? createIframeMount(
|
|
7834
|
+
{ position: hostPositionForMode(resolved.mode) },
|
|
7835
|
+
resolved.position,
|
|
7767
7836
|
initialHostMode,
|
|
7768
|
-
|
|
7837
|
+
resolved.mode,
|
|
7769
7838
|
opts.target ?? null
|
|
7770
7839
|
) : createShadowMount({
|
|
7771
|
-
position: hostPositionForMode(
|
|
7840
|
+
position: hostPositionForMode(resolved.mode),
|
|
7772
7841
|
target: opts.target ?? null
|
|
7773
7842
|
});
|
|
7774
|
-
const persistence = createPersistence(currentOptions.widgetId, currentOptions.storage);
|
|
7775
|
-
const applyResolvedHostAttributes = () => {
|
|
7776
|
-
const cachedThemeMode = persistence.loadUserPrefs().themeMode;
|
|
7777
|
-
applyHostAttributes(
|
|
7778
|
-
mountResult.hostElement,
|
|
7779
|
-
cachedThemeMode ? { ...currentOptions, themeMode: cachedThemeMode } : currentOptions
|
|
7780
|
-
);
|
|
7781
|
-
};
|
|
7782
|
-
applyResolvedHostAttributes();
|
|
7783
|
-
applyMode(mountResult.hostElement, initialHostMode);
|
|
7784
7843
|
mountResult.hostElement.dataset.widgetId = widgetId;
|
|
7785
7844
|
const bus = new EventBus();
|
|
7845
|
+
const persistence = createPersistence(widgetId, resolved.storage);
|
|
7786
7846
|
const reportError = (error) => {
|
|
7787
7847
|
bus.emit("error", error);
|
|
7788
|
-
|
|
7789
|
-
};
|
|
7790
|
-
const renderApp = () => {
|
|
7791
|
-
render(
|
|
7792
|
-
h(
|
|
7793
|
-
ErrorBoundary,
|
|
7794
|
-
{ onError: reportError },
|
|
7795
|
-
h(App, { bus, hostElement: mountResult.hostElement, options: currentOptions })
|
|
7796
|
-
),
|
|
7797
|
-
mountResult.appRoot
|
|
7798
|
-
);
|
|
7848
|
+
runtime.getOptions().onError?.(error);
|
|
7799
7849
|
};
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
renderApp();
|
|
7808
|
-
});
|
|
7809
|
-
const unsubscribeTracker = createTracker(bus, {
|
|
7810
|
-
getOptions: () => currentOptions,
|
|
7811
|
-
getVisitorId: () => persistence.getVisitorId(),
|
|
7812
|
-
getConversationId: () => persistence.loadConversationId()
|
|
7850
|
+
const runtime = createWidgetRuntime({
|
|
7851
|
+
bus,
|
|
7852
|
+
host: mountResult.hostElement,
|
|
7853
|
+
appRoot: mountResult.appRoot,
|
|
7854
|
+
persistence,
|
|
7855
|
+
initialRaw: opts,
|
|
7856
|
+
reportError
|
|
7813
7857
|
});
|
|
7858
|
+
runtime.render();
|
|
7814
7859
|
const host = mountResult.hostElement;
|
|
7815
7860
|
let unsubscribeHooks = null;
|
|
7816
7861
|
const applyUpdate = (patch) => {
|
|
7817
7862
|
if (patch.debug !== void 0) setLogLevel(patch.debug);
|
|
7818
|
-
|
|
7819
|
-
currentOptions = resolveOptions(rawOptions);
|
|
7820
|
-
applyResolvedHostAttributes();
|
|
7821
|
-
renderApp();
|
|
7863
|
+
runtime.patchUserOptions(patch);
|
|
7822
7864
|
};
|
|
7823
7865
|
const instance = {
|
|
7824
7866
|
widgetId,
|
|
@@ -7837,7 +7879,7 @@ function mount(opts) {
|
|
|
7837
7879
|
// context; App re-handshakes with the SAME visitor/conversation.
|
|
7838
7880
|
setUserContext: (userContext) => {
|
|
7839
7881
|
log20.debug("setUserContext", { keys: Object.keys(userContext) });
|
|
7840
|
-
applyUpdate({ userContext: { ...
|
|
7882
|
+
applyUpdate({ userContext: { ...runtime.getUserOptions().userContext, ...userContext } });
|
|
7841
7883
|
},
|
|
7842
7884
|
clearUserContext: () => {
|
|
7843
7885
|
log20.debug("clearUserContext");
|
|
@@ -7845,7 +7887,7 @@ function mount(opts) {
|
|
|
7845
7887
|
},
|
|
7846
7888
|
setPageContext: (pageContext) => {
|
|
7847
7889
|
log20.debug("setPageContext", { keys: Object.keys(pageContext) });
|
|
7848
|
-
applyUpdate({ pageContext: { ...
|
|
7890
|
+
applyUpdate({ pageContext: { ...runtime.getUserOptions().pageContext, ...pageContext } });
|
|
7849
7891
|
},
|
|
7850
7892
|
clearPageContext: () => {
|
|
7851
7893
|
log20.debug("clearPageContext");
|
|
@@ -7860,7 +7902,7 @@ function mount(opts) {
|
|
|
7860
7902
|
destroy: () => {
|
|
7861
7903
|
log20.info("destroy", { widgetId });
|
|
7862
7904
|
unsubscribeHooks?.();
|
|
7863
|
-
|
|
7905
|
+
runtime.destroy();
|
|
7864
7906
|
bus.clear();
|
|
7865
7907
|
render(null, mountResult.appRoot);
|
|
7866
7908
|
mountResult.destroy();
|
|
@@ -7899,18 +7941,6 @@ function hook(widgetId, event, listener) {
|
|
|
7899
7941
|
}
|
|
7900
7942
|
var version = "0.1.0";
|
|
7901
7943
|
var brand = BRAND;
|
|
7902
|
-
function resolveInitialHostMode(options) {
|
|
7903
|
-
if (options.mode === "standalone") return "standalone";
|
|
7904
|
-
if (options.mode === "inline") return "inline";
|
|
7905
|
-
const persistence = createPersistence(options.widgetId, options.storage);
|
|
7906
|
-
const { panelOpen, panelSize } = resolveInitialPanelState(
|
|
7907
|
-
options,
|
|
7908
|
-
currentViewportWidth(),
|
|
7909
|
-
persistence.loadPanelOpen(),
|
|
7910
|
-
persistence.loadPanelSize()
|
|
7911
|
-
);
|
|
7912
|
-
return computeHostMode(options.mode, panelSize, panelOpen);
|
|
7913
|
-
}
|
|
7914
7944
|
export {
|
|
7915
7945
|
HOOK_WILDCARD,
|
|
7916
7946
|
brand,
|