@absolutejs/voice 0.0.22-beta.153 → 0.0.22-beta.154

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.
@@ -468,6 +468,269 @@ var createVoiceDeliveryRuntime = (path = "/api/voice-delivery-runtime", options
468
468
  tick: store.tick
469
469
  };
470
470
  };
471
+ // src/client/opsActionCenter.ts
472
+ var createVoiceOpsActionCenterActions = (options = {}) => {
473
+ const deliveryRuntimePath = options.deliveryRuntimePath ?? "/api/voice-delivery-runtime";
474
+ const actions = [];
475
+ if (options.includeProductionReadiness !== false) {
476
+ actions.push({
477
+ description: "Refresh the production readiness report.",
478
+ id: "production-readiness",
479
+ label: "Refresh readiness",
480
+ method: "GET",
481
+ path: options.productionReadinessPath ?? "/api/production-readiness"
482
+ });
483
+ }
484
+ if (options.includeDeliveryRuntime !== false) {
485
+ actions.push({
486
+ description: "Drain pending and failed audit/trace deliveries.",
487
+ id: "delivery-runtime.tick",
488
+ label: "Tick delivery workers",
489
+ method: "POST",
490
+ path: `${deliveryRuntimePath.replace(/\/$/, "")}/tick`
491
+ }, {
492
+ description: "Move reviewed dead letters back to live delivery queues.",
493
+ id: "delivery-runtime.requeue-dead-letters",
494
+ label: "Requeue dead letters",
495
+ method: "POST",
496
+ path: `${deliveryRuntimePath.replace(/\/$/, "")}/requeue-dead-letters`
497
+ });
498
+ }
499
+ if (options.includeTurnLatencyProof !== false) {
500
+ actions.push({
501
+ description: "Run the synthetic turn latency proof.",
502
+ id: "turn-latency.proof",
503
+ label: "Run latency proof",
504
+ method: "POST",
505
+ path: options.turnLatencyProofPath ?? "/api/turn-latency/proof"
506
+ });
507
+ }
508
+ if (options.includeProviderSimulation !== false) {
509
+ const pathPrefix = options.providerSimulationPathPrefix ?? "/api/stt-simulate";
510
+ for (const provider of options.providers ?? []) {
511
+ actions.push({
512
+ description: `Simulate ${provider} provider failure.`,
513
+ id: `provider.${provider}.failure`,
514
+ label: `Simulate ${provider} failure`,
515
+ method: "POST",
516
+ path: `${pathPrefix}/failure?provider=${encodeURIComponent(provider)}`
517
+ }, {
518
+ description: `Mark ${provider} provider recovered.`,
519
+ id: `provider.${provider}.recovery`,
520
+ label: `Recover ${provider}`,
521
+ method: "POST",
522
+ path: `${pathPrefix}/recovery?provider=${encodeURIComponent(provider)}`
523
+ });
524
+ }
525
+ }
526
+ return actions;
527
+ };
528
+ var runVoiceOpsAction = async (action, options = {}) => {
529
+ const fetchImpl = options.fetch ?? globalThis.fetch;
530
+ const response = await fetchImpl(action.path, {
531
+ method: action.method ?? "POST"
532
+ });
533
+ const body = await response.json().catch(() => null);
534
+ if (!response.ok) {
535
+ const message = body && typeof body === "object" && "error" in body ? String(body.error) : `Voice ops action "${action.id}" failed: HTTP ${response.status}`;
536
+ throw new Error(message);
537
+ }
538
+ return {
539
+ actionId: action.id,
540
+ body,
541
+ ok: response.ok,
542
+ ranAt: Date.now(),
543
+ status: response.status
544
+ };
545
+ };
546
+ var createVoiceOpsActionCenterStore = (options = {}) => {
547
+ const listeners = new Set;
548
+ let closed = false;
549
+ let timer;
550
+ let snapshot = {
551
+ actions: options.actions ?? createVoiceOpsActionCenterActions(),
552
+ error: null,
553
+ isRunning: false
554
+ };
555
+ const emit = () => {
556
+ for (const listener of listeners) {
557
+ listener();
558
+ }
559
+ };
560
+ const setActions = (actions) => {
561
+ snapshot = { ...snapshot, actions, updatedAt: Date.now() };
562
+ emit();
563
+ };
564
+ const run = async (actionId) => {
565
+ if (closed) {
566
+ return snapshot.lastResult;
567
+ }
568
+ const action = snapshot.actions.find((item) => item.id === actionId);
569
+ if (!action) {
570
+ throw new Error(`Voice ops action "${actionId}" is not configured.`);
571
+ }
572
+ if (action.disabled) {
573
+ throw new Error(`Voice ops action "${actionId}" is disabled.`);
574
+ }
575
+ snapshot = {
576
+ ...snapshot,
577
+ error: null,
578
+ isRunning: true,
579
+ runningActionId: action.id
580
+ };
581
+ emit();
582
+ try {
583
+ const result = await runVoiceOpsAction(action, options);
584
+ snapshot = {
585
+ ...snapshot,
586
+ error: null,
587
+ isRunning: false,
588
+ lastResult: result,
589
+ runningActionId: undefined,
590
+ updatedAt: Date.now()
591
+ };
592
+ emit();
593
+ return result;
594
+ } catch (error) {
595
+ snapshot = {
596
+ ...snapshot,
597
+ error: error instanceof Error ? error.message : String(error),
598
+ isRunning: false,
599
+ runningActionId: undefined
600
+ };
601
+ emit();
602
+ throw error;
603
+ }
604
+ };
605
+ const close = () => {
606
+ closed = true;
607
+ if (timer) {
608
+ clearInterval(timer);
609
+ timer = undefined;
610
+ }
611
+ listeners.clear();
612
+ };
613
+ if (options.intervalMs && options.intervalMs > 0) {
614
+ timer = setInterval(() => {
615
+ emit();
616
+ }, options.intervalMs);
617
+ }
618
+ return {
619
+ close,
620
+ getServerSnapshot: () => snapshot,
621
+ getSnapshot: () => snapshot,
622
+ run,
623
+ setActions,
624
+ subscribe: (listener) => {
625
+ listeners.add(listener);
626
+ return () => {
627
+ listeners.delete(listener);
628
+ };
629
+ }
630
+ };
631
+ };
632
+
633
+ // src/client/opsActionCenterWidget.ts
634
+ var DEFAULT_TITLE2 = "Voice Ops Action Center";
635
+ var DEFAULT_DESCRIPTION2 = "Run production voice proofs and operator actions from one primitive panel.";
636
+ var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
637
+ var createVoiceOpsActionCenterViewModel = (snapshot, options = {}) => {
638
+ const status = snapshot.error ? "error" : snapshot.isRunning ? "running" : snapshot.lastResult ? "completed" : "ready";
639
+ return {
640
+ actions: snapshot.actions.map((action) => ({
641
+ description: action.description ?? "",
642
+ disabled: Boolean(action.disabled || snapshot.isRunning),
643
+ id: action.id,
644
+ isRunning: snapshot.runningActionId === action.id,
645
+ label: action.label
646
+ })),
647
+ description: options.description ?? DEFAULT_DESCRIPTION2,
648
+ error: snapshot.error,
649
+ isRunning: snapshot.isRunning,
650
+ label: status === "error" ? "Needs attention" : status === "running" ? "Running" : status === "completed" ? "Action completed" : "Ready",
651
+ lastResultLabel: snapshot.lastResult ? `${snapshot.lastResult.actionId} returned HTTP ${snapshot.lastResult.status}` : "No action has run yet.",
652
+ status,
653
+ title: options.title ?? DEFAULT_TITLE2
654
+ };
655
+ };
656
+ var renderVoiceOpsActionCenterHTML = (snapshot, options = {}) => {
657
+ const model = createVoiceOpsActionCenterViewModel(snapshot, options);
658
+ const actions = model.actions.map((action) => `<button type="button" data-absolute-voice-ops-action="${escapeHtml2(action.id)}"${action.disabled ? " disabled" : ""}>
659
+ ${escapeHtml2(action.isRunning ? "Working..." : action.label)}
660
+ </button>`).join("");
661
+ return `<section class="absolute-voice-ops-action-center absolute-voice-ops-action-center--${escapeHtml2(model.status)}">
662
+ <header class="absolute-voice-ops-action-center__header">
663
+ <span class="absolute-voice-ops-action-center__eyebrow">${escapeHtml2(model.title)}</span>
664
+ <strong class="absolute-voice-ops-action-center__label">${escapeHtml2(model.label)}</strong>
665
+ </header>
666
+ <p class="absolute-voice-ops-action-center__description">${escapeHtml2(model.description)}</p>
667
+ <div class="absolute-voice-ops-action-center__actions">${actions}</div>
668
+ <p class="absolute-voice-ops-action-center__result">${escapeHtml2(model.lastResultLabel)}</p>
669
+ ${model.error ? `<p class="absolute-voice-ops-action-center__error">${escapeHtml2(model.error)}</p>` : ""}
670
+ </section>`;
671
+ };
672
+ var getVoiceOpsActionCenterCSS = () => `.absolute-voice-ops-action-center{border:1px solid #d5cbb8;border-radius:20px;background:#fffaf1;color:#17130b;padding:18px;box-shadow:0 18px 40px rgba(58,42,16,.12);font-family:inherit}.absolute-voice-ops-action-center--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-ops-action-center__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-ops-action-center__eyebrow{color:#725d37;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-ops-action-center__label{font-size:28px;line-height:1}.absolute-voice-ops-action-center__description,.absolute-voice-ops-action-center__result{color:#5b4b2f;margin:12px 0 0}.absolute-voice-ops-action-center__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}.absolute-voice-ops-action-center__actions button{background:#7c4a03;border:0;border-radius:999px;color:#fff8e8;cursor:pointer;font:inherit;font-weight:800;padding:8px 12px}.absolute-voice-ops-action-center__actions button:disabled{cursor:not-allowed;opacity:.5}.absolute-voice-ops-action-center__error{color:#9f1239;font-weight:700}`;
673
+ var mountVoiceOpsActionCenter = (element, options = {}) => {
674
+ const store = createVoiceOpsActionCenterStore(options);
675
+ const render = () => {
676
+ element.innerHTML = renderVoiceOpsActionCenterHTML(store.getSnapshot(), options);
677
+ };
678
+ const unsubscribe = store.subscribe(render);
679
+ const handleClick = (event) => {
680
+ const target = event.target;
681
+ if (!(target instanceof Element)) {
682
+ return;
683
+ }
684
+ const action = target.closest("[data-absolute-voice-ops-action]");
685
+ const actionId = action?.getAttribute("data-absolute-voice-ops-action");
686
+ if (actionId) {
687
+ store.run(actionId).catch(() => {});
688
+ }
689
+ };
690
+ element.addEventListener?.("click", handleClick);
691
+ render();
692
+ return {
693
+ close: () => {
694
+ element.removeEventListener?.("click", handleClick);
695
+ unsubscribe();
696
+ store.close();
697
+ },
698
+ run: store.run
699
+ };
700
+ };
701
+ var defineVoiceOpsActionCenterElement = (tagName = "absolute-voice-ops-action-center", options = {}) => {
702
+ if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
703
+ return;
704
+ }
705
+ customElements.define(tagName, class AbsoluteVoiceOpsActionCenterElement extends HTMLElement {
706
+ mounted;
707
+ connectedCallback() {
708
+ this.mounted = mountVoiceOpsActionCenter(this, {
709
+ ...options,
710
+ description: this.getAttribute("description") ?? options.description,
711
+ title: this.getAttribute("title") ?? options.title
712
+ });
713
+ }
714
+ disconnectedCallback() {
715
+ this.mounted?.close();
716
+ this.mounted = undefined;
717
+ }
718
+ });
719
+ };
720
+
721
+ // src/svelte/createVoiceOpsActionCenter.ts
722
+ var createVoiceOpsActionCenter = (options = {}) => {
723
+ const store = createVoiceOpsActionCenterStore(options);
724
+ return {
725
+ close: store.close,
726
+ getHTML: () => renderVoiceOpsActionCenterHTML(store.getSnapshot(), options),
727
+ getSnapshot: store.getSnapshot,
728
+ getViewModel: () => createVoiceOpsActionCenterViewModel(store.getSnapshot(), options),
729
+ run: store.run,
730
+ setActions: store.setActions,
731
+ subscribe: store.subscribe
732
+ };
733
+ };
471
734
  // src/client/opsStatus.ts
472
735
  var fetchVoiceOpsStatus = async (path = "/api/voice/ops-status", options = {}) => {
473
736
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -548,8 +811,8 @@ var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) =
548
811
  };
549
812
 
550
813
  // src/client/opsStatusWidget.ts
551
- var DEFAULT_TITLE2 = "Voice Ops Status";
552
- var DEFAULT_DESCRIPTION2 = "Certified workflow, provider, and handoff readiness from your AbsoluteJS voice app.";
814
+ var DEFAULT_TITLE3 = "Voice Ops Status";
815
+ var DEFAULT_DESCRIPTION3 = "Certified workflow, provider, and handoff readiness from your AbsoluteJS voice app.";
553
816
  var SURFACE_LABELS = {
554
817
  handoffs: "Handoffs",
555
818
  providers: "Providers",
@@ -557,7 +820,7 @@ var SURFACE_LABELS = {
557
820
  sessions: "Sessions",
558
821
  workflows: "Workflows"
559
822
  };
560
- var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
823
+ var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
561
824
  var readNumber = (value, key) => value && typeof value === "object" && (key in value) ? Number(value[key] ?? 0) : 0;
562
825
  var surfaceDetail = (surface) => {
563
826
  const total = readNumber(surface, "total");
@@ -597,7 +860,7 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
597
860
  };
598
861
  });
599
862
  return {
600
- description: options.description ?? DEFAULT_DESCRIPTION2,
863
+ description: options.description ?? DEFAULT_DESCRIPTION3,
601
864
  error: snapshot.error,
602
865
  isLoading: snapshot.isLoading,
603
866
  label: getVoiceOpsStatusLabel(report, snapshot.error),
@@ -605,31 +868,31 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
605
868
  passed: report?.passed ?? 0,
606
869
  status: snapshot.error ? "error" : report ? report.status : snapshot.isLoading ? "loading" : "loading",
607
870
  surfaces,
608
- title: options.title ?? DEFAULT_TITLE2,
871
+ title: options.title ?? DEFAULT_TITLE3,
609
872
  total: report?.total ?? 0,
610
873
  updatedAt: snapshot.updatedAt
611
874
  };
612
875
  };
613
876
  var renderVoiceOpsStatusHTML = (snapshot, options = {}) => {
614
877
  const model = createVoiceOpsStatusViewModel(snapshot, options);
615
- const surfaces = model.surfaces.length ? model.surfaces.map((surface) => `<li class="absolute-voice-ops-status__surface absolute-voice-ops-status__surface--${escapeHtml2(surface.status)}">
616
- <span>${escapeHtml2(surface.label)}</span>
617
- <strong>${escapeHtml2(surface.detail)}</strong>
878
+ const surfaces = model.surfaces.length ? model.surfaces.map((surface) => `<li class="absolute-voice-ops-status__surface absolute-voice-ops-status__surface--${escapeHtml3(surface.status)}">
879
+ <span>${escapeHtml3(surface.label)}</span>
880
+ <strong>${escapeHtml3(surface.detail)}</strong>
618
881
  </li>`).join("") : '<li class="absolute-voice-ops-status__surface"><span>Status</span><strong>Waiting for first check</strong></li>';
619
- const links = model.links.length ? `<nav class="absolute-voice-ops-status__links">${model.links.slice(0, 4).map((link) => `<a href="${escapeHtml2(link.href)}">${escapeHtml2(link.label)}</a>`).join("")}</nav>` : "";
620
- return `<section class="absolute-voice-ops-status absolute-voice-ops-status--${escapeHtml2(model.status)}">
882
+ const links = model.links.length ? `<nav class="absolute-voice-ops-status__links">${model.links.slice(0, 4).map((link) => `<a href="${escapeHtml3(link.href)}">${escapeHtml3(link.label)}</a>`).join("")}</nav>` : "";
883
+ return `<section class="absolute-voice-ops-status absolute-voice-ops-status--${escapeHtml3(model.status)}">
621
884
  <header class="absolute-voice-ops-status__header">
622
- <span class="absolute-voice-ops-status__eyebrow">${escapeHtml2(model.title)}</span>
623
- <strong class="absolute-voice-ops-status__label">${escapeHtml2(model.label)}</strong>
885
+ <span class="absolute-voice-ops-status__eyebrow">${escapeHtml3(model.title)}</span>
886
+ <strong class="absolute-voice-ops-status__label">${escapeHtml3(model.label)}</strong>
624
887
  </header>
625
- <p class="absolute-voice-ops-status__description">${escapeHtml2(model.description)}</p>
888
+ <p class="absolute-voice-ops-status__description">${escapeHtml3(model.description)}</p>
626
889
  <div class="absolute-voice-ops-status__summary">
627
890
  <span>${model.passed} passing</span>
628
891
  <span>${Math.max(model.total - model.passed, 0)} failing</span>
629
892
  <span>${model.total} checks</span>
630
893
  </div>
631
894
  <ul class="absolute-voice-ops-status__surfaces">${surfaces}</ul>
632
- ${model.error ? `<p class="absolute-voice-ops-status__error">${escapeHtml2(model.error)}</p>` : ""}
895
+ ${model.error ? `<p class="absolute-voice-ops-status__error">${escapeHtml3(model.error)}</p>` : ""}
633
896
  ${links}
634
897
  </section>`;
635
898
  };
@@ -764,7 +1027,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
764
1027
  };
765
1028
 
766
1029
  // src/client/providerSimulationControlsWidget.ts
767
- var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1030
+ var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
768
1031
  var formatKind = (kind) => (kind ?? "stt").toUpperCase();
769
1032
  var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
770
1033
  const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
@@ -784,18 +1047,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
784
1047
  };
785
1048
  var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
786
1049
  const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
787
- const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml3(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml3(provider.provider)} ${escapeHtml3(formatKind(options.kind))} failure</button>`).join("");
788
- const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml3(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml3(provider.provider)} recovered</button>`).join("");
1050
+ const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml4(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml4(provider.provider)} ${escapeHtml4(formatKind(options.kind))} failure</button>`).join("");
1051
+ const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml4(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml4(provider.provider)} recovered</button>`).join("");
789
1052
  return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
790
1053
  <header class="absolute-voice-provider-simulation__header">
791
- <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml3(model.title)}</span>
792
- <strong class="absolute-voice-provider-simulation__label">${escapeHtml3(model.label)}</strong>
1054
+ <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml4(model.title)}</span>
1055
+ <strong class="absolute-voice-provider-simulation__label">${escapeHtml4(model.label)}</strong>
793
1056
  </header>
794
- <p class="absolute-voice-provider-simulation__description">${escapeHtml3(model.description)}</p>
795
- ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml3(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
1057
+ <p class="absolute-voice-provider-simulation__description">${escapeHtml4(model.description)}</p>
1058
+ ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml4(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
796
1059
  <div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
797
- ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml3(snapshot.error)}</p>` : ""}
798
- ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml3(model.resultText)}</pre>` : ""}
1060
+ ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml4(snapshot.error)}</p>` : ""}
1061
+ ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml4(model.resultText)}</pre>` : ""}
799
1062
  </section>`;
800
1063
  };
801
1064
  var bindVoiceProviderSimulationControls = (element, store) => {
@@ -950,9 +1213,9 @@ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities",
950
1213
  };
951
1214
 
952
1215
  // src/client/providerCapabilitiesWidget.ts
953
- var DEFAULT_TITLE3 = "Provider Capabilities";
954
- var DEFAULT_DESCRIPTION3 = "Configured, selected, and healthy voice providers for this deployment.";
955
- var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1216
+ var DEFAULT_TITLE4 = "Provider Capabilities";
1217
+ var DEFAULT_DESCRIPTION4 = "Configured, selected, and healthy voice providers for this deployment.";
1218
+ var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
956
1219
  var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
957
1220
  var formatKind2 = (kind) => kind.toUpperCase();
958
1221
  var formatStatus = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
@@ -996,36 +1259,36 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
996
1259
  const selectedCount = snapshot.report?.selected ?? capabilities.filter((capability) => capability.selected).length;
997
1260
  return {
998
1261
  capabilities,
999
- description: options.description ?? DEFAULT_DESCRIPTION3,
1262
+ description: options.description ?? DEFAULT_DESCRIPTION4,
1000
1263
  error: snapshot.error,
1001
1264
  isLoading: snapshot.isLoading,
1002
1265
  label: snapshot.error ? "Unavailable" : capabilities.length ? warningCount > 0 ? `${warningCount} needs attention` : `${selectedCount} selected` : snapshot.isLoading ? "Checking" : "No capabilities",
1003
1266
  status: snapshot.error ? "error" : capabilities.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1004
- title: options.title ?? DEFAULT_TITLE3,
1267
+ title: options.title ?? DEFAULT_TITLE4,
1005
1268
  updatedAt: snapshot.updatedAt
1006
1269
  };
1007
1270
  };
1008
1271
  var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
1009
1272
  const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
1010
- const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml4(capability.status)}">
1273
+ const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml5(capability.status)}">
1011
1274
  <header>
1012
- <strong>${escapeHtml4(capability.label)}</strong>
1013
- <span>${escapeHtml4(formatStatus(capability.status))}</span>
1275
+ <strong>${escapeHtml5(capability.label)}</strong>
1276
+ <span>${escapeHtml5(formatStatus(capability.status))}</span>
1014
1277
  </header>
1015
- <p>${escapeHtml4(capability.detail)}</p>
1278
+ <p>${escapeHtml5(capability.detail)}</p>
1016
1279
  <dl>${capability.rows.map((row) => `<div>
1017
- <dt>${escapeHtml4(row.label)}</dt>
1018
- <dd>${escapeHtml4(row.value)}</dd>
1280
+ <dt>${escapeHtml5(row.label)}</dt>
1281
+ <dd>${escapeHtml5(row.value)}</dd>
1019
1282
  </div>`).join("")}</dl>
1020
1283
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
1021
- return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml4(model.status)}">
1284
+ return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml5(model.status)}">
1022
1285
  <header class="absolute-voice-provider-capabilities__header">
1023
- <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml4(model.title)}</span>
1024
- <strong class="absolute-voice-provider-capabilities__label">${escapeHtml4(model.label)}</strong>
1286
+ <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml5(model.title)}</span>
1287
+ <strong class="absolute-voice-provider-capabilities__label">${escapeHtml5(model.label)}</strong>
1025
1288
  </header>
1026
- <p class="absolute-voice-provider-capabilities__description">${escapeHtml4(model.description)}</p>
1289
+ <p class="absolute-voice-provider-capabilities__description">${escapeHtml5(model.description)}</p>
1027
1290
  ${capabilities}
1028
- ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml4(model.error)}</p>` : ""}
1291
+ ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml5(model.error)}</p>` : ""}
1029
1292
  </section>`;
1030
1293
  };
1031
1294
  var getVoiceProviderCapabilitiesCSS = () => `.absolute-voice-provider-capabilities{border:1px solid #bfd7ea;border-radius:20px;background:#f6fbff;color:#08131f;padding:18px;box-shadow:0 18px 40px rgba(14,51,78,.12);font-family:inherit}.absolute-voice-provider-capabilities--error,.absolute-voice-provider-capabilities--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-capabilities__header,.absolute-voice-provider-capabilities__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-capabilities__eyebrow{color:#255f85;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-capabilities__label{font-size:24px;line-height:1}.absolute-voice-provider-capabilities__description,.absolute-voice-provider-capabilities__provider p,.absolute-voice-provider-capabilities__provider dt,.absolute-voice-provider-capabilities__empty{color:#405467}.absolute-voice-provider-capabilities__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-capabilities__provider{background:#fff;border:1px solid #d7e7f3;border-radius:16px;padding:14px}.absolute-voice-provider-capabilities__provider--selected,.absolute-voice-provider-capabilities__provider--healthy{border-color:#86efac}.absolute-voice-provider-capabilities__provider--degraded,.absolute-voice-provider-capabilities__provider--rate-limited,.absolute-voice-provider-capabilities__provider--suppressed,.absolute-voice-provider-capabilities__provider--unconfigured{border-color:#f2a7a7}.absolute-voice-provider-capabilities__provider p{margin:10px 0}.absolute-voice-provider-capabilities__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-capabilities__provider div{background:#f6fbff;border:1px solid #d7e7f3;border-radius:12px;padding:8px}.absolute-voice-provider-capabilities__provider dt{font-size:12px}.absolute-voice-provider-capabilities__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-capabilities__empty{margin:14px 0 0}.absolute-voice-provider-capabilities__error{color:#9f1239;font-weight:700}`;
@@ -1798,9 +2061,9 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
1798
2061
  };
1799
2062
 
1800
2063
  // src/client/providerStatusWidget.ts
1801
- var DEFAULT_TITLE4 = "Voice Providers";
1802
- var DEFAULT_DESCRIPTION4 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
1803
- var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2064
+ var DEFAULT_TITLE5 = "Voice Providers";
2065
+ var DEFAULT_DESCRIPTION5 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
2066
+ var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1804
2067
  var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
1805
2068
  var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
1806
2069
  var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
@@ -1844,37 +2107,37 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
1844
2107
  const warningCount = providers.filter((provider) => isWarningStatus2(provider.status)).length;
1845
2108
  const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
1846
2109
  return {
1847
- description: options.description ?? DEFAULT_DESCRIPTION4,
2110
+ description: options.description ?? DEFAULT_DESCRIPTION5,
1848
2111
  error: snapshot.error,
1849
2112
  isLoading: snapshot.isLoading,
1850
2113
  label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
1851
2114
  providers,
1852
2115
  status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1853
- title: options.title ?? DEFAULT_TITLE4,
2116
+ title: options.title ?? DEFAULT_TITLE5,
1854
2117
  updatedAt: snapshot.updatedAt
1855
2118
  };
1856
2119
  };
1857
2120
  var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
1858
2121
  const model = createVoiceProviderStatusViewModel(snapshot, options);
1859
- const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml5(provider.status)}">
2122
+ const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml6(provider.status)}">
1860
2123
  <header>
1861
- <strong>${escapeHtml5(provider.label)}</strong>
1862
- <span>${escapeHtml5(formatStatus2(provider.status))}</span>
2124
+ <strong>${escapeHtml6(provider.label)}</strong>
2125
+ <span>${escapeHtml6(formatStatus2(provider.status))}</span>
1863
2126
  </header>
1864
- <p>${escapeHtml5(provider.detail)}</p>
2127
+ <p>${escapeHtml6(provider.detail)}</p>
1865
2128
  <dl>${provider.rows.map((row) => `<div>
1866
- <dt>${escapeHtml5(row.label)}</dt>
1867
- <dd>${escapeHtml5(row.value)}</dd>
2129
+ <dt>${escapeHtml6(row.label)}</dt>
2130
+ <dd>${escapeHtml6(row.value)}</dd>
1868
2131
  </div>`).join("")}</dl>
1869
2132
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
1870
- return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml5(model.status)}">
2133
+ return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml6(model.status)}">
1871
2134
  <header class="absolute-voice-provider-status__header">
1872
- <span class="absolute-voice-provider-status__eyebrow">${escapeHtml5(model.title)}</span>
1873
- <strong class="absolute-voice-provider-status__label">${escapeHtml5(model.label)}</strong>
2135
+ <span class="absolute-voice-provider-status__eyebrow">${escapeHtml6(model.title)}</span>
2136
+ <strong class="absolute-voice-provider-status__label">${escapeHtml6(model.label)}</strong>
1874
2137
  </header>
1875
- <p class="absolute-voice-provider-status__description">${escapeHtml5(model.description)}</p>
2138
+ <p class="absolute-voice-provider-status__description">${escapeHtml6(model.description)}</p>
1876
2139
  ${providers}
1877
- ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml5(model.error)}</p>` : ""}
2140
+ ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml6(model.error)}</p>` : ""}
1878
2141
  </section>`;
1879
2142
  };
1880
2143
  var getVoiceProviderStatusCSS = () => `.absolute-voice-provider-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-provider-status--error,.absolute-voice-provider-status--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-status__header,.absolute-voice-provider-status__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-status__label{font-size:24px;line-height:1}.absolute-voice-provider-status__description,.absolute-voice-provider-status__provider p,.absolute-voice-provider-status__provider dt,.absolute-voice-provider-status__empty{color:#514733}.absolute-voice-provider-status__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-status__provider{background:#fff;border:1px solid #eee4d2;border-radius:16px;padding:14px}.absolute-voice-provider-status__provider--degraded,.absolute-voice-provider-status__provider--rate-limited,.absolute-voice-provider-status__provider--suppressed{border-color:#f2a7a7}.absolute-voice-provider-status__provider--recoverable{border-color:#fbbf24}.absolute-voice-provider-status__provider p{margin:10px 0}.absolute-voice-provider-status__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-status__provider div{background:#fffaf0;border:1px solid #eee4d2;border-radius:12px;padding:8px}.absolute-voice-provider-status__provider dt{font-size:12px}.absolute-voice-provider-status__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-status__empty{margin:14px 0 0}.absolute-voice-provider-status__error{color:#9f1239;font-weight:700}`;
@@ -2005,9 +2268,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
2005
2268
  };
2006
2269
 
2007
2270
  // src/client/routingStatusWidget.ts
2008
- var DEFAULT_TITLE5 = "Voice Routing";
2009
- var DEFAULT_DESCRIPTION5 = "Latest provider routing decision from the self-hosted trace store.";
2010
- var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2271
+ var DEFAULT_TITLE6 = "Voice Routing";
2272
+ var DEFAULT_DESCRIPTION6 = "Latest provider routing decision from the self-hosted trace store.";
2273
+ var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2011
2274
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
2012
2275
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
2013
2276
  const decision = snapshot.decision;
@@ -2031,30 +2294,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
2031
2294
  ] : [];
2032
2295
  return {
2033
2296
  decision,
2034
- description: options.description ?? DEFAULT_DESCRIPTION5,
2297
+ description: options.description ?? DEFAULT_DESCRIPTION6,
2035
2298
  error: snapshot.error,
2036
2299
  isLoading: snapshot.isLoading,
2037
2300
  label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
2038
2301
  rows,
2039
2302
  status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
2040
- title: options.title ?? DEFAULT_TITLE5,
2303
+ title: options.title ?? DEFAULT_TITLE6,
2041
2304
  updatedAt: snapshot.updatedAt
2042
2305
  };
2043
2306
  };
2044
2307
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
2045
2308
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
2046
2309
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
2047
- <span>${escapeHtml6(row.label)}</span>
2048
- <strong>${escapeHtml6(row.value)}</strong>
2310
+ <span>${escapeHtml7(row.label)}</span>
2311
+ <strong>${escapeHtml7(row.value)}</strong>
2049
2312
  </div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
2050
- return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml6(model.status)}">
2313
+ return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml7(model.status)}">
2051
2314
  <header class="absolute-voice-routing-status__header">
2052
- <span class="absolute-voice-routing-status__eyebrow">${escapeHtml6(model.title)}</span>
2053
- <strong class="absolute-voice-routing-status__label">${escapeHtml6(model.label)}</strong>
2315
+ <span class="absolute-voice-routing-status__eyebrow">${escapeHtml7(model.title)}</span>
2316
+ <strong class="absolute-voice-routing-status__label">${escapeHtml7(model.label)}</strong>
2054
2317
  </header>
2055
- <p class="absolute-voice-routing-status__description">${escapeHtml6(model.description)}</p>
2318
+ <p class="absolute-voice-routing-status__description">${escapeHtml7(model.description)}</p>
2056
2319
  ${rows}
2057
- ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml6(model.error)}</p>` : ""}
2320
+ ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml7(model.error)}</p>` : ""}
2058
2321
  </section>`;
2059
2322
  };
2060
2323
  var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}`;
@@ -2185,9 +2448,9 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
2185
2448
  };
2186
2449
 
2187
2450
  // src/client/traceTimelineWidget.ts
2188
- var DEFAULT_TITLE6 = "Voice Traces";
2189
- var DEFAULT_DESCRIPTION6 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
2190
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2451
+ var DEFAULT_TITLE7 = "Voice Traces";
2452
+ var DEFAULT_DESCRIPTION7 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
2453
+ var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2191
2454
  var formatMs = (value) => typeof value === "number" ? `${value}ms` : "n/a";
2192
2455
  var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
2193
2456
  var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
@@ -2201,34 +2464,34 @@ var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
2201
2464
  const failed = sessions.filter((session) => session.status === "failed").length;
2202
2465
  const warnings = sessions.filter((session) => session.status === "warning").length;
2203
2466
  return {
2204
- description: options.description ?? DEFAULT_DESCRIPTION6,
2467
+ description: options.description ?? DEFAULT_DESCRIPTION7,
2205
2468
  error: snapshot.error,
2206
2469
  isLoading: snapshot.isLoading,
2207
2470
  label: snapshot.error ? "Unavailable" : failed > 0 ? `${failed} failed` : warnings > 0 ? `${warnings} warning` : sessions.length ? `${sessions.length} recent` : snapshot.isLoading ? "Checking" : "No traces yet",
2208
2471
  sessions,
2209
2472
  status: snapshot.error ? "error" : failed > 0 ? "failed" : warnings > 0 ? "warning" : sessions.length ? "ready" : snapshot.isLoading ? "loading" : "empty",
2210
- title: options.title ?? DEFAULT_TITLE6,
2473
+ title: options.title ?? DEFAULT_TITLE7,
2211
2474
  updatedAt: snapshot.updatedAt
2212
2475
  };
2213
2476
  };
2214
2477
  var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
2215
2478
  const model = createVoiceTraceTimelineViewModel(snapshot, options);
2216
- const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml7(session.status)}">
2479
+ const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml8(session.status)}">
2217
2480
  <header>
2218
- <strong>${escapeHtml7(session.sessionId)}</strong>
2219
- <span>${escapeHtml7(session.status)}</span>
2481
+ <strong>${escapeHtml8(session.sessionId)}</strong>
2482
+ <span>${escapeHtml8(session.status)}</span>
2220
2483
  </header>
2221
- <p>${escapeHtml7(session.label)} \xB7 ${escapeHtml7(session.durationLabel)} \xB7 ${escapeHtml7(session.providerLabel)}</p>
2222
- <a href="${escapeHtml7(session.detailHref)}">Open timeline</a>
2484
+ <p>${escapeHtml8(session.label)} \xB7 ${escapeHtml8(session.durationLabel)} \xB7 ${escapeHtml8(session.providerLabel)}</p>
2485
+ <a href="${escapeHtml8(session.detailHref)}">Open timeline</a>
2223
2486
  </article>`).join("")}</div>` : '<p class="absolute-voice-trace-timeline__empty">Run a voice session to see call timelines.</p>';
2224
- return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml7(model.status)}">
2487
+ return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml8(model.status)}">
2225
2488
  <header class="absolute-voice-trace-timeline__header">
2226
- <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml7(model.title)}</span>
2227
- <strong class="absolute-voice-trace-timeline__label">${escapeHtml7(model.label)}</strong>
2489
+ <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml8(model.title)}</span>
2490
+ <strong class="absolute-voice-trace-timeline__label">${escapeHtml8(model.label)}</strong>
2228
2491
  </header>
2229
- <p class="absolute-voice-trace-timeline__description">${escapeHtml7(model.description)}</p>
2492
+ <p class="absolute-voice-trace-timeline__description">${escapeHtml8(model.description)}</p>
2230
2493
  ${sessions}
2231
- ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml7(model.error)}</p>` : ""}
2494
+ ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml8(model.error)}</p>` : ""}
2232
2495
  </section>`;
2233
2496
  };
2234
2497
  var getVoiceTraceTimelineCSS = () => `.absolute-voice-trace-timeline{border:1px solid #bad7d3;border-radius:20px;background:#f3fffb;color:#09201c;padding:18px;box-shadow:0 18px 40px rgba(9,32,28,.12);font-family:inherit}.absolute-voice-trace-timeline--error,.absolute-voice-trace-timeline--failed{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-trace-timeline--warning{border-color:#fbbf24;background:#fffaf0}.absolute-voice-trace-timeline__header,.absolute-voice-trace-timeline__session header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-trace-timeline__eyebrow{color:#17665b;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-trace-timeline__label{font-size:24px;line-height:1}.absolute-voice-trace-timeline__description,.absolute-voice-trace-timeline__session p,.absolute-voice-trace-timeline__empty{color:#35544f}.absolute-voice-trace-timeline__sessions{display:grid;gap:12px;margin-top:14px}.absolute-voice-trace-timeline__session{background:#fff;border:1px solid #cfe7e2;border-radius:16px;padding:14px}.absolute-voice-trace-timeline__session--failed{border-color:#f2a7a7}.absolute-voice-trace-timeline__session--warning{border-color:#fbbf24}.absolute-voice-trace-timeline__session p{margin:10px 0}.absolute-voice-trace-timeline__session a{color:#0f766e;font-weight:800}.absolute-voice-trace-timeline__empty{margin:14px 0 0}.absolute-voice-trace-timeline__error{color:#9f1239;font-weight:700}`;
@@ -2385,10 +2648,10 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
2385
2648
  };
2386
2649
 
2387
2650
  // src/client/turnLatencyWidget.ts
2388
- var DEFAULT_TITLE7 = "Turn Latency";
2389
- var DEFAULT_DESCRIPTION7 = "Per-turn timing from first transcript to commit and assistant response start.";
2651
+ var DEFAULT_TITLE8 = "Turn Latency";
2652
+ var DEFAULT_DESCRIPTION8 = "Per-turn timing from first transcript to commit and assistant response start.";
2390
2653
  var DEFAULT_PROOF_LABEL = "Run latency proof";
2391
- var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2654
+ var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2392
2655
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
2393
2656
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2394
2657
  const turns = (snapshot.report?.turns ?? []).map((turn) => ({
@@ -2402,39 +2665,39 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2402
2665
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2403
2666
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2404
2667
  return {
2405
- description: options.description ?? DEFAULT_DESCRIPTION7,
2668
+ description: options.description ?? DEFAULT_DESCRIPTION8,
2406
2669
  error: snapshot.error,
2407
2670
  isLoading: snapshot.isLoading,
2408
2671
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs2(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
2409
2672
  proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
2410
2673
  showProofAction: Boolean(options.proofPath),
2411
2674
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2412
- title: options.title ?? DEFAULT_TITLE7,
2675
+ title: options.title ?? DEFAULT_TITLE8,
2413
2676
  turns,
2414
2677
  updatedAt: snapshot.updatedAt
2415
2678
  };
2416
2679
  };
2417
2680
  var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
2418
2681
  const model = createVoiceTurnLatencyViewModel(snapshot, options);
2419
- const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml8(turn.status)}">
2682
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml9(turn.status)}">
2420
2683
  <header>
2421
- <strong>${escapeHtml8(turn.label)}</strong>
2422
- <span>${escapeHtml8(turn.status)}</span>
2684
+ <strong>${escapeHtml9(turn.label)}</strong>
2685
+ <span>${escapeHtml9(turn.status)}</span>
2423
2686
  </header>
2424
2687
  <dl>${turn.rows.map((row) => `<div>
2425
- <dt>${escapeHtml8(row.label)}</dt>
2426
- <dd>${escapeHtml8(row.value)}</dd>
2688
+ <dt>${escapeHtml9(row.label)}</dt>
2689
+ <dd>${escapeHtml9(row.value)}</dd>
2427
2690
  </div>`).join("")}</dl>
2428
2691
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
2429
- return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml8(model.status)}">
2692
+ return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml9(model.status)}">
2430
2693
  <header class="absolute-voice-turn-latency__header">
2431
- <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml8(model.title)}</span>
2432
- <strong class="absolute-voice-turn-latency__label">${escapeHtml8(model.label)}</strong>
2694
+ <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml9(model.title)}</span>
2695
+ <strong class="absolute-voice-turn-latency__label">${escapeHtml9(model.label)}</strong>
2433
2696
  </header>
2434
- <p class="absolute-voice-turn-latency__description">${escapeHtml8(model.description)}</p>
2435
- ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml8(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
2697
+ <p class="absolute-voice-turn-latency__description">${escapeHtml9(model.description)}</p>
2698
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml9(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
2436
2699
  ${turns}
2437
- ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml8(model.error)}</p>` : ""}
2700
+ ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml9(model.error)}</p>` : ""}
2438
2701
  </section>`;
2439
2702
  };
2440
2703
  var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
@@ -2573,9 +2836,9 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
2573
2836
  };
2574
2837
 
2575
2838
  // src/client/turnQualityWidget.ts
2576
- var DEFAULT_TITLE8 = "Turn Quality";
2577
- var DEFAULT_DESCRIPTION8 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2578
- var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2839
+ var DEFAULT_TITLE9 = "Turn Quality";
2840
+ var DEFAULT_DESCRIPTION9 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2841
+ var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2579
2842
  var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
2580
2843
  var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
2581
2844
  var getTurnDetail = (turn) => {
@@ -2613,37 +2876,37 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
2613
2876
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2614
2877
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2615
2878
  return {
2616
- description: options.description ?? DEFAULT_DESCRIPTION8,
2879
+ description: options.description ?? DEFAULT_DESCRIPTION9,
2617
2880
  error: snapshot.error,
2618
2881
  isLoading: snapshot.isLoading,
2619
2882
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
2620
2883
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2621
- title: options.title ?? DEFAULT_TITLE8,
2884
+ title: options.title ?? DEFAULT_TITLE9,
2622
2885
  turns,
2623
2886
  updatedAt: snapshot.updatedAt
2624
2887
  };
2625
2888
  };
2626
2889
  var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
2627
2890
  const model = createVoiceTurnQualityViewModel(snapshot, options);
2628
- const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml9(turn.status)}">
2891
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml10(turn.status)}">
2629
2892
  <header>
2630
- <strong>${escapeHtml9(turn.label)}</strong>
2631
- <span>${escapeHtml9(turn.status)}</span>
2893
+ <strong>${escapeHtml10(turn.label)}</strong>
2894
+ <span>${escapeHtml10(turn.status)}</span>
2632
2895
  </header>
2633
- <p>${escapeHtml9(turn.detail)}</p>
2896
+ <p>${escapeHtml10(turn.detail)}</p>
2634
2897
  <dl>${turn.rows.map((row) => `<div>
2635
- <dt>${escapeHtml9(row.label)}</dt>
2636
- <dd>${escapeHtml9(row.value)}</dd>
2898
+ <dt>${escapeHtml10(row.label)}</dt>
2899
+ <dd>${escapeHtml10(row.value)}</dd>
2637
2900
  </div>`).join("")}</dl>
2638
2901
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
2639
- return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml9(model.status)}">
2902
+ return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml10(model.status)}">
2640
2903
  <header class="absolute-voice-turn-quality__header">
2641
- <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml9(model.title)}</span>
2642
- <strong class="absolute-voice-turn-quality__label">${escapeHtml9(model.label)}</strong>
2904
+ <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml10(model.title)}</span>
2905
+ <strong class="absolute-voice-turn-quality__label">${escapeHtml10(model.label)}</strong>
2643
2906
  </header>
2644
- <p class="absolute-voice-turn-quality__description">${escapeHtml9(model.description)}</p>
2907
+ <p class="absolute-voice-turn-quality__description">${escapeHtml10(model.description)}</p>
2645
2908
  ${turns}
2646
- ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml9(model.error)}</p>` : ""}
2909
+ ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml10(model.error)}</p>` : ""}
2647
2910
  </section>`;
2648
2911
  };
2649
2912
  var getVoiceTurnQualityCSS = () => `.absolute-voice-turn-quality{border:1px solid #e4d1a3;border-radius:20px;background:#fff9eb;color:#17120a;padding:18px;box-shadow:0 18px 40px rgba(73,48,14,.12);font-family:inherit}.absolute-voice-turn-quality--error,.absolute-voice-turn-quality--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-turn-quality__header,.absolute-voice-turn-quality__turn header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-turn-quality__eyebrow{color:#8a5a0a;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-turn-quality__label{font-size:24px;line-height:1}.absolute-voice-turn-quality__description,.absolute-voice-turn-quality__turn p,.absolute-voice-turn-quality__turn dt,.absolute-voice-turn-quality__empty{color:#5a4930}.absolute-voice-turn-quality__turns{display:grid;gap:12px;margin-top:14px}.absolute-voice-turn-quality__turn{background:#fff;border:1px solid #f0dfba;border-radius:16px;padding:14px}.absolute-voice-turn-quality__turn--pass{border-color:#86efac}.absolute-voice-turn-quality__turn--warn,.absolute-voice-turn-quality__turn--unknown{border-color:#fbbf24}.absolute-voice-turn-quality__turn--fail{border-color:#f2a7a7}.absolute-voice-turn-quality__turn p{margin:10px 0}.absolute-voice-turn-quality__turn dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-turn-quality__turn div{background:#fff9eb;border:1px solid #f0dfba;border-radius:12px;padding:8px}.absolute-voice-turn-quality__turn dt{font-size:12px}.absolute-voice-turn-quality__turn dd{font-weight:800;margin:4px 0 0}.absolute-voice-turn-quality__empty{margin:14px 0 0}.absolute-voice-turn-quality__error{color:#9f1239;font-weight:700}`;
@@ -3425,6 +3688,7 @@ export {
3425
3688
  createVoiceProviderSimulationControls,
3426
3689
  createVoiceProviderCapabilities,
3427
3690
  createVoiceOpsStatus,
3691
+ createVoiceOpsActionCenter,
3428
3692
  createVoiceDeliveryRuntime,
3429
3693
  createVoiceController,
3430
3694
  createVoiceCampaignDialerProof