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

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.
package/dist/index.d.ts CHANGED
@@ -46,7 +46,7 @@ export { assertVoiceProviderRoutingContract, runVoiceProviderRoutingContract } f
46
46
  export { createVoicePhoneAgentProductionSmokeHTMLHandler, createVoicePhoneAgentProductionSmokeJSONHandler, createVoicePhoneAgentProductionSmokeRoutes, renderVoicePhoneAgentProductionSmokeHTML, runVoicePhoneAgentProductionSmokeContract } from './phoneAgentProductionSmoke';
47
47
  export { buildVoiceProductionReadinessGate, buildVoiceProductionReadinessReport, createVoiceProductionReadinessRoutes, renderVoiceProductionReadinessHTML, summarizeVoiceProductionReadinessGate } from './productionReadiness';
48
48
  export { createVoiceReadinessProfile, recommendVoiceReadinessProfile } from './readinessProfiles';
49
- export { evaluateVoiceProviderStackGaps, recommendVoiceProviderStack } from './providerStackRecommendations';
49
+ export { buildVoiceProviderContractMatrix, createVoiceProviderContractMatrixHTMLHandler, createVoiceProviderContractMatrixJSONHandler, createVoiceProviderContractMatrixRoutes, evaluateVoiceProviderStackGaps, renderVoiceProviderContractMatrixHTML, recommendVoiceProviderStack } from './providerStackRecommendations';
50
50
  export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
51
51
  export { summarizeVoiceOpsStatus } from './opsStatus';
52
52
  export { createVoiceOpsStatusRoutes, renderVoiceOpsStatusHTML } from './opsStatusRoutes';
@@ -106,7 +106,7 @@ export type { VoiceOpsConsoleLink, VoiceOpsConsoleReport, VoiceOpsConsoleRoutesO
106
106
  export type { VoiceOpsStatus, VoiceOpsStatusLink, VoiceOpsStatusOptions, VoiceOpsStatusReport, VoiceOpsStatusRoutesOptions } from './opsStatus';
107
107
  export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptions, VoiceProductionReadinessAuditRequirement, VoiceProductionReadinessAuditSummary, VoiceProductionReadinessCheck, VoiceProductionReadinessGateIssue, VoiceProductionReadinessGateOptions, VoiceProductionReadinessGateProfile, VoiceProductionReadinessGateProfileSurface, VoiceProductionReadinessGateReport, VoiceProductionReadinessOpsActionHistoryOptions, VoiceProductionReadinessOpsActionHistorySummary, VoiceProductionReadinessProfileExplanation, VoiceProductionReadinessProfileSurface, VoiceProductionReadinessProofSource, VoiceProductionReadinessReport, VoiceProductionReadinessRoutesOptions, VoiceProductionReadinessTraceDeliverySummary, VoiceProductionReadinessAuditDeliveryOptions, VoiceProductionReadinessAuditDeliverySummary, VoiceProductionReadinessTraceDeliveryOptions, VoiceProductionReadinessStatus } from './productionReadiness';
108
108
  export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
109
- export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
109
+ export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderContractCheck, VoiceProviderContractCheckStatus, VoiceProviderContractDefinition, VoiceProviderContractMatrixHandlerOptions, VoiceProviderContractMatrixHTMLHandlerOptions, VoiceProviderContractMatrixInput, VoiceProviderContractMatrixReport, VoiceProviderContractMatrixRoutesOptions, VoiceProviderContractMatrixRow, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
110
110
  export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
111
111
  export type { VoiceResilienceIOSimulator, VoiceResilienceLink, VoiceResiliencePageData, VoiceResilienceRoutesOptions, VoiceResilienceSimulationProvider, VoiceRoutingKindSummary, VoiceRoutingDecisionSummary, VoiceRoutingDecisionSummaryOptions, VoiceRoutingEvent, VoiceRoutingEventKind, VoiceRoutingSessionSummary, VoiceRoutingSessionSummaryOptions } from './resilienceRoutes';
112
112
  export type { VoiceIOProviderRouterEvent, VoiceIOProviderRouterOptions, VoiceIOProviderRouterPolicy, VoiceIOProviderRouterPolicyConfig, VoiceSTTProviderRouterOptions, VoiceTTSProviderRouterOptions } from './providerAdapters';
package/dist/index.js CHANGED
@@ -20139,6 +20139,7 @@ var readinessGateCodes = {
20139
20139
  "Live latency proof": "voice.readiness.live_latency",
20140
20140
  "Operator action history": "voice.readiness.operator_action_history",
20141
20141
  "Phone agent production smoke": "voice.readiness.phone_agent_smoke",
20142
+ "Provider contract matrix": "voice.readiness.provider_contract_matrix",
20142
20143
  "Provider fallback recovery": "voice.readiness.provider_fallback_recovery",
20143
20144
  "Provider health": "voice.readiness.provider_health",
20144
20145
  "Provider routing contracts": "voice.readiness.provider_routing_contracts",
@@ -20220,6 +20221,12 @@ var resolveProviderStack = async (options, input) => {
20220
20221
  }
20221
20222
  return typeof options.providerStack === "function" ? await options.providerStack(input) : options.providerStack;
20222
20223
  };
20224
+ var resolveProviderContractMatrix = async (options, input) => {
20225
+ if (options.providerContractMatrix === false || options.providerContractMatrix === undefined) {
20226
+ return;
20227
+ }
20228
+ return typeof options.providerContractMatrix === "function" ? await options.providerContractMatrix(input) : options.providerContractMatrix;
20229
+ };
20223
20230
  var resolvePhoneAgentSmokes = async (options, input) => {
20224
20231
  if (options.phoneAgentSmokes === false || options.phoneAgentSmokes === undefined) {
20225
20232
  return;
@@ -20480,6 +20487,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20480
20487
  agentSquadContracts,
20481
20488
  providerRoutingContracts,
20482
20489
  providerStack,
20490
+ providerContractMatrix,
20483
20491
  phoneAgentSmokes,
20484
20492
  reconnectContracts,
20485
20493
  bargeInReports,
@@ -20511,6 +20519,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20511
20519
  resolveAgentSquadContracts(options, { query, request }),
20512
20520
  resolveProviderRoutingContracts(options, { query, request }),
20513
20521
  resolveProviderStack(options, { query, request }),
20522
+ resolveProviderContractMatrix(options, { query, request }),
20514
20523
  resolvePhoneAgentSmokes(options, { query, request }),
20515
20524
  resolveReconnectContracts(options, { query, request }),
20516
20525
  resolveBargeInReports(options, { query, request }),
@@ -20721,6 +20730,26 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20721
20730
  ]
20722
20731
  });
20723
20732
  }
20733
+ if (providerContractMatrix) {
20734
+ const blocked = providerContractMatrix.rows.filter((row) => row.status !== "pass");
20735
+ checks.push({
20736
+ detail: providerContractMatrix.status === "pass" ? `${providerContractMatrix.passed} provider contract row(s) are production-ready.` : blocked.length > 0 ? blocked.map((row) => {
20737
+ const issues = row.checks.filter((check) => check.status !== "pass").map((check) => check.label).join(", ");
20738
+ return `${row.kind.toUpperCase()} ${row.provider}: ${issues}`;
20739
+ }).join("; ") + "." : "Provider contract matrix needs review.",
20740
+ href: options.links?.providerRoutingContracts ?? options.links?.resilience ?? "/resilience",
20741
+ label: "Provider contract matrix",
20742
+ status: providerContractMatrix.status,
20743
+ value: `${providerContractMatrix.passed}/${providerContractMatrix.total}`,
20744
+ actions: providerContractMatrix.status === "pass" ? [] : [
20745
+ {
20746
+ description: "Open provider capabilities and inspect missing env, fallback, streaming, latency, or capability contracts.",
20747
+ href: options.links?.providerRoutingContracts ?? options.links?.resilience ?? "/resilience",
20748
+ label: "Open provider matrix"
20749
+ }
20750
+ ]
20751
+ });
20752
+ }
20724
20753
  if (phoneAgentSmokeSummary) {
20725
20754
  checks.push({
20726
20755
  detail: phoneAgentSmokeSummary.status === "pass" ? `${phoneAgentSmokeSummary.passed} phone-agent smoke contract(s) are passing.` : phoneAgentSmokeSummary.total === 0 ? "No phone-agent production smoke contracts are configured." : `${phoneAgentSmokeSummary.failed} phone-agent production smoke contract(s) failed.`,
@@ -20916,6 +20945,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20916
20945
  total: providers.length
20917
20946
  },
20918
20947
  providerStack,
20948
+ providerContractMatrix,
20919
20949
  providerRecovery,
20920
20950
  phoneAgentSmokes: phoneAgentSmokeSummary,
20921
20951
  providerRoutingContracts: providerRoutingContractSummary,
@@ -21312,6 +21342,8 @@ var recommendVoiceReadinessProfile = (options) => {
21312
21342
  };
21313
21343
  };
21314
21344
  // src/providerStackRecommendations.ts
21345
+ import { Elysia as Elysia34 } from "elysia";
21346
+ var escapeHtml36 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21315
21347
  var profileProviderPriorities = {
21316
21348
  "meeting-recorder": {
21317
21349
  llm: ["openai", "anthropic", "gemini"],
@@ -21394,6 +21426,126 @@ var recommendVoiceProviderStack = (input) => {
21394
21426
  stacks
21395
21427
  };
21396
21428
  };
21429
+ var rollupContractStatus = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
21430
+ var buildVoiceProviderContractMatrix = (input) => {
21431
+ const rows = input.contracts.map((contract) => {
21432
+ const configured = contract.configured !== false;
21433
+ const missingEnv = (contract.requiredEnv ?? []).filter((name) => !contract.env?.[name]);
21434
+ const missingCapabilities = (contract.requiredCapabilities ?? []).filter((capability) => !includesCapability(contract.capabilities ?? [], capability));
21435
+ const checks = [
21436
+ {
21437
+ detail: configured ? "Provider is configured for this deployment." : "Provider is declared but not configured.",
21438
+ key: "configured",
21439
+ label: "Configured",
21440
+ status: configured ? "pass" : "fail"
21441
+ },
21442
+ {
21443
+ detail: missingEnv.length === 0 ? "Required environment is present." : `Missing env: ${missingEnv.join(", ")}.`,
21444
+ key: "env",
21445
+ label: "Required env",
21446
+ status: missingEnv.length === 0 ? "pass" : "fail"
21447
+ },
21448
+ {
21449
+ detail: contract.latencyBudgetMs !== undefined ? `Latency budget is ${contract.latencyBudgetMs}ms.` : "No latency budget declared.",
21450
+ key: "latencyBudget",
21451
+ label: "Latency budget",
21452
+ status: contract.latencyBudgetMs !== undefined ? "pass" : "warn"
21453
+ },
21454
+ {
21455
+ detail: (contract.fallbackProviders ?? []).length > 0 ? `Fallback providers: ${contract.fallbackProviders?.join(", ")}.` : "No fallback provider declared.",
21456
+ key: "fallback",
21457
+ label: "Fallback",
21458
+ status: (contract.fallbackProviders ?? []).length > 0 ? "pass" : "warn"
21459
+ },
21460
+ {
21461
+ detail: contract.streaming ? "Streaming is supported." : "Streaming support is not declared.",
21462
+ key: "streaming",
21463
+ label: "Streaming",
21464
+ status: contract.streaming ? "pass" : "warn"
21465
+ },
21466
+ {
21467
+ detail: missingCapabilities.length === 0 ? "Required capabilities are declared." : `Missing capabilities: ${missingCapabilities.join(", ")}.`,
21468
+ key: "capabilities",
21469
+ label: "Capabilities",
21470
+ status: missingCapabilities.length === 0 ? "pass" : "warn"
21471
+ }
21472
+ ];
21473
+ const status = rollupContractStatus(checks);
21474
+ return {
21475
+ checks,
21476
+ configured,
21477
+ kind: contract.kind,
21478
+ provider: contract.provider,
21479
+ selected: contract.selected === true,
21480
+ status
21481
+ };
21482
+ });
21483
+ const failed = rows.filter((row) => row.status === "fail").length;
21484
+ const warned = rows.filter((row) => row.status === "warn").length;
21485
+ return {
21486
+ failed,
21487
+ passed: rows.filter((row) => row.status === "pass").length,
21488
+ rows,
21489
+ status: failed > 0 ? "fail" : warned > 0 ? "warn" : "pass",
21490
+ total: rows.length,
21491
+ warned
21492
+ };
21493
+ };
21494
+ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "function" ? await matrix() : matrix;
21495
+ var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
21496
+ const title = options.title ?? "Voice Provider Contract Matrix";
21497
+ const rows = report.rows.map((row) => {
21498
+ const checks = row.checks.map((check) => `<li class="${escapeHtml36(check.status)}"><strong>${escapeHtml36(check.label)}</strong><span>${escapeHtml36(check.detail ?? check.status)}</span></li>`).join("");
21499
+ return `<article class="row ${escapeHtml36(row.status)}">
21500
+ <div>
21501
+ <p class="eyebrow">${escapeHtml36(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
21502
+ <h2>${escapeHtml36(row.provider)}</h2>
21503
+ <p class="status ${escapeHtml36(row.status)}">${escapeHtml36(row.status.toUpperCase())}</p>
21504
+ </div>
21505
+ <ul>${checks}</ul>
21506
+ </article>`;
21507
+ }).join("");
21508
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(title)}</title><style>body{background:#0f1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.row{background:#17201b;border:1px solid #2d3b32;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(125,211,252,.12))}.eyebrow{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.status.pass,.row.pass,.pass{border-color:rgba(34,197,94,.65)}.status.warn,.row.warn,.warn{border-color:rgba(245,158,11,.7)}.status.fail,.row.fail,.fail{border-color:rgba(239,68,68,.75)}.row{display:grid;gap:20px;grid-template-columns:minmax(180px,.45fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#111814;border:1px solid #2d3b32;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider contracts</p><h1>${escapeHtml36(title)}</h1><p>Self-hosted provider proof for configured state, required env, latency budgets, fallback, streaming, and declared capabilities.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section>${rows || '<article class="row"><p>No provider contracts configured.</p></article>'}</main></body></html>`;
21509
+ };
21510
+ var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
21511
+ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
21512
+ const report = buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(options.matrix));
21513
+ const body = await (options.render ?? renderVoiceProviderContractMatrixHTML)(report, { title: options.title });
21514
+ return new Response(body, {
21515
+ headers: {
21516
+ "Content-Type": "text/html; charset=utf-8"
21517
+ }
21518
+ });
21519
+ };
21520
+ var createVoiceProviderContractMatrixRoutes = (options) => {
21521
+ const path = options.path ?? "/api/provider-contracts";
21522
+ const htmlPath = options.htmlPath ?? "/provider-contracts";
21523
+ const routes = new Elysia34({
21524
+ name: options.name ?? "absolutejs-voice-provider-contract-matrix"
21525
+ });
21526
+ const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
21527
+ routes.get(path, async () => {
21528
+ const report = await jsonHandler();
21529
+ return new Response(JSON.stringify(report), {
21530
+ headers: {
21531
+ "Content-Type": "application/json; charset=utf-8",
21532
+ ...options.headers
21533
+ }
21534
+ });
21535
+ });
21536
+ if (htmlPath !== false) {
21537
+ routes.get(htmlPath, async () => {
21538
+ const response = await createVoiceProviderContractMatrixHTMLHandler(options)();
21539
+ return new Response(response.body, {
21540
+ headers: {
21541
+ ...Object.fromEntries(response.headers.entries()),
21542
+ ...options.headers
21543
+ }
21544
+ });
21545
+ });
21546
+ }
21547
+ return routes;
21548
+ };
21397
21549
  var normalizeCapability = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, "");
21398
21550
  var includesCapability = (capabilities, required) => {
21399
21551
  const normalizedRequired = normalizeCapability(required);
@@ -21427,7 +21579,7 @@ var evaluateVoiceProviderStackGaps = (input) => {
21427
21579
  };
21428
21580
  };
21429
21581
  // src/opsConsoleRoutes.ts
21430
- import { Elysia as Elysia34 } from "elysia";
21582
+ import { Elysia as Elysia35 } from "elysia";
21431
21583
  var DEFAULT_LINKS = [
21432
21584
  {
21433
21585
  description: "Quality gates for CI, deploy checks, and production readiness.",
@@ -21462,7 +21614,7 @@ var DEFAULT_LINKS = [
21462
21614
  label: "Handoffs"
21463
21615
  }
21464
21616
  ];
21465
- var escapeHtml36 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21617
+ var escapeHtml37 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21466
21618
  var countProviderStatuses = (providers) => {
21467
21619
  const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
21468
21620
  const healthy = providers.filter((provider) => provider.status === "healthy").length;
@@ -21531,20 +21683,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
21531
21683
  trace
21532
21684
  };
21533
21685
  };
21534
- var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml36(input.label)}</span><strong>${escapeHtml36(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml36(input.status)}">${escapeHtml36(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml36(input.href)}">Open</a>` : ""}</article>`;
21686
+ var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml37(input.label)}</span><strong>${escapeHtml37(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml37(input.status)}">${escapeHtml37(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml37(input.href)}">Open</a>` : ""}</article>`;
21535
21687
  var renderVoiceOpsConsoleHTML = (report, options = {}) => {
21536
21688
  const links = report.links.map((link) => `<article class="surface">
21537
- <div><h2>${escapeHtml36(link.label)}</h2>${link.description ? `<p>${escapeHtml36(link.description)}</p>` : ""}</div>
21538
- <p><a href="${escapeHtml36(link.href)}">Open ${escapeHtml36(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml36(link.statusHref)}">Status</a>` : ""}</p>
21689
+ <div><h2>${escapeHtml37(link.label)}</h2>${link.description ? `<p>${escapeHtml37(link.description)}</p>` : ""}</div>
21690
+ <p><a href="${escapeHtml37(link.href)}">Open ${escapeHtml37(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml37(link.statusHref)}">Status</a>` : ""}</p>
21539
21691
  </article>`).join("");
21540
- const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml36(session.sessionId)}</td><td>${escapeHtml36(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml36(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
21541
- const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml36(event.kind)}</td><td>${escapeHtml36(event.provider ?? "unknown")}</td><td>${escapeHtml36(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml36(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
21692
+ const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml37(session.sessionId)}</td><td>${escapeHtml37(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml37(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
21693
+ const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml37(event.kind)}</td><td>${escapeHtml37(event.provider ?? "unknown")}</td><td>${escapeHtml37(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml37(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
21542
21694
  const title = options.title ?? "AbsoluteJS Voice Ops Console";
21543
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#101316;color:#f6f2e8;margin:0}main{max-width:1180px;margin:auto;padding:32px}a{color:#fbbf24}header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;margin-bottom:24px}.eyebrow{color:#fbbf24;font-weight:800;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.5rem);line-height:.95;margin:.2rem 0 1rem}.muted{color:#a8b0b8}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.metric,.surface{background:#181d22;border:1px solid #2a323a;border-radius:20px;padding:18px}.metric strong{display:block;font-size:2.2rem;margin:.25rem 0}.pass,.healthy{color:#86efac}.fail,.failed,.degraded{color:#fca5a5}.surfaces{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:24px 0}table{width:100%;border-collapse:collapse;background:#181d22;border-radius:16px;overflow:hidden;margin:12px 0 28px}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left}section{margin-top:30px}@media(max-width:700px){main{padding:20px}header{display:block}}</style></head><body><main><header><div><p class="eyebrow">Self-hosted voice operations</p><h1>${escapeHtml36(title)}</h1><p class="muted">One deployable control plane for quality gates, failover, traces, sessions, handoffs, and provider health.</p></div><p class="muted">Checked ${escapeHtml36(new Date(report.checkedAt).toLocaleString())}</p></header><div class="grid">${renderMetricCard({ label: "Quality", value: report.quality.status, status: report.quality.status, href: "/quality" })}${renderMetricCard({ label: "Events", value: report.eventCount, href: "/diagnostics" })}${renderMetricCard({ label: "Sessions", value: report.sessions.total, status: report.sessions.failed > 0 ? "failed" : "healthy", href: "/sessions" })}${renderMetricCard({ label: "Handoffs failed", value: report.handoffs.failed, status: report.handoffs.failed > 0 ? "failed" : "healthy", href: "/handoffs" })}${renderMetricCard({ label: "Providers degraded", value: report.providers.degraded, status: report.providers.degraded > 0 ? "degraded" : "healthy", href: "/resilience" })}</div><section><h2>Operational Surfaces</h2><div class="surfaces">${links}</div></section><section><h2>Recent Sessions</h2><table><thead><tr><th>Session</th><th>Status</th><th>Turns</th><th>Errors</th><th>Replay</th></tr></thead><tbody>${sessions}</tbody></table></section><section><h2>Recent Provider Routing</h2><table><thead><tr><th>Kind</th><th>Provider</th><th>Status</th><th>Elapsed</th><th>Session</th></tr></thead><tbody>${routing}</tbody></table></section></main></body></html>`;
21695
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml37(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#101316;color:#f6f2e8;margin:0}main{max-width:1180px;margin:auto;padding:32px}a{color:#fbbf24}header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;margin-bottom:24px}.eyebrow{color:#fbbf24;font-weight:800;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.5rem);line-height:.95;margin:.2rem 0 1rem}.muted{color:#a8b0b8}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.metric,.surface{background:#181d22;border:1px solid #2a323a;border-radius:20px;padding:18px}.metric strong{display:block;font-size:2.2rem;margin:.25rem 0}.pass,.healthy{color:#86efac}.fail,.failed,.degraded{color:#fca5a5}.surfaces{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:24px 0}table{width:100%;border-collapse:collapse;background:#181d22;border-radius:16px;overflow:hidden;margin:12px 0 28px}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left}section{margin-top:30px}@media(max-width:700px){main{padding:20px}header{display:block}}</style></head><body><main><header><div><p class="eyebrow">Self-hosted voice operations</p><h1>${escapeHtml37(title)}</h1><p class="muted">One deployable control plane for quality gates, failover, traces, sessions, handoffs, and provider health.</p></div><p class="muted">Checked ${escapeHtml37(new Date(report.checkedAt).toLocaleString())}</p></header><div class="grid">${renderMetricCard({ label: "Quality", value: report.quality.status, status: report.quality.status, href: "/quality" })}${renderMetricCard({ label: "Events", value: report.eventCount, href: "/diagnostics" })}${renderMetricCard({ label: "Sessions", value: report.sessions.total, status: report.sessions.failed > 0 ? "failed" : "healthy", href: "/sessions" })}${renderMetricCard({ label: "Handoffs failed", value: report.handoffs.failed, status: report.handoffs.failed > 0 ? "failed" : "healthy", href: "/handoffs" })}${renderMetricCard({ label: "Providers degraded", value: report.providers.degraded, status: report.providers.degraded > 0 ? "degraded" : "healthy", href: "/resilience" })}</div><section><h2>Operational Surfaces</h2><div class="surfaces">${links}</div></section><section><h2>Recent Sessions</h2><table><thead><tr><th>Session</th><th>Status</th><th>Turns</th><th>Errors</th><th>Replay</th></tr></thead><tbody>${sessions}</tbody></table></section><section><h2>Recent Provider Routing</h2><table><thead><tr><th>Kind</th><th>Provider</th><th>Status</th><th>Elapsed</th><th>Session</th></tr></thead><tbody>${routing}</tbody></table></section></main></body></html>`;
21544
21696
  };
21545
21697
  var createVoiceOpsConsoleRoutes = (options) => {
21546
21698
  const path = options.path ?? "/ops-console";
21547
- const routes = new Elysia34({
21699
+ const routes = new Elysia35({
21548
21700
  name: options.name ?? "absolutejs-voice-ops-console"
21549
21701
  });
21550
21702
  const getReport = () => buildVoiceOpsConsoleReport(options);
@@ -21732,19 +21884,19 @@ var summarizeVoiceOpsStatus = async (options) => {
21732
21884
  };
21733
21885
  };
21734
21886
  // src/opsStatusRoutes.ts
21735
- import { Elysia as Elysia35 } from "elysia";
21736
- var escapeHtml37 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21887
+ import { Elysia as Elysia36 } from "elysia";
21888
+ var escapeHtml38 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21737
21889
  var renderVoiceOpsStatusHTML = (report, options = {}) => {
21738
21890
  const title = options.title ?? "AbsoluteJS Voice Ops Status";
21739
21891
  const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
21740
21892
  const value = "recovered" in surface ? surface.total === 0 ? "0 events" : `${surface.recovered}/${surface.total}` : ("auditTotal" in surface) ? `${surface.auditTotal + surface.traceTotal} deliveries` : ("total" in surface) ? `${Math.max(surface.total - ("failed" in surface ? surface.failed : ("degraded" in surface) ? surface.degraded : 0), 0)}/${surface.total}` : surface.status;
21741
- return `<article class="surface ${escapeHtml37(surface.status)}"><span>${escapeHtml37(surface.status.toUpperCase())}</span><h2>${escapeHtml37(key)}</h2><strong>${escapeHtml37(value)}</strong></article>`;
21893
+ return `<article class="surface ${escapeHtml38(surface.status)}"><span>${escapeHtml38(surface.status.toUpperCase())}</span><h2>${escapeHtml38(key)}</h2><strong>${escapeHtml38(value)}</strong></article>`;
21742
21894
  }).join("");
21743
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml37(title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.surfaces{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.surface{background:#151d26;border:1px solid #283544;border-radius:20px;padding:18px}.surface span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.surface strong{font-size:1.5rem}.pass{border-color:rgba(34,197,94,.55)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Ops status</p><h1>${escapeHtml37(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml37(report.status)}">Overall: ${escapeHtml37(report.status.toUpperCase())}</p><p>${report.passed}/${report.total} checks passing</p></section><section class="surfaces">${surfaces || '<article class="surface pass"><span>PASS</span><h2>No checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
21895
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.surfaces{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.surface{background:#151d26;border:1px solid #283544;border-radius:20px;padding:18px}.surface span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.surface strong{font-size:1.5rem}.pass{border-color:rgba(34,197,94,.55)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Ops status</p><h1>${escapeHtml38(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml38(report.status)}">Overall: ${escapeHtml38(report.status.toUpperCase())}</p><p>${report.passed}/${report.total} checks passing</p></section><section class="surfaces">${surfaces || '<article class="surface pass"><span>PASS</span><h2>No checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
21744
21896
  };
21745
21897
  var createVoiceOpsStatusRoutes = (options) => {
21746
21898
  const path = options.path ?? "/api/voice/ops-status";
21747
- const routes = new Elysia35({
21899
+ const routes = new Elysia36({
21748
21900
  name: options.name ?? "absolutejs-voice-ops-status"
21749
21901
  });
21750
21902
  routes.get(path, async () => summarizeVoiceOpsStatus(options));
@@ -22177,8 +22329,8 @@ var createVoiceTTSProviderRouter = (options) => {
22177
22329
  };
22178
22330
  };
22179
22331
  // src/traceDeliveryRoutes.ts
22180
- import { Elysia as Elysia36 } from "elysia";
22181
- var escapeHtml38 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
22332
+ import { Elysia as Elysia37 } from "elysia";
22333
+ var escapeHtml39 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
22182
22334
  var getString12 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
22183
22335
  var getNumber7 = (value) => {
22184
22336
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -22259,14 +22411,14 @@ var renderSinkResults2 = (delivery) => {
22259
22411
  if (entries.length === 0) {
22260
22412
  return "<p>No sink delivery attempts recorded yet.</p>";
22261
22413
  }
22262
- return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml38(sinkId)}</strong>: ${escapeHtml38(result.status)}${result.deliveredTo ? ` to ${escapeHtml38(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml38(result.error)})` : ""}</li>`).join("")}</ul>`;
22414
+ return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml39(sinkId)}</strong>: ${escapeHtml39(result.status)}${result.deliveredTo ? ` to ${escapeHtml39(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml39(result.error)})` : ""}</li>`).join("")}</ul>`;
22263
22415
  };
22264
- var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml38(event.type)} <small>${escapeHtml38(event.id)}</small>${event.sessionId ? ` session=${escapeHtml38(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
22416
+ var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml39(event.type)} <small>${escapeHtml39(event.id)}</small>${event.sessionId ? ` session=${escapeHtml39(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
22265
22417
  var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
22266
22418
  const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
22267
- const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml38(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
22268
- const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml38(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml38(delivery.deliveryStatus)}</span><h2>${escapeHtml38(delivery.id)}</h2><p>${escapeHtml38(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml38(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml38(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
22269
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(title)}</title><style>body{background:#0f1318;color:#f4efe1;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(14,165,233,.14));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.grid{display:grid;gap:12px;grid-template-columns:repeat(4,1fr);margin-bottom:16px}.grid article,.delivery{background:#151b22;border:1px solid #26313d;border-radius:22px;padding:18px}.grid span,.delivery span{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.grid strong{display:block;font-size:2rem}.deliveries{display:grid;gap:14px}.delivery.failed{border-color:rgba(239,68,68,.75)}.delivery.pending{border-color:rgba(245,158,11,.7)}.delivery.delivered{border-color:rgba(34,197,94,.55)}.delivery.skipped{border-color:rgba(148,163,184,.6)}.head{align-items:start;display:flex;gap:14px;justify-content:space-between}.delivery h2{font-size:1.05rem;margin:.3rem 0;overflow-wrap:anywhere}.delivery h3{margin:1rem 0 .3rem}.delivery p,.delivery li{color:#c8d0d8}.error{color:#fecaca!important}button{background:#86efac;border:0;border-radius:999px;color:#07111f;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}@media(max-width:760px){main{padding:20px}.grid{grid-template-columns:1fr 1fr}.head{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Trace export health</p><h1>${escapeHtml38(title)}</h1><p>Checked ${escapeHtml38(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid3(report)}<section class="deliveries">${rows || "<p>No trace deliveries match this filter.</p>"}</section></main></body></html>`;
22419
+ const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml39(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
22420
+ const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml39(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml39(delivery.deliveryStatus)}</span><h2>${escapeHtml39(delivery.id)}</h2><p>${escapeHtml39(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml39(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml39(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
22421
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(title)}</title><style>body{background:#0f1318;color:#f4efe1;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(14,165,233,.14));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.grid{display:grid;gap:12px;grid-template-columns:repeat(4,1fr);margin-bottom:16px}.grid article,.delivery{background:#151b22;border:1px solid #26313d;border-radius:22px;padding:18px}.grid span,.delivery span{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.grid strong{display:block;font-size:2rem}.deliveries{display:grid;gap:14px}.delivery.failed{border-color:rgba(239,68,68,.75)}.delivery.pending{border-color:rgba(245,158,11,.7)}.delivery.delivered{border-color:rgba(34,197,94,.55)}.delivery.skipped{border-color:rgba(148,163,184,.6)}.head{align-items:start;display:flex;gap:14px;justify-content:space-between}.delivery h2{font-size:1.05rem;margin:.3rem 0;overflow-wrap:anywhere}.delivery h3{margin:1rem 0 .3rem}.delivery p,.delivery li{color:#c8d0d8}.error{color:#fecaca!important}button{background:#86efac;border:0;border-radius:999px;color:#07111f;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}@media(max-width:760px){main{padding:20px}.grid{grid-template-columns:1fr 1fr}.head{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Trace export health</p><h1>${escapeHtml39(title)}</h1><p>Checked ${escapeHtml39(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid3(report)}<section class="deliveries">${rows || "<p>No trace deliveries match this filter.</p>"}</section></main></body></html>`;
22270
22422
  };
22271
22423
  var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
22272
22424
  var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
@@ -22286,7 +22438,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
22286
22438
  const path = options.path ?? "/api/voice-trace-deliveries";
22287
22439
  const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
22288
22440
  const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
22289
- const routes = new Elysia36({
22441
+ const routes = new Elysia37({
22290
22442
  name: options.name ?? "absolutejs-voice-trace-deliveries"
22291
22443
  }).get(path, createVoiceTraceDeliveryJSONHandler(options));
22292
22444
  if (htmlPath !== false) {
@@ -22304,8 +22456,8 @@ var createVoiceTraceDeliveryRoutes = (options) => {
22304
22456
  return routes;
22305
22457
  };
22306
22458
  // src/traceTimeline.ts
22307
- import { Elysia as Elysia37 } from "elysia";
22308
- var escapeHtml39 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
22459
+ import { Elysia as Elysia38 } from "elysia";
22460
+ var escapeHtml40 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
22309
22461
  var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
22310
22462
  var getNumber8 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
22311
22463
  var firstString3 = (payload, keys) => {
@@ -22473,20 +22625,20 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
22473
22625
  };
22474
22626
  };
22475
22627
  var formatMs3 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
22476
- var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${escapeHtml39(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs3(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs3(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
22628
+ var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${escapeHtml40(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs3(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs3(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
22477
22629
  var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
22478
- const events = session.events.map((event) => `<tr class="${escapeHtml39(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml39(event.type)}</td><td>${escapeHtml39(event.label)}</td><td>${escapeHtml39(event.provider ?? "")}</td><td>${escapeHtml39(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
22479
- const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml39(issue.severity)}">${escapeHtml39(issue.code)}: ${escapeHtml39(issue.message)}</li>`).join("") : "<li>none</li>";
22480
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml39(session.sessionId)}</h1><p class="status ${escapeHtml39(session.status)}">${escapeHtml39(session.status)}</p></header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs3(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards2(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
22630
+ const events = session.events.map((event) => `<tr class="${escapeHtml40(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml40(event.type)}</td><td>${escapeHtml40(event.label)}</td><td>${escapeHtml40(event.provider ?? "")}</td><td>${escapeHtml40(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
22631
+ const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml40(issue.severity)}">${escapeHtml40(issue.code)}: ${escapeHtml40(issue.message)}</li>`).join("") : "<li>none</li>";
22632
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml40(options.title ?? "Voice Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml40(session.sessionId)}</h1><p class="status ${escapeHtml40(session.status)}">${escapeHtml40(session.status)}</p></header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs3(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards2(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
22481
22633
  };
22482
- var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml39(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml39(session.sessionId)}</a></td><td>${escapeHtml39(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs3(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml39(provider.provider)).join(", ")}</td></tr>`).join("");
22634
+ var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml40(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml40(session.sessionId)}</a></td><td>${escapeHtml40(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs3(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml40(provider.provider)).join(", ")}</td></tr>`).join("");
22483
22635
  var timelineCSS = "body{background:#0f1318;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}a{color:#fbbf24}.eyebrow{color:#fbbf24;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.5rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #475569;border-radius:999px;display:inline-flex;padding:8px 12px}.healthy{color:#86efac}.warning{color:#fbbf24}.failed,.error{color:#fca5a5}.metrics,.providers{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));margin:20px 0}.metrics article,.providers article{background:#181f27;border:1px solid #2b3642;border-radius:20px;padding:16px}.metrics span,dt,.muted{color:#a8b0b8}.metrics strong{display:block;font-size:2rem}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:12px 0 0}dd{font-weight:800;margin:4px 0 0}table{background:#181f27;border-collapse:collapse;border-radius:18px;overflow:hidden;width:100%}td,th{border-bottom:1px solid #2b3642;padding:12px;text-align:left}section{margin-top:28px}@media(max-width:760px){main{padding:20px}table{font-size:.9rem}}";
22484
- var renderVoiceTraceTimelineHTML = (report, options = {}) => `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml39(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
22636
+ var renderVoiceTraceTimelineHTML = (report, options = {}) => `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml40(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml40(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
22485
22637
  var createVoiceTraceTimelineRoutes = (options) => {
22486
22638
  const path = options.path ?? "/api/voice-traces";
22487
22639
  const htmlPath = options.htmlPath ?? "/traces";
22488
22640
  const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
22489
- const routes = new Elysia37({
22641
+ const routes = new Elysia38({
22490
22642
  name: options.name ?? "absolutejs-voice-trace-timelines"
22491
22643
  });
22492
22644
  const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
@@ -23139,7 +23291,7 @@ var createVoiceMemoryStore = () => {
23139
23291
  return { get, getOrCreate, list, remove, set };
23140
23292
  };
23141
23293
  // src/opsWebhook.ts
23142
- import { Elysia as Elysia38 } from "elysia";
23294
+ import { Elysia as Elysia39 } from "elysia";
23143
23295
  var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
23144
23296
  var signVoiceOpsWebhookBody = async (input) => {
23145
23297
  const encoder = new TextEncoder;
@@ -23269,7 +23421,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
23269
23421
  };
23270
23422
  var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
23271
23423
  const path = options.path ?? "/api/voice-ops/webhook";
23272
- return new Elysia38().post(path, async ({ body, request, set }) => {
23424
+ return new Elysia39().post(path, async ({ body, request, set }) => {
23273
23425
  const bodyText = typeof body === "string" ? body : JSON.stringify(body);
23274
23426
  if (options.signingSecret) {
23275
23427
  const verification = await verifyVoiceOpsWebhookSignature({
@@ -24203,6 +24355,7 @@ export {
24203
24355
  renderVoiceReconnectContractHTML,
24204
24356
  renderVoiceQualityHTML,
24205
24357
  renderVoiceProviderHealthHTML,
24358
+ renderVoiceProviderContractMatrixHTML,
24206
24359
  renderVoiceProviderCapabilityHTML,
24207
24360
  renderVoiceProductionReadinessHTML,
24208
24361
  renderVoicePhoneAgentProductionSmokeHTML,
@@ -24359,6 +24512,9 @@ export {
24359
24512
  createVoiceProviderHealthRoutes,
24360
24513
  createVoiceProviderHealthJSONHandler,
24361
24514
  createVoiceProviderHealthHTMLHandler,
24515
+ createVoiceProviderContractMatrixRoutes,
24516
+ createVoiceProviderContractMatrixJSONHandler,
24517
+ createVoiceProviderContractMatrixHTMLHandler,
24362
24518
  createVoiceProviderCapabilityRoutes,
24363
24519
  createVoiceProviderCapabilityJSONHandler,
24364
24520
  createVoiceProviderCapabilityHTMLHandler,
@@ -24511,6 +24667,7 @@ export {
24511
24667
  claimVoiceOpsTask,
24512
24668
  buildVoiceTraceReplay,
24513
24669
  buildVoiceTraceDeliveryReport,
24670
+ buildVoiceProviderContractMatrix,
24514
24671
  buildVoiceProductionReadinessReport,
24515
24672
  buildVoiceProductionReadinessGate,
24516
24673
  buildVoiceOpsTaskFromSLABreach,
@@ -11,7 +11,7 @@ import type { VoicePhoneAgentProductionSmokeReport } from './phoneAgentProductio
11
11
  import type { VoiceReconnectContractReport } from './reconnectContract';
12
12
  import type { VoiceAuditEventStore, VoiceAuditEventType, VoiceAuditOutcome } from './audit';
13
13
  import { type VoiceAuditSinkDeliveryStore } from './auditSinks';
14
- import type { VoiceProviderStackCapabilityGapReport } from './providerStackRecommendations';
14
+ import type { VoiceProviderContractMatrixReport, VoiceProviderStackCapabilityGapReport } from './providerStackRecommendations';
15
15
  export type VoiceProductionReadinessStatus = 'fail' | 'pass' | 'warn';
16
16
  export type VoiceProductionReadinessAction = {
17
17
  description?: string;
@@ -139,6 +139,7 @@ export type VoiceProductionReadinessReport = {
139
139
  total: number;
140
140
  };
141
141
  providerStack?: VoiceProviderStackCapabilityGapReport;
142
+ providerContractMatrix?: VoiceProviderContractMatrixReport;
142
143
  providerRecovery: VoiceProviderFallbackRecoverySummary;
143
144
  phoneAgentSmokes?: {
144
145
  failed: number;
@@ -303,6 +304,10 @@ export type VoiceProductionReadinessRoutesOptions = {
303
304
  query: Record<string, unknown>;
304
305
  request: Request;
305
306
  }) => Promise<VoiceProviderStackCapabilityGapReport> | VoiceProviderStackCapabilityGapReport);
307
+ providerContractMatrix?: false | VoiceProviderContractMatrixReport | ((input: {
308
+ query: Record<string, unknown>;
309
+ request: Request;
310
+ }) => Promise<VoiceProviderContractMatrixReport> | VoiceProviderContractMatrixReport);
306
311
  reconnectContracts?: false | readonly VoiceReconnectContractReport[] | ((input: {
307
312
  query: Record<string, unknown>;
308
313
  request: Request;
@@ -1,3 +1,4 @@
1
+ import { Elysia } from 'elysia';
1
2
  import type { VoiceReadinessProfileName } from './readinessProfiles';
2
3
  export type VoiceProviderStackKind = 'llm' | 'stt' | 'tts';
3
4
  export type VoiceProviderStackInput<TProvider extends string = string> = {
@@ -35,5 +36,90 @@ export type VoiceProviderStackCapabilityGapInput<TProvider extends string = stri
35
36
  recommendation?: VoiceProviderStackRecommendation<TProvider>;
36
37
  required?: Partial<Record<VoiceProviderStackKind, readonly string[]>>;
37
38
  };
39
+ export type VoiceProviderContractCheckStatus = 'fail' | 'pass' | 'warn';
40
+ export type VoiceProviderContractCheck = {
41
+ detail?: string;
42
+ key: string;
43
+ label: string;
44
+ status: VoiceProviderContractCheckStatus;
45
+ };
46
+ export type VoiceProviderContractDefinition<TProvider extends string = string> = {
47
+ capabilities?: readonly string[];
48
+ configured?: boolean;
49
+ env?: Record<string, string | undefined>;
50
+ fallbackProviders?: readonly TProvider[];
51
+ kind: VoiceProviderStackKind;
52
+ latencyBudgetMs?: number;
53
+ provider: TProvider;
54
+ requiredCapabilities?: readonly string[];
55
+ requiredEnv?: readonly string[];
56
+ selected?: boolean;
57
+ streaming?: boolean;
58
+ };
59
+ export type VoiceProviderContractMatrixInput<TProvider extends string = string> = {
60
+ contracts: readonly VoiceProviderContractDefinition<TProvider>[];
61
+ };
62
+ export type VoiceProviderContractMatrixHandlerOptions<TProvider extends string = string> = VoiceProviderContractMatrixInput<TProvider> | (() => Promise<VoiceProviderContractMatrixInput<TProvider>> | VoiceProviderContractMatrixInput<TProvider>);
63
+ export type VoiceProviderContractMatrixHTMLHandlerOptions<TProvider extends string = string> = {
64
+ matrix: VoiceProviderContractMatrixHandlerOptions<TProvider>;
65
+ render?: (report: VoiceProviderContractMatrixReport<TProvider>) => string | Promise<string>;
66
+ title?: string;
67
+ };
68
+ export type VoiceProviderContractMatrixRoutesOptions<TProvider extends string = string> = VoiceProviderContractMatrixHTMLHandlerOptions<TProvider> & {
69
+ headers?: HeadersInit;
70
+ htmlPath?: false | string;
71
+ name?: string;
72
+ path?: string;
73
+ };
74
+ export type VoiceProviderContractMatrixRow<TProvider extends string = string> = {
75
+ checks: VoiceProviderContractCheck[];
76
+ configured: boolean;
77
+ kind: VoiceProviderStackKind;
78
+ provider: TProvider;
79
+ selected: boolean;
80
+ status: VoiceProviderContractCheckStatus;
81
+ };
82
+ export type VoiceProviderContractMatrixReport<TProvider extends string = string> = {
83
+ failed: number;
84
+ passed: number;
85
+ rows: VoiceProviderContractMatrixRow<TProvider>[];
86
+ status: VoiceProviderContractCheckStatus;
87
+ total: number;
88
+ warned: number;
89
+ };
38
90
  export declare const recommendVoiceProviderStack: <TProvider extends string = string>(input: VoiceProviderStackInput<TProvider>) => VoiceProviderStackRecommendation<TProvider>;
91
+ export declare const buildVoiceProviderContractMatrix: <TProvider extends string = string>(input: VoiceProviderContractMatrixInput<TProvider>) => VoiceProviderContractMatrixReport<TProvider>;
92
+ export declare const renderVoiceProviderContractMatrixHTML: <TProvider extends string = string>(report: VoiceProviderContractMatrixReport<TProvider>, options?: {
93
+ title?: string;
94
+ }) => string;
95
+ export declare const createVoiceProviderContractMatrixJSONHandler: <TProvider extends string = string>(matrix: VoiceProviderContractMatrixHandlerOptions<TProvider>) => () => Promise<VoiceProviderContractMatrixReport<TProvider>>;
96
+ export declare const createVoiceProviderContractMatrixHTMLHandler: <TProvider extends string = string>(options: VoiceProviderContractMatrixHTMLHandlerOptions<TProvider>) => () => Promise<Response>;
97
+ export declare const createVoiceProviderContractMatrixRoutes: <TProvider extends string = string>(options: VoiceProviderContractMatrixRoutesOptions<TProvider>) => Elysia<"", {
98
+ decorator: {};
99
+ store: {};
100
+ derive: {};
101
+ resolve: {};
102
+ }, {
103
+ typebox: {};
104
+ error: {};
105
+ }, {
106
+ schema: {};
107
+ standaloneSchema: {};
108
+ macro: {};
109
+ macroFn: {};
110
+ parser: {};
111
+ response: {};
112
+ }, {}, {
113
+ derive: {};
114
+ resolve: {};
115
+ schema: {};
116
+ standaloneSchema: {};
117
+ response: {};
118
+ }, {
119
+ derive: {};
120
+ resolve: {};
121
+ schema: {};
122
+ standaloneSchema: {};
123
+ response: {};
124
+ }>;
39
125
  export declare const evaluateVoiceProviderStackGaps: <TProvider extends string = string>(input: VoiceProviderStackCapabilityGapInput<TProvider>) => VoiceProviderStackCapabilityGapReport<TProvider>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.165",
3
+ "version": "0.0.22-beta.167",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",