@absolutejs/voice 0.0.22-beta.152 → 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.
@@ -190,6 +190,12 @@ var createVoiceCampaignDialerProofStore = (path = "/api/voice/campaigns/dialer-p
190
190
  // src/svelte/createVoiceCampaignDialerProof.ts
191
191
  var createVoiceCampaignDialerProof = (path = "/api/voice/campaigns/dialer-proof", options = {}) => createVoiceCampaignDialerProofStore(path, options);
192
192
  // src/client/deliveryRuntime.ts
193
+ var getDefaultActionPath = (path, action, options) => {
194
+ if (action === "tick") {
195
+ return options.tickPath ?? `${path.replace(/\/$/, "")}/tick`;
196
+ }
197
+ return options.requeueDeadLettersPath ?? `${path.replace(/\/$/, "")}/requeue-dead-letters`;
198
+ };
193
199
  var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", options = {}) => {
194
200
  const fetchImpl = options.fetch ?? globalThis.fetch;
195
201
  const response = await fetchImpl(path);
@@ -198,11 +204,29 @@ var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", opt
198
204
  }
199
205
  return await response.json();
200
206
  };
207
+ var runVoiceDeliveryRuntimeAction = async (action, path = "/api/voice-delivery-runtime", options = {}) => {
208
+ const fetchImpl = options.fetch ?? globalThis.fetch;
209
+ const response = await fetchImpl(getDefaultActionPath(path, action, options), {
210
+ method: "POST"
211
+ });
212
+ if (!response.ok) {
213
+ throw new Error(`Voice delivery runtime ${action} failed: HTTP ${response.status}`);
214
+ }
215
+ const body = await response.json();
216
+ return {
217
+ action,
218
+ result: body.result,
219
+ summary: body.summary,
220
+ updatedAt: Date.now()
221
+ };
222
+ };
201
223
  var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", options = {}) => {
202
224
  const listeners = new Set;
203
225
  let closed = false;
204
226
  let timer;
205
227
  let snapshot = {
228
+ actionError: null,
229
+ actionStatus: "idle",
206
230
  error: null,
207
231
  isLoading: false
208
232
  };
@@ -224,6 +248,7 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
224
248
  try {
225
249
  const report = await fetchVoiceDeliveryRuntime(path, options);
226
250
  snapshot = {
251
+ ...snapshot,
227
252
  error: null,
228
253
  isLoading: false,
229
254
  report,
@@ -241,6 +266,37 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
241
266
  throw error;
242
267
  }
243
268
  };
269
+ const runAction = async (action) => {
270
+ if (closed) {
271
+ return snapshot.lastAction;
272
+ }
273
+ snapshot = {
274
+ ...snapshot,
275
+ actionError: null,
276
+ actionStatus: "running"
277
+ };
278
+ emit();
279
+ try {
280
+ const result = await runVoiceDeliveryRuntimeAction(action, path, options);
281
+ snapshot = {
282
+ ...snapshot,
283
+ actionError: null,
284
+ actionStatus: "completed",
285
+ lastAction: result
286
+ };
287
+ emit();
288
+ await refresh();
289
+ return result;
290
+ } catch (error) {
291
+ snapshot = {
292
+ ...snapshot,
293
+ actionError: error instanceof Error ? error.message : String(error),
294
+ actionStatus: "failed"
295
+ };
296
+ emit();
297
+ throw error;
298
+ }
299
+ };
244
300
  const close = () => {
245
301
  closed = true;
246
302
  if (timer) {
@@ -258,7 +314,9 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
258
314
  close,
259
315
  getServerSnapshot: () => snapshot,
260
316
  getSnapshot: () => snapshot,
317
+ requeueDeadLetters: () => runAction("requeue-dead-letters"),
261
318
  refresh,
319
+ tick: () => runAction("tick"),
262
320
  subscribe: (listener) => {
263
321
  listeners.add(listener);
264
322
  return () => {
@@ -307,6 +365,8 @@ var createVoiceDeliveryRuntimeViewModel = (snapshot, options = {}) => {
307
365
  return {
308
366
  description: options.description ?? DEFAULT_DESCRIPTION,
309
367
  error: snapshot.error,
368
+ actionError: snapshot.actionError,
369
+ actionStatus: snapshot.actionStatus,
310
370
  isLoading: snapshot.isLoading,
311
371
  isRunning: Boolean(report?.isRunning),
312
372
  label: snapshot.error ? "Unavailable" : report ? report.isRunning ? "Running" : "Stopped" : "Checking",
@@ -323,6 +383,11 @@ var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
323
383
  <strong>${escapeHtml(surface.detail)}</strong>
324
384
  <small>${String(surface.failed)} failed &middot; ${String(surface.deadLettered)} dead-lettered</small>
325
385
  </li>`).join("");
386
+ const actions = options.includeActions === false ? "" : `<div class="absolute-voice-delivery-runtime__actions">
387
+ <button type="button" data-absolute-voice-delivery-runtime-action="tick">${model.actionStatus === "running" ? "Working..." : "Tick workers"}</button>
388
+ <button type="button" data-absolute-voice-delivery-runtime-action="requeue-dead-letters"${model.surfaces.some((surface) => surface.deadLettered > 0) ? "" : " disabled"}>Requeue dead letters</button>
389
+ </div>`;
390
+ const actionError = model.actionError ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml(model.actionError)}</p>` : "";
326
391
  return `<section class="absolute-voice-delivery-runtime absolute-voice-delivery-runtime--${escapeHtml(model.status)}">
327
392
  <header class="absolute-voice-delivery-runtime__header">
328
393
  <span class="absolute-voice-delivery-runtime__eyebrow">${escapeHtml(model.title)}</span>
@@ -330,20 +395,38 @@ var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
330
395
  </header>
331
396
  <p class="absolute-voice-delivery-runtime__description">${escapeHtml(model.description)}</p>
332
397
  <ul class="absolute-voice-delivery-runtime__surfaces">${surfaces}</ul>
398
+ ${actions}
399
+ ${actionError}
333
400
  ${model.error ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml(model.error)}</p>` : ""}
334
401
  </section>`;
335
402
  };
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}`;
403
+ 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__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}.absolute-voice-delivery-runtime__actions button{background:#134e2d;border:0;border-radius:999px;color:#f6fff9;cursor:pointer;font:inherit;font-weight:800;padding:8px 12px}.absolute-voice-delivery-runtime__actions button:disabled{cursor:not-allowed;opacity:.48}.absolute-voice-delivery-runtime__error{color:#9f1239;font-weight:700}`;
337
404
  var mountVoiceDeliveryRuntime = (element, path = "/api/voice-delivery-runtime", options = {}) => {
338
405
  const store = createVoiceDeliveryRuntimeStore(path, options);
339
406
  const render = () => {
340
407
  element.innerHTML = renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options);
341
408
  };
342
409
  const unsubscribe = store.subscribe(render);
410
+ const handleClick = (event) => {
411
+ const target = event.target;
412
+ if (!(target instanceof Element)) {
413
+ return;
414
+ }
415
+ const action = target.closest("[data-absolute-voice-delivery-runtime-action]");
416
+ const actionName = action?.getAttribute("data-absolute-voice-delivery-runtime-action");
417
+ if (actionName === "tick") {
418
+ store.tick().catch(() => {});
419
+ }
420
+ if (actionName === "requeue-dead-letters") {
421
+ store.requeueDeadLetters().catch(() => {});
422
+ }
423
+ };
424
+ element.addEventListener?.("click", handleClick);
343
425
  render();
344
426
  store.refresh().catch(() => {});
345
427
  return {
346
428
  close: () => {
429
+ element.removeEventListener?.("click", handleClick);
347
430
  unsubscribe();
348
431
  store.close();
349
432
  },
@@ -379,7 +462,272 @@ var createVoiceDeliveryRuntime = (path = "/api/voice-delivery-runtime", options
379
462
  getHTML: () => renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options),
380
463
  getSnapshot: store.getSnapshot,
381
464
  getViewModel: () => createVoiceDeliveryRuntimeViewModel(store.getSnapshot(), options),
465
+ requeueDeadLetters: store.requeueDeadLetters,
382
466
  refresh: store.refresh,
467
+ subscribe: store.subscribe,
468
+ tick: store.tick
469
+ };
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,
383
731
  subscribe: store.subscribe
384
732
  };
385
733
  };
@@ -463,8 +811,8 @@ var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) =
463
811
  };
464
812
 
465
813
  // src/client/opsStatusWidget.ts
466
- var DEFAULT_TITLE2 = "Voice Ops Status";
467
- 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.";
468
816
  var SURFACE_LABELS = {
469
817
  handoffs: "Handoffs",
470
818
  providers: "Providers",
@@ -472,7 +820,7 @@ var SURFACE_LABELS = {
472
820
  sessions: "Sessions",
473
821
  workflows: "Workflows"
474
822
  };
475
- 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;");
476
824
  var readNumber = (value, key) => value && typeof value === "object" && (key in value) ? Number(value[key] ?? 0) : 0;
477
825
  var surfaceDetail = (surface) => {
478
826
  const total = readNumber(surface, "total");
@@ -512,7 +860,7 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
512
860
  };
513
861
  });
514
862
  return {
515
- description: options.description ?? DEFAULT_DESCRIPTION2,
863
+ description: options.description ?? DEFAULT_DESCRIPTION3,
516
864
  error: snapshot.error,
517
865
  isLoading: snapshot.isLoading,
518
866
  label: getVoiceOpsStatusLabel(report, snapshot.error),
@@ -520,31 +868,31 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
520
868
  passed: report?.passed ?? 0,
521
869
  status: snapshot.error ? "error" : report ? report.status : snapshot.isLoading ? "loading" : "loading",
522
870
  surfaces,
523
- title: options.title ?? DEFAULT_TITLE2,
871
+ title: options.title ?? DEFAULT_TITLE3,
524
872
  total: report?.total ?? 0,
525
873
  updatedAt: snapshot.updatedAt
526
874
  };
527
875
  };
528
876
  var renderVoiceOpsStatusHTML = (snapshot, options = {}) => {
529
877
  const model = createVoiceOpsStatusViewModel(snapshot, options);
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>
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>
533
881
  </li>`).join("") : '<li class="absolute-voice-ops-status__surface"><span>Status</span><strong>Waiting for first check</strong></li>';
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)}">
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)}">
536
884
  <header class="absolute-voice-ops-status__header">
537
- <span class="absolute-voice-ops-status__eyebrow">${escapeHtml2(model.title)}</span>
538
- <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>
539
887
  </header>
540
- <p class="absolute-voice-ops-status__description">${escapeHtml2(model.description)}</p>
888
+ <p class="absolute-voice-ops-status__description">${escapeHtml3(model.description)}</p>
541
889
  <div class="absolute-voice-ops-status__summary">
542
890
  <span>${model.passed} passing</span>
543
891
  <span>${Math.max(model.total - model.passed, 0)} failing</span>
544
892
  <span>${model.total} checks</span>
545
893
  </div>
546
894
  <ul class="absolute-voice-ops-status__surfaces">${surfaces}</ul>
547
- ${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>` : ""}
548
896
  ${links}
549
897
  </section>`;
550
898
  };
@@ -679,7 +1027,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
679
1027
  };
680
1028
 
681
1029
  // src/client/providerSimulationControlsWidget.ts
682
- 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;");
683
1031
  var formatKind = (kind) => (kind ?? "stt").toUpperCase();
684
1032
  var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
685
1033
  const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
@@ -699,18 +1047,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
699
1047
  };
700
1048
  var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
701
1049
  const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
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("");
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("");
704
1052
  return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
705
1053
  <header class="absolute-voice-provider-simulation__header">
706
- <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml3(model.title)}</span>
707
- <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>
708
1056
  </header>
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>`}
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>`}
711
1059
  <div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
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>` : ""}
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>` : ""}
714
1062
  </section>`;
715
1063
  };
716
1064
  var bindVoiceProviderSimulationControls = (element, store) => {
@@ -865,9 +1213,9 @@ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities",
865
1213
  };
866
1214
 
867
1215
  // src/client/providerCapabilitiesWidget.ts
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;");
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;");
871
1219
  var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
872
1220
  var formatKind2 = (kind) => kind.toUpperCase();
873
1221
  var formatStatus = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
@@ -911,36 +1259,36 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
911
1259
  const selectedCount = snapshot.report?.selected ?? capabilities.filter((capability) => capability.selected).length;
912
1260
  return {
913
1261
  capabilities,
914
- description: options.description ?? DEFAULT_DESCRIPTION3,
1262
+ description: options.description ?? DEFAULT_DESCRIPTION4,
915
1263
  error: snapshot.error,
916
1264
  isLoading: snapshot.isLoading,
917
1265
  label: snapshot.error ? "Unavailable" : capabilities.length ? warningCount > 0 ? `${warningCount} needs attention` : `${selectedCount} selected` : snapshot.isLoading ? "Checking" : "No capabilities",
918
1266
  status: snapshot.error ? "error" : capabilities.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
919
- title: options.title ?? DEFAULT_TITLE3,
1267
+ title: options.title ?? DEFAULT_TITLE4,
920
1268
  updatedAt: snapshot.updatedAt
921
1269
  };
922
1270
  };
923
1271
  var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
924
1272
  const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
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)}">
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)}">
926
1274
  <header>
927
- <strong>${escapeHtml4(capability.label)}</strong>
928
- <span>${escapeHtml4(formatStatus(capability.status))}</span>
1275
+ <strong>${escapeHtml5(capability.label)}</strong>
1276
+ <span>${escapeHtml5(formatStatus(capability.status))}</span>
929
1277
  </header>
930
- <p>${escapeHtml4(capability.detail)}</p>
1278
+ <p>${escapeHtml5(capability.detail)}</p>
931
1279
  <dl>${capability.rows.map((row) => `<div>
932
- <dt>${escapeHtml4(row.label)}</dt>
933
- <dd>${escapeHtml4(row.value)}</dd>
1280
+ <dt>${escapeHtml5(row.label)}</dt>
1281
+ <dd>${escapeHtml5(row.value)}</dd>
934
1282
  </div>`).join("")}</dl>
935
1283
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
936
- 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)}">
937
1285
  <header class="absolute-voice-provider-capabilities__header">
938
- <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml4(model.title)}</span>
939
- <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>
940
1288
  </header>
941
- <p class="absolute-voice-provider-capabilities__description">${escapeHtml4(model.description)}</p>
1289
+ <p class="absolute-voice-provider-capabilities__description">${escapeHtml5(model.description)}</p>
942
1290
  ${capabilities}
943
- ${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>` : ""}
944
1292
  </section>`;
945
1293
  };
946
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}`;
@@ -1713,9 +2061,9 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
1713
2061
  };
1714
2062
 
1715
2063
  // src/client/providerStatusWidget.ts
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;");
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;");
1719
2067
  var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
1720
2068
  var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
1721
2069
  var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
@@ -1759,37 +2107,37 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
1759
2107
  const warningCount = providers.filter((provider) => isWarningStatus2(provider.status)).length;
1760
2108
  const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
1761
2109
  return {
1762
- description: options.description ?? DEFAULT_DESCRIPTION4,
2110
+ description: options.description ?? DEFAULT_DESCRIPTION5,
1763
2111
  error: snapshot.error,
1764
2112
  isLoading: snapshot.isLoading,
1765
2113
  label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
1766
2114
  providers,
1767
2115
  status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1768
- title: options.title ?? DEFAULT_TITLE4,
2116
+ title: options.title ?? DEFAULT_TITLE5,
1769
2117
  updatedAt: snapshot.updatedAt
1770
2118
  };
1771
2119
  };
1772
2120
  var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
1773
2121
  const model = createVoiceProviderStatusViewModel(snapshot, options);
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)}">
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)}">
1775
2123
  <header>
1776
- <strong>${escapeHtml5(provider.label)}</strong>
1777
- <span>${escapeHtml5(formatStatus2(provider.status))}</span>
2124
+ <strong>${escapeHtml6(provider.label)}</strong>
2125
+ <span>${escapeHtml6(formatStatus2(provider.status))}</span>
1778
2126
  </header>
1779
- <p>${escapeHtml5(provider.detail)}</p>
2127
+ <p>${escapeHtml6(provider.detail)}</p>
1780
2128
  <dl>${provider.rows.map((row) => `<div>
1781
- <dt>${escapeHtml5(row.label)}</dt>
1782
- <dd>${escapeHtml5(row.value)}</dd>
2129
+ <dt>${escapeHtml6(row.label)}</dt>
2130
+ <dd>${escapeHtml6(row.value)}</dd>
1783
2131
  </div>`).join("")}</dl>
1784
2132
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
1785
- 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)}">
1786
2134
  <header class="absolute-voice-provider-status__header">
1787
- <span class="absolute-voice-provider-status__eyebrow">${escapeHtml5(model.title)}</span>
1788
- <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>
1789
2137
  </header>
1790
- <p class="absolute-voice-provider-status__description">${escapeHtml5(model.description)}</p>
2138
+ <p class="absolute-voice-provider-status__description">${escapeHtml6(model.description)}</p>
1791
2139
  ${providers}
1792
- ${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>` : ""}
1793
2141
  </section>`;
1794
2142
  };
1795
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}`;
@@ -1920,9 +2268,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
1920
2268
  };
1921
2269
 
1922
2270
  // src/client/routingStatusWidget.ts
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;");
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;");
1926
2274
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
1927
2275
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
1928
2276
  const decision = snapshot.decision;
@@ -1946,30 +2294,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
1946
2294
  ] : [];
1947
2295
  return {
1948
2296
  decision,
1949
- description: options.description ?? DEFAULT_DESCRIPTION5,
2297
+ description: options.description ?? DEFAULT_DESCRIPTION6,
1950
2298
  error: snapshot.error,
1951
2299
  isLoading: snapshot.isLoading,
1952
2300
  label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
1953
2301
  rows,
1954
2302
  status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
1955
- title: options.title ?? DEFAULT_TITLE5,
2303
+ title: options.title ?? DEFAULT_TITLE6,
1956
2304
  updatedAt: snapshot.updatedAt
1957
2305
  };
1958
2306
  };
1959
2307
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
1960
2308
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
1961
2309
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
1962
- <span>${escapeHtml6(row.label)}</span>
1963
- <strong>${escapeHtml6(row.value)}</strong>
2310
+ <span>${escapeHtml7(row.label)}</span>
2311
+ <strong>${escapeHtml7(row.value)}</strong>
1964
2312
  </div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
1965
- 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)}">
1966
2314
  <header class="absolute-voice-routing-status__header">
1967
- <span class="absolute-voice-routing-status__eyebrow">${escapeHtml6(model.title)}</span>
1968
- <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>
1969
2317
  </header>
1970
- <p class="absolute-voice-routing-status__description">${escapeHtml6(model.description)}</p>
2318
+ <p class="absolute-voice-routing-status__description">${escapeHtml7(model.description)}</p>
1971
2319
  ${rows}
1972
- ${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>` : ""}
1973
2321
  </section>`;
1974
2322
  };
1975
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}`;
@@ -2100,9 +2448,9 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
2100
2448
  };
2101
2449
 
2102
2450
  // src/client/traceTimelineWidget.ts
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;");
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;");
2106
2454
  var formatMs = (value) => typeof value === "number" ? `${value}ms` : "n/a";
2107
2455
  var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
2108
2456
  var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
@@ -2116,34 +2464,34 @@ var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
2116
2464
  const failed = sessions.filter((session) => session.status === "failed").length;
2117
2465
  const warnings = sessions.filter((session) => session.status === "warning").length;
2118
2466
  return {
2119
- description: options.description ?? DEFAULT_DESCRIPTION6,
2467
+ description: options.description ?? DEFAULT_DESCRIPTION7,
2120
2468
  error: snapshot.error,
2121
2469
  isLoading: snapshot.isLoading,
2122
2470
  label: snapshot.error ? "Unavailable" : failed > 0 ? `${failed} failed` : warnings > 0 ? `${warnings} warning` : sessions.length ? `${sessions.length} recent` : snapshot.isLoading ? "Checking" : "No traces yet",
2123
2471
  sessions,
2124
2472
  status: snapshot.error ? "error" : failed > 0 ? "failed" : warnings > 0 ? "warning" : sessions.length ? "ready" : snapshot.isLoading ? "loading" : "empty",
2125
- title: options.title ?? DEFAULT_TITLE6,
2473
+ title: options.title ?? DEFAULT_TITLE7,
2126
2474
  updatedAt: snapshot.updatedAt
2127
2475
  };
2128
2476
  };
2129
2477
  var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
2130
2478
  const model = createVoiceTraceTimelineViewModel(snapshot, options);
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)}">
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)}">
2132
2480
  <header>
2133
- <strong>${escapeHtml7(session.sessionId)}</strong>
2134
- <span>${escapeHtml7(session.status)}</span>
2481
+ <strong>${escapeHtml8(session.sessionId)}</strong>
2482
+ <span>${escapeHtml8(session.status)}</span>
2135
2483
  </header>
2136
- <p>${escapeHtml7(session.label)} \xB7 ${escapeHtml7(session.durationLabel)} \xB7 ${escapeHtml7(session.providerLabel)}</p>
2137
- <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>
2138
2486
  </article>`).join("")}</div>` : '<p class="absolute-voice-trace-timeline__empty">Run a voice session to see call timelines.</p>';
2139
- 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)}">
2140
2488
  <header class="absolute-voice-trace-timeline__header">
2141
- <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml7(model.title)}</span>
2142
- <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>
2143
2491
  </header>
2144
- <p class="absolute-voice-trace-timeline__description">${escapeHtml7(model.description)}</p>
2492
+ <p class="absolute-voice-trace-timeline__description">${escapeHtml8(model.description)}</p>
2145
2493
  ${sessions}
2146
- ${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>` : ""}
2147
2495
  </section>`;
2148
2496
  };
2149
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}`;
@@ -2300,10 +2648,10 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
2300
2648
  };
2301
2649
 
2302
2650
  // src/client/turnLatencyWidget.ts
2303
- var DEFAULT_TITLE7 = "Turn Latency";
2304
- 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.";
2305
2653
  var DEFAULT_PROOF_LABEL = "Run latency proof";
2306
- 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;");
2307
2655
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
2308
2656
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2309
2657
  const turns = (snapshot.report?.turns ?? []).map((turn) => ({
@@ -2317,39 +2665,39 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2317
2665
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2318
2666
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2319
2667
  return {
2320
- description: options.description ?? DEFAULT_DESCRIPTION7,
2668
+ description: options.description ?? DEFAULT_DESCRIPTION8,
2321
2669
  error: snapshot.error,
2322
2670
  isLoading: snapshot.isLoading,
2323
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",
2324
2672
  proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
2325
2673
  showProofAction: Boolean(options.proofPath),
2326
2674
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2327
- title: options.title ?? DEFAULT_TITLE7,
2675
+ title: options.title ?? DEFAULT_TITLE8,
2328
2676
  turns,
2329
2677
  updatedAt: snapshot.updatedAt
2330
2678
  };
2331
2679
  };
2332
2680
  var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
2333
2681
  const model = createVoiceTurnLatencyViewModel(snapshot, options);
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)}">
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)}">
2335
2683
  <header>
2336
- <strong>${escapeHtml8(turn.label)}</strong>
2337
- <span>${escapeHtml8(turn.status)}</span>
2684
+ <strong>${escapeHtml9(turn.label)}</strong>
2685
+ <span>${escapeHtml9(turn.status)}</span>
2338
2686
  </header>
2339
2687
  <dl>${turn.rows.map((row) => `<div>
2340
- <dt>${escapeHtml8(row.label)}</dt>
2341
- <dd>${escapeHtml8(row.value)}</dd>
2688
+ <dt>${escapeHtml9(row.label)}</dt>
2689
+ <dd>${escapeHtml9(row.value)}</dd>
2342
2690
  </div>`).join("")}</dl>
2343
2691
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
2344
- 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)}">
2345
2693
  <header class="absolute-voice-turn-latency__header">
2346
- <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml8(model.title)}</span>
2347
- <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>
2348
2696
  </header>
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>` : ""}
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>` : ""}
2351
2699
  ${turns}
2352
- ${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>` : ""}
2353
2701
  </section>`;
2354
2702
  };
2355
2703
  var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
@@ -2488,9 +2836,9 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
2488
2836
  };
2489
2837
 
2490
2838
  // src/client/turnQualityWidget.ts
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;");
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;");
2494
2842
  var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
2495
2843
  var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
2496
2844
  var getTurnDetail = (turn) => {
@@ -2528,37 +2876,37 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
2528
2876
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2529
2877
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2530
2878
  return {
2531
- description: options.description ?? DEFAULT_DESCRIPTION8,
2879
+ description: options.description ?? DEFAULT_DESCRIPTION9,
2532
2880
  error: snapshot.error,
2533
2881
  isLoading: snapshot.isLoading,
2534
2882
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
2535
2883
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2536
- title: options.title ?? DEFAULT_TITLE8,
2884
+ title: options.title ?? DEFAULT_TITLE9,
2537
2885
  turns,
2538
2886
  updatedAt: snapshot.updatedAt
2539
2887
  };
2540
2888
  };
2541
2889
  var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
2542
2890
  const model = createVoiceTurnQualityViewModel(snapshot, options);
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)}">
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)}">
2544
2892
  <header>
2545
- <strong>${escapeHtml9(turn.label)}</strong>
2546
- <span>${escapeHtml9(turn.status)}</span>
2893
+ <strong>${escapeHtml10(turn.label)}</strong>
2894
+ <span>${escapeHtml10(turn.status)}</span>
2547
2895
  </header>
2548
- <p>${escapeHtml9(turn.detail)}</p>
2896
+ <p>${escapeHtml10(turn.detail)}</p>
2549
2897
  <dl>${turn.rows.map((row) => `<div>
2550
- <dt>${escapeHtml9(row.label)}</dt>
2551
- <dd>${escapeHtml9(row.value)}</dd>
2898
+ <dt>${escapeHtml10(row.label)}</dt>
2899
+ <dd>${escapeHtml10(row.value)}</dd>
2552
2900
  </div>`).join("")}</dl>
2553
2901
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
2554
- 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)}">
2555
2903
  <header class="absolute-voice-turn-quality__header">
2556
- <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml9(model.title)}</span>
2557
- <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>
2558
2906
  </header>
2559
- <p class="absolute-voice-turn-quality__description">${escapeHtml9(model.description)}</p>
2907
+ <p class="absolute-voice-turn-quality__description">${escapeHtml10(model.description)}</p>
2560
2908
  ${turns}
2561
- ${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>` : ""}
2562
2910
  </section>`;
2563
2911
  };
2564
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}`;
@@ -3340,6 +3688,7 @@ export {
3340
3688
  createVoiceProviderSimulationControls,
3341
3689
  createVoiceProviderCapabilities,
3342
3690
  createVoiceOpsStatus,
3691
+ createVoiceOpsActionCenter,
3343
3692
  createVoiceDeliveryRuntime,
3344
3693
  createVoiceController,
3345
3694
  createVoiceCampaignDialerProof