@absolutejs/voice 0.0.22-beta.150 → 0.0.22-beta.152

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.
@@ -189,6 +189,200 @@ var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-p
189
189
 
190
190
  // src/svelte/createVoiceCampaignDialerProof.ts
191
191
  var createVoiceCampaignDialerProof = (path = "/api/voice/campaigns/dialer-proof", options = {}) => createVoiceCampaignDialerProofStore(path, options);
192
+ // src/client/deliveryRuntime.ts
193
+ var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", options = {}) => {
194
+ const fetchImpl = options.fetch ?? globalThis.fetch;
195
+ const response = await fetchImpl(path);
196
+ if (!response.ok) {
197
+ throw new Error(`Voice delivery runtime failed: HTTP ${response.status}`);
198
+ }
199
+ return await response.json();
200
+ };
201
+ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", options = {}) => {
202
+ const listeners = new Set;
203
+ let closed = false;
204
+ let timer;
205
+ let snapshot = {
206
+ error: null,
207
+ isLoading: false
208
+ };
209
+ const emit = () => {
210
+ for (const listener of listeners) {
211
+ listener();
212
+ }
213
+ };
214
+ const refresh = async () => {
215
+ if (closed) {
216
+ return snapshot.report;
217
+ }
218
+ snapshot = {
219
+ ...snapshot,
220
+ error: null,
221
+ isLoading: true
222
+ };
223
+ emit();
224
+ try {
225
+ const report = await fetchVoiceDeliveryRuntime(path, options);
226
+ snapshot = {
227
+ error: null,
228
+ isLoading: false,
229
+ report,
230
+ updatedAt: Date.now()
231
+ };
232
+ emit();
233
+ return report;
234
+ } catch (error) {
235
+ snapshot = {
236
+ ...snapshot,
237
+ error: error instanceof Error ? error.message : String(error),
238
+ isLoading: false
239
+ };
240
+ emit();
241
+ throw error;
242
+ }
243
+ };
244
+ const close = () => {
245
+ closed = true;
246
+ if (timer) {
247
+ clearInterval(timer);
248
+ timer = undefined;
249
+ }
250
+ listeners.clear();
251
+ };
252
+ if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
253
+ timer = setInterval(() => {
254
+ refresh().catch(() => {});
255
+ }, options.intervalMs);
256
+ }
257
+ return {
258
+ close,
259
+ getServerSnapshot: () => snapshot,
260
+ getSnapshot: () => snapshot,
261
+ refresh,
262
+ subscribe: (listener) => {
263
+ listeners.add(listener);
264
+ return () => {
265
+ listeners.delete(listener);
266
+ };
267
+ }
268
+ };
269
+ };
270
+
271
+ // src/client/deliveryRuntimeWidget.ts
272
+ var DEFAULT_TITLE = "Voice Delivery Runtime";
273
+ var DEFAULT_DESCRIPTION = "Audit and trace delivery worker health from your AbsoluteJS voice app.";
274
+ var escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
275
+ var createSurface = (id, summary) => {
276
+ if (!summary) {
277
+ return {
278
+ deadLettered: 0,
279
+ detail: "Worker disabled",
280
+ failed: 0,
281
+ id,
282
+ label: id === "audit" ? "Audit delivery" : "Trace delivery",
283
+ pending: 0,
284
+ status: "disabled",
285
+ total: 0
286
+ };
287
+ }
288
+ const blocked = summary.failed + summary.deadLettered;
289
+ return {
290
+ deadLettered: summary.deadLettered,
291
+ detail: `${summary.delivered}/${summary.total} delivered, ${summary.pending} pending`,
292
+ failed: summary.failed,
293
+ id,
294
+ label: id === "audit" ? "Audit delivery" : "Trace delivery",
295
+ pending: summary.pending,
296
+ status: blocked > 0 ? "warn" : "pass",
297
+ total: summary.total
298
+ };
299
+ };
300
+ var createVoiceDeliveryRuntimeViewModel = (snapshot, options = {}) => {
301
+ const report = snapshot.report;
302
+ const surfaces = [
303
+ createSurface("audit", report?.summary.audit),
304
+ createSurface("trace", report?.summary.trace)
305
+ ];
306
+ const hasWarnings = surfaces.some((surface) => surface.status === "warn");
307
+ return {
308
+ description: options.description ?? DEFAULT_DESCRIPTION,
309
+ error: snapshot.error,
310
+ isLoading: snapshot.isLoading,
311
+ isRunning: Boolean(report?.isRunning),
312
+ label: snapshot.error ? "Unavailable" : report ? report.isRunning ? "Running" : "Stopped" : "Checking",
313
+ status: snapshot.error ? "error" : report ? hasWarnings ? "warn" : "pass" : "loading",
314
+ surfaces,
315
+ title: options.title ?? DEFAULT_TITLE,
316
+ updatedAt: snapshot.updatedAt
317
+ };
318
+ };
319
+ var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
320
+ const model = createVoiceDeliveryRuntimeViewModel(snapshot, options);
321
+ const surfaces = model.surfaces.map((surface) => `<li class="absolute-voice-delivery-runtime__surface absolute-voice-delivery-runtime__surface--${escapeHtml(surface.status)}">
322
+ <span>${escapeHtml(surface.label)}</span>
323
+ <strong>${escapeHtml(surface.detail)}</strong>
324
+ <small>${String(surface.failed)} failed &middot; ${String(surface.deadLettered)} dead-lettered</small>
325
+ </li>`).join("");
326
+ return `<section class="absolute-voice-delivery-runtime absolute-voice-delivery-runtime--${escapeHtml(model.status)}">
327
+ <header class="absolute-voice-delivery-runtime__header">
328
+ <span class="absolute-voice-delivery-runtime__eyebrow">${escapeHtml(model.title)}</span>
329
+ <strong class="absolute-voice-delivery-runtime__label">${escapeHtml(model.label)}</strong>
330
+ </header>
331
+ <p class="absolute-voice-delivery-runtime__description">${escapeHtml(model.description)}</p>
332
+ <ul class="absolute-voice-delivery-runtime__surfaces">${surfaces}</ul>
333
+ ${model.error ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml(model.error)}</p>` : ""}
334
+ </section>`;
335
+ };
336
+ var getVoiceDeliveryRuntimeCSS = () => `.absolute-voice-delivery-runtime{border:1px solid #c9d8cf;border-radius:20px;background:#f6fff9;color:#0d1b12;padding:18px;box-shadow:0 18px 40px rgba(19,55,35,.12);font-family:inherit}.absolute-voice-delivery-runtime--warn,.absolute-voice-delivery-runtime--error{border-color:#f2b56b;background:#fff9ed}.absolute-voice-delivery-runtime__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-delivery-runtime__eyebrow{color:#4e6b59;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-delivery-runtime__label{font-size:28px;line-height:1}.absolute-voice-delivery-runtime__description{color:#33483b;margin:12px 0 0}.absolute-voice-delivery-runtime__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-delivery-runtime__surface{background:#fff;border:1px solid #d9eadf;border-radius:14px;display:grid;gap:4px;padding:10px 12px}.absolute-voice-delivery-runtime__surface--warn{border-color:#f2b56b}.absolute-voice-delivery-runtime__surface--disabled{opacity:.72}.absolute-voice-delivery-runtime__surface span,.absolute-voice-delivery-runtime__surface small{color:#587063}.absolute-voice-delivery-runtime__error{color:#9f1239;font-weight:700}`;
337
+ var mountVoiceDeliveryRuntime = (element, path = "/api/voice-delivery-runtime", options = {}) => {
338
+ const store = createVoiceDeliveryRuntimeStore(path, options);
339
+ const render = () => {
340
+ element.innerHTML = renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options);
341
+ };
342
+ const unsubscribe = store.subscribe(render);
343
+ render();
344
+ store.refresh().catch(() => {});
345
+ return {
346
+ close: () => {
347
+ unsubscribe();
348
+ store.close();
349
+ },
350
+ refresh: store.refresh
351
+ };
352
+ };
353
+ var defineVoiceDeliveryRuntimeElement = (tagName = "absolute-voice-delivery-runtime") => {
354
+ if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
355
+ return;
356
+ }
357
+ customElements.define(tagName, class AbsoluteVoiceDeliveryRuntimeElement extends HTMLElement {
358
+ mounted;
359
+ connectedCallback() {
360
+ const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
361
+ this.mounted = mountVoiceDeliveryRuntime(this, this.getAttribute("path") ?? "/api/voice-delivery-runtime", {
362
+ description: this.getAttribute("description") ?? undefined,
363
+ intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
364
+ title: this.getAttribute("title") ?? undefined
365
+ });
366
+ }
367
+ disconnectedCallback() {
368
+ this.mounted?.close();
369
+ this.mounted = undefined;
370
+ }
371
+ });
372
+ };
373
+
374
+ // src/svelte/createVoiceDeliveryRuntime.ts
375
+ var createVoiceDeliveryRuntime = (path = "/api/voice-delivery-runtime", options = {}) => {
376
+ const store = createVoiceDeliveryRuntimeStore(path, options);
377
+ return {
378
+ close: store.close,
379
+ getHTML: () => renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options),
380
+ getSnapshot: store.getSnapshot,
381
+ getViewModel: () => createVoiceDeliveryRuntimeViewModel(store.getSnapshot(), options),
382
+ refresh: store.refresh,
383
+ subscribe: store.subscribe
384
+ };
385
+ };
192
386
  // src/client/opsStatus.ts
193
387
  var fetchVoiceOpsStatus = async (path = "/api/voice/ops-status", options = {}) => {
194
388
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -269,8 +463,8 @@ var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) =
269
463
  };
270
464
 
271
465
  // src/client/opsStatusWidget.ts
272
- var DEFAULT_TITLE = "Voice Ops Status";
273
- var DEFAULT_DESCRIPTION = "Certified workflow, provider, and handoff readiness from your AbsoluteJS voice app.";
466
+ var DEFAULT_TITLE2 = "Voice Ops Status";
467
+ var DEFAULT_DESCRIPTION2 = "Certified workflow, provider, and handoff readiness from your AbsoluteJS voice app.";
274
468
  var SURFACE_LABELS = {
275
469
  handoffs: "Handoffs",
276
470
  providers: "Providers",
@@ -278,7 +472,7 @@ var SURFACE_LABELS = {
278
472
  sessions: "Sessions",
279
473
  workflows: "Workflows"
280
474
  };
281
- var escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
475
+ var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
282
476
  var readNumber = (value, key) => value && typeof value === "object" && (key in value) ? Number(value[key] ?? 0) : 0;
283
477
  var surfaceDetail = (surface) => {
284
478
  const total = readNumber(surface, "total");
@@ -318,7 +512,7 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
318
512
  };
319
513
  });
320
514
  return {
321
- description: options.description ?? DEFAULT_DESCRIPTION,
515
+ description: options.description ?? DEFAULT_DESCRIPTION2,
322
516
  error: snapshot.error,
323
517
  isLoading: snapshot.isLoading,
324
518
  label: getVoiceOpsStatusLabel(report, snapshot.error),
@@ -326,31 +520,31 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
326
520
  passed: report?.passed ?? 0,
327
521
  status: snapshot.error ? "error" : report ? report.status : snapshot.isLoading ? "loading" : "loading",
328
522
  surfaces,
329
- title: options.title ?? DEFAULT_TITLE,
523
+ title: options.title ?? DEFAULT_TITLE2,
330
524
  total: report?.total ?? 0,
331
525
  updatedAt: snapshot.updatedAt
332
526
  };
333
527
  };
334
528
  var renderVoiceOpsStatusHTML = (snapshot, options = {}) => {
335
529
  const model = createVoiceOpsStatusViewModel(snapshot, options);
336
- const surfaces = model.surfaces.length ? model.surfaces.map((surface) => `<li class="absolute-voice-ops-status__surface absolute-voice-ops-status__surface--${escapeHtml(surface.status)}">
337
- <span>${escapeHtml(surface.label)}</span>
338
- <strong>${escapeHtml(surface.detail)}</strong>
530
+ const surfaces = model.surfaces.length ? model.surfaces.map((surface) => `<li class="absolute-voice-ops-status__surface absolute-voice-ops-status__surface--${escapeHtml2(surface.status)}">
531
+ <span>${escapeHtml2(surface.label)}</span>
532
+ <strong>${escapeHtml2(surface.detail)}</strong>
339
533
  </li>`).join("") : '<li class="absolute-voice-ops-status__surface"><span>Status</span><strong>Waiting for first check</strong></li>';
340
- const links = model.links.length ? `<nav class="absolute-voice-ops-status__links">${model.links.slice(0, 4).map((link) => `<a href="${escapeHtml(link.href)}">${escapeHtml(link.label)}</a>`).join("")}</nav>` : "";
341
- return `<section class="absolute-voice-ops-status absolute-voice-ops-status--${escapeHtml(model.status)}">
534
+ 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>` : "";
535
+ return `<section class="absolute-voice-ops-status absolute-voice-ops-status--${escapeHtml2(model.status)}">
342
536
  <header class="absolute-voice-ops-status__header">
343
- <span class="absolute-voice-ops-status__eyebrow">${escapeHtml(model.title)}</span>
344
- <strong class="absolute-voice-ops-status__label">${escapeHtml(model.label)}</strong>
537
+ <span class="absolute-voice-ops-status__eyebrow">${escapeHtml2(model.title)}</span>
538
+ <strong class="absolute-voice-ops-status__label">${escapeHtml2(model.label)}</strong>
345
539
  </header>
346
- <p class="absolute-voice-ops-status__description">${escapeHtml(model.description)}</p>
540
+ <p class="absolute-voice-ops-status__description">${escapeHtml2(model.description)}</p>
347
541
  <div class="absolute-voice-ops-status__summary">
348
542
  <span>${model.passed} passing</span>
349
543
  <span>${Math.max(model.total - model.passed, 0)} failing</span>
350
544
  <span>${model.total} checks</span>
351
545
  </div>
352
546
  <ul class="absolute-voice-ops-status__surfaces">${surfaces}</ul>
353
- ${model.error ? `<p class="absolute-voice-ops-status__error">${escapeHtml(model.error)}</p>` : ""}
547
+ ${model.error ? `<p class="absolute-voice-ops-status__error">${escapeHtml2(model.error)}</p>` : ""}
354
548
  ${links}
355
549
  </section>`;
356
550
  };
@@ -485,7 +679,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
485
679
  };
486
680
 
487
681
  // src/client/providerSimulationControlsWidget.ts
488
- var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
682
+ var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
489
683
  var formatKind = (kind) => (kind ?? "stt").toUpperCase();
490
684
  var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
491
685
  const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
@@ -505,18 +699,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
505
699
  };
506
700
  var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
507
701
  const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
508
- const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml2(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml2(provider.provider)} ${escapeHtml2(formatKind(options.kind))} failure</button>`).join("");
509
- const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml2(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml2(provider.provider)} recovered</button>`).join("");
702
+ 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("");
703
+ 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("");
510
704
  return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
511
705
  <header class="absolute-voice-provider-simulation__header">
512
- <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml2(model.title)}</span>
513
- <strong class="absolute-voice-provider-simulation__label">${escapeHtml2(model.label)}</strong>
706
+ <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml3(model.title)}</span>
707
+ <strong class="absolute-voice-provider-simulation__label">${escapeHtml3(model.label)}</strong>
514
708
  </header>
515
- <p class="absolute-voice-provider-simulation__description">${escapeHtml2(model.description)}</p>
516
- ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml2(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
709
+ <p class="absolute-voice-provider-simulation__description">${escapeHtml3(model.description)}</p>
710
+ ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml3(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
517
711
  <div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
518
- ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml2(snapshot.error)}</p>` : ""}
519
- ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml2(model.resultText)}</pre>` : ""}
712
+ ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml3(snapshot.error)}</p>` : ""}
713
+ ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml3(model.resultText)}</pre>` : ""}
520
714
  </section>`;
521
715
  };
522
716
  var bindVoiceProviderSimulationControls = (element, store) => {
@@ -671,9 +865,9 @@ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities",
671
865
  };
672
866
 
673
867
  // src/client/providerCapabilitiesWidget.ts
674
- var DEFAULT_TITLE2 = "Provider Capabilities";
675
- var DEFAULT_DESCRIPTION2 = "Configured, selected, and healthy voice providers for this deployment.";
676
- var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
868
+ var DEFAULT_TITLE3 = "Provider Capabilities";
869
+ var DEFAULT_DESCRIPTION3 = "Configured, selected, and healthy voice providers for this deployment.";
870
+ var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
677
871
  var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
678
872
  var formatKind2 = (kind) => kind.toUpperCase();
679
873
  var formatStatus = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
@@ -717,36 +911,36 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
717
911
  const selectedCount = snapshot.report?.selected ?? capabilities.filter((capability) => capability.selected).length;
718
912
  return {
719
913
  capabilities,
720
- description: options.description ?? DEFAULT_DESCRIPTION2,
914
+ description: options.description ?? DEFAULT_DESCRIPTION3,
721
915
  error: snapshot.error,
722
916
  isLoading: snapshot.isLoading,
723
917
  label: snapshot.error ? "Unavailable" : capabilities.length ? warningCount > 0 ? `${warningCount} needs attention` : `${selectedCount} selected` : snapshot.isLoading ? "Checking" : "No capabilities",
724
918
  status: snapshot.error ? "error" : capabilities.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
725
- title: options.title ?? DEFAULT_TITLE2,
919
+ title: options.title ?? DEFAULT_TITLE3,
726
920
  updatedAt: snapshot.updatedAt
727
921
  };
728
922
  };
729
923
  var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
730
924
  const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
731
- 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--${escapeHtml3(capability.status)}">
925
+ 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)}">
732
926
  <header>
733
- <strong>${escapeHtml3(capability.label)}</strong>
734
- <span>${escapeHtml3(formatStatus(capability.status))}</span>
927
+ <strong>${escapeHtml4(capability.label)}</strong>
928
+ <span>${escapeHtml4(formatStatus(capability.status))}</span>
735
929
  </header>
736
- <p>${escapeHtml3(capability.detail)}</p>
930
+ <p>${escapeHtml4(capability.detail)}</p>
737
931
  <dl>${capability.rows.map((row) => `<div>
738
- <dt>${escapeHtml3(row.label)}</dt>
739
- <dd>${escapeHtml3(row.value)}</dd>
932
+ <dt>${escapeHtml4(row.label)}</dt>
933
+ <dd>${escapeHtml4(row.value)}</dd>
740
934
  </div>`).join("")}</dl>
741
935
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
742
- return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml3(model.status)}">
936
+ return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml4(model.status)}">
743
937
  <header class="absolute-voice-provider-capabilities__header">
744
- <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml3(model.title)}</span>
745
- <strong class="absolute-voice-provider-capabilities__label">${escapeHtml3(model.label)}</strong>
938
+ <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml4(model.title)}</span>
939
+ <strong class="absolute-voice-provider-capabilities__label">${escapeHtml4(model.label)}</strong>
746
940
  </header>
747
- <p class="absolute-voice-provider-capabilities__description">${escapeHtml3(model.description)}</p>
941
+ <p class="absolute-voice-provider-capabilities__description">${escapeHtml4(model.description)}</p>
748
942
  ${capabilities}
749
- ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml3(model.error)}</p>` : ""}
943
+ ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml4(model.error)}</p>` : ""}
750
944
  </section>`;
751
945
  };
752
946
  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}`;
@@ -1519,9 +1713,9 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
1519
1713
  };
1520
1714
 
1521
1715
  // src/client/providerStatusWidget.ts
1522
- var DEFAULT_TITLE3 = "Voice Providers";
1523
- var DEFAULT_DESCRIPTION3 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
1524
- var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1716
+ var DEFAULT_TITLE4 = "Voice Providers";
1717
+ var DEFAULT_DESCRIPTION4 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
1718
+ var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1525
1719
  var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
1526
1720
  var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
1527
1721
  var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
@@ -1565,37 +1759,37 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
1565
1759
  const warningCount = providers.filter((provider) => isWarningStatus2(provider.status)).length;
1566
1760
  const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
1567
1761
  return {
1568
- description: options.description ?? DEFAULT_DESCRIPTION3,
1762
+ description: options.description ?? DEFAULT_DESCRIPTION4,
1569
1763
  error: snapshot.error,
1570
1764
  isLoading: snapshot.isLoading,
1571
1765
  label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
1572
1766
  providers,
1573
1767
  status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1574
- title: options.title ?? DEFAULT_TITLE3,
1768
+ title: options.title ?? DEFAULT_TITLE4,
1575
1769
  updatedAt: snapshot.updatedAt
1576
1770
  };
1577
1771
  };
1578
1772
  var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
1579
1773
  const model = createVoiceProviderStatusViewModel(snapshot, options);
1580
- 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--${escapeHtml4(provider.status)}">
1774
+ 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)}">
1581
1775
  <header>
1582
- <strong>${escapeHtml4(provider.label)}</strong>
1583
- <span>${escapeHtml4(formatStatus2(provider.status))}</span>
1776
+ <strong>${escapeHtml5(provider.label)}</strong>
1777
+ <span>${escapeHtml5(formatStatus2(provider.status))}</span>
1584
1778
  </header>
1585
- <p>${escapeHtml4(provider.detail)}</p>
1779
+ <p>${escapeHtml5(provider.detail)}</p>
1586
1780
  <dl>${provider.rows.map((row) => `<div>
1587
- <dt>${escapeHtml4(row.label)}</dt>
1588
- <dd>${escapeHtml4(row.value)}</dd>
1781
+ <dt>${escapeHtml5(row.label)}</dt>
1782
+ <dd>${escapeHtml5(row.value)}</dd>
1589
1783
  </div>`).join("")}</dl>
1590
1784
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
1591
- return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml4(model.status)}">
1785
+ return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml5(model.status)}">
1592
1786
  <header class="absolute-voice-provider-status__header">
1593
- <span class="absolute-voice-provider-status__eyebrow">${escapeHtml4(model.title)}</span>
1594
- <strong class="absolute-voice-provider-status__label">${escapeHtml4(model.label)}</strong>
1787
+ <span class="absolute-voice-provider-status__eyebrow">${escapeHtml5(model.title)}</span>
1788
+ <strong class="absolute-voice-provider-status__label">${escapeHtml5(model.label)}</strong>
1595
1789
  </header>
1596
- <p class="absolute-voice-provider-status__description">${escapeHtml4(model.description)}</p>
1790
+ <p class="absolute-voice-provider-status__description">${escapeHtml5(model.description)}</p>
1597
1791
  ${providers}
1598
- ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml4(model.error)}</p>` : ""}
1792
+ ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml5(model.error)}</p>` : ""}
1599
1793
  </section>`;
1600
1794
  };
1601
1795
  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}`;
@@ -1726,9 +1920,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
1726
1920
  };
1727
1921
 
1728
1922
  // src/client/routingStatusWidget.ts
1729
- var DEFAULT_TITLE4 = "Voice Routing";
1730
- var DEFAULT_DESCRIPTION4 = "Latest provider routing decision from the self-hosted trace store.";
1731
- var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1923
+ var DEFAULT_TITLE5 = "Voice Routing";
1924
+ var DEFAULT_DESCRIPTION5 = "Latest provider routing decision from the self-hosted trace store.";
1925
+ var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1732
1926
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
1733
1927
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
1734
1928
  const decision = snapshot.decision;
@@ -1752,30 +1946,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
1752
1946
  ] : [];
1753
1947
  return {
1754
1948
  decision,
1755
- description: options.description ?? DEFAULT_DESCRIPTION4,
1949
+ description: options.description ?? DEFAULT_DESCRIPTION5,
1756
1950
  error: snapshot.error,
1757
1951
  isLoading: snapshot.isLoading,
1758
1952
  label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
1759
1953
  rows,
1760
1954
  status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
1761
- title: options.title ?? DEFAULT_TITLE4,
1955
+ title: options.title ?? DEFAULT_TITLE5,
1762
1956
  updatedAt: snapshot.updatedAt
1763
1957
  };
1764
1958
  };
1765
1959
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
1766
1960
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
1767
1961
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
1768
- <span>${escapeHtml5(row.label)}</span>
1769
- <strong>${escapeHtml5(row.value)}</strong>
1962
+ <span>${escapeHtml6(row.label)}</span>
1963
+ <strong>${escapeHtml6(row.value)}</strong>
1770
1964
  </div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
1771
- return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml5(model.status)}">
1965
+ return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml6(model.status)}">
1772
1966
  <header class="absolute-voice-routing-status__header">
1773
- <span class="absolute-voice-routing-status__eyebrow">${escapeHtml5(model.title)}</span>
1774
- <strong class="absolute-voice-routing-status__label">${escapeHtml5(model.label)}</strong>
1967
+ <span class="absolute-voice-routing-status__eyebrow">${escapeHtml6(model.title)}</span>
1968
+ <strong class="absolute-voice-routing-status__label">${escapeHtml6(model.label)}</strong>
1775
1969
  </header>
1776
- <p class="absolute-voice-routing-status__description">${escapeHtml5(model.description)}</p>
1970
+ <p class="absolute-voice-routing-status__description">${escapeHtml6(model.description)}</p>
1777
1971
  ${rows}
1778
- ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml5(model.error)}</p>` : ""}
1972
+ ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml6(model.error)}</p>` : ""}
1779
1973
  </section>`;
1780
1974
  };
1781
1975
  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}`;
@@ -1906,9 +2100,9 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
1906
2100
  };
1907
2101
 
1908
2102
  // src/client/traceTimelineWidget.ts
1909
- var DEFAULT_TITLE5 = "Voice Traces";
1910
- var DEFAULT_DESCRIPTION5 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
1911
- var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2103
+ var DEFAULT_TITLE6 = "Voice Traces";
2104
+ var DEFAULT_DESCRIPTION6 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
2105
+ var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1912
2106
  var formatMs = (value) => typeof value === "number" ? `${value}ms` : "n/a";
1913
2107
  var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
1914
2108
  var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
@@ -1922,34 +2116,34 @@ var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
1922
2116
  const failed = sessions.filter((session) => session.status === "failed").length;
1923
2117
  const warnings = sessions.filter((session) => session.status === "warning").length;
1924
2118
  return {
1925
- description: options.description ?? DEFAULT_DESCRIPTION5,
2119
+ description: options.description ?? DEFAULT_DESCRIPTION6,
1926
2120
  error: snapshot.error,
1927
2121
  isLoading: snapshot.isLoading,
1928
2122
  label: snapshot.error ? "Unavailable" : failed > 0 ? `${failed} failed` : warnings > 0 ? `${warnings} warning` : sessions.length ? `${sessions.length} recent` : snapshot.isLoading ? "Checking" : "No traces yet",
1929
2123
  sessions,
1930
2124
  status: snapshot.error ? "error" : failed > 0 ? "failed" : warnings > 0 ? "warning" : sessions.length ? "ready" : snapshot.isLoading ? "loading" : "empty",
1931
- title: options.title ?? DEFAULT_TITLE5,
2125
+ title: options.title ?? DEFAULT_TITLE6,
1932
2126
  updatedAt: snapshot.updatedAt
1933
2127
  };
1934
2128
  };
1935
2129
  var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
1936
2130
  const model = createVoiceTraceTimelineViewModel(snapshot, options);
1937
- 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--${escapeHtml6(session.status)}">
2131
+ 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)}">
1938
2132
  <header>
1939
- <strong>${escapeHtml6(session.sessionId)}</strong>
1940
- <span>${escapeHtml6(session.status)}</span>
2133
+ <strong>${escapeHtml7(session.sessionId)}</strong>
2134
+ <span>${escapeHtml7(session.status)}</span>
1941
2135
  </header>
1942
- <p>${escapeHtml6(session.label)} \xB7 ${escapeHtml6(session.durationLabel)} \xB7 ${escapeHtml6(session.providerLabel)}</p>
1943
- <a href="${escapeHtml6(session.detailHref)}">Open timeline</a>
2136
+ <p>${escapeHtml7(session.label)} \xB7 ${escapeHtml7(session.durationLabel)} \xB7 ${escapeHtml7(session.providerLabel)}</p>
2137
+ <a href="${escapeHtml7(session.detailHref)}">Open timeline</a>
1944
2138
  </article>`).join("")}</div>` : '<p class="absolute-voice-trace-timeline__empty">Run a voice session to see call timelines.</p>';
1945
- return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml6(model.status)}">
2139
+ return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml7(model.status)}">
1946
2140
  <header class="absolute-voice-trace-timeline__header">
1947
- <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml6(model.title)}</span>
1948
- <strong class="absolute-voice-trace-timeline__label">${escapeHtml6(model.label)}</strong>
2141
+ <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml7(model.title)}</span>
2142
+ <strong class="absolute-voice-trace-timeline__label">${escapeHtml7(model.label)}</strong>
1949
2143
  </header>
1950
- <p class="absolute-voice-trace-timeline__description">${escapeHtml6(model.description)}</p>
2144
+ <p class="absolute-voice-trace-timeline__description">${escapeHtml7(model.description)}</p>
1951
2145
  ${sessions}
1952
- ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml6(model.error)}</p>` : ""}
2146
+ ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml7(model.error)}</p>` : ""}
1953
2147
  </section>`;
1954
2148
  };
1955
2149
  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}`;
@@ -2106,10 +2300,10 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
2106
2300
  };
2107
2301
 
2108
2302
  // src/client/turnLatencyWidget.ts
2109
- var DEFAULT_TITLE6 = "Turn Latency";
2110
- var DEFAULT_DESCRIPTION6 = "Per-turn timing from first transcript to commit and assistant response start.";
2303
+ var DEFAULT_TITLE7 = "Turn Latency";
2304
+ var DEFAULT_DESCRIPTION7 = "Per-turn timing from first transcript to commit and assistant response start.";
2111
2305
  var DEFAULT_PROOF_LABEL = "Run latency proof";
2112
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2306
+ var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2113
2307
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
2114
2308
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2115
2309
  const turns = (snapshot.report?.turns ?? []).map((turn) => ({
@@ -2123,39 +2317,39 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2123
2317
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2124
2318
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2125
2319
  return {
2126
- description: options.description ?? DEFAULT_DESCRIPTION6,
2320
+ description: options.description ?? DEFAULT_DESCRIPTION7,
2127
2321
  error: snapshot.error,
2128
2322
  isLoading: snapshot.isLoading,
2129
2323
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs2(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
2130
2324
  proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
2131
2325
  showProofAction: Boolean(options.proofPath),
2132
2326
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2133
- title: options.title ?? DEFAULT_TITLE6,
2327
+ title: options.title ?? DEFAULT_TITLE7,
2134
2328
  turns,
2135
2329
  updatedAt: snapshot.updatedAt
2136
2330
  };
2137
2331
  };
2138
2332
  var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
2139
2333
  const model = createVoiceTurnLatencyViewModel(snapshot, options);
2140
- 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--${escapeHtml7(turn.status)}">
2334
+ 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)}">
2141
2335
  <header>
2142
- <strong>${escapeHtml7(turn.label)}</strong>
2143
- <span>${escapeHtml7(turn.status)}</span>
2336
+ <strong>${escapeHtml8(turn.label)}</strong>
2337
+ <span>${escapeHtml8(turn.status)}</span>
2144
2338
  </header>
2145
2339
  <dl>${turn.rows.map((row) => `<div>
2146
- <dt>${escapeHtml7(row.label)}</dt>
2147
- <dd>${escapeHtml7(row.value)}</dd>
2340
+ <dt>${escapeHtml8(row.label)}</dt>
2341
+ <dd>${escapeHtml8(row.value)}</dd>
2148
2342
  </div>`).join("")}</dl>
2149
2343
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
2150
- return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml7(model.status)}">
2344
+ return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml8(model.status)}">
2151
2345
  <header class="absolute-voice-turn-latency__header">
2152
- <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml7(model.title)}</span>
2153
- <strong class="absolute-voice-turn-latency__label">${escapeHtml7(model.label)}</strong>
2346
+ <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml8(model.title)}</span>
2347
+ <strong class="absolute-voice-turn-latency__label">${escapeHtml8(model.label)}</strong>
2154
2348
  </header>
2155
- <p class="absolute-voice-turn-latency__description">${escapeHtml7(model.description)}</p>
2156
- ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml7(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
2349
+ <p class="absolute-voice-turn-latency__description">${escapeHtml8(model.description)}</p>
2350
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml8(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
2157
2351
  ${turns}
2158
- ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml7(model.error)}</p>` : ""}
2352
+ ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml8(model.error)}</p>` : ""}
2159
2353
  </section>`;
2160
2354
  };
2161
2355
  var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
@@ -2294,9 +2488,9 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
2294
2488
  };
2295
2489
 
2296
2490
  // src/client/turnQualityWidget.ts
2297
- var DEFAULT_TITLE7 = "Turn Quality";
2298
- var DEFAULT_DESCRIPTION7 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2299
- var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2491
+ var DEFAULT_TITLE8 = "Turn Quality";
2492
+ var DEFAULT_DESCRIPTION8 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2493
+ var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2300
2494
  var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
2301
2495
  var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
2302
2496
  var getTurnDetail = (turn) => {
@@ -2334,37 +2528,37 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
2334
2528
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2335
2529
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2336
2530
  return {
2337
- description: options.description ?? DEFAULT_DESCRIPTION7,
2531
+ description: options.description ?? DEFAULT_DESCRIPTION8,
2338
2532
  error: snapshot.error,
2339
2533
  isLoading: snapshot.isLoading,
2340
2534
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
2341
2535
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2342
- title: options.title ?? DEFAULT_TITLE7,
2536
+ title: options.title ?? DEFAULT_TITLE8,
2343
2537
  turns,
2344
2538
  updatedAt: snapshot.updatedAt
2345
2539
  };
2346
2540
  };
2347
2541
  var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
2348
2542
  const model = createVoiceTurnQualityViewModel(snapshot, options);
2349
- 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--${escapeHtml8(turn.status)}">
2543
+ 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)}">
2350
2544
  <header>
2351
- <strong>${escapeHtml8(turn.label)}</strong>
2352
- <span>${escapeHtml8(turn.status)}</span>
2545
+ <strong>${escapeHtml9(turn.label)}</strong>
2546
+ <span>${escapeHtml9(turn.status)}</span>
2353
2547
  </header>
2354
- <p>${escapeHtml8(turn.detail)}</p>
2548
+ <p>${escapeHtml9(turn.detail)}</p>
2355
2549
  <dl>${turn.rows.map((row) => `<div>
2356
- <dt>${escapeHtml8(row.label)}</dt>
2357
- <dd>${escapeHtml8(row.value)}</dd>
2550
+ <dt>${escapeHtml9(row.label)}</dt>
2551
+ <dd>${escapeHtml9(row.value)}</dd>
2358
2552
  </div>`).join("")}</dl>
2359
2553
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
2360
- return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml8(model.status)}">
2554
+ return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml9(model.status)}">
2361
2555
  <header class="absolute-voice-turn-quality__header">
2362
- <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml8(model.title)}</span>
2363
- <strong class="absolute-voice-turn-quality__label">${escapeHtml8(model.label)}</strong>
2556
+ <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml9(model.title)}</span>
2557
+ <strong class="absolute-voice-turn-quality__label">${escapeHtml9(model.label)}</strong>
2364
2558
  </header>
2365
- <p class="absolute-voice-turn-quality__description">${escapeHtml8(model.description)}</p>
2559
+ <p class="absolute-voice-turn-quality__description">${escapeHtml9(model.description)}</p>
2366
2560
  ${turns}
2367
- ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml8(model.error)}</p>` : ""}
2561
+ ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml9(model.error)}</p>` : ""}
2368
2562
  </section>`;
2369
2563
  };
2370
2564
  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}`;
@@ -3146,6 +3340,7 @@ export {
3146
3340
  createVoiceProviderSimulationControls,
3147
3341
  createVoiceProviderCapabilities,
3148
3342
  createVoiceOpsStatus,
3343
+ createVoiceDeliveryRuntime,
3149
3344
  createVoiceController,
3150
3345
  createVoiceCampaignDialerProof
3151
3346
  };