@syntrologie/adapt-chatbot 2.53.0 → 2.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/runtime.js CHANGED
@@ -1334,6 +1334,24 @@ var ChatTransport = class {
1334
1334
  };
1335
1335
  var chatTransport = new ChatTransport();
1336
1336
 
1337
+ // src/findSmartCanvas.ts
1338
+ function findSmartCanvas() {
1339
+ if (typeof document === "undefined") return null;
1340
+ const find = (root) => {
1341
+ const direct = root.querySelector("smart-canvas");
1342
+ if (direct) return direct;
1343
+ for (const el of root.querySelectorAll("*")) {
1344
+ const sr = el.shadowRoot;
1345
+ if (sr) {
1346
+ const found = find(sr);
1347
+ if (found) return found;
1348
+ }
1349
+ }
1350
+ return null;
1351
+ };
1352
+ return find(document);
1353
+ }
1354
+
1337
1355
  // src/observer/allowlist.ts
1338
1356
  var MAX_TEXT_LEN = 200;
1339
1357
  var SIGNIFICANT_CLICK_TAGS = /* @__PURE__ */ new Set(["button", "a"]);
@@ -2113,6 +2131,47 @@ function registerLeadConnectorBridge() {
2113
2131
  registerLeadConnectorBridge();
2114
2132
 
2115
2133
  // src/support-chat/boot.ts
2134
+ var SUPPORT_CHAT_WATCH_TICK_MS = 500;
2135
+ var SUPPORT_CHAT_WATCH_MAX_MS = 30 * 60 * 1e3;
2136
+ var watches = /* @__PURE__ */ new Map();
2137
+ function settleWatch(bridge, watch) {
2138
+ clearInterval(watch.timer);
2139
+ watches.delete(bridge);
2140
+ if (watch.suppressNative) bridge.hideNative();
2141
+ for (const cb of watch.listeners) cb();
2142
+ watch.listeners.clear();
2143
+ }
2144
+ function ensureWatch(bridge, suppressNative) {
2145
+ const existing = watches.get(bridge);
2146
+ if (existing) {
2147
+ existing.suppressNative = existing.suppressNative || suppressNative;
2148
+ return existing;
2149
+ }
2150
+ console.info(
2151
+ `supportChat.bridge: vendor '${bridge.vendor}' is not on the page yet \u2014 watching for it (delayed-script hosts load it on the first interaction)`
2152
+ );
2153
+ const watch = {
2154
+ startedAt: Date.now(),
2155
+ suppressNative,
2156
+ listeners: /* @__PURE__ */ new Set(),
2157
+ timer: setInterval(() => {
2158
+ if (bridge.detect()) {
2159
+ settleWatch(bridge, watch);
2160
+ return;
2161
+ }
2162
+ if (Date.now() - watch.startedAt >= SUPPORT_CHAT_WATCH_MAX_MS) {
2163
+ clearInterval(watch.timer);
2164
+ watches.delete(bridge);
2165
+ watch.listeners.clear();
2166
+ console.warn(
2167
+ `supportChat.bridge: vendor '${bridge.vendor}' never appeared within ${SUPPORT_CHAT_WATCH_MAX_MS / 6e4} minutes \u2014 handoff disabled`
2168
+ );
2169
+ }
2170
+ }, SUPPORT_CHAT_WATCH_TICK_MS)
2171
+ };
2172
+ watches.set(bridge, watch);
2173
+ return watch;
2174
+ }
2116
2175
  function bootSupportChat(cfg2) {
2117
2176
  if (!cfg2?.vendor) return void 0;
2118
2177
  registerCrispBridge();
@@ -2127,442 +2186,29 @@ function bootSupportChat(cfg2) {
2127
2186
  leadConnectorBridge.configure({ widgetId: cfg2.widgetId });
2128
2187
  }
2129
2188
  const bridge = getSupportChatBridge(cfg2.vendor);
2130
- if (!bridge || !bridge.detect()) {
2131
- console.warn(
2132
- `supportChat.bridge: vendor '${cfg2.vendor}' not detected on this page \u2014 handoff disabled`
2133
- );
2189
+ if (!bridge) {
2190
+ console.warn(`supportChat.bridge: no bridge for vendor '${cfg2.vendor}' \u2014 handoff disabled`);
2134
2191
  return void 0;
2135
2192
  }
2136
- if (cfg2.suppressNative) bridge.hideNative();
2137
- return bridge;
2138
- }
2139
-
2140
- // src/AdaptiveChatBarMountable.ts
2141
- var STATE_KEY = "__syntroChatBarMount";
2142
- function getState(container) {
2143
- return container[STATE_KEY] ?? null;
2144
- }
2145
- function setState(container, state) {
2146
- container[STATE_KEY] = state;
2147
- }
2148
- function applyPlaceholder(bar, cfg2) {
2149
- if (cfg2.placeholder !== void 0) bar.placeholder = cfg2.placeholder;
2150
- if (cfg2.assistantName !== void 0) bar.assistantName = cfg2.assistantName;
2151
- if (cfg2.personas !== void 0) bar.personas = cfg2.personas;
2152
- if (cfg2.greeting !== void 0) bar.greeting = cfg2.greeting;
2153
- if (cfg2.voiceInput !== void 0) bar.voiceInput = cfg2.voiceInput;
2154
- bar.introSuggestion = cfg2.introSuggestion;
2155
- bar.forceExpanded = cfg2.forceExpanded === true;
2156
- if (typeof cfg2.maximized === "boolean") {
2157
- bar.maximized = cfg2.maximized;
2193
+ if (bridge.detect()) {
2194
+ if (cfg2.suppressNative) bridge.hideNative();
2195
+ return bridge;
2158
2196
  }
2197
+ ensureWatch(bridge, cfg2.suppressNative === true);
2198
+ return bridge;
2159
2199
  }
2160
- var _elementStore = null;
2161
- var _templateWidgetMap = /* @__PURE__ */ new Map();
2162
- var SERVER_MOUNTED_TILE_WIDGETS = ["syntro-product-reco-carousel"];
2163
- function resolveTileWidget(templateId) {
2164
- return _templateWidgetMap.get(templateId);
2165
- }
2166
- function refreshTemplateWidgetMap(uiTemplates) {
2167
- _templateWidgetMap.clear();
2168
- for (const tag of SERVER_MOUNTED_TILE_WIDGETS) {
2169
- _templateWidgetMap.set(tag, tag);
2170
- }
2171
- if (!uiTemplates) return;
2172
- const tiles = uiTemplates.tiles;
2173
- if (!Array.isArray(tiles)) return;
2174
- for (const t of tiles) {
2175
- const id = typeof t?.id === "string" ? t.id : null;
2176
- const widget = typeof t?.widget === "string" ? t.widget : null;
2177
- if (id && widget) _templateWidgetMap.set(id, widget);
2200
+ function onSupportChatReady(bridge, cb) {
2201
+ if (bridge.detect()) {
2202
+ cb();
2203
+ return () => {
2204
+ };
2178
2205
  }
2179
- }
2180
- function getOrCreateElementStore(runtime2) {
2181
- if (_elementStore) return _elementStore;
2182
- _elementStore = new ElementInstanceStore({
2183
- actions: runtime2.actions,
2184
- // Pass the runtime's event bus so ItemHandler can broadcast
2185
- // `element.compositional_append` / `_patch` / `_remove` events
2186
- // to container widgets (chips strip, FAQ accordion, nav tips).
2187
- events: {
2188
- publish: runtime2.events.publish.bind(runtime2.events),
2189
- subscribe: runtime2.events.subscribe?.bind(runtime2.events)
2190
- },
2191
- handlers: [new TileHandler(resolveTileWidget), new ActionHandler(), new ItemHandler()],
2192
- resolveTileWidget
2193
- });
2194
- setElementInstanceStore(_elementStore);
2195
- return _elementStore;
2196
- }
2197
- var _hydrationStarted = false;
2198
- function hydrateOnce(runtime2, backendUrl) {
2199
- if (_hydrationStarted) return;
2200
- _hydrationStarted = true;
2201
- const store = getOrCreateElementStore(runtime2);
2202
- const trimmed = backendUrl.replace(/\/$/, "");
2203
- const endpoint = trimmed ? `${trimmed}/api/adaptive/mounted_elements` : "/api/adaptive/mounted_elements";
2204
- fetchMountedElements({ endpoint, token: runtime2.token }).then((response) => {
2205
- if (!response) return;
2206
- void store.hydrate(response.mounted_elements);
2207
- });
2208
- }
2209
- var PAGE_LEVEL_KINDS = /* @__PURE__ */ new Set(["view", "scroll", "idle", "hesitation", "hover", "nav"]);
2210
- function buildObserverEnrich(runtimeRef) {
2211
- return (ev, raw) => {
2212
- const extract = runtimeRef.getProductIdentity;
2213
- if (typeof extract !== "function") return ev;
2214
- if (ev.kind === "click") {
2215
- const chain = raw.properties.$elements;
2216
- if (!Array.isArray(chain)) return ev;
2217
- const id = extract(chain);
2218
- if (!id) return ev;
2219
- return {
2220
- ...ev,
2221
- product: {
2222
- handle: id.productHandle,
2223
- url: id.productUrl,
2224
- ...id.productTitle ? { title: id.productTitle } : {}
2225
- }
2226
- };
2227
- }
2228
- if (!ev.product && PAGE_LEVEL_KINDS.has(ev.kind) && typeof location !== "undefined") {
2229
- const id = extract([{ href: location.pathname }]);
2230
- if (!id) return ev;
2231
- return {
2232
- ...ev,
2233
- product: {
2234
- handle: id.productHandle,
2235
- url: id.productUrl,
2236
- ...id.productTitle ? { title: id.productTitle } : {}
2237
- }
2238
- };
2239
- }
2240
- return ev;
2241
- };
2242
- }
2243
- var _nudgeSurfaceWired = false;
2244
- var _nudgeListener = null;
2245
- function wireNudgeSurface(runtime2, backendUrl) {
2246
- if (_nudgeSurfaceWired || typeof document === "undefined") return;
2247
- _nudgeSurfaceWired = true;
2248
- _nudgeListener = (e) => {
2249
- try {
2250
- const detail = e.detail;
2251
- const isIntent = detail?.phase === "intent";
2252
- if (!isIntent) {
2253
- const store = getOrCreateElementStore(runtime2);
2254
- const trimmed = backendUrl.replace(/\/$/, "");
2255
- const endpoint = trimmed ? `${trimmed}/api/adaptive/mounted_elements` : "/api/adaptive/mounted_elements";
2256
- void fetchMountedElements({ endpoint, token: runtime2.token }).then((response) => {
2257
- if (!response) return;
2258
- void store.hydrate(response.mounted_elements);
2259
- });
2260
- }
2261
- if (detail?.suppressToast === true) return;
2262
- const findCanvas = (root) => {
2263
- const direct = root.querySelector("smart-canvas");
2264
- if (direct) return direct;
2265
- for (const el of root.querySelectorAll("*")) {
2266
- const sr = el.shadowRoot;
2267
- if (sr) {
2268
- const found = findCanvas(sr);
2269
- if (found) return found;
2270
- }
2271
- }
2272
- return null;
2273
- };
2274
- const canvas = findCanvas(document);
2275
- const messageId = e.detail?.messageId;
2276
- const nudgeText = messageId ? (chatSession.getState().messages.find((m) => m.id === messageId)?.text ?? "").trim() : "";
2277
- const title = nudgeText ? nudgeText.length > 140 ? `${nudgeText.slice(0, 137)}\u2026` : nudgeText : "I put something together for you";
2278
- canvas?.previewNotification?.({
2279
- title,
2280
- body: "Tap to take a look"
2281
- });
2282
- } catch (err) {
2283
- console.warn("[adaptive-chatbot] nudge surface reaction failed", err);
2284
- }
2206
+ const watch = ensureWatch(bridge, false);
2207
+ watch.listeners.add(cb);
2208
+ return () => {
2209
+ watch.listeners.delete(cb);
2285
2210
  };
2286
- document.addEventListener("syntro:nudge", _nudgeListener);
2287
- }
2288
- function configureTransportIfPossible(cfg2) {
2289
- if (!cfg2.runtime) return;
2290
- const backendUrl = cfg2.runtime.backendUrl;
2291
- if (!backendUrl) return;
2292
- const elementsActive = cfg2.elementsEnabled === true && cfg2.uiTemplates != null;
2293
- refreshTemplateWidgetMap(elementsActive ? cfg2.uiTemplates : void 0);
2294
- const forwardedProps = elementsActive ? { elementsEnabled: true, uiTemplates: cfg2.uiTemplates } : void 0;
2295
- if (elementsActive) publishTemplatesIfPossible(backendUrl, cfg2.uiTemplates, cfg2.runtime?.token);
2296
- const runtime2 = cfg2.runtime;
2297
- const onElementMutation = elementsActive ? (mutations) => {
2298
- void getOrCreateElementStore(runtime2).apply(mutations);
2299
- } : void 0;
2300
- if (elementsActive) {
2301
- hydrateOnce(runtime2, backendUrl);
2302
- }
2303
- const persona = pickPersona(cfg2.personas ?? null);
2304
- chatTransport.configure({
2305
- ...cfg2,
2306
- backendUrl,
2307
- forwardedProps,
2308
- onElementMutation,
2309
- activeLidSlot: cfg2._syntroSlotName,
2310
- personaId: persona?.id,
2311
- personaName: persona?.name,
2312
- personaRole: persona?.role_title
2313
- });
2314
- void chatTransport.startSessionStream();
2315
- wireNudgeSurface(runtime2, backendUrl);
2316
- startObserverIfPossible(cfg2);
2317
- }
2318
- var _templatesPublished = false;
2319
- function publishTemplatesIfPossible(backendUrl, uiTemplates, token) {
2320
- if (_templatesPublished || typeof window === "undefined") return;
2321
- if (!uiTemplates || typeof uiTemplates !== "object") return;
2322
- _templatesPublished = true;
2323
- const headers2 = { "Content-Type": "application/json" };
2324
- if (token) headers2.Authorization = `Bearer ${token}`;
2325
- const editorToken = readEditorToken();
2326
- if (editorToken) headers2["X-Syntro-Editor-Token"] = editorToken;
2327
- const trimmed = backendUrl.replace(/\/$/, "");
2328
- void fetch(`${trimmed}/api/adaptive/templates`, {
2329
- method: "POST",
2330
- headers: headers2,
2331
- credentials: "include",
2332
- body: JSON.stringify({ ui_templates: uiTemplates })
2333
- }).catch(() => {
2334
- });
2335
- }
2336
- var _diveDeeperWired = false;
2337
- function wireDiveDeeperListener() {
2338
- if (_diveDeeperWired || typeof window === "undefined") return;
2339
- _diveDeeperWired = true;
2340
- window.addEventListener(DIVE_DEEPER_EVENT, (e) => {
2341
- const detail = e.detail ?? {};
2342
- const prompt = typeof detail.prompt === "string" && detail.prompt.trim() ? detail.prompt : detail.title ? "I'd like to dive deeper on this, I didn't see what I needed." : "";
2343
- if (!prompt) return;
2344
- const origin = { kind: "dive-deeper" };
2345
- if (detail.title) origin.title = detail.title;
2346
- if (detail.context) origin.context = detail.context;
2347
- chatSession.send(prompt, { forwardedProps: { origin } });
2348
- if (!chatSession.hasTransport()) {
2349
- chatSession.error("Chat backend not configured \u2014 set backendUrl in the canvas config.");
2350
- }
2351
- });
2352
2211
  }
2353
- var _observerStarted = false;
2354
- var _observerRuntime = null;
2355
- var _observerHandle = null;
2356
- var _observerBusUnsubscribe = null;
2357
- function startObserverIfPossible(cfg2) {
2358
- if (typeof window === "undefined") return;
2359
- const runtimeRef = cfg2.runtime;
2360
- if (!runtimeRef?.events?.subscribe) return;
2361
- if (_observerStarted && _observerRuntime === runtimeRef) return;
2362
- if (_observerStarted) {
2363
- _observerBusUnsubscribe?.();
2364
- _observerHandle?.stop();
2365
- _observerBusUnsubscribe = null;
2366
- _observerHandle = null;
2367
- _observerStarted = false;
2368
- }
2369
- const trimmed = (runtimeRef.backendUrl ?? "").replace(/\/$/, "");
2370
- const url = trimmed ? `${trimmed}/api/adaptive/observation` : "/api/adaptive/observation";
2371
- const runtimeId = (method) => {
2372
- try {
2373
- const v = runtimeRef.telemetry?.[method]?.();
2374
- return typeof v === "string" && v.length > 0 ? v : null;
2375
- } catch {
2376
- return null;
2377
- }
2378
- };
2379
- const getDistinctId = () => runtimeId("getDistinctId");
2380
- const getSessionId = () => runtimeId("getSessionId");
2381
- const token = () => {
2382
- const t = runtimeRef.token;
2383
- return typeof t === "string" ? t : "";
2384
- };
2385
- const enrich = buildObserverEnrich(runtimeRef);
2386
- const handle = startObserver({ url, token, getDistinctId, getSessionId, enrich });
2387
- window.__syntroObserverStats = () => handle.stats();
2388
- const unsubscribe = runtimeRef.events.subscribe({}, (evt) => {
2389
- const raw = busEventToRawEvent(evt);
2390
- if (raw) handle.ingest(raw);
2391
- });
2392
- _observerRuntime = runtimeRef;
2393
- _observerHandle = handle;
2394
- _observerBusUnsubscribe = unsubscribe;
2395
- _observerStarted = true;
2396
- }
2397
- function wireListeners(bar, state) {
2398
- const onMessageSent = (e) => {
2399
- const text = e.detail.text;
2400
- chatSession.send(text, { activeLidSlot: state.cfg._syntroSlotName });
2401
- if (!chatSession.hasTransport()) {
2402
- chatSession.error("Chat backend not configured \u2014 set backendUrl in the canvas config.");
2403
- }
2404
- };
2405
- const onInterrupt = () => {
2406
- chatSession.interrupt();
2407
- };
2408
- const onToolCallApproved = (e) => {
2409
- const detail = e.detail;
2410
- chatSession.resolveToolCall(detail.toolCallId, {}, detail.approved);
2411
- };
2412
- const onClose = () => {
2413
- state.cfg.onClose?.();
2414
- };
2415
- bar.addEventListener("chat-message-sent", onMessageSent);
2416
- bar.addEventListener("chat-interrupt", onInterrupt);
2417
- bar.addEventListener("canvas-close", onClose);
2418
- bar.addEventListener("trail-toolcall-approved", onToolCallApproved);
2419
- return () => {
2420
- bar.removeEventListener("chat-message-sent", onMessageSent);
2421
- bar.removeEventListener("chat-interrupt", onInterrupt);
2422
- bar.removeEventListener("canvas-close", onClose);
2423
- bar.removeEventListener("trail-toolcall-approved", onToolCallApproved);
2424
- };
2425
- }
2426
- var AdaptiveChatBarMountable = {
2427
- mount(container, mountConfig) {
2428
- const cfg2 = mountConfig ?? {};
2429
- configureTransportIfPossible(cfg2);
2430
- bootSupportChat(cfg2.supportChat);
2431
- wireDiveDeeperListener();
2432
- const bar = document.createElement("adaptive-chat-bar");
2433
- applyPlaceholder(bar, cfg2);
2434
- const widgets = cfg2.runtime?.widgets;
2435
- if (widgets) {
2436
- bar.mountInlineWidget = (widgetId, container2, props) => {
2437
- if (!widgets.has(widgetId)) return null;
2438
- const handle = widgets.mount(widgetId, container2, props);
2439
- const element = container2.firstElementChild;
2440
- if (!element) {
2441
- handle.unmount?.();
2442
- return null;
2443
- }
2444
- return { element, cleanup: () => handle.unmount?.() };
2445
- };
2446
- }
2447
- const unsubSession = chatSession.subscribe((s) => {
2448
- bar.messages = [...s.messages];
2449
- bar.inFlight = s.inFlight;
2450
- bar.thinkingText = s.thinkingText;
2451
- });
2452
- const runtimeEvents = cfg2.runtime ? cfg2.runtime.events : void 0;
2453
- const refreshReceipts = () => {
2454
- const store = _elementStore;
2455
- if (store) {
2456
- bar.tileReceipts = store.listTileReceipts();
2457
- bar.inlineWidgets = store.listInlineWidgets();
2458
- }
2459
- };
2460
- let unsubReceipts;
2461
- if (runtimeEvents?.subscribe) {
2462
- unsubReceipts = runtimeEvents.subscribe(
2463
- { names: [TILE_MOUNTED_EVENT, TILE_UNMOUNTED_EVENT] },
2464
- refreshReceipts
2465
- );
2466
- }
2467
- refreshReceipts();
2468
- const state = { bar, cleanup: () => {
2469
- }, cfg: cfg2 };
2470
- const unwireListeners = wireListeners(bar, state);
2471
- container.appendChild(bar);
2472
- const unsubFallback = chatTransport.onFallback(() => {
2473
- bar.remove();
2474
- container.innerHTML = renderFallbackHtml(state.cfg.fallback);
2475
- });
2476
- state.cleanup = () => {
2477
- unsubSession();
2478
- unsubFallback();
2479
- unsubReceipts?.();
2480
- unwireListeners();
2481
- bar.remove();
2482
- setState(container, null);
2483
- };
2484
- setState(container, state);
2485
- return state.cleanup;
2486
- },
2487
- update(container, mountConfig) {
2488
- const state = getState(container);
2489
- if (!state) return;
2490
- const cfg2 = mountConfig ?? {};
2491
- configureTransportIfPossible(cfg2);
2492
- applyPlaceholder(state.bar, cfg2);
2493
- state.cfg = cfg2;
2494
- }
2495
- };
2496
-
2497
- // src/AdaptiveChipsStripMountable.ts
2498
- var STATE_KEY2 = "__syntroChipsStripMount";
2499
- function getState2(container) {
2500
- return container[STATE_KEY2] ?? null;
2501
- }
2502
- function setState2(container, state) {
2503
- container[STATE_KEY2] = state;
2504
- }
2505
- function applyProps(strip, cfg2) {
2506
- if (cfg2.chips !== void 0) strip.chips = cfg2.chips;
2507
- if (cfg2.runtime !== void 0) {
2508
- strip.runtimeRef = cfg2.runtime;
2509
- }
2510
- if (cfg2.chromeless !== void 0) strip.chromeless = cfg2.chromeless;
2511
- }
2512
- var AdaptiveChipsStripMountable = {
2513
- mount(container, mountConfig) {
2514
- const cfg2 = mountConfig ?? {};
2515
- const strip = document.createElement("adaptive-chips-strip");
2516
- applyProps(strip, cfg2);
2517
- const state = {
2518
- strip,
2519
- listeners: {
2520
- revealed: (e) => {
2521
- const cb = cfg2.onChipRevealed;
2522
- if (cb) {
2523
- cb(
2524
- e.detail
2525
- );
2526
- }
2527
- },
2528
- dismissed: (e) => {
2529
- const cb = cfg2.onChipDismissed;
2530
- if (cb) cb(e.detail);
2531
- }
2532
- }
2533
- };
2534
- strip.addEventListener("chip-revealed", state.listeners.revealed);
2535
- strip.addEventListener("chip-dismissed", state.listeners.dismissed);
2536
- container.appendChild(strip);
2537
- setState2(container, state);
2538
- return () => {
2539
- strip.removeEventListener("chip-revealed", state.listeners.revealed);
2540
- strip.removeEventListener("chip-dismissed", state.listeners.dismissed);
2541
- strip.remove();
2542
- setState2(container, null);
2543
- };
2544
- },
2545
- update(container, mountConfig) {
2546
- const state = getState2(container);
2547
- if (!state) return;
2548
- const cfg2 = mountConfig ?? {};
2549
- applyProps(state.strip, cfg2);
2550
- state.strip.removeEventListener("chip-revealed", state.listeners.revealed);
2551
- state.strip.removeEventListener("chip-dismissed", state.listeners.dismissed);
2552
- state.listeners.revealed = (e) => {
2553
- const cb = cfg2.onChipRevealed;
2554
- if (cb) {
2555
- cb(e.detail);
2556
- }
2557
- };
2558
- state.listeners.dismissed = (e) => {
2559
- const cb = cfg2.onChipDismissed;
2560
- if (cb) cb(e.detail);
2561
- };
2562
- state.strip.addEventListener("chip-revealed", state.listeners.revealed);
2563
- state.strip.addEventListener("chip-dismissed", state.listeners.dismissed);
2564
- }
2565
- };
2566
2212
 
2567
2213
  // src/LeaveAMessageLit.ts
2568
2214
  import { html, LitElement, nothing } from "lit";
@@ -2707,8 +2353,14 @@ var trailHostStyles = {
2707
2353
  width: "100%",
2708
2354
  boxSizing: "border-box"
2709
2355
  };
2710
- var PERSIST_NAMESPACE = "supportchat";
2711
- var PERSIST_KEY = "leave-a-message";
2356
+ var LEAVE_A_MESSAGE_PERSIST_NAMESPACE = "supportchat";
2357
+ var LEAVE_A_MESSAGE_PERSIST_KEY = "leave-a-message";
2358
+ var PERSIST_NAMESPACE = LEAVE_A_MESSAGE_PERSIST_NAMESPACE;
2359
+ var PERSIST_KEY = LEAVE_A_MESSAGE_PERSIST_KEY;
2360
+ var liveCards = /* @__PURE__ */ new Set();
2361
+ function liveLeaveAMessageCards() {
2362
+ return liveCards;
2363
+ }
2712
2364
  var lamUidCounter = 0;
2713
2365
  var LeaveAMessageLit = class extends LitElement {
2714
2366
  constructor() {
@@ -2878,6 +2530,10 @@ var LeaveAMessageLit = class extends LitElement {
2878
2530
  super.connectedCallback();
2879
2531
  this._loadPersisted();
2880
2532
  this.addEventListener("keydown", this._onKeyDown);
2533
+ liveCards.add(this);
2534
+ if (this.bridge) {
2535
+ this._readyUnsub = onSupportChatReady(this.bridge, () => this.requestUpdate());
2536
+ }
2881
2537
  }
2882
2538
  updated() {
2883
2539
  if (this.state !== "form" && this.bridge && this.bridge.detect() && !this._unsubscribe) {
@@ -2886,15 +2542,36 @@ var LeaveAMessageLit = class extends LitElement {
2886
2542
  }
2887
2543
  disconnectedCallback() {
2888
2544
  this.removeEventListener("keydown", this._onKeyDown);
2545
+ liveCards.delete(this);
2546
+ this._readyUnsub?.();
2547
+ this._readyUnsub = void 0;
2889
2548
  this._unsubscribe?.();
2890
2549
  this._unsubscribe = void 0;
2891
2550
  this._noticeHandle?.dismiss();
2892
2551
  this._noticeHandle = void 0;
2893
2552
  super.disconnectedCallback();
2894
2553
  }
2554
+ /** Is this card's own vendor subscription delivering replies? While it
2555
+ * is, the page-level inbox leaves every message to the card. */
2556
+ get isListening() {
2557
+ return this._unsubscribe !== void 0;
2558
+ }
2559
+ /** Hand the card a team message that arrived through the page-level
2560
+ * inbox (support-chat/inbox.ts) while the card was mounted but not yet
2561
+ * listening — a compose-step card the concierge put up moments before
2562
+ * the team's own message landed. */
2563
+ receiveOperatorMessage(text) {
2564
+ this._onReply(text);
2565
+ }
2566
+ /** Open the thread face — what tapping the mail face or an announcement
2567
+ * does. Used by the page-level inbox when its announcement is tapped
2568
+ * after a card has already mounted and hydrated the thread. */
2569
+ showThread() {
2570
+ this._flip();
2571
+ }
2895
2572
  /** Read the injected persistence store, if any (I2). */
2896
2573
  _persistStore() {
2897
- return this.runtime?.state?.user?.ns?.(PERSIST_NAMESPACE);
2574
+ return this.runtime?.state?.ns?.(PERSIST_NAMESPACE);
2898
2575
  }
2899
2576
  /** Hydrate {state, transcript, email} from a prior page's mount. */
2900
2577
  _loadPersisted() {
@@ -2968,20 +2645,8 @@ var LeaveAMessageLit = class extends LitElement {
2968
2645
  if (typeof document === "undefined") return;
2969
2646
  const title = this.replyToast?.title?.trim();
2970
2647
  if (!title) return;
2971
- const find = (root) => {
2972
- const direct = root.querySelector("smart-canvas");
2973
- if (direct) return direct;
2974
- for (const el of root.querySelectorAll("*")) {
2975
- const sr = el.shadowRoot;
2976
- if (sr) {
2977
- const found = find(sr);
2978
- if (found) return found;
2979
- }
2980
- }
2981
- return null;
2982
- };
2983
2648
  try {
2984
- const canvas = find(document);
2649
+ const canvas = findSmartCanvas();
2985
2650
  this._noticeHandle?.dismiss();
2986
2651
  this._noticeHandle = void 0;
2987
2652
  const handle = canvas?.previewNotification?.({
@@ -3179,6 +2844,544 @@ function registerLeaveAMessageLit() {
3179
2844
  }
3180
2845
  registerLeaveAMessageLit();
3181
2846
 
2847
+ // src/support-chat/inbox.ts
2848
+ var LEAVE_A_MESSAGE_WIDGET_ID = "adaptive-chatbot:leave-a-message";
2849
+ var SUPPORT_CHAT_INBOX_INSTANCE_ID = "supportchat-inbox";
2850
+ function findLeaveAMessageTemplate(uiTemplates) {
2851
+ const tiles = uiTemplates?.tiles;
2852
+ if (!Array.isArray(tiles)) return void 0;
2853
+ const t = tiles.find((x) => x?.widget === LEAVE_A_MESSAGE_WIDGET_ID);
2854
+ if (!t) return void 0;
2855
+ const slot = typeof t.default_slot === "string" && t.default_slot ? t.default_slot : "drawer";
2856
+ const props = t.default_widget_props && typeof t.default_widget_props === "object" ? t.default_widget_props : {};
2857
+ return { slot, props };
2858
+ }
2859
+ var _wired;
2860
+ function wireSupportChatInbox(opts) {
2861
+ const { bridge, inbox, runtime: runtime2, uiTemplates } = opts;
2862
+ const store = runtime2?.state?.ns?.(LEAVE_A_MESSAGE_PERSIST_NAMESPACE);
2863
+ let replyUnsub;
2864
+ let mountUnsub;
2865
+ let unmountUnsub;
2866
+ let notice;
2867
+ let localSlot;
2868
+ const readThread = () => store?.get(LEAVE_A_MESSAGE_PERSIST_KEY) ?? {};
2869
+ const openThread = () => {
2870
+ const thread = readThread();
2871
+ store?.set(LEAVE_A_MESSAGE_PERSIST_KEY, { ...thread, state: "flipped" });
2872
+ notice = void 0;
2873
+ const live = liveLeaveAMessageCards().values().next().value;
2874
+ if (live) {
2875
+ live.showThread();
2876
+ return;
2877
+ }
2878
+ const template = findLeaveAMessageTemplate(uiTemplates);
2879
+ if (!template || !inbox || !runtime2) {
2880
+ console.warn(
2881
+ `supportChat.inbox: cannot open the thread \u2014 uiTemplates declares no ${LEAVE_A_MESSAGE_WIDGET_ID} tile for this workspace`
2882
+ );
2883
+ return;
2884
+ }
2885
+ const props = {
2886
+ slot: template.slot,
2887
+ instance_id: SUPPORT_CHAT_INBOX_INSTANCE_ID,
2888
+ widget: LEAVE_A_MESSAGE_WIDGET_ID,
2889
+ props: { ...template.props, title: inbox.title, message: "", context_summary: "" }
2890
+ };
2891
+ localSlot = template.slot;
2892
+ runtime2.events.publish(TILE_MOUNTED_EVENT, props);
2893
+ };
2894
+ const onMessage = (text) => {
2895
+ const card = liveLeaveAMessageCards().values().next().value;
2896
+ if (card) {
2897
+ if (!card.isListening) card.receiveOperatorMessage(text);
2898
+ return;
2899
+ }
2900
+ if (!inbox) {
2901
+ console.warn(
2902
+ `supportChat.inbox: a '${bridge.vendor}' team message arrived with no handoff card mounted and no supportChat.inbox authored \u2014 dropped`
2903
+ );
2904
+ return;
2905
+ }
2906
+ const thread = readThread();
2907
+ store?.set(LEAVE_A_MESSAGE_PERSIST_KEY, {
2908
+ ...thread,
2909
+ state: thread.state === "flipped" ? "flipped" : "mail",
2910
+ transcript: [...thread.transcript ?? [], { role: "operator", text }]
2911
+ });
2912
+ const canvas = findSmartCanvas();
2913
+ notice?.dismiss();
2914
+ notice = void 0;
2915
+ const handle = canvas?.previewNotification?.({
2916
+ title: inbox.toastTitle,
2917
+ body: text,
2918
+ persistent: true,
2919
+ onTap: openThread
2920
+ });
2921
+ if (handle && typeof handle.dismiss === "function") notice = handle;
2922
+ };
2923
+ const readyUnsub = onSupportChatReady(bridge, () => {
2924
+ replyUnsub = bridge.onOperatorReply(onMessage);
2925
+ });
2926
+ if (runtime2?.events.subscribe) {
2927
+ mountUnsub = runtime2.events.subscribe({ names: [TILE_MOUNTED_EVENT] }, (e) => {
2928
+ const p = e.props;
2929
+ if (!localSlot || p?.widget !== LEAVE_A_MESSAGE_WIDGET_ID) return;
2930
+ if (p.instance_id === SUPPORT_CHAT_INBOX_INSTANCE_ID) return;
2931
+ const unmount = {
2932
+ slot: localSlot,
2933
+ instance_id: SUPPORT_CHAT_INBOX_INSTANCE_ID
2934
+ };
2935
+ localSlot = void 0;
2936
+ runtime2.events.publish(TILE_UNMOUNTED_EVENT, unmount);
2937
+ });
2938
+ unmountUnsub = runtime2.events.subscribe({ names: [TILE_UNMOUNTED_EVENT] }, (e) => {
2939
+ const p = e.props;
2940
+ if (p?.instance_id === SUPPORT_CHAT_INBOX_INSTANCE_ID) localSlot = void 0;
2941
+ });
2942
+ }
2943
+ const cleanup = () => {
2944
+ readyUnsub();
2945
+ replyUnsub?.();
2946
+ replyUnsub = void 0;
2947
+ mountUnsub?.();
2948
+ mountUnsub = void 0;
2949
+ unmountUnsub?.();
2950
+ unmountUnsub = void 0;
2951
+ notice?.dismiss();
2952
+ notice = void 0;
2953
+ if (_wired === cleanup) _wired = void 0;
2954
+ };
2955
+ _wired = cleanup;
2956
+ return cleanup;
2957
+ }
2958
+ function isSupportChatInboxWired() {
2959
+ return _wired !== void 0;
2960
+ }
2961
+
2962
+ // src/AdaptiveChatBarMountable.ts
2963
+ var STATE_KEY = "__syntroChatBarMount";
2964
+ function getState(container) {
2965
+ return container[STATE_KEY] ?? null;
2966
+ }
2967
+ function setState(container, state) {
2968
+ container[STATE_KEY] = state;
2969
+ }
2970
+ function applyPlaceholder(bar, cfg2) {
2971
+ if (cfg2.placeholder !== void 0) bar.placeholder = cfg2.placeholder;
2972
+ if (cfg2.assistantName !== void 0) bar.assistantName = cfg2.assistantName;
2973
+ if (cfg2.personas !== void 0) bar.personas = cfg2.personas;
2974
+ if (cfg2.greeting !== void 0) bar.greeting = cfg2.greeting;
2975
+ if (cfg2.voiceInput !== void 0) bar.voiceInput = cfg2.voiceInput;
2976
+ bar.introSuggestion = cfg2.introSuggestion;
2977
+ bar.forceExpanded = cfg2.forceExpanded === true;
2978
+ if (typeof cfg2.maximized === "boolean") {
2979
+ bar.maximized = cfg2.maximized;
2980
+ }
2981
+ }
2982
+ var _elementStore = null;
2983
+ var _templateWidgetMap = /* @__PURE__ */ new Map();
2984
+ var SERVER_MOUNTED_TILE_WIDGETS = ["syntro-product-reco-carousel"];
2985
+ function resolveTileWidget(templateId) {
2986
+ return _templateWidgetMap.get(templateId);
2987
+ }
2988
+ function refreshTemplateWidgetMap(uiTemplates) {
2989
+ _templateWidgetMap.clear();
2990
+ for (const tag of SERVER_MOUNTED_TILE_WIDGETS) {
2991
+ _templateWidgetMap.set(tag, tag);
2992
+ }
2993
+ if (!uiTemplates) return;
2994
+ const tiles = uiTemplates.tiles;
2995
+ if (!Array.isArray(tiles)) return;
2996
+ for (const t of tiles) {
2997
+ const id = typeof t?.id === "string" ? t.id : null;
2998
+ const widget = typeof t?.widget === "string" ? t.widget : null;
2999
+ if (id && widget) _templateWidgetMap.set(id, widget);
3000
+ }
3001
+ }
3002
+ function getOrCreateElementStore(runtime2) {
3003
+ if (_elementStore) return _elementStore;
3004
+ _elementStore = new ElementInstanceStore({
3005
+ actions: runtime2.actions,
3006
+ // Pass the runtime's event bus so ItemHandler can broadcast
3007
+ // `element.compositional_append` / `_patch` / `_remove` events
3008
+ // to container widgets (chips strip, FAQ accordion, nav tips).
3009
+ events: {
3010
+ publish: runtime2.events.publish.bind(runtime2.events),
3011
+ subscribe: runtime2.events.subscribe?.bind(runtime2.events)
3012
+ },
3013
+ handlers: [new TileHandler(resolveTileWidget), new ActionHandler(), new ItemHandler()],
3014
+ resolveTileWidget
3015
+ });
3016
+ setElementInstanceStore(_elementStore);
3017
+ return _elementStore;
3018
+ }
3019
+ var _hydrationStarted = false;
3020
+ function hydrateOnce(runtime2, backendUrl) {
3021
+ if (_hydrationStarted) return;
3022
+ _hydrationStarted = true;
3023
+ const store = getOrCreateElementStore(runtime2);
3024
+ const trimmed = backendUrl.replace(/\/$/, "");
3025
+ const endpoint = trimmed ? `${trimmed}/api/adaptive/mounted_elements` : "/api/adaptive/mounted_elements";
3026
+ fetchMountedElements({ endpoint, token: runtime2.token }).then((response) => {
3027
+ if (!response) return;
3028
+ void store.hydrate(response.mounted_elements);
3029
+ });
3030
+ }
3031
+ var PAGE_LEVEL_KINDS = /* @__PURE__ */ new Set(["view", "scroll", "idle", "hesitation", "hover", "nav"]);
3032
+ function buildObserverEnrich(runtimeRef) {
3033
+ return (ev, raw) => {
3034
+ const extract = runtimeRef.getProductIdentity;
3035
+ if (typeof extract !== "function") return ev;
3036
+ if (ev.kind === "click") {
3037
+ const chain = raw.properties.$elements;
3038
+ if (!Array.isArray(chain)) return ev;
3039
+ const id = extract(chain);
3040
+ if (!id) return ev;
3041
+ return {
3042
+ ...ev,
3043
+ product: {
3044
+ handle: id.productHandle,
3045
+ url: id.productUrl,
3046
+ ...id.productTitle ? { title: id.productTitle } : {}
3047
+ }
3048
+ };
3049
+ }
3050
+ if (!ev.product && PAGE_LEVEL_KINDS.has(ev.kind) && typeof location !== "undefined") {
3051
+ const id = extract([{ href: location.pathname }]);
3052
+ if (!id) return ev;
3053
+ return {
3054
+ ...ev,
3055
+ product: {
3056
+ handle: id.productHandle,
3057
+ url: id.productUrl,
3058
+ ...id.productTitle ? { title: id.productTitle } : {}
3059
+ }
3060
+ };
3061
+ }
3062
+ return ev;
3063
+ };
3064
+ }
3065
+ var _nudgeSurfaceWired = false;
3066
+ var _nudgeListener = null;
3067
+ function wireNudgeSurface(runtime2, backendUrl) {
3068
+ if (_nudgeSurfaceWired || typeof document === "undefined") return;
3069
+ _nudgeSurfaceWired = true;
3070
+ _nudgeListener = (e) => {
3071
+ try {
3072
+ const detail = e.detail;
3073
+ const isIntent = detail?.phase === "intent";
3074
+ if (!isIntent) {
3075
+ const store = getOrCreateElementStore(runtime2);
3076
+ const trimmed = backendUrl.replace(/\/$/, "");
3077
+ const endpoint = trimmed ? `${trimmed}/api/adaptive/mounted_elements` : "/api/adaptive/mounted_elements";
3078
+ void fetchMountedElements({ endpoint, token: runtime2.token }).then((response) => {
3079
+ if (!response) return;
3080
+ void store.hydrate(response.mounted_elements);
3081
+ });
3082
+ }
3083
+ if (detail?.suppressToast === true) return;
3084
+ const canvas = findSmartCanvas();
3085
+ const messageId = e.detail?.messageId;
3086
+ const nudgeText = messageId ? (chatSession.getState().messages.find((m) => m.id === messageId)?.text ?? "").trim() : "";
3087
+ const title = nudgeText ? nudgeText.length > 140 ? `${nudgeText.slice(0, 137)}\u2026` : nudgeText : "I put something together for you";
3088
+ canvas?.previewNotification?.({
3089
+ title,
3090
+ body: "Tap to take a look"
3091
+ });
3092
+ } catch (err) {
3093
+ console.warn("[adaptive-chatbot] nudge surface reaction failed", err);
3094
+ }
3095
+ };
3096
+ document.addEventListener("syntro:nudge", _nudgeListener);
3097
+ }
3098
+ function configureTransportIfPossible(cfg2) {
3099
+ if (!cfg2.runtime) return;
3100
+ const backendUrl = cfg2.runtime.backendUrl;
3101
+ if (!backendUrl) return;
3102
+ const elementsActive = cfg2.elementsEnabled === true && cfg2.uiTemplates != null;
3103
+ refreshTemplateWidgetMap(elementsActive ? cfg2.uiTemplates : void 0);
3104
+ const forwardedProps = elementsActive ? { elementsEnabled: true, uiTemplates: cfg2.uiTemplates } : void 0;
3105
+ if (elementsActive) publishTemplatesIfPossible(backendUrl, cfg2.uiTemplates, cfg2.runtime?.token);
3106
+ const runtime2 = cfg2.runtime;
3107
+ const onElementMutation = elementsActive ? (mutations) => {
3108
+ void getOrCreateElementStore(runtime2).apply(mutations);
3109
+ } : void 0;
3110
+ if (elementsActive) {
3111
+ hydrateOnce(runtime2, backendUrl);
3112
+ }
3113
+ const persona = pickPersona(cfg2.personas ?? null);
3114
+ chatTransport.configure({
3115
+ ...cfg2,
3116
+ backendUrl,
3117
+ forwardedProps,
3118
+ onElementMutation,
3119
+ activeLidSlot: cfg2._syntroSlotName,
3120
+ personaId: persona?.id,
3121
+ personaName: persona?.name,
3122
+ personaRole: persona?.role_title
3123
+ });
3124
+ void chatTransport.startSessionStream();
3125
+ wireNudgeSurface(runtime2, backendUrl);
3126
+ startObserverIfPossible(cfg2);
3127
+ }
3128
+ var _templatesPublished = false;
3129
+ function publishTemplatesIfPossible(backendUrl, uiTemplates, token) {
3130
+ if (_templatesPublished || typeof window === "undefined") return;
3131
+ if (!uiTemplates || typeof uiTemplates !== "object") return;
3132
+ _templatesPublished = true;
3133
+ const headers2 = { "Content-Type": "application/json" };
3134
+ if (token) headers2.Authorization = `Bearer ${token}`;
3135
+ const editorToken = readEditorToken();
3136
+ if (editorToken) headers2["X-Syntro-Editor-Token"] = editorToken;
3137
+ const trimmed = backendUrl.replace(/\/$/, "");
3138
+ void fetch(`${trimmed}/api/adaptive/templates`, {
3139
+ method: "POST",
3140
+ headers: headers2,
3141
+ credentials: "include",
3142
+ body: JSON.stringify({ ui_templates: uiTemplates })
3143
+ }).catch(() => {
3144
+ });
3145
+ }
3146
+ var _diveDeeperWired = false;
3147
+ function wireDiveDeeperListener() {
3148
+ if (_diveDeeperWired || typeof window === "undefined") return;
3149
+ _diveDeeperWired = true;
3150
+ window.addEventListener(DIVE_DEEPER_EVENT, (e) => {
3151
+ const detail = e.detail ?? {};
3152
+ const prompt = typeof detail.prompt === "string" && detail.prompt.trim() ? detail.prompt : detail.title ? "I'd like to dive deeper on this, I didn't see what I needed." : "";
3153
+ if (!prompt) return;
3154
+ const origin = { kind: "dive-deeper" };
3155
+ if (detail.title) origin.title = detail.title;
3156
+ if (detail.context) origin.context = detail.context;
3157
+ chatSession.send(prompt, { forwardedProps: { origin } });
3158
+ if (!chatSession.hasTransport()) {
3159
+ chatSession.error("Chat backend not configured \u2014 set backendUrl in the canvas config.");
3160
+ }
3161
+ });
3162
+ }
3163
+ var _observerStarted = false;
3164
+ var _observerRuntime = null;
3165
+ var _observerHandle = null;
3166
+ var _observerBusUnsubscribe = null;
3167
+ function startObserverIfPossible(cfg2) {
3168
+ if (typeof window === "undefined") return;
3169
+ const runtimeRef = cfg2.runtime;
3170
+ if (!runtimeRef?.events?.subscribe) return;
3171
+ if (_observerStarted && _observerRuntime === runtimeRef) return;
3172
+ if (_observerStarted) {
3173
+ _observerBusUnsubscribe?.();
3174
+ _observerHandle?.stop();
3175
+ _observerBusUnsubscribe = null;
3176
+ _observerHandle = null;
3177
+ _observerStarted = false;
3178
+ }
3179
+ const trimmed = (runtimeRef.backendUrl ?? "").replace(/\/$/, "");
3180
+ const url = trimmed ? `${trimmed}/api/adaptive/observation` : "/api/adaptive/observation";
3181
+ const runtimeId = (method) => {
3182
+ try {
3183
+ const v = runtimeRef.telemetry?.[method]?.();
3184
+ return typeof v === "string" && v.length > 0 ? v : null;
3185
+ } catch {
3186
+ return null;
3187
+ }
3188
+ };
3189
+ const getDistinctId = () => runtimeId("getDistinctId");
3190
+ const getSessionId = () => runtimeId("getSessionId");
3191
+ const token = () => {
3192
+ const t = runtimeRef.token;
3193
+ return typeof t === "string" ? t : "";
3194
+ };
3195
+ const enrich = buildObserverEnrich(runtimeRef);
3196
+ const handle = startObserver({ url, token, getDistinctId, getSessionId, enrich });
3197
+ window.__syntroObserverStats = () => handle.stats();
3198
+ const unsubscribe = runtimeRef.events.subscribe({}, (evt) => {
3199
+ const raw = busEventToRawEvent(evt);
3200
+ if (raw) handle.ingest(raw);
3201
+ });
3202
+ _observerRuntime = runtimeRef;
3203
+ _observerHandle = handle;
3204
+ _observerBusUnsubscribe = unsubscribe;
3205
+ _observerStarted = true;
3206
+ }
3207
+ function wireListeners(bar, state) {
3208
+ const onMessageSent = (e) => {
3209
+ const text = e.detail.text;
3210
+ chatSession.send(text, { activeLidSlot: state.cfg._syntroSlotName });
3211
+ if (!chatSession.hasTransport()) {
3212
+ chatSession.error("Chat backend not configured \u2014 set backendUrl in the canvas config.");
3213
+ }
3214
+ };
3215
+ const onInterrupt = () => {
3216
+ chatSession.interrupt();
3217
+ };
3218
+ const onToolCallApproved = (e) => {
3219
+ const detail = e.detail;
3220
+ chatSession.resolveToolCall(detail.toolCallId, {}, detail.approved);
3221
+ };
3222
+ const onClose = () => {
3223
+ state.cfg.onClose?.();
3224
+ };
3225
+ bar.addEventListener("chat-message-sent", onMessageSent);
3226
+ bar.addEventListener("chat-interrupt", onInterrupt);
3227
+ bar.addEventListener("canvas-close", onClose);
3228
+ bar.addEventListener("trail-toolcall-approved", onToolCallApproved);
3229
+ return () => {
3230
+ bar.removeEventListener("chat-message-sent", onMessageSent);
3231
+ bar.removeEventListener("chat-interrupt", onInterrupt);
3232
+ bar.removeEventListener("canvas-close", onClose);
3233
+ bar.removeEventListener("trail-toolcall-approved", onToolCallApproved);
3234
+ };
3235
+ }
3236
+ var AdaptiveChatBarMountable = {
3237
+ mount(container, mountConfig) {
3238
+ const cfg2 = mountConfig ?? {};
3239
+ configureTransportIfPossible(cfg2);
3240
+ const bridge = bootSupportChat(cfg2.supportChat);
3241
+ if (bridge && !isSupportChatInboxWired()) {
3242
+ wireSupportChatInbox({
3243
+ bridge,
3244
+ inbox: cfg2.supportChat?.inbox,
3245
+ runtime: cfg2.runtime,
3246
+ uiTemplates: cfg2.uiTemplates
3247
+ });
3248
+ }
3249
+ wireDiveDeeperListener();
3250
+ const bar = document.createElement("adaptive-chat-bar");
3251
+ applyPlaceholder(bar, cfg2);
3252
+ const widgets = cfg2.runtime?.widgets;
3253
+ if (widgets) {
3254
+ bar.mountInlineWidget = (widgetId, container2, props) => {
3255
+ if (!widgets.has(widgetId)) return null;
3256
+ const handle = widgets.mount(widgetId, container2, props);
3257
+ const element = container2.firstElementChild;
3258
+ if (!element) {
3259
+ handle.unmount?.();
3260
+ return null;
3261
+ }
3262
+ return { element, cleanup: () => handle.unmount?.() };
3263
+ };
3264
+ }
3265
+ const unsubSession = chatSession.subscribe((s) => {
3266
+ bar.messages = [...s.messages];
3267
+ bar.inFlight = s.inFlight;
3268
+ bar.thinkingText = s.thinkingText;
3269
+ });
3270
+ const runtimeEvents = cfg2.runtime ? cfg2.runtime.events : void 0;
3271
+ const refreshReceipts = () => {
3272
+ const store = _elementStore;
3273
+ if (store) {
3274
+ bar.tileReceipts = store.listTileReceipts();
3275
+ bar.inlineWidgets = store.listInlineWidgets();
3276
+ }
3277
+ };
3278
+ let unsubReceipts;
3279
+ if (runtimeEvents?.subscribe) {
3280
+ unsubReceipts = runtimeEvents.subscribe(
3281
+ { names: [TILE_MOUNTED_EVENT, TILE_UNMOUNTED_EVENT] },
3282
+ refreshReceipts
3283
+ );
3284
+ }
3285
+ refreshReceipts();
3286
+ const state = { bar, cleanup: () => {
3287
+ }, cfg: cfg2 };
3288
+ const unwireListeners = wireListeners(bar, state);
3289
+ container.appendChild(bar);
3290
+ const unsubFallback = chatTransport.onFallback(() => {
3291
+ bar.remove();
3292
+ container.innerHTML = renderFallbackHtml(state.cfg.fallback);
3293
+ });
3294
+ state.cleanup = () => {
3295
+ unsubSession();
3296
+ unsubFallback();
3297
+ unsubReceipts?.();
3298
+ unwireListeners();
3299
+ bar.remove();
3300
+ setState(container, null);
3301
+ };
3302
+ setState(container, state);
3303
+ return state.cleanup;
3304
+ },
3305
+ update(container, mountConfig) {
3306
+ const state = getState(container);
3307
+ if (!state) return;
3308
+ const cfg2 = mountConfig ?? {};
3309
+ configureTransportIfPossible(cfg2);
3310
+ applyPlaceholder(state.bar, cfg2);
3311
+ state.cfg = cfg2;
3312
+ }
3313
+ };
3314
+
3315
+ // src/AdaptiveChipsStripMountable.ts
3316
+ var STATE_KEY2 = "__syntroChipsStripMount";
3317
+ function getState2(container) {
3318
+ return container[STATE_KEY2] ?? null;
3319
+ }
3320
+ function setState2(container, state) {
3321
+ container[STATE_KEY2] = state;
3322
+ }
3323
+ function applyProps(strip, cfg2) {
3324
+ if (cfg2.chips !== void 0) strip.chips = cfg2.chips;
3325
+ if (cfg2.runtime !== void 0) {
3326
+ strip.runtimeRef = cfg2.runtime;
3327
+ }
3328
+ if (cfg2.chromeless !== void 0) strip.chromeless = cfg2.chromeless;
3329
+ }
3330
+ var AdaptiveChipsStripMountable = {
3331
+ mount(container, mountConfig) {
3332
+ const cfg2 = mountConfig ?? {};
3333
+ const strip = document.createElement("adaptive-chips-strip");
3334
+ applyProps(strip, cfg2);
3335
+ const state = {
3336
+ strip,
3337
+ listeners: {
3338
+ revealed: (e) => {
3339
+ const cb = cfg2.onChipRevealed;
3340
+ if (cb) {
3341
+ cb(
3342
+ e.detail
3343
+ );
3344
+ }
3345
+ },
3346
+ dismissed: (e) => {
3347
+ const cb = cfg2.onChipDismissed;
3348
+ if (cb) cb(e.detail);
3349
+ }
3350
+ }
3351
+ };
3352
+ strip.addEventListener("chip-revealed", state.listeners.revealed);
3353
+ strip.addEventListener("chip-dismissed", state.listeners.dismissed);
3354
+ container.appendChild(strip);
3355
+ setState2(container, state);
3356
+ return () => {
3357
+ strip.removeEventListener("chip-revealed", state.listeners.revealed);
3358
+ strip.removeEventListener("chip-dismissed", state.listeners.dismissed);
3359
+ strip.remove();
3360
+ setState2(container, null);
3361
+ };
3362
+ },
3363
+ update(container, mountConfig) {
3364
+ const state = getState2(container);
3365
+ if (!state) return;
3366
+ const cfg2 = mountConfig ?? {};
3367
+ applyProps(state.strip, cfg2);
3368
+ state.strip.removeEventListener("chip-revealed", state.listeners.revealed);
3369
+ state.strip.removeEventListener("chip-dismissed", state.listeners.dismissed);
3370
+ state.listeners.revealed = (e) => {
3371
+ const cb = cfg2.onChipRevealed;
3372
+ if (cb) {
3373
+ cb(e.detail);
3374
+ }
3375
+ };
3376
+ state.listeners.dismissed = (e) => {
3377
+ const cb = cfg2.onChipDismissed;
3378
+ if (cb) cb(e.detail);
3379
+ };
3380
+ state.strip.addEventListener("chip-revealed", state.listeners.revealed);
3381
+ state.strip.addEventListener("chip-dismissed", state.listeners.dismissed);
3382
+ }
3383
+ };
3384
+
3182
3385
  // src/NavLinkMountable.ts
3183
3386
  var STATE_KEY3 = "__syntroNavLinkMount";
3184
3387
  var SAFE_NAVIGATION_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);