@absolutejs/voice 0.0.22-beta.167 → 0.0.22-beta.169

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.
@@ -0,0 +1,8 @@
1
+ import { type VoiceProviderContractsClientOptions } from '../client/providerContracts';
2
+ export declare const useVoiceProviderContracts: <TProvider extends string = string>(path?: string, options?: VoiceProviderContractsClientOptions) => {
3
+ refresh: () => Promise<import("..").VoiceProviderContractMatrixReport<TProvider> | undefined>;
4
+ error: string | null;
5
+ isLoading: boolean;
6
+ report?: import("..").VoiceProviderContractMatrixReport<TProvider> | undefined;
7
+ updatedAt?: number;
8
+ };
@@ -0,0 +1,10 @@
1
+ import { type VoiceProviderContractsWidgetOptions } from '../client/providerContractsWidget';
2
+ export declare const createVoiceProviderContracts: <TProvider extends string = string>(path?: string, options?: VoiceProviderContractsWidgetOptions) => {
3
+ getHTML: () => string;
4
+ getViewModel: () => import("../client").VoiceProviderContractsViewModel<TProvider>;
5
+ close: () => void;
6
+ getServerSnapshot: () => import("../client").VoiceProviderContractsSnapshot<TProvider>;
7
+ getSnapshot: () => import("../client").VoiceProviderContractsSnapshot<TProvider>;
8
+ refresh: () => Promise<import("..").VoiceProviderContractMatrixReport<TProvider> | undefined>;
9
+ subscribe: (listener: () => void) => () => void;
10
+ };
@@ -4,6 +4,7 @@ export { createVoiceOpsActionCenter } from './createVoiceOpsActionCenter';
4
4
  export { createVoiceOpsStatus } from './createVoiceOpsStatus';
5
5
  export { createVoiceProviderSimulationControls } from './createVoiceProviderSimulationControls';
6
6
  export { createVoiceProviderCapabilities } from './createVoiceProviderCapabilities';
7
+ export { createVoiceProviderContracts } from './createVoiceProviderContracts';
7
8
  export { createVoiceStream } from './createVoiceStream';
8
9
  export { createVoiceProviderStatus } from './createVoiceProviderStatus';
9
10
  export { createVoiceRoutingStatus } from './createVoiceRoutingStatus';
@@ -1367,6 +1367,197 @@ var createVoiceProviderCapabilities = (path = "/api/provider-capabilities", opti
1367
1367
  getViewModel: () => createVoiceProviderCapabilitiesViewModel(store.getSnapshot(), options)
1368
1368
  };
1369
1369
  };
1370
+ // src/client/providerContracts.ts
1371
+ var fetchVoiceProviderContracts = async (path = "/api/provider-contracts", options = {}) => {
1372
+ const fetchImpl = options.fetch ?? globalThis.fetch;
1373
+ const response = await fetchImpl(path);
1374
+ if (!response.ok) {
1375
+ throw new Error(`Voice provider contracts failed: HTTP ${response.status}`);
1376
+ }
1377
+ return await response.json();
1378
+ };
1379
+ var createVoiceProviderContractsStore = (path = "/api/provider-contracts", options = {}) => {
1380
+ const listeners = new Set;
1381
+ let closed = false;
1382
+ let timer;
1383
+ let snapshot = {
1384
+ error: null,
1385
+ isLoading: false
1386
+ };
1387
+ const emit = () => {
1388
+ for (const listener of listeners) {
1389
+ listener();
1390
+ }
1391
+ };
1392
+ const refresh = async () => {
1393
+ if (closed) {
1394
+ return snapshot.report;
1395
+ }
1396
+ snapshot = { ...snapshot, error: null, isLoading: true };
1397
+ emit();
1398
+ try {
1399
+ const report = await fetchVoiceProviderContracts(path, options);
1400
+ snapshot = {
1401
+ error: null,
1402
+ isLoading: false,
1403
+ report,
1404
+ updatedAt: Date.now()
1405
+ };
1406
+ emit();
1407
+ return report;
1408
+ } catch (error) {
1409
+ snapshot = {
1410
+ ...snapshot,
1411
+ error: error instanceof Error ? error.message : String(error),
1412
+ isLoading: false
1413
+ };
1414
+ emit();
1415
+ throw error;
1416
+ }
1417
+ };
1418
+ const close = () => {
1419
+ closed = true;
1420
+ if (timer) {
1421
+ clearInterval(timer);
1422
+ timer = undefined;
1423
+ }
1424
+ listeners.clear();
1425
+ };
1426
+ if (options.intervalMs && options.intervalMs > 0) {
1427
+ timer = setInterval(() => {
1428
+ refresh().catch(() => {});
1429
+ }, options.intervalMs);
1430
+ }
1431
+ return {
1432
+ close,
1433
+ getServerSnapshot: () => snapshot,
1434
+ getSnapshot: () => snapshot,
1435
+ refresh,
1436
+ subscribe: (listener) => {
1437
+ listeners.add(listener);
1438
+ return () => {
1439
+ listeners.delete(listener);
1440
+ };
1441
+ }
1442
+ };
1443
+ };
1444
+
1445
+ // src/client/providerContractsWidget.ts
1446
+ var DEFAULT_TITLE5 = "Provider Contracts";
1447
+ var DEFAULT_DESCRIPTION5 = "Production contract coverage for provider env, latency, fallback, streaming, and capabilities.";
1448
+ var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1449
+ var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
1450
+ var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
1451
+ var contractDetail = (row) => {
1452
+ const failing = row.checks.filter((check) => check.status !== "pass");
1453
+ if (failing.length === 0) {
1454
+ return "Provider contract is production-ready.";
1455
+ }
1456
+ return failing.map((check) => `${check.label}: ${check.detail ?? check.status}`).join(" ");
1457
+ };
1458
+ var createVoiceProviderContractsViewModel = (snapshot, options = {}) => {
1459
+ const rows = (snapshot.report?.rows ?? []).map((row) => ({
1460
+ ...row,
1461
+ detail: contractDetail(row),
1462
+ label: `${formatProvider2(row.provider)} ${row.kind.toUpperCase()}`,
1463
+ remediations: row.checks.filter((check) => check.status !== "pass" && check.remediation).map((check) => ({
1464
+ detail: check.remediation?.detail ?? "",
1465
+ href: check.remediation?.href,
1466
+ label: check.remediation?.label ?? check.label
1467
+ })),
1468
+ rows: [
1469
+ { label: "Status", value: formatStatus2(row.status) },
1470
+ { label: "Selected", value: row.selected ? "Yes" : "No" },
1471
+ { label: "Configured", value: row.configured ? "Yes" : "No" },
1472
+ {
1473
+ label: "Checks",
1474
+ value: row.checks.map((check) => `${check.label}: ${formatStatus2(check.status)}`).join(", ")
1475
+ }
1476
+ ]
1477
+ }));
1478
+ const warningCount = snapshot.report ? snapshot.report.failed + snapshot.report.warned : rows.filter((row) => row.status !== "pass").length;
1479
+ return {
1480
+ description: options.description ?? DEFAULT_DESCRIPTION5,
1481
+ error: snapshot.error,
1482
+ isLoading: snapshot.isLoading,
1483
+ label: snapshot.error ? "Unavailable" : rows.length ? warningCount > 0 ? `${warningCount} needs attention` : `${rows.length} passing` : snapshot.isLoading ? "Checking" : "No contracts",
1484
+ rows,
1485
+ status: snapshot.error ? "error" : rows.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
1486
+ title: options.title ?? DEFAULT_TITLE5,
1487
+ updatedAt: snapshot.updatedAt
1488
+ };
1489
+ };
1490
+ var renderVoiceProviderContractsHTML = (snapshot, options = {}) => {
1491
+ const model = createVoiceProviderContractsViewModel(snapshot, options);
1492
+ const rows = model.rows.length ? `<div class="absolute-voice-provider-contracts__rows">${model.rows.map((row) => `<article class="absolute-voice-provider-contracts__row absolute-voice-provider-contracts__row--${escapeHtml6(row.status)}">
1493
+ <header>
1494
+ <strong>${escapeHtml6(row.label)}</strong>
1495
+ <span>${escapeHtml6(formatStatus2(row.status))}</span>
1496
+ </header>
1497
+ <p>${escapeHtml6(row.detail)}</p>
1498
+ ${row.remediations.length ? `<ul class="absolute-voice-provider-contracts__remediations">${row.remediations.map((remediation) => `<li>${remediation.href ? `<a href="${escapeHtml6(remediation.href)}">${escapeHtml6(remediation.label)}</a>` : `<strong>${escapeHtml6(remediation.label)}</strong>`}<span>${escapeHtml6(remediation.detail)}</span></li>`).join("")}</ul>` : ""}
1499
+ <dl>${row.rows.map((item) => `<div>
1500
+ <dt>${escapeHtml6(item.label)}</dt>
1501
+ <dd>${escapeHtml6(item.value)}</dd>
1502
+ </div>`).join("")}</dl>
1503
+ </article>`).join("")}</div>` : '<p class="absolute-voice-provider-contracts__empty">Configure provider contracts to see production coverage.</p>';
1504
+ return `<section class="absolute-voice-provider-contracts absolute-voice-provider-contracts--${escapeHtml6(model.status)}">
1505
+ <header class="absolute-voice-provider-contracts__header">
1506
+ <span class="absolute-voice-provider-contracts__eyebrow">${escapeHtml6(model.title)}</span>
1507
+ <strong class="absolute-voice-provider-contracts__label">${escapeHtml6(model.label)}</strong>
1508
+ </header>
1509
+ <p class="absolute-voice-provider-contracts__description">${escapeHtml6(model.description)}</p>
1510
+ ${rows}
1511
+ ${model.error ? `<p class="absolute-voice-provider-contracts__error">${escapeHtml6(model.error)}</p>` : ""}
1512
+ </section>`;
1513
+ };
1514
+ var getVoiceProviderContractsCSS = () => `.absolute-voice-provider-contracts{border:1px solid #b8dcc7;border-radius:20px;background:#f7fff9;color:#09140d;padding:18px;box-shadow:0 18px 40px rgba(21,83,45,.12);font-family:inherit}.absolute-voice-provider-contracts--error,.absolute-voice-provider-contracts--warning{border-color:#f2a7a7;background:#fff7f4}.absolute-voice-provider-contracts__header,.absolute-voice-provider-contracts__row header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-contracts__eyebrow{color:#166534;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-contracts__label{font-size:24px;line-height:1}.absolute-voice-provider-contracts__description,.absolute-voice-provider-contracts__row p,.absolute-voice-provider-contracts__row dt,.absolute-voice-provider-contracts__empty{color:#405448}.absolute-voice-provider-contracts__rows{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-contracts__row{background:#fff;border:1px solid #d6eadb;border-radius:16px;padding:14px}.absolute-voice-provider-contracts__row--pass{border-color:#86efac}.absolute-voice-provider-contracts__row--warn,.absolute-voice-provider-contracts__row--fail{border-color:#f2a7a7}.absolute-voice-provider-contracts__row p{margin:10px 0}.absolute-voice-provider-contracts__remediations{display:grid;gap:8px;list-style:none;margin:0 0 10px;padding:0}.absolute-voice-provider-contracts__remediations li{background:#fff7ed;border:1px solid #fed7aa;border-radius:12px;display:grid;gap:3px;padding:8px}.absolute-voice-provider-contracts__remediations a,.absolute-voice-provider-contracts__remediations strong{color:#9a3412}.absolute-voice-provider-contracts__remediations span{color:#7c2d12}.absolute-voice-provider-contracts__row dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-contracts__row div{background:#f7fff9;border:1px solid #d6eadb;border-radius:12px;padding:8px}.absolute-voice-provider-contracts__row dt{font-size:12px}.absolute-voice-provider-contracts__row dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-contracts__error{color:#9f1239;font-weight:700}`;
1515
+ var mountVoiceProviderContracts = (element, path = "/api/provider-contracts", options = {}) => {
1516
+ const store = createVoiceProviderContractsStore(path, options);
1517
+ const render = () => {
1518
+ element.innerHTML = renderVoiceProviderContractsHTML(store.getSnapshot(), options);
1519
+ };
1520
+ const unsubscribe = store.subscribe(render);
1521
+ render();
1522
+ store.refresh().catch(() => {});
1523
+ return {
1524
+ close: () => {
1525
+ unsubscribe();
1526
+ store.close();
1527
+ },
1528
+ refresh: store.refresh
1529
+ };
1530
+ };
1531
+ var defineVoiceProviderContractsElement = (tagName = "absolute-voice-provider-contracts") => {
1532
+ if (typeof window === "undefined" || typeof customElements === "undefined" || customElements.get(tagName)) {
1533
+ return;
1534
+ }
1535
+ customElements.define(tagName, class AbsoluteVoiceProviderContractsElement extends HTMLElement {
1536
+ mounted;
1537
+ connectedCallback() {
1538
+ const intervalMs = Number(this.getAttribute("interval-ms") ?? 5000);
1539
+ this.mounted = mountVoiceProviderContracts(this, this.getAttribute("path") ?? "/api/provider-contracts", {
1540
+ description: this.getAttribute("description") ?? undefined,
1541
+ intervalMs: Number.isFinite(intervalMs) ? intervalMs : 5000,
1542
+ title: this.getAttribute("title") ?? undefined
1543
+ });
1544
+ }
1545
+ disconnectedCallback() {
1546
+ this.mounted?.close();
1547
+ this.mounted = undefined;
1548
+ }
1549
+ });
1550
+ };
1551
+
1552
+ // src/svelte/createVoiceProviderContracts.ts
1553
+ var createVoiceProviderContracts = (path = "/api/provider-contracts", options = {}) => {
1554
+ const store = createVoiceProviderContractsStore(path, options);
1555
+ return {
1556
+ ...store,
1557
+ getHTML: () => renderVoiceProviderContractsHTML(store.getSnapshot(), options),
1558
+ getViewModel: () => createVoiceProviderContractsViewModel(store.getSnapshot(), options)
1559
+ };
1560
+ };
1370
1561
  // src/client/actions.ts
1371
1562
  var normalizeErrorMessage = (value) => {
1372
1563
  if (typeof value === "string" && value.trim()) {
@@ -2090,11 +2281,11 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
2090
2281
  };
2091
2282
 
2092
2283
  // src/client/providerStatusWidget.ts
2093
- var DEFAULT_TITLE5 = "Voice Providers";
2094
- var DEFAULT_DESCRIPTION5 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
2095
- var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2096
- var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
2097
- var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
2284
+ var DEFAULT_TITLE6 = "Voice Providers";
2285
+ var DEFAULT_DESCRIPTION6 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
2286
+ var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2287
+ var formatProvider3 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
2288
+ var formatStatus3 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
2098
2289
  var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
2099
2290
  var formatSuppression = (value) => typeof value === "number" ? `${Math.ceil(value / 1000)}s` : "None";
2100
2291
  var getProviderDetail = (provider) => {
@@ -2120,7 +2311,7 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
2120
2311
  const providers = snapshot.providers.map((provider) => ({
2121
2312
  ...provider,
2122
2313
  detail: getProviderDetail(provider),
2123
- label: `${formatProvider2(provider.provider)}${provider.recommended ? " recommended" : ""}`,
2314
+ label: `${formatProvider3(provider.provider)}${provider.recommended ? " recommended" : ""}`,
2124
2315
  rows: [
2125
2316
  { label: "Runs", value: String(provider.runCount) },
2126
2317
  { label: "Avg latency", value: formatLatency(provider.averageElapsedMs) },
@@ -2136,37 +2327,37 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
2136
2327
  const warningCount = providers.filter((provider) => isWarningStatus2(provider.status)).length;
2137
2328
  const healthyCount = providers.filter((provider) => provider.status === "healthy").length;
2138
2329
  return {
2139
- description: options.description ?? DEFAULT_DESCRIPTION5,
2330
+ description: options.description ?? DEFAULT_DESCRIPTION6,
2140
2331
  error: snapshot.error,
2141
2332
  isLoading: snapshot.isLoading,
2142
2333
  label: snapshot.error ? "Unavailable" : providers.length ? warningCount > 0 ? `${warningCount} needs attention` : `${healthyCount} healthy` : snapshot.isLoading ? "Checking" : "No provider traffic",
2143
2334
  providers,
2144
2335
  status: snapshot.error ? "error" : providers.length ? warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2145
- title: options.title ?? DEFAULT_TITLE5,
2336
+ title: options.title ?? DEFAULT_TITLE6,
2146
2337
  updatedAt: snapshot.updatedAt
2147
2338
  };
2148
2339
  };
2149
2340
  var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
2150
2341
  const model = createVoiceProviderStatusViewModel(snapshot, options);
2151
- 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)}">
2342
+ 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--${escapeHtml7(provider.status)}">
2152
2343
  <header>
2153
- <strong>${escapeHtml6(provider.label)}</strong>
2154
- <span>${escapeHtml6(formatStatus2(provider.status))}</span>
2344
+ <strong>${escapeHtml7(provider.label)}</strong>
2345
+ <span>${escapeHtml7(formatStatus3(provider.status))}</span>
2155
2346
  </header>
2156
- <p>${escapeHtml6(provider.detail)}</p>
2347
+ <p>${escapeHtml7(provider.detail)}</p>
2157
2348
  <dl>${provider.rows.map((row) => `<div>
2158
- <dt>${escapeHtml6(row.label)}</dt>
2159
- <dd>${escapeHtml6(row.value)}</dd>
2349
+ <dt>${escapeHtml7(row.label)}</dt>
2350
+ <dd>${escapeHtml7(row.value)}</dd>
2160
2351
  </div>`).join("")}</dl>
2161
2352
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
2162
- return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml6(model.status)}">
2353
+ return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml7(model.status)}">
2163
2354
  <header class="absolute-voice-provider-status__header">
2164
- <span class="absolute-voice-provider-status__eyebrow">${escapeHtml6(model.title)}</span>
2165
- <strong class="absolute-voice-provider-status__label">${escapeHtml6(model.label)}</strong>
2355
+ <span class="absolute-voice-provider-status__eyebrow">${escapeHtml7(model.title)}</span>
2356
+ <strong class="absolute-voice-provider-status__label">${escapeHtml7(model.label)}</strong>
2166
2357
  </header>
2167
- <p class="absolute-voice-provider-status__description">${escapeHtml6(model.description)}</p>
2358
+ <p class="absolute-voice-provider-status__description">${escapeHtml7(model.description)}</p>
2168
2359
  ${providers}
2169
- ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml6(model.error)}</p>` : ""}
2360
+ ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml7(model.error)}</p>` : ""}
2170
2361
  </section>`;
2171
2362
  };
2172
2363
  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}`;
@@ -2297,9 +2488,9 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
2297
2488
  };
2298
2489
 
2299
2490
  // src/client/routingStatusWidget.ts
2300
- var DEFAULT_TITLE6 = "Voice Routing";
2301
- var DEFAULT_DESCRIPTION6 = "Latest provider routing decision from the self-hosted trace store.";
2302
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2491
+ var DEFAULT_TITLE7 = "Voice Routing";
2492
+ var DEFAULT_DESCRIPTION7 = "Latest provider routing decision from the self-hosted trace store.";
2493
+ var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2303
2494
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
2304
2495
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
2305
2496
  const decision = snapshot.decision;
@@ -2323,30 +2514,30 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
2323
2514
  ] : [];
2324
2515
  return {
2325
2516
  decision,
2326
- description: options.description ?? DEFAULT_DESCRIPTION6,
2517
+ description: options.description ?? DEFAULT_DESCRIPTION7,
2327
2518
  error: snapshot.error,
2328
2519
  isLoading: snapshot.isLoading,
2329
2520
  label: snapshot.error ? "Unavailable" : decision ? `${formatValue(decision.kind).toUpperCase()} ${formatValue(decision.status, "unknown")}` : snapshot.isLoading ? "Checking" : "No routing yet",
2330
2521
  rows,
2331
2522
  status: snapshot.error ? "error" : decision ? "ready" : snapshot.isLoading ? "loading" : "empty",
2332
- title: options.title ?? DEFAULT_TITLE6,
2523
+ title: options.title ?? DEFAULT_TITLE7,
2333
2524
  updatedAt: snapshot.updatedAt
2334
2525
  };
2335
2526
  };
2336
2527
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
2337
2528
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
2338
2529
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
2339
- <span>${escapeHtml7(row.label)}</span>
2340
- <strong>${escapeHtml7(row.value)}</strong>
2530
+ <span>${escapeHtml8(row.label)}</span>
2531
+ <strong>${escapeHtml8(row.value)}</strong>
2341
2532
  </div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
2342
- return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml7(model.status)}">
2533
+ return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml8(model.status)}">
2343
2534
  <header class="absolute-voice-routing-status__header">
2344
- <span class="absolute-voice-routing-status__eyebrow">${escapeHtml7(model.title)}</span>
2345
- <strong class="absolute-voice-routing-status__label">${escapeHtml7(model.label)}</strong>
2535
+ <span class="absolute-voice-routing-status__eyebrow">${escapeHtml8(model.title)}</span>
2536
+ <strong class="absolute-voice-routing-status__label">${escapeHtml8(model.label)}</strong>
2346
2537
  </header>
2347
- <p class="absolute-voice-routing-status__description">${escapeHtml7(model.description)}</p>
2538
+ <p class="absolute-voice-routing-status__description">${escapeHtml8(model.description)}</p>
2348
2539
  ${rows}
2349
- ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml7(model.error)}</p>` : ""}
2540
+ ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml8(model.error)}</p>` : ""}
2350
2541
  </section>`;
2351
2542
  };
2352
2543
  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}`;
@@ -2477,9 +2668,9 @@ var createVoiceTraceTimelineStore = (path = "/api/voice-traces", options = {}) =
2477
2668
  };
2478
2669
 
2479
2670
  // src/client/traceTimelineWidget.ts
2480
- var DEFAULT_TITLE7 = "Voice Traces";
2481
- var DEFAULT_DESCRIPTION7 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
2482
- var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2671
+ var DEFAULT_TITLE8 = "Voice Traces";
2672
+ var DEFAULT_DESCRIPTION8 = "Latest call timelines with provider latency, fallbacks, handoffs, and errors from your self-hosted trace store.";
2673
+ var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2483
2674
  var formatMs = (value) => typeof value === "number" ? `${value}ms` : "n/a";
2484
2675
  var formatProviders = (session) => session.providers.length ? session.providers.map((provider) => provider.provider).join(", ") : "No providers";
2485
2676
  var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
@@ -2493,34 +2684,34 @@ var createVoiceTraceTimelineViewModel = (snapshot, options = {}) => {
2493
2684
  const failed = sessions.filter((session) => session.status === "failed").length;
2494
2685
  const warnings = sessions.filter((session) => session.status === "warning").length;
2495
2686
  return {
2496
- description: options.description ?? DEFAULT_DESCRIPTION7,
2687
+ description: options.description ?? DEFAULT_DESCRIPTION8,
2497
2688
  error: snapshot.error,
2498
2689
  isLoading: snapshot.isLoading,
2499
2690
  label: snapshot.error ? "Unavailable" : failed > 0 ? `${failed} failed` : warnings > 0 ? `${warnings} warning` : sessions.length ? `${sessions.length} recent` : snapshot.isLoading ? "Checking" : "No traces yet",
2500
2691
  sessions,
2501
2692
  status: snapshot.error ? "error" : failed > 0 ? "failed" : warnings > 0 ? "warning" : sessions.length ? "ready" : snapshot.isLoading ? "loading" : "empty",
2502
- title: options.title ?? DEFAULT_TITLE7,
2693
+ title: options.title ?? DEFAULT_TITLE8,
2503
2694
  updatedAt: snapshot.updatedAt
2504
2695
  };
2505
2696
  };
2506
2697
  var renderVoiceTraceTimelineWidgetHTML = (snapshot, options = {}) => {
2507
2698
  const model = createVoiceTraceTimelineViewModel(snapshot, options);
2508
- 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)}">
2699
+ 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--${escapeHtml9(session.status)}">
2509
2700
  <header>
2510
- <strong>${escapeHtml8(session.sessionId)}</strong>
2511
- <span>${escapeHtml8(session.status)}</span>
2701
+ <strong>${escapeHtml9(session.sessionId)}</strong>
2702
+ <span>${escapeHtml9(session.status)}</span>
2512
2703
  </header>
2513
- <p>${escapeHtml8(session.label)} \xB7 ${escapeHtml8(session.durationLabel)} \xB7 ${escapeHtml8(session.providerLabel)}</p>
2514
- <a href="${escapeHtml8(session.detailHref)}">Open timeline</a>
2704
+ <p>${escapeHtml9(session.label)} \xB7 ${escapeHtml9(session.durationLabel)} \xB7 ${escapeHtml9(session.providerLabel)}</p>
2705
+ <a href="${escapeHtml9(session.detailHref)}">Open timeline</a>
2515
2706
  </article>`).join("")}</div>` : '<p class="absolute-voice-trace-timeline__empty">Run a voice session to see call timelines.</p>';
2516
- return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml8(model.status)}">
2707
+ return `<section class="absolute-voice-trace-timeline absolute-voice-trace-timeline--${escapeHtml9(model.status)}">
2517
2708
  <header class="absolute-voice-trace-timeline__header">
2518
- <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml8(model.title)}</span>
2519
- <strong class="absolute-voice-trace-timeline__label">${escapeHtml8(model.label)}</strong>
2709
+ <span class="absolute-voice-trace-timeline__eyebrow">${escapeHtml9(model.title)}</span>
2710
+ <strong class="absolute-voice-trace-timeline__label">${escapeHtml9(model.label)}</strong>
2520
2711
  </header>
2521
- <p class="absolute-voice-trace-timeline__description">${escapeHtml8(model.description)}</p>
2712
+ <p class="absolute-voice-trace-timeline__description">${escapeHtml9(model.description)}</p>
2522
2713
  ${sessions}
2523
- ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml8(model.error)}</p>` : ""}
2714
+ ${model.error ? `<p class="absolute-voice-trace-timeline__error">${escapeHtml9(model.error)}</p>` : ""}
2524
2715
  </section>`;
2525
2716
  };
2526
2717
  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}`;
@@ -2677,10 +2868,10 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
2677
2868
  };
2678
2869
 
2679
2870
  // src/client/turnLatencyWidget.ts
2680
- var DEFAULT_TITLE8 = "Turn Latency";
2681
- var DEFAULT_DESCRIPTION8 = "Per-turn timing from first transcript to commit and assistant response start.";
2871
+ var DEFAULT_TITLE9 = "Turn Latency";
2872
+ var DEFAULT_DESCRIPTION9 = "Per-turn timing from first transcript to commit and assistant response start.";
2682
2873
  var DEFAULT_PROOF_LABEL = "Run latency proof";
2683
- var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2874
+ var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2684
2875
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
2685
2876
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2686
2877
  const turns = (snapshot.report?.turns ?? []).map((turn) => ({
@@ -2694,39 +2885,39 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
2694
2885
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2695
2886
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2696
2887
  return {
2697
- description: options.description ?? DEFAULT_DESCRIPTION8,
2888
+ description: options.description ?? DEFAULT_DESCRIPTION9,
2698
2889
  error: snapshot.error,
2699
2890
  isLoading: snapshot.isLoading,
2700
2891
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} slow` : warningCount > 0 ? `${warningCount} warnings` : `avg ${formatMs2(snapshot.report?.averageTotalMs)}` : snapshot.isLoading ? "Checking" : "No turns",
2701
2892
  proofLabel: options.proofPath ? options.proofLabel ?? DEFAULT_PROOF_LABEL : undefined,
2702
2893
  showProofAction: Boolean(options.proofPath),
2703
2894
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2704
- title: options.title ?? DEFAULT_TITLE8,
2895
+ title: options.title ?? DEFAULT_TITLE9,
2705
2896
  turns,
2706
2897
  updatedAt: snapshot.updatedAt
2707
2898
  };
2708
2899
  };
2709
2900
  var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
2710
2901
  const model = createVoiceTurnLatencyViewModel(snapshot, options);
2711
- 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)}">
2902
+ 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--${escapeHtml10(turn.status)}">
2712
2903
  <header>
2713
- <strong>${escapeHtml9(turn.label)}</strong>
2714
- <span>${escapeHtml9(turn.status)}</span>
2904
+ <strong>${escapeHtml10(turn.label)}</strong>
2905
+ <span>${escapeHtml10(turn.status)}</span>
2715
2906
  </header>
2716
2907
  <dl>${turn.rows.map((row) => `<div>
2717
- <dt>${escapeHtml9(row.label)}</dt>
2718
- <dd>${escapeHtml9(row.value)}</dd>
2908
+ <dt>${escapeHtml10(row.label)}</dt>
2909
+ <dd>${escapeHtml10(row.value)}</dd>
2719
2910
  </div>`).join("")}</dl>
2720
2911
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
2721
- return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml9(model.status)}">
2912
+ return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml10(model.status)}">
2722
2913
  <header class="absolute-voice-turn-latency__header">
2723
- <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml9(model.title)}</span>
2724
- <strong class="absolute-voice-turn-latency__label">${escapeHtml9(model.label)}</strong>
2914
+ <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml10(model.title)}</span>
2915
+ <strong class="absolute-voice-turn-latency__label">${escapeHtml10(model.label)}</strong>
2725
2916
  </header>
2726
- <p class="absolute-voice-turn-latency__description">${escapeHtml9(model.description)}</p>
2727
- ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml9(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
2917
+ <p class="absolute-voice-turn-latency__description">${escapeHtml10(model.description)}</p>
2918
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml10(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
2728
2919
  ${turns}
2729
- ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml9(model.error)}</p>` : ""}
2920
+ ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml10(model.error)}</p>` : ""}
2730
2921
  </section>`;
2731
2922
  };
2732
2923
  var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
@@ -2865,9 +3056,9 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
2865
3056
  };
2866
3057
 
2867
3058
  // src/client/turnQualityWidget.ts
2868
- var DEFAULT_TITLE9 = "Turn Quality";
2869
- var DEFAULT_DESCRIPTION9 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
2870
- var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3059
+ var DEFAULT_TITLE10 = "Turn Quality";
3060
+ var DEFAULT_DESCRIPTION10 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
3061
+ var escapeHtml11 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2871
3062
  var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
2872
3063
  var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
2873
3064
  var getTurnDetail = (turn) => {
@@ -2905,37 +3096,37 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
2905
3096
  const warningCount = snapshot.report?.warnings ?? turns.filter((turn) => turn.status === "warn").length;
2906
3097
  const failedCount = snapshot.report?.failed ?? turns.filter((turn) => turn.status === "fail").length;
2907
3098
  return {
2908
- description: options.description ?? DEFAULT_DESCRIPTION9,
3099
+ description: options.description ?? DEFAULT_DESCRIPTION10,
2909
3100
  error: snapshot.error,
2910
3101
  isLoading: snapshot.isLoading,
2911
3102
  label: snapshot.error ? "Unavailable" : turns.length ? failedCount > 0 ? `${failedCount} failed` : warningCount > 0 ? `${warningCount} warnings` : `${turns.length} healthy` : snapshot.isLoading ? "Checking" : "No turns",
2912
3103
  status: snapshot.error ? "error" : turns.length ? failedCount > 0 || warningCount > 0 ? "warning" : "ready" : snapshot.isLoading ? "loading" : "empty",
2913
- title: options.title ?? DEFAULT_TITLE9,
3104
+ title: options.title ?? DEFAULT_TITLE10,
2914
3105
  turns,
2915
3106
  updatedAt: snapshot.updatedAt
2916
3107
  };
2917
3108
  };
2918
3109
  var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
2919
3110
  const model = createVoiceTurnQualityViewModel(snapshot, options);
2920
- 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)}">
3111
+ 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--${escapeHtml11(turn.status)}">
2921
3112
  <header>
2922
- <strong>${escapeHtml10(turn.label)}</strong>
2923
- <span>${escapeHtml10(turn.status)}</span>
3113
+ <strong>${escapeHtml11(turn.label)}</strong>
3114
+ <span>${escapeHtml11(turn.status)}</span>
2924
3115
  </header>
2925
- <p>${escapeHtml10(turn.detail)}</p>
3116
+ <p>${escapeHtml11(turn.detail)}</p>
2926
3117
  <dl>${turn.rows.map((row) => `<div>
2927
- <dt>${escapeHtml10(row.label)}</dt>
2928
- <dd>${escapeHtml10(row.value)}</dd>
3118
+ <dt>${escapeHtml11(row.label)}</dt>
3119
+ <dd>${escapeHtml11(row.value)}</dd>
2929
3120
  </div>`).join("")}</dl>
2930
3121
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
2931
- return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml10(model.status)}">
3122
+ return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml11(model.status)}">
2932
3123
  <header class="absolute-voice-turn-quality__header">
2933
- <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml10(model.title)}</span>
2934
- <strong class="absolute-voice-turn-quality__label">${escapeHtml10(model.label)}</strong>
3124
+ <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml11(model.title)}</span>
3125
+ <strong class="absolute-voice-turn-quality__label">${escapeHtml11(model.label)}</strong>
2935
3126
  </header>
2936
- <p class="absolute-voice-turn-quality__description">${escapeHtml10(model.description)}</p>
3127
+ <p class="absolute-voice-turn-quality__description">${escapeHtml11(model.description)}</p>
2937
3128
  ${turns}
2938
- ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml10(model.error)}</p>` : ""}
3129
+ ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml11(model.error)}</p>` : ""}
2939
3130
  </section>`;
2940
3131
  };
2941
3132
  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}`;
@@ -3715,6 +3906,7 @@ export {
3715
3906
  createVoiceRoutingStatus,
3716
3907
  createVoiceProviderStatus,
3717
3908
  createVoiceProviderSimulationControls,
3909
+ createVoiceProviderContracts,
3718
3910
  createVoiceProviderCapabilities,
3719
3911
  createVoiceOpsStatus,
3720
3912
  createVoiceOpsActionCenter,
@@ -0,0 +1,21 @@
1
+ export declare const VoiceProviderContracts: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
2
+ description: StringConstructor;
3
+ intervalMs: NumberConstructor;
4
+ path: {
5
+ default: string;
6
+ type: StringConstructor;
7
+ };
8
+ title: StringConstructor;
9
+ }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
10
+ [key: string]: any;
11
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
12
+ description: StringConstructor;
13
+ intervalMs: NumberConstructor;
14
+ path: {
15
+ default: string;
16
+ type: StringConstructor;
17
+ };
18
+ title: StringConstructor;
19
+ }>> & Readonly<{}>, {
20
+ path: string;
21
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -3,6 +3,7 @@ export { VoiceOpsActionCenter } from './VoiceOpsActionCenter';
3
3
  export { VoiceDeliveryRuntime } from './VoiceDeliveryRuntime';
4
4
  export { VoiceProviderSimulationControls } from './VoiceProviderSimulationControls';
5
5
  export { VoiceProviderCapabilities } from './VoiceProviderCapabilities';
6
+ export { VoiceProviderContracts } from './VoiceProviderContracts';
6
7
  export { VoiceProviderStatus } from './VoiceProviderStatus';
7
8
  export { VoiceRoutingStatus } from './VoiceRoutingStatus';
8
9
  export { VoiceTurnLatency } from './VoiceTurnLatency';
@@ -15,6 +16,7 @@ export { useVoiceStream } from './useVoiceStream';
15
16
  export { useVoiceController } from './useVoiceController';
16
17
  export { useVoiceProviderStatus } from './useVoiceProviderStatus';
17
18
  export { useVoiceProviderCapabilities } from './useVoiceProviderCapabilities';
19
+ export { useVoiceProviderContracts } from './useVoiceProviderContracts';
18
20
  export { useVoiceProviderSimulationControls } from './useVoiceProviderSimulationControls';
19
21
  export { useVoiceRoutingStatus } from './useVoiceRoutingStatus';
20
22
  export { useVoiceTraceTimeline } from './useVoiceTraceTimeline';