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

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,285 @@ 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 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
+ };
199
+ var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", options = {}) => {
200
+ const fetchImpl = options.fetch ?? globalThis.fetch;
201
+ const response = await fetchImpl(path);
202
+ if (!response.ok) {
203
+ throw new Error(`Voice delivery runtime failed: HTTP ${response.status}`);
204
+ }
205
+ return await response.json();
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
+ };
223
+ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", options = {}) => {
224
+ const listeners = new Set;
225
+ let closed = false;
226
+ let timer;
227
+ let snapshot = {
228
+ actionError: null,
229
+ actionStatus: "idle",
230
+ error: null,
231
+ isLoading: false
232
+ };
233
+ const emit = () => {
234
+ for (const listener of listeners) {
235
+ listener();
236
+ }
237
+ };
238
+ const refresh = async () => {
239
+ if (closed) {
240
+ return snapshot.report;
241
+ }
242
+ snapshot = {
243
+ ...snapshot,
244
+ error: null,
245
+ isLoading: true
246
+ };
247
+ emit();
248
+ try {
249
+ const report = await fetchVoiceDeliveryRuntime(path, options);
250
+ snapshot = {
251
+ ...snapshot,
252
+ error: null,
253
+ isLoading: false,
254
+ report,
255
+ updatedAt: Date.now()
256
+ };
257
+ emit();
258
+ return report;
259
+ } catch (error) {
260
+ snapshot = {
261
+ ...snapshot,
262
+ error: error instanceof Error ? error.message : String(error),
263
+ isLoading: false
264
+ };
265
+ emit();
266
+ throw error;
267
+ }
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
+ };
300
+ const close = () => {
301
+ closed = true;
302
+ if (timer) {
303
+ clearInterval(timer);
304
+ timer = undefined;
305
+ }
306
+ listeners.clear();
307
+ };
308
+ if (typeof window !== "undefined" && options.intervalMs && options.intervalMs > 0) {
309
+ timer = setInterval(() => {
310
+ refresh().catch(() => {});
311
+ }, options.intervalMs);
312
+ }
313
+ return {
314
+ close,
315
+ getServerSnapshot: () => snapshot,
316
+ getSnapshot: () => snapshot,
317
+ requeueDeadLetters: () => runAction("requeue-dead-letters"),
318
+ refresh,
319
+ tick: () => runAction("tick"),
320
+ subscribe: (listener) => {
321
+ listeners.add(listener);
322
+ return () => {
323
+ listeners.delete(listener);
324
+ };
325
+ }
326
+ };
327
+ };
328
+
329
+ // src/client/deliveryRuntimeWidget.ts
330
+ var DEFAULT_TITLE = "Voice Delivery Runtime";
331
+ var DEFAULT_DESCRIPTION = "Audit and trace delivery worker health from your AbsoluteJS voice app.";
332
+ var escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
333
+ var createSurface = (id, summary) => {
334
+ if (!summary) {
335
+ return {
336
+ deadLettered: 0,
337
+ detail: "Worker disabled",
338
+ failed: 0,
339
+ id,
340
+ label: id === "audit" ? "Audit delivery" : "Trace delivery",
341
+ pending: 0,
342
+ status: "disabled",
343
+ total: 0
344
+ };
345
+ }
346
+ const blocked = summary.failed + summary.deadLettered;
347
+ return {
348
+ deadLettered: summary.deadLettered,
349
+ detail: `${summary.delivered}/${summary.total} delivered, ${summary.pending} pending`,
350
+ failed: summary.failed,
351
+ id,
352
+ label: id === "audit" ? "Audit delivery" : "Trace delivery",
353
+ pending: summary.pending,
354
+ status: blocked > 0 ? "warn" : "pass",
355
+ total: summary.total
356
+ };
357
+ };
358
+ var createVoiceDeliveryRuntimeViewModel = (snapshot, options = {}) => {
359
+ const report = snapshot.report;
360
+ const surfaces = [
361
+ createSurface("audit", report?.summary.audit),
362
+ createSurface("trace", report?.summary.trace)
363
+ ];
364
+ const hasWarnings = surfaces.some((surface) => surface.status === "warn");
365
+ return {
366
+ description: options.description ?? DEFAULT_DESCRIPTION,
367
+ error: snapshot.error,
368
+ actionError: snapshot.actionError,
369
+ actionStatus: snapshot.actionStatus,
370
+ isLoading: snapshot.isLoading,
371
+ isRunning: Boolean(report?.isRunning),
372
+ label: snapshot.error ? "Unavailable" : report ? report.isRunning ? "Running" : "Stopped" : "Checking",
373
+ status: snapshot.error ? "error" : report ? hasWarnings ? "warn" : "pass" : "loading",
374
+ surfaces,
375
+ title: options.title ?? DEFAULT_TITLE,
376
+ updatedAt: snapshot.updatedAt
377
+ };
378
+ };
379
+ var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
380
+ const model = createVoiceDeliveryRuntimeViewModel(snapshot, options);
381
+ const surfaces = model.surfaces.map((surface) => `<li class="absolute-voice-delivery-runtime__surface absolute-voice-delivery-runtime__surface--${escapeHtml(surface.status)}">
382
+ <span>${escapeHtml(surface.label)}</span>
383
+ <strong>${escapeHtml(surface.detail)}</strong>
384
+ <small>${String(surface.failed)} failed &middot; ${String(surface.deadLettered)} dead-lettered</small>
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>` : "";
391
+ return `<section class="absolute-voice-delivery-runtime absolute-voice-delivery-runtime--${escapeHtml(model.status)}">
392
+ <header class="absolute-voice-delivery-runtime__header">
393
+ <span class="absolute-voice-delivery-runtime__eyebrow">${escapeHtml(model.title)}</span>
394
+ <strong class="absolute-voice-delivery-runtime__label">${escapeHtml(model.label)}</strong>
395
+ </header>
396
+ <p class="absolute-voice-delivery-runtime__description">${escapeHtml(model.description)}</p>
397
+ <ul class="absolute-voice-delivery-runtime__surfaces">${surfaces}</ul>
398
+ ${actions}
399
+ ${actionError}
400
+ ${model.error ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml(model.error)}</p>` : ""}
401
+ </section>`;
402
+ };
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}`;
404
+ var mountVoiceDeliveryRuntime = (element, path = "/api/voice-delivery-runtime", options = {}) => {
405
+ const store = createVoiceDeliveryRuntimeStore(path, options);
406
+ const render = () => {
407
+ element.innerHTML = renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options);
408
+ };
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);
425
+ render();
426
+ store.refresh().catch(() => {});
427
+ return {
428
+ close: () => {
429
+ element.removeEventListener?.("click", handleClick);
430
+ unsubscribe();
431
+ store.close();
432
+ },
433
+ refresh: store.refresh
434
+ };
435
+ };
436
+ var defineVoiceDeliveryRuntimeElement = (tagName = "absolute-voice-delivery-runtime") => {
437
+ if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
438
+ return;
439
+ }
440
+ customElements.define(tagName, class AbsoluteVoiceDeliveryRuntimeElement extends HTMLElement {
441
+ mounted;
442
+ connectedCallback() {
443
+ const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
444
+ this.mounted = mountVoiceDeliveryRuntime(this, this.getAttribute("path") ?? "/api/voice-delivery-runtime", {
445
+ description: this.getAttribute("description") ?? undefined,
446
+ intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
447
+ title: this.getAttribute("title") ?? undefined
448
+ });
449
+ }
450
+ disconnectedCallback() {
451
+ this.mounted?.close();
452
+ this.mounted = undefined;
453
+ }
454
+ });
455
+ };
456
+
457
+ // src/svelte/createVoiceDeliveryRuntime.ts
458
+ var createVoiceDeliveryRuntime = (path = "/api/voice-delivery-runtime", options = {}) => {
459
+ const store = createVoiceDeliveryRuntimeStore(path, options);
460
+ return {
461
+ close: store.close,
462
+ getHTML: () => renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options),
463
+ getSnapshot: store.getSnapshot,
464
+ getViewModel: () => createVoiceDeliveryRuntimeViewModel(store.getSnapshot(), options),
465
+ requeueDeadLetters: store.requeueDeadLetters,
466
+ refresh: store.refresh,
467
+ subscribe: store.subscribe,
468
+ tick: store.tick
469
+ };
470
+ };
192
471
  // src/client/opsStatus.ts
193
472
  var fetchVoiceOpsStatus = async (path = "/api/voice/ops-status", options = {}) => {
194
473
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -269,8 +548,8 @@ var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) =
269
548
  };
270
549
 
271
550
  // 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.";
551
+ var DEFAULT_TITLE2 = "Voice Ops Status";
552
+ var DEFAULT_DESCRIPTION2 = "Certified workflow, provider, and handoff readiness from your AbsoluteJS voice app.";
274
553
  var SURFACE_LABELS = {
275
554
  handoffs: "Handoffs",
276
555
  providers: "Providers",
@@ -278,7 +557,7 @@ var SURFACE_LABELS = {
278
557
  sessions: "Sessions",
279
558
  workflows: "Workflows"
280
559
  };
281
- var escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
560
+ var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
282
561
  var readNumber = (value, key) => value && typeof value === "object" && (key in value) ? Number(value[key] ?? 0) : 0;
283
562
  var surfaceDetail = (surface) => {
284
563
  const total = readNumber(surface, "total");
@@ -318,7 +597,7 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
318
597
  };
319
598
  });
320
599
  return {
321
- description: options.description ?? DEFAULT_DESCRIPTION,
600
+ description: options.description ?? DEFAULT_DESCRIPTION2,
322
601
  error: snapshot.error,
323
602
  isLoading: snapshot.isLoading,
324
603
  label: getVoiceOpsStatusLabel(report, snapshot.error),
@@ -326,31 +605,31 @@ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
326
605
  passed: report?.passed ?? 0,
327
606
  status: snapshot.error ? "error" : report ? report.status : snapshot.isLoading ? "loading" : "loading",
328
607
  surfaces,
329
- title: options.title ?? DEFAULT_TITLE,
608
+ title: options.title ?? DEFAULT_TITLE2,
330
609
  total: report?.total ?? 0,
331
610
  updatedAt: snapshot.updatedAt
332
611
  };
333
612
  };
334
613
  var renderVoiceOpsStatusHTML = (snapshot, options = {}) => {
335
614
  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>
615
+ const surfaces = model.surfaces.length ? model.surfaces.map((surface) => `<li class="absolute-voice-ops-status__surface absolute-voice-ops-status__surface--${escapeHtml2(surface.status)}">
616
+ <span>${escapeHtml2(surface.label)}</span>
617
+ <strong>${escapeHtml2(surface.detail)}</strong>
339
618
  </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)}">
619
+ const links = model.links.length ? `<nav class="absolute-voice-ops-status__links">${model.links.slice(0, 4).map((link) => `<a href="${escapeHtml2(link.href)}">${escapeHtml2(link.label)}</a>`).join("")}</nav>` : "";
620
+ return `<section class="absolute-voice-ops-status absolute-voice-ops-status--${escapeHtml2(model.status)}">
342
621
  <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>
622
+ <span class="absolute-voice-ops-status__eyebrow">${escapeHtml2(model.title)}</span>
623
+ <strong class="absolute-voice-ops-status__label">${escapeHtml2(model.label)}</strong>
345
624
  </header>
346
- <p class="absolute-voice-ops-status__description">${escapeHtml(model.description)}</p>
625
+ <p class="absolute-voice-ops-status__description">${escapeHtml2(model.description)}</p>
347
626
  <div class="absolute-voice-ops-status__summary">
348
627
  <span>${model.passed} passing</span>
349
628
  <span>${Math.max(model.total - model.passed, 0)} failing</span>
350
629
  <span>${model.total} checks</span>
351
630
  </div>
352
631
  <ul class="absolute-voice-ops-status__surfaces">${surfaces}</ul>
353
- ${model.error ? `<p class="absolute-voice-ops-status__error">${escapeHtml(model.error)}</p>` : ""}
632
+ ${model.error ? `<p class="absolute-voice-ops-status__error">${escapeHtml2(model.error)}</p>` : ""}
354
633
  ${links}
355
634
  </section>`;
356
635
  };
@@ -485,7 +764,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
485
764
  };
486
765
 
487
766
  // src/client/providerSimulationControlsWidget.ts
488
- var escapeHtml2 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
767
+ var escapeHtml3 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
489
768
  var formatKind = (kind) => (kind ?? "stt").toUpperCase();
490
769
  var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
491
770
  const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
@@ -505,18 +784,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
505
784
  };
506
785
  var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
507
786
  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("");
787
+ const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml3(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml3(provider.provider)} ${escapeHtml3(formatKind(options.kind))} failure</button>`).join("");
788
+ const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml3(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml3(provider.provider)} recovered</button>`).join("");
510
789
  return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
511
790
  <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>
791
+ <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml3(model.title)}</span>
792
+ <strong class="absolute-voice-provider-simulation__label">${escapeHtml3(model.label)}</strong>
514
793
  </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>`}
794
+ <p class="absolute-voice-provider-simulation__description">${escapeHtml3(model.description)}</p>
795
+ ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml3(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
517
796
  <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>` : ""}
797
+ ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml3(snapshot.error)}</p>` : ""}
798
+ ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml3(model.resultText)}</pre>` : ""}
520
799
  </section>`;
521
800
  };
522
801
  var bindVoiceProviderSimulationControls = (element, store) => {
@@ -671,9 +950,9 @@ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities",
671
950
  };
672
951
 
673
952
  // 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;");
953
+ var DEFAULT_TITLE3 = "Provider Capabilities";
954
+ var DEFAULT_DESCRIPTION3 = "Configured, selected, and healthy voice providers for this deployment.";
955
+ var escapeHtml4 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
677
956
  var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
678
957
  var formatKind2 = (kind) => kind.toUpperCase();
679
958
  var formatStatus = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
@@ -717,36 +996,36 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
717
996
  const selectedCount = snapshot.report?.selected ?? capabilities.filter((capability) => capability.selected).length;
718
997
  return {
719
998
  capabilities,
720
- description: options.description ?? DEFAULT_DESCRIPTION2,
999
+ description: options.description ?? DEFAULT_DESCRIPTION3,
721
1000
  error: snapshot.error,
722
1001
  isLoading: snapshot.isLoading,
723
1002
  label: snapshot.error ? "Unavailable" : capabilities.length ? warningCount > 0 ? `${warningCount} needs attention` : `${selectedCount} selected` : snapshot.isLoading ? "Checking" : "No capabilities",
724
1003
  status: snapshot.error ? "error" : capabilities.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
725
- title: options.title ?? DEFAULT_TITLE2,
1004
+ title: options.title ?? DEFAULT_TITLE3,
726
1005
  updatedAt: snapshot.updatedAt
727
1006
  };
728
1007
  };
729
1008
  var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
730
1009
  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)}">
1010
+ const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml4(capability.status)}">
732
1011
  <header>
733
- <strong>${escapeHtml3(capability.label)}</strong>
734
- <span>${escapeHtml3(formatStatus(capability.status))}</span>
1012
+ <strong>${escapeHtml4(capability.label)}</strong>
1013
+ <span>${escapeHtml4(formatStatus(capability.status))}</span>
735
1014
  </header>
736
- <p>${escapeHtml3(capability.detail)}</p>
1015
+ <p>${escapeHtml4(capability.detail)}</p>
737
1016
  <dl>${capability.rows.map((row) => `<div>
738
- <dt>${escapeHtml3(row.label)}</dt>
739
- <dd>${escapeHtml3(row.value)}</dd>
1017
+ <dt>${escapeHtml4(row.label)}</dt>
1018
+ <dd>${escapeHtml4(row.value)}</dd>
740
1019
  </div>`).join("")}</dl>
741
1020
  </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)}">
1021
+ return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml4(model.status)}">
743
1022
  <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>
1023
+ <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml4(model.title)}</span>
1024
+ <strong class="absolute-voice-provider-capabilities__label">${escapeHtml4(model.label)}</strong>
746
1025
  </header>
747
- <p class="absolute-voice-provider-capabilities__description">${escapeHtml3(model.description)}</p>
1026
+ <p class="absolute-voice-provider-capabilities__description">${escapeHtml4(model.description)}</p>
748
1027
  ${capabilities}
749
- ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml3(model.error)}</p>` : ""}
1028
+ ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml4(model.error)}</p>` : ""}
750
1029
  </section>`;
751
1030
  };
752
1031
  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 +1798,9 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
1519
1798
  };
1520
1799
 
1521
1800
  // 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;");
1801
+ var DEFAULT_TITLE4 = "Voice Providers";
1802
+ var DEFAULT_DESCRIPTION4 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
1803
+ var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1525
1804
  var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
1526
1805
  var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
1527
1806
  var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
@@ -1565,37 +1844,37 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
1565
1844
  const warningCount = providers.filter((provider) => isWarningStatus2(provider.status)).length;
1566
1845
  const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
1567
1846
  return {
1568
- description: options.description ?? DEFAULT_DESCRIPTION3,
1847
+ description: options.description ?? DEFAULT_DESCRIPTION4,
1569
1848
  error: snapshot.error,
1570
1849
  isLoading: snapshot.isLoading,
1571
1850
  label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
1572
1851
  providers,
1573
1852
  status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1574
- title: options.title ?? DEFAULT_TITLE3,
1853
+ title: options.title ?? DEFAULT_TITLE4,
1575
1854
  updatedAt: snapshot.updatedAt
1576
1855
  };
1577
1856
  };
1578
1857
  var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
1579
1858
  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)}">
1859
+ const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml5(provider.status)}">
1581
1860
  <header>
1582
- <strong>${escapeHtml4(provider.label)}</strong>
1583
- <span>${escapeHtml4(formatStatus2(provider.status))}</span>
1861
+ <strong>${escapeHtml5(provider.label)}</strong>
1862
+ <span>${escapeHtml5(formatStatus2(provider.status))}</span>
1584
1863
  </header>
1585
- <p>${escapeHtml4(provider.detail)}</p>
1864
+ <p>${escapeHtml5(provider.detail)}</p>
1586
1865
  <dl>${provider.rows.map((row) => `<div>
1587
- <dt>${escapeHtml4(row.label)}</dt>
1588
- <dd>${escapeHtml4(row.value)}</dd>
1866
+ <dt>${escapeHtml5(row.label)}</dt>
1867
+ <dd>${escapeHtml5(row.value)}</dd>
1589
1868
  </div>`).join("")}</dl>
1590
1869
  </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)}">
1870
+ return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml5(model.status)}">
1592
1871
  <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>
1872
+ <span class="absolute-voice-provider-status__eyebrow">${escapeHtml5(model.title)}</span>
1873
+ <strong class="absolute-voice-provider-status__label">${escapeHtml5(model.label)}</strong>
1595
1874
  </header>
1596
- <p class="absolute-voice-provider-status__description">${escapeHtml4(model.description)}</p>
1875
+ <p class="absolute-voice-provider-status__description">${escapeHtml5(model.description)}</p>
1597
1876
  ${providers}
1598
- ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml4(model.error)}</p>` : ""}
1877
+ ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml5(model.error)}</p>` : ""}
1599
1878
  </section>`;
1600
1879
  };
1601
1880
  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 +2005,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
1726
2005
  };
1727
2006
 
1728
2007
  // 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;");
2008
+ var DEFAULT_TITLE5 = "Voice Routing";
2009
+ var DEFAULT_DESCRIPTION5 = "Latest provider routing decision from the self-hosted trace store.";
2010
+ var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1732
2011
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
1733
2012
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
1734
2013
  const decision = snapshot.decision;
@@ -1752,30 +2031,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
1752
2031
  ] : [];
1753
2032
  return {
1754
2033
  decision,
1755
- description: options.description ?? DEFAULT_DESCRIPTION4,
2034
+ description: options.description ?? DEFAULT_DESCRIPTION5,
1756
2035
  error: snapshot.error,
1757
2036
  isLoading: snapshot.isLoading,
1758
2037
  label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
1759
2038
  rows,
1760
2039
  status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
1761
- title: options.title ?? DEFAULT_TITLE4,
2040
+ title: options.title ?? DEFAULT_TITLE5,
1762
2041
  updatedAt: snapshot.updatedAt
1763
2042
  };
1764
2043
  };
1765
2044
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
1766
2045
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
1767
2046
  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>
2047
+ <span>${escapeHtml6(row.label)}</span>
2048
+ <strong>${escapeHtml6(row.value)}</strong>
1770
2049
  </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)}">
2050
+ return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml6(model.status)}">
1772
2051
  <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>
2052
+ <span class="absolute-voice-routing-status__eyebrow">${escapeHtml6(model.title)}</span>
2053
+ <strong class="absolute-voice-routing-status__label">${escapeHtml6(model.label)}</strong>
1775
2054
  </header>
1776
- <p class="absolute-voice-routing-status__description">${escapeHtml5(model.description)}</p>
2055
+ <p class="absolute-voice-routing-status__description">${escapeHtml6(model.description)}</p>
1777
2056
  ${rows}
1778
- ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml5(model.error)}</p>` : ""}
2057
+ ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml6(model.error)}</p>` : ""}
1779
2058
  </section>`;
1780
2059
  };
1781
2060
  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 +2185,9 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
1906
2185
  };
1907
2186
 
1908
2187
  // 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;");
2188
+ var DEFAULT_TITLE6 = "Voice Traces";
2189
+ var DEFAULT_DESCRIPTION6 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
2190
+ var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1912
2191
  var formatMs = (value) => typeof value === "number" ? `${value}ms` : "n/a";
1913
2192
  var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
1914
2193
  var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
@@ -1922,34 +2201,34 @@ var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
1922
2201
  const failed = sessions.filter((session) => session.status === "failed").length;
1923
2202
  const warnings = sessions.filter((session) => session.status === "warning").length;
1924
2203
  return {
1925
- description: options.description ?? DEFAULT_DESCRIPTION5,
2204
+ description: options.description ?? DEFAULT_DESCRIPTION6,
1926
2205
  error: snapshot.error,
1927
2206
  isLoading: snapshot.isLoading,
1928
2207
  label: snapshot.error ? "Unavailable" : failed > 0 ? `${failed} failed` : warnings > 0 ? `${warnings} warning` : sessions.length ? `${sessions.length} recent` : snapshot.isLoading ? "Checking" : "No traces yet",
1929
2208
  sessions,
1930
2209
  status: snapshot.error ? "error" : failed > 0 ? "failed" : warnings > 0 ? "warning" : sessions.length ? "ready" : snapshot.isLoading ? "loading" : "empty",
1931
- title: options.title ?? DEFAULT_TITLE5,
2210
+ title: options.title ?? DEFAULT_TITLE6,
1932
2211
  updatedAt: snapshot.updatedAt
1933
2212
  };
1934
2213
  };
1935
2214
  var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
1936
2215
  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)}">
2216
+ const sessions = model.sessions.length ? `<div class="absolute-voice-trace-timeline__sessions">${model.sessions.map((session) => `<article class="absolute-voice-trace-timeline__session absolute-voice-trace-timeline__session--${escapeHtml7(session.status)}">
1938
2217
  <header>
1939
- <strong>${escapeHtml6(session.sessionId)}</strong>
1940
- <span>${escapeHtml6(session.status)}</span>
2218
+ <strong>${escapeHtml7(session.sessionId)}</strong>
2219
+ <span>${escapeHtml7(session.status)}</span>
1941
2220
  </header>
1942
- <p>${escapeHtml6(session.label)} \xB7 ${escapeHtml6(session.durationLabel)} \xB7 ${escapeHtml6(session.providerLabel)}</p>
1943
- <a href="${escapeHtml6(session.detailHref)}">Open timeline</a>
2221
+ <p>${escapeHtml7(session.label)} \xB7 ${escapeHtml7(session.durationLabel)} \xB7 ${escapeHtml7(session.providerLabel)}</p>
2222
+ <a href="${escapeHtml7(session.detailHref)}">Open timeline</a>
1944
2223
  </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)}">
2224
+ return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml7(model.status)}">
1946
2225
  <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>
2226
+ <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml7(model.title)}</span>
2227
+ <strong class="absolute-voice-trace-timeline__label">${escapeHtml7(model.label)}</strong>
1949
2228
  </header>
1950
- <p class="absolute-voice-trace-timeline__description">${escapeHtml6(model.description)}</p>
2229
+ <p class="absolute-voice-trace-timeline__description">${escapeHtml7(model.description)}</p>
1951
2230
  ${sessions}
1952
- ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml6(model.error)}</p>` : ""}
2231
+ ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml7(model.error)}</p>` : ""}
1953
2232
  </section>`;
1954
2233
  };
1955
2234
  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 +2385,10 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
2106
2385
  };
2107
2386
 
2108
2387
  // 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.";
2388
+ var DEFAULT_TITLE7 = "Turn Latency";
2389
+ var DEFAULT_DESCRIPTION7 = "Per-turn timing from first transcript to commit and assistant response start.";
2111
2390
  var DEFAULT_PROOF_LABEL = "Run latency proof";
2112
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2391
+ var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2113
2392
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
2114
2393
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2115
2394
  const turns = (snapshot.report?.turns ?? []).map((turn) => ({
@@ -2123,39 +2402,39 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2123
2402
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2124
2403
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2125
2404
  return {
2126
- description: options.description ?? DEFAULT_DESCRIPTION6,
2405
+ description: options.description ?? DEFAULT_DESCRIPTION7,
2127
2406
  error: snapshot.error,
2128
2407
  isLoading: snapshot.isLoading,
2129
2408
  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
2409
  proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
2131
2410
  showProofAction: Boolean(options.proofPath),
2132
2411
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2133
- title: options.title ?? DEFAULT_TITLE6,
2412
+ title: options.title ?? DEFAULT_TITLE7,
2134
2413
  turns,
2135
2414
  updatedAt: snapshot.updatedAt
2136
2415
  };
2137
2416
  };
2138
2417
  var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
2139
2418
  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)}">
2419
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml8(turn.status)}">
2141
2420
  <header>
2142
- <strong>${escapeHtml7(turn.label)}</strong>
2143
- <span>${escapeHtml7(turn.status)}</span>
2421
+ <strong>${escapeHtml8(turn.label)}</strong>
2422
+ <span>${escapeHtml8(turn.status)}</span>
2144
2423
  </header>
2145
2424
  <dl>${turn.rows.map((row) => `<div>
2146
- <dt>${escapeHtml7(row.label)}</dt>
2147
- <dd>${escapeHtml7(row.value)}</dd>
2425
+ <dt>${escapeHtml8(row.label)}</dt>
2426
+ <dd>${escapeHtml8(row.value)}</dd>
2148
2427
  </div>`).join("")}</dl>
2149
2428
  </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)}">
2429
+ return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml8(model.status)}">
2151
2430
  <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>
2431
+ <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml8(model.title)}</span>
2432
+ <strong class="absolute-voice-turn-latency__label">${escapeHtml8(model.label)}</strong>
2154
2433
  </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>` : ""}
2434
+ <p class="absolute-voice-turn-latency__description">${escapeHtml8(model.description)}</p>
2435
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml8(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
2157
2436
  ${turns}
2158
- ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml7(model.error)}</p>` : ""}
2437
+ ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml8(model.error)}</p>` : ""}
2159
2438
  </section>`;
2160
2439
  };
2161
2440
  var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
@@ -2294,9 +2573,9 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
2294
2573
  };
2295
2574
 
2296
2575
  // 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;");
2576
+ var DEFAULT_TITLE8 = "Turn Quality";
2577
+ var DEFAULT_DESCRIPTION8 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2578
+ var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2300
2579
  var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
2301
2580
  var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
2302
2581
  var getTurnDetail = (turn) => {
@@ -2334,37 +2613,37 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
2334
2613
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2335
2614
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2336
2615
  return {
2337
- description: options.description ?? DEFAULT_DESCRIPTION7,
2616
+ description: options.description ?? DEFAULT_DESCRIPTION8,
2338
2617
  error: snapshot.error,
2339
2618
  isLoading: snapshot.isLoading,
2340
2619
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
2341
2620
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2342
- title: options.title ?? DEFAULT_TITLE7,
2621
+ title: options.title ?? DEFAULT_TITLE8,
2343
2622
  turns,
2344
2623
  updatedAt: snapshot.updatedAt
2345
2624
  };
2346
2625
  };
2347
2626
  var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
2348
2627
  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)}">
2628
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml9(turn.status)}">
2350
2629
  <header>
2351
- <strong>${escapeHtml8(turn.label)}</strong>
2352
- <span>${escapeHtml8(turn.status)}</span>
2630
+ <strong>${escapeHtml9(turn.label)}</strong>
2631
+ <span>${escapeHtml9(turn.status)}</span>
2353
2632
  </header>
2354
- <p>${escapeHtml8(turn.detail)}</p>
2633
+ <p>${escapeHtml9(turn.detail)}</p>
2355
2634
  <dl>${turn.rows.map((row) => `<div>
2356
- <dt>${escapeHtml8(row.label)}</dt>
2357
- <dd>${escapeHtml8(row.value)}</dd>
2635
+ <dt>${escapeHtml9(row.label)}</dt>
2636
+ <dd>${escapeHtml9(row.value)}</dd>
2358
2637
  </div>`).join("")}</dl>
2359
2638
  </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)}">
2639
+ return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml9(model.status)}">
2361
2640
  <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>
2641
+ <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml9(model.title)}</span>
2642
+ <strong class="absolute-voice-turn-quality__label">${escapeHtml9(model.label)}</strong>
2364
2643
  </header>
2365
- <p class="absolute-voice-turn-quality__description">${escapeHtml8(model.description)}</p>
2644
+ <p class="absolute-voice-turn-quality__description">${escapeHtml9(model.description)}</p>
2366
2645
  ${turns}
2367
- ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml8(model.error)}</p>` : ""}
2646
+ ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml9(model.error)}</p>` : ""}
2368
2647
  </section>`;
2369
2648
  };
2370
2649
  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 +3425,7 @@ export {
3146
3425
  createVoiceProviderSimulationControls,
3147
3426
  createVoiceProviderCapabilities,
3148
3427
  createVoiceOpsStatus,
3428
+ createVoiceDeliveryRuntime,
3149
3429
  createVoiceController,
3150
3430
  createVoiceCampaignDialerProof
3151
3431
  };