@absolutejs/voice 0.0.22-beta.130 → 0.0.22-beta.131

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.js CHANGED
@@ -9995,9 +9995,134 @@ var createVoiceBargeInRoutes = (options) => {
9995
9995
  });
9996
9996
  return routes;
9997
9997
  };
9998
- // src/diagnosticsRoutes.ts
9998
+ // src/reconnectContract.ts
9999
9999
  import { Elysia as Elysia8 } from "elysia";
10000
10000
  var escapeHtml11 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10001
+ var unique = (values) => [...new Set(values)];
10002
+ var findDuplicateTurnIds = (snapshots) => {
10003
+ const duplicates = new Set;
10004
+ for (const snapshot of snapshots) {
10005
+ const seen = new Set;
10006
+ for (const turnId of snapshot.turnIds ?? []) {
10007
+ if (seen.has(turnId)) {
10008
+ duplicates.add(turnId);
10009
+ }
10010
+ seen.add(turnId);
10011
+ }
10012
+ }
10013
+ return [...duplicates].sort();
10014
+ };
10015
+ var runVoiceReconnectContract = (options) => {
10016
+ const snapshots = [...options.snapshots].sort((left, right) => left.at - right.at);
10017
+ const issues = [];
10018
+ const statuses = unique(snapshots.map((snapshot) => snapshot.reconnect.status));
10019
+ const attempts = Math.max(0, ...snapshots.map((snapshot) => snapshot.reconnect.attempts));
10020
+ const maxAttempts = Math.max(0, ...snapshots.map((snapshot) => snapshot.reconnect.maxAttempts));
10021
+ const reconnected = statuses.includes("reconnecting");
10022
+ const resumed = statuses.includes("resumed");
10023
+ const exhausted = statuses.includes("exhausted");
10024
+ const duplicateTurnIds = findDuplicateTurnIds(snapshots);
10025
+ const requireReconnect = options.requireReconnect ?? true;
10026
+ const requireResume = options.requireResume ?? true;
10027
+ const requireReplayProtection = options.requireReplayProtection ?? true;
10028
+ if (snapshots.length === 0) {
10029
+ issues.push({
10030
+ code: "reconnect.no_snapshots",
10031
+ message: "No reconnect snapshots were provided.",
10032
+ severity: "error"
10033
+ });
10034
+ }
10035
+ if (requireReconnect && !reconnected) {
10036
+ issues.push({
10037
+ code: "reconnect.not_observed",
10038
+ message: "No reconnecting state was observed.",
10039
+ severity: "error"
10040
+ });
10041
+ }
10042
+ if (requireResume && reconnected && !resumed) {
10043
+ issues.push({
10044
+ code: exhausted ? "reconnect.exhausted_before_resume" : "reconnect.resume_not_observed",
10045
+ message: exhausted ? "Reconnect exhausted before a resumed state was observed." : "Reconnect started but no resumed state was observed.",
10046
+ severity: "error"
10047
+ });
10048
+ }
10049
+ for (const snapshot of snapshots) {
10050
+ const { reconnect } = snapshot;
10051
+ if (reconnect.maxAttempts > 0 && reconnect.attempts > reconnect.maxAttempts) {
10052
+ issues.push({
10053
+ code: "reconnect.max_attempts_exceeded",
10054
+ message: `Reconnect attempts exceeded maxAttempts at ${snapshot.at}.`,
10055
+ severity: "error"
10056
+ });
10057
+ }
10058
+ if (reconnect.status === "reconnecting" && reconnect.nextAttemptAt !== undefined && reconnect.nextAttemptAt < snapshot.at) {
10059
+ issues.push({
10060
+ code: "reconnect.stale_next_attempt",
10061
+ message: `Reconnect nextAttemptAt is older than the snapshot at ${snapshot.at}.`,
10062
+ severity: "warning"
10063
+ });
10064
+ }
10065
+ }
10066
+ if (requireReplayProtection && duplicateTurnIds.length > 0) {
10067
+ issues.push({
10068
+ code: "reconnect.duplicate_turn_ids",
10069
+ message: `Replay produced duplicate turn ids: ${duplicateTurnIds.join(", ")}.`,
10070
+ severity: "error"
10071
+ });
10072
+ }
10073
+ const pass = issues.every((issue) => issue.severity !== "error");
10074
+ return {
10075
+ checkedAt: Date.now(),
10076
+ issues,
10077
+ pass,
10078
+ snapshotCount: snapshots.length,
10079
+ statuses,
10080
+ summary: {
10081
+ attempts,
10082
+ duplicateTurnIds,
10083
+ exhausted,
10084
+ maxAttempts,
10085
+ reconnected,
10086
+ resumed
10087
+ }
10088
+ };
10089
+ };
10090
+ var renderVoiceReconnectContractHTML = (report) => {
10091
+ const issues = report.issues.map((issue) => `<li class="${escapeHtml11(issue.severity)}"><strong>${escapeHtml11(issue.code)}</strong>: ${escapeHtml11(issue.message)}</li>`).join("");
10092
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Voice Reconnect Contract</title><style>body{background:#0d1117;color:#f8fafc;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,.card{background:#151b23;border:1px solid #30363d;border-radius:18px;margin-bottom:16px;padding:20px}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.25rem,7vw,4.5rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0d1117;border:1px solid #30363d;border-radius:999px;padding:7px 10px}.pass{color:#86efac}.fail,.error{color:#fca5a5}.warning{color:#fde68a}li{margin:8px 0}</style></head><body><main><section class="hero"><p class="eyebrow">Reconnect Resume Proof</p><h1>Voice reconnect contract</h1><div class="summary"><span class="pill ${report.pass ? "pass" : "fail"}">${report.pass ? "pass" : "fail"}</span><span class="pill">${String(report.snapshotCount)} snapshots</span><span class="pill">${String(report.summary.attempts)} attempts</span><span class="pill">statuses ${escapeHtml11(report.statuses.join(", ") || "none")}</span></div></section><section class="card"><h2>Summary</h2><p>reconnected ${String(report.summary.reconnected)} \xB7 resumed ${String(report.summary.resumed)} \xB7 exhausted ${String(report.summary.exhausted)} \xB7 duplicate turns ${String(report.summary.duplicateTurnIds.length)}</p></section><section class="card"><h2>Issues</h2>${issues ? `<ul>${issues}</ul>` : '<p class="pass">No contract issues.</p>'}</section></main></body></html>`;
10093
+ };
10094
+ var createVoiceReconnectContractRoutes = (options) => {
10095
+ const path = options.path ?? "/api/voice/reconnect-contract";
10096
+ const htmlPath = options.htmlPath ?? "/voice/reconnect-contract";
10097
+ const buildReport = async () => runVoiceReconnectContract({
10098
+ requireReconnect: options.requireReconnect,
10099
+ requireReplayProtection: options.requireReplayProtection,
10100
+ requireResume: options.requireResume,
10101
+ snapshots: await options.getSnapshots()
10102
+ });
10103
+ const app = new Elysia8({ name: options.name ?? "absolutejs-voice-reconnect-contract" }).get(path, async () => new Response(JSON.stringify(await buildReport()), {
10104
+ headers: {
10105
+ "content-type": "application/json; charset=utf-8",
10106
+ ...options.headers
10107
+ }
10108
+ }));
10109
+ if (htmlPath !== false) {
10110
+ app.get(htmlPath, async () => {
10111
+ const report = await buildReport();
10112
+ const html = options.render ? await options.render(report) : renderVoiceReconnectContractHTML(report);
10113
+ return new Response(html, {
10114
+ headers: {
10115
+ "content-type": "text/html; charset=utf-8",
10116
+ ...options.headers
10117
+ }
10118
+ });
10119
+ });
10120
+ }
10121
+ return app;
10122
+ };
10123
+ // src/diagnosticsRoutes.ts
10124
+ import { Elysia as Elysia9 } from "elysia";
10125
+ var escapeHtml12 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10001
10126
  var getString5 = (value) => typeof value === "string" && value.trim() ? value : undefined;
10002
10127
  var getNumber4 = (value) => {
10003
10128
  const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : undefined;
@@ -10063,9 +10188,9 @@ var renderDiagnosticsIndex = (input) => {
10063
10188
  const rows = [...sessions.entries()].sort(([, left], [, right]) => (right.at(-1)?.at ?? 0) - (left.at(-1)?.at ?? 0)).slice(0, 50).map(([sessionId, events]) => {
10064
10189
  const summary = summarizeVoiceTrace(events);
10065
10190
  const encoded = encodeURIComponent(sessionId);
10066
- return `<tr><td>${escapeHtml11(sessionId)}</td><td>${summary.eventCount}</td><td>${summary.turnCount}</td><td>${summary.errorCount}</td><td><a href="${input.basePath}/html?sessionId=${encoded}&redact=true">HTML</a> \xB7 <a href="${input.basePath}/markdown?sessionId=${encoded}&redact=true">Markdown</a> \xB7 <a href="${input.basePath}/json?sessionId=${encoded}&redact=true">JSON</a></td></tr>`;
10191
+ return `<tr><td>${escapeHtml12(sessionId)}</td><td>${summary.eventCount}</td><td>${summary.turnCount}</td><td>${summary.errorCount}</td><td><a href="${input.basePath}/html?sessionId=${encoded}&redact=true">HTML</a> \xB7 <a href="${input.basePath}/markdown?sessionId=${encoded}&redact=true">Markdown</a> \xB7 <a href="${input.basePath}/json?sessionId=${encoded}&redact=true">JSON</a></td></tr>`;
10067
10192
  }).join("");
10068
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml11(input.title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}table{width:100%;border-collapse:collapse;background:white}td,th{border-bottom:1px solid #eee;padding:.7rem;text-align:left}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml11(input.title)}</h1><p>Recent voice trace diagnostics. Exports support filters: sessionId, traceId, turnId, scenarioId, type, provider, status, since, until, limit, redact.</p><table><thead><tr><th>Session</th><th>Events</th><th>Turns</th><th>Errors</th><th>Exports</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
10193
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml12(input.title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}table{width:100%;border-collapse:collapse;background:white}td,th{border-bottom:1px solid #eee;padding:.7rem;text-align:left}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml12(input.title)}</h1><p>Recent voice trace diagnostics. Exports support filters: sessionId, traceId, turnId, scenarioId, type, provider, status, since, until, limit, redact.</p><table><thead><tr><th>Session</th><th>Events</th><th>Turns</th><th>Errors</th><th>Exports</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
10069
10194
  };
10070
10195
  var withRedaction = (events, query, defaultRedact) => {
10071
10196
  const shouldRedact = query.redact === undefined ? defaultRedact : getBoolean(query.redact);
@@ -10074,7 +10199,7 @@ var withRedaction = (events, query, defaultRedact) => {
10074
10199
  var createVoiceDiagnosticsRoutes = (options) => {
10075
10200
  const path = options.path ?? "/diagnostics";
10076
10201
  const title = options.title ?? "AbsoluteJS Voice Diagnostics";
10077
- const routes = new Elysia8({
10202
+ const routes = new Elysia9({
10078
10203
  name: options.name ?? "absolutejs-voice-diagnostics"
10079
10204
  });
10080
10205
  routes.get(path, async () => {
@@ -10131,8 +10256,8 @@ var createVoiceDiagnosticsRoutes = (options) => {
10131
10256
  return routes;
10132
10257
  };
10133
10258
  // src/demoReadyRoutes.ts
10134
- import { Elysia as Elysia9 } from "elysia";
10135
- var escapeHtml12 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10259
+ import { Elysia as Elysia10 } from "elysia";
10260
+ var escapeHtml13 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10136
10261
  var rollupStatus = (sections) => sections.some((section) => section.status === "fail") ? "fail" : sections.some((section) => section.status === "warn") ? "warn" : "pass";
10137
10262
  var resolveLoader = async (loader, input) => typeof loader === "function" ? await loader(input) : loader;
10138
10263
  var buildVoiceDemoReadyReport = async (options, input = {}) => {
@@ -10216,17 +10341,17 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
10216
10341
  };
10217
10342
  };
10218
10343
  var renderVoiceDemoReadyHTML = (report) => {
10219
- const sections = report.sections.map((section) => `<article class="section ${escapeHtml12(section.status)}">
10220
- <div><span>${escapeHtml12(section.status.toUpperCase())}</span><h2>${escapeHtml12(section.label)}</h2>${section.description ? `<p>${escapeHtml12(section.description)}</p>` : ""}</div>
10221
- <strong>${escapeHtml12(String(section.value ?? section.status))}</strong>
10222
- ${section.href ? `<a href="${escapeHtml12(section.href)}">Open</a>` : ""}
10344
+ const sections = report.sections.map((section) => `<article class="section ${escapeHtml13(section.status)}">
10345
+ <div><span>${escapeHtml13(section.status.toUpperCase())}</span><h2>${escapeHtml13(section.label)}</h2>${section.description ? `<p>${escapeHtml13(section.description)}</p>` : ""}</div>
10346
+ <strong>${escapeHtml13(String(section.value ?? section.status))}</strong>
10347
+ ${section.href ? `<a href="${escapeHtml13(section.href)}">Open</a>` : ""}
10223
10348
  </article>`).join("");
10224
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml12(report.title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;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}.sections{display:grid;gap:14px}.section{align-items:center;background:#151d26;border:1px solid #283544;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.section span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.section h2{margin:.2rem 0}.section p{color:#b9c0c8;margin:.2rem 0 0}.section strong{font-size:1.4rem}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.65)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}@media(max-width:760px){main{padding:20px}.section{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Demo readiness</p><h1>${escapeHtml12(report.title)}</h1><p>One customer-facing checklist for the self-hosted voice proof surfaces: ops status, production readiness, phone setup, and phone smoke traces.</p><p class="status ${escapeHtml12(report.status)}">Overall: ${escapeHtml12(report.status.toUpperCase())}</p><p>Checked ${escapeHtml12(new Date(report.checkedAt).toLocaleString())}</p></section><section class="sections">${sections || '<article class="section warn"><div><span>WARN</span><h2>No checks configured</h2><p>Add ops status, production readiness, phone setup, or phone smoke loaders.</p></div><strong>warn</strong></article>'}</section></main></body></html>`;
10349
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml13(report.title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;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}.sections{display:grid;gap:14px}.section{align-items:center;background:#151d26;border:1px solid #283544;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.section span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.section h2{margin:.2rem 0}.section p{color:#b9c0c8;margin:.2rem 0 0}.section strong{font-size:1.4rem}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.65)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}@media(max-width:760px){main{padding:20px}.section{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Demo readiness</p><h1>${escapeHtml13(report.title)}</h1><p>One customer-facing checklist for the self-hosted voice proof surfaces: ops status, production readiness, phone setup, and phone smoke traces.</p><p class="status ${escapeHtml13(report.status)}">Overall: ${escapeHtml13(report.status.toUpperCase())}</p><p>Checked ${escapeHtml13(new Date(report.checkedAt).toLocaleString())}</p></section><section class="sections">${sections || '<article class="section warn"><div><span>WARN</span><h2>No checks configured</h2><p>Add ops status, production readiness, phone setup, or phone smoke loaders.</p></div><strong>warn</strong></article>'}</section></main></body></html>`;
10225
10350
  };
10226
10351
  var createVoiceDemoReadyRoutes = (options) => {
10227
10352
  const path = options.path ?? "/api/demo-ready";
10228
10353
  const htmlPath = options.htmlPath ?? "/demo-ready";
10229
- const routes = new Elysia9({
10354
+ const routes = new Elysia10({
10230
10355
  name: options.name ?? "absolutejs-voice-demo-ready"
10231
10356
  });
10232
10357
  routes.get(path, async ({ query, request }) => buildVoiceDemoReadyReport(options, { query, request }));
@@ -10447,16 +10572,16 @@ var applyVoiceDataRetentionPolicy = async (options) => {
10447
10572
  };
10448
10573
  var buildVoiceDataRetentionPlan = (options) => applyVoiceDataRetentionPolicy({ ...options, dryRun: true });
10449
10574
  // src/evalRoutes.ts
10450
- import { Elysia as Elysia12 } from "elysia";
10575
+ import { Elysia as Elysia13 } from "elysia";
10451
10576
  import { mkdir } from "fs/promises";
10452
10577
  import { dirname } from "path";
10453
10578
 
10454
10579
  // src/qualityRoutes.ts
10455
- import { Elysia as Elysia11 } from "elysia";
10580
+ import { Elysia as Elysia12 } from "elysia";
10456
10581
 
10457
10582
  // src/handoffHealth.ts
10458
- import { Elysia as Elysia10 } from "elysia";
10459
- var escapeHtml13 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10583
+ import { Elysia as Elysia11 } from "elysia";
10584
+ var escapeHtml14 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10460
10585
  var getString6 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
10461
10586
  var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
10462
10587
  var increment3 = (record, key) => {
@@ -10574,10 +10699,10 @@ var renderActionSummary = (summary) => {
10574
10699
  return [
10575
10700
  '<section class="voice-handoff-health-columns">',
10576
10701
  "<article><h3>Actions</h3>",
10577
- actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml13(action)}: ${String(count)}</li>`).join("")}</ul>`,
10702
+ actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml14(action)}: ${String(count)}</li>`).join("")}</ul>`,
10578
10703
  "</article>",
10579
10704
  "<article><h3>Adapters</h3>",
10580
- adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml13(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
10705
+ adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml14(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
10581
10706
  "</article>",
10582
10707
  "</section>"
10583
10708
  ].join("");
@@ -10591,22 +10716,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
10591
10716
  summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
10592
10717
  '<div class="voice-handoff-health-events">',
10593
10718
  ...summary.events.map((event) => [
10594
- `<article class="${escapeHtml13(event.status)}">`,
10719
+ `<article class="${escapeHtml14(event.status)}">`,
10595
10720
  '<div class="voice-handoff-health-event-header">',
10596
- `<strong>${escapeHtml13(event.action ?? "handoff")}</strong>`,
10597
- `<span>${escapeHtml13(event.status)}</span>`,
10721
+ `<strong>${escapeHtml14(event.action ?? "handoff")}</strong>`,
10722
+ `<span>${escapeHtml14(event.status)}</span>`,
10598
10723
  "</div>",
10599
- `<p><small>${escapeHtml13(event.sessionId)}</small></p>`,
10600
- event.target ? `<p>Target: ${escapeHtml13(event.target)}</p>` : "",
10601
- event.reason ? `<p>Reason: ${escapeHtml13(event.reason)}</p>` : "",
10724
+ `<p><small>${escapeHtml14(event.sessionId)}</small></p>`,
10725
+ event.target ? `<p>Target: ${escapeHtml14(event.target)}</p>` : "",
10726
+ event.reason ? `<p>Reason: ${escapeHtml14(event.reason)}</p>` : "",
10602
10727
  event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
10603
10728
  "<li>",
10604
- `${escapeHtml13(delivery.adapterId)}: ${escapeHtml13(delivery.status)}`,
10605
- delivery.deliveredTo ? ` to ${escapeHtml13(delivery.deliveredTo)}` : "",
10606
- delivery.error ? ` (${escapeHtml13(delivery.error)})` : "",
10729
+ `${escapeHtml14(delivery.adapterId)}: ${escapeHtml14(delivery.status)}`,
10730
+ delivery.deliveredTo ? ` to ${escapeHtml14(delivery.deliveredTo)}` : "",
10731
+ delivery.error ? ` (${escapeHtml14(delivery.error)})` : "",
10607
10732
  "</li>"
10608
10733
  ].join("")).join("")}</ul>` : "",
10609
- event.replayHref ? `<p><a href="${escapeHtml13(event.replayHref)}">Open replay</a></p>` : "",
10734
+ event.replayHref ? `<p><a href="${escapeHtml14(event.replayHref)}">Open replay</a></p>` : "",
10610
10735
  "</article>"
10611
10736
  ].join("")),
10612
10737
  "</div>"
@@ -10638,7 +10763,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
10638
10763
  var createVoiceHandoffHealthRoutes = (options = {}) => {
10639
10764
  const path = options.path ?? "/api/voice-handoffs";
10640
10765
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
10641
- const routes = new Elysia10({
10766
+ const routes = new Elysia11({
10642
10767
  name: options.name ?? "absolutejs-voice-handoff-health"
10643
10768
  }).get(path, createVoiceHandoffHealthJSONHandler(options));
10644
10769
  if (htmlPath) {
@@ -10759,17 +10884,17 @@ var evaluateVoiceQuality = async (input) => {
10759
10884
  thresholds
10760
10885
  };
10761
10886
  };
10762
- var escapeHtml14 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10887
+ var escapeHtml15 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10763
10888
  var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
10764
10889
  var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
10765
10890
  var renderVoiceQualityHTML = (report, options = {}) => {
10766
- const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml14(metric.label)}</td><td>${escapeHtml14(formatMetricValue(metric))}</td><td>${escapeHtml14(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml14(key)}</code></td></tr>`).join("");
10767
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml14(link.href)}">${escapeHtml14(link.label)}</a>`).join("")}</nav>` : "";
10891
+ const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml15(metric.label)}</td><td>${escapeHtml15(formatMetricValue(metric))}</td><td>${escapeHtml15(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml15(key)}</code></td></tr>`).join("");
10892
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml15(link.href)}">${escapeHtml15(link.label)}</a>`).join("")}</nav>` : "";
10768
10893
  return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>AbsoluteJS Voice Quality</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1100px;margin:auto}nav{display:flex;flex-wrap:wrap;gap:.5rem;margin:0 0 1.25rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;padding:.35rem .75rem;font-weight:800}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}table{border-collapse:collapse;width:100%;background:white;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}.pass td{border-left:4px solid #16a34a}.fail td{border-left:4px solid #dc2626}code{background:#f3f4f6;padding:.15rem .3rem;border-radius:.3rem}</style></head><body><main>${links}<h1>Voice quality gates</h1><p class="status ${report.status}">${report.status}</p><p>${report.eventCount} event(s) checked.</p><table><thead><tr><th>Metric</th><th>Actual</th><th>Threshold</th><th>Status</th><th>Key</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
10769
10894
  };
10770
10895
  var createVoiceQualityRoutes = (options) => {
10771
10896
  const path = options.path ?? "/quality";
10772
- const routes = new Elysia11({
10897
+ const routes = new Elysia12({
10773
10898
  name: options.name ?? "absolutejs-voice-quality"
10774
10899
  });
10775
10900
  const getReport = () => evaluateVoiceQuality({
@@ -10798,7 +10923,7 @@ var createVoiceQualityRoutes = (options) => {
10798
10923
  };
10799
10924
 
10800
10925
  // src/evalRoutes.ts
10801
- var escapeHtml15 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10926
+ var escapeHtml16 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10802
10927
  var rate2 = (count, total) => count / Math.max(1, total);
10803
10928
  var normalizeSearchText = (value) => value.trim().toLowerCase();
10804
10929
  var getString8 = (value) => typeof value === "string" ? value : undefined;
@@ -11107,44 +11232,44 @@ var formatTime = (value) => value === undefined ? "unknown" : new Date(value).to
11107
11232
  var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
11108
11233
  var renderVoiceEvalHTML = (report, options = {}) => {
11109
11234
  const title = options.title ?? "AbsoluteJS Voice Evals";
11110
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml15(link.href)}">${escapeHtml15(link.label)}</a>`).join("")}</nav>` : "";
11111
- const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml15(bucket.key)}</td><td>${bucket.total}</td><td>${bucket.passed}</td><td>${bucket.failed}</td></tr>`).join("") : '<tr><td colspan="4">No eval buckets yet.</td></tr>';
11235
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml16(link.href)}">${escapeHtml16(link.label)}</a>`).join("")}</nav>` : "";
11236
+ const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml16(bucket.key)}</td><td>${bucket.total}</td><td>${bucket.passed}</td><td>${bucket.failed}</td></tr>`).join("") : '<tr><td colspan="4">No eval buckets yet.</td></tr>';
11112
11237
  const sessions = report.sessions.length ? report.sessions.map((session) => {
11113
11238
  const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
11114
- return `<tr class="${session.status}"><td>${escapeHtml15(session.sessionId)}</td><td>${escapeHtml15(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml15(formatTime(session.endedAt))}</td><td>${escapeHtml15(failedMetrics || "none")}</td></tr>`;
11239
+ return `<tr class="${session.status}"><td>${escapeHtml16(session.sessionId)}</td><td>${escapeHtml16(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml16(formatTime(session.endedAt))}</td><td>${escapeHtml16(failedMetrics || "none")}</td></tr>`;
11115
11240
  }).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
11116
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{color:#166534}.fail{color:#991b1b}.status.pass{background:#dcfce7}.status.fail{background:#fee2e2}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}table{border-collapse:collapse;background:white;width:100%;margin:1rem 0 2rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml15(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div><h2>Trend</h2><table><thead><tr><th>Day</th><th>Total</th><th>Passed</th><th>Failed</th></tr></thead><tbody>${trend}</tbody></table><h2>Session Eval Results</h2><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Last event</th><th>Failed metrics</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
11241
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml16(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{color:#166534}.fail{color:#991b1b}.status.pass{background:#dcfce7}.status.fail{background:#fee2e2}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}table{border-collapse:collapse;background:white;width:100%;margin:1rem 0 2rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml16(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div><h2>Trend</h2><table><thead><tr><th>Day</th><th>Total</th><th>Passed</th><th>Failed</th></tr></thead><tbody>${trend}</tbody></table><h2>Session Eval Results</h2><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Last event</th><th>Failed metrics</th></tr></thead><tbody>${sessions}</tbody></table></main></body></html>`;
11117
11242
  };
11118
11243
  var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
11119
11244
  const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
11120
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml15(link.href)}">${escapeHtml15(link.label)}</a>`).join("")}</nav>` : "";
11121
- const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml15(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
11122
- const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml15(id)}</li>`).join("") : "<li>none</li>";
11123
- const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml15(id)}</li>`).join("") : "<li>none</li>";
11124
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1000px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{background:#dcfce7;color:#166534}.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}section{background:white;border:1px solid #e7e5e4;border-radius:1rem;margin:1rem 0;padding:1rem}</style></head><body><main>${links}<h1>${escapeHtml15(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml15(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml15(formatPercent(comparison.current.passRate))}</strong></article><article class="card"><span>Failed delta</span><strong>${comparison.deltas.failed}</strong></article><article class="card"><span>Pass rate delta</span><strong>${escapeHtml15(formatPercent(comparison.deltas.passRate))}</strong></article></div><section><h2>Regression Reasons</h2><ul>${reasons}</ul></section><section><h2>New Failed Sessions</h2><ul>${newFailures}</ul></section><section><h2>Recovered Sessions</h2><ul>${recovered}</ul></section></main></body></html>`;
11245
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml16(link.href)}">${escapeHtml16(link.label)}</a>`).join("")}</nav>` : "";
11246
+ const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml16(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
11247
+ const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml16(id)}</li>`).join("") : "<li>none</li>";
11248
+ const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml16(id)}</li>`).join("") : "<li>none</li>";
11249
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml16(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1000px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.pass{background:#dcfce7;color:#166534}.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}section{background:white;border:1px solid #e7e5e4;border-radius:1rem;margin:1rem 0;padding:1rem}</style></head><body><main>${links}<h1>${escapeHtml16(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml16(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml16(formatPercent(comparison.current.passRate))}</strong></article><article class="card"><span>Failed delta</span><strong>${comparison.deltas.failed}</strong></article><article class="card"><span>Pass rate delta</span><strong>${escapeHtml16(formatPercent(comparison.deltas.passRate))}</strong></article></div><section><h2>Regression Reasons</h2><ul>${reasons}</ul></section><section><h2>New Failed Sessions</h2><ul>${newFailures}</ul></section><section><h2>Recovered Sessions</h2><ul>${recovered}</ul></section></main></body></html>`;
11125
11250
  };
11126
11251
  var renderVoiceScenarioEvalHTML = (report, options = {}) => {
11127
11252
  const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
11128
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml15(link.href)}">${escapeHtml15(link.label)}</a>`).join("")}</nav>` : "";
11253
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml16(link.href)}">${escapeHtml16(link.label)}</a>`).join("")}</nav>` : "";
11129
11254
  const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
11130
- const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml15(issue)}</li>`).join("")}</ul>` : "";
11131
- const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml15(session.sessionId)}</td><td>${escapeHtml15(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml15(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
11132
- return `<section class="scenario ${scenario.status}"><h2>${escapeHtml15(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml15(scenario.description)}</p>` : ""}<p class="status ${scenario.status}">${scenario.status}</p><p>${scenario.passed} passed, ${scenario.failed} failed, ${scenario.matchedSessions} matched.</p>${scenarioIssues}<table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Issues</th></tr></thead><tbody>${sessions}</tbody></table></section>`;
11255
+ const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml16(issue)}</li>`).join("")}</ul>` : "";
11256
+ const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml16(session.sessionId)}</td><td>${escapeHtml16(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml16(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
11257
+ return `<section class="scenario ${scenario.status}"><h2>${escapeHtml16(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml16(scenario.description)}</p>` : ""}<p class="status ${scenario.status}">${scenario.status}</p><p>${scenario.passed} passed, ${scenario.failed} failed, ${scenario.matchedSessions} matched.</p>${scenarioIssues}<table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Issues</th></tr></thead><tbody>${sessions}</tbody></table></section>`;
11133
11258
  }).join("") : "<section><p>No scenarios configured.</p></section>";
11134
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml15(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${scenarios}</main></body></html>`;
11259
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml16(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml16(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${scenarios}</main></body></html>`;
11135
11260
  };
11136
11261
  var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
11137
11262
  const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
11138
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml15(link.href)}">${escapeHtml15(link.label)}</a>`).join("")}</nav>` : "";
11263
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml16(link.href)}">${escapeHtml16(link.label)}</a>`).join("")}</nav>` : "";
11139
11264
  const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
11140
- const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml15(scenario.label)}</td><td>${escapeHtml15(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml15([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
11141
- return `<section class="${fixture.status}"><h2>${escapeHtml15(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml15(fixture.description)}</p>` : ""}<p class="status ${fixture.status}">${fixture.status}</p><table><thead><tr><th>Scenario</th><th>Status</th><th>Sessions</th><th>Issues</th></tr></thead><tbody>${scenarios}</tbody></table></section>`;
11265
+ const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml16(scenario.label)}</td><td>${escapeHtml16(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml16([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
11266
+ return `<section class="${fixture.status}"><h2>${escapeHtml16(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml16(fixture.description)}</p>` : ""}<p class="status ${fixture.status}">${fixture.status}</p><table><thead><tr><th>Scenario</th><th>Status</th><th>Sessions</th><th>Issues</th></tr></thead><tbody>${scenarios}</tbody></table></section>`;
11142
11267
  }).join("") : "<section><p>No scenario fixtures configured.</p></section>";
11143
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml15(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${fixtures}</main></body></html>`;
11268
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml16(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;margin:2rem;background:#f8f7f2;color:#181713}main{max-width:1180px;margin:auto}nav{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}nav a{background:#181713;border-radius:999px;color:white;padding:.35rem .7rem;text-decoration:none}.status{border-radius:999px;display:inline-flex;font-weight:800;padding:.35rem .75rem}.status.pass{background:#dcfce7;color:#166534}.status.fail{background:#fee2e2;color:#991b1b}.grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:1rem 0}.card,section{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.card strong{display:block;font-size:2rem}section{margin:1rem 0}table{border-collapse:collapse;width:100%;margin-top:1rem}td,th{border-bottom:1px solid #eee;padding:.75rem;text-align:left}tr.fail td{border-left:4px solid #dc2626}tr.pass td{border-left:4px solid #16a34a}</style></head><body><main>${links}<h1>${escapeHtml16(title)}</h1><p class="status ${report.status}">${report.status}</p><div class="grid"><article class="card"><span>Total</span><strong>${report.total}</strong></article><article class="card"><span>Passed</span><strong>${report.passed}</strong></article><article class="card"><span>Failed</span><strong>${report.failed}</strong></article></div>${fixtures}</main></body></html>`;
11144
11269
  };
11145
11270
  var createVoiceEvalRoutes = (options) => {
11146
11271
  const path = options.path ?? "/evals";
11147
- const routes = new Elysia12({
11272
+ const routes = new Elysia13({
11148
11273
  name: options.name ?? "absolutejs-voice-evals"
11149
11274
  });
11150
11275
  const getReport = () => runVoiceSessionEvals({
@@ -11278,11 +11403,11 @@ var createVoiceEvalRoutes = (options) => {
11278
11403
  return routes;
11279
11404
  };
11280
11405
  // src/simulationSuite.ts
11281
- import { Elysia as Elysia15 } from "elysia";
11406
+ import { Elysia as Elysia16 } from "elysia";
11282
11407
 
11283
11408
  // src/outcomeContract.ts
11284
- import { Elysia as Elysia13 } from "elysia";
11285
- var escapeHtml16 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11409
+ import { Elysia as Elysia14 } from "elysia";
11410
+ var escapeHtml17 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11286
11411
  var getPayloadString = (event, key) => typeof event.payload[key] === "string" ? event.payload[key] : undefined;
11287
11412
  var toList = async (input) => Array.isArray(input) ? input : await input?.list() ?? [];
11288
11413
  var hydrateSessions = async (input) => {
@@ -11390,9 +11515,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
11390
11515
  const contracts = report.contracts.map((contract) => `<section class="contract ${contract.pass ? "pass" : "fail"}">
11391
11516
  <div class="contract-header">
11392
11517
  <div>
11393
- <p class="eyebrow">${escapeHtml16(contract.contractId)}</p>
11394
- <h2>${escapeHtml16(contract.label ?? contract.contractId)}</h2>
11395
- ${contract.description ? `<p>${escapeHtml16(contract.description)}</p>` : ""}
11518
+ <p class="eyebrow">${escapeHtml17(contract.contractId)}</p>
11519
+ <h2>${escapeHtml17(contract.label ?? contract.contractId)}</h2>
11520
+ ${contract.description ? `<p>${escapeHtml17(contract.description)}</p>` : ""}
11396
11521
  </div>
11397
11522
  <strong>${contract.pass ? "pass" : "fail"}</strong>
11398
11523
  </div>
@@ -11403,9 +11528,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
11403
11528
  <span>handoffs ${String(contract.matched.handoffs)}</span>
11404
11529
  <span>events ${String(contract.matched.integrationEvents)}</span>
11405
11530
  </div>
11406
- ${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml16(issue.message)}</li>`).join("")}</ul>` : ""}
11531
+ ${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml17(issue.message)}</li>`).join("")}</ul>` : ""}
11407
11532
  </section>`).join("");
11408
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml16(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(14,165,233,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary,.grid{display:flex;flex-wrap:wrap;gap:10px}.pill,.grid span{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}li{margin:8px 0}@media(max-width:800px){main{padding:18px}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Business Outcome Verification</p><h1>${escapeHtml16(title)}</h1><div class="summary"><span class="pill ${report.status}">${report.status}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section>${contracts || '<section class="contract"><p>No outcome contracts configured.</p></section>'}</main></body></html>`;
11533
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml17(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(14,165,233,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary,.grid{display:flex;flex-wrap:wrap;gap:10px}.pill,.grid span{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}li{margin:8px 0}@media(max-width:800px){main{padding:18px}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Business Outcome Verification</p><h1>${escapeHtml17(title)}</h1><div class="summary"><span class="pill ${report.status}">${report.status}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section>${contracts || '<section class="contract"><p>No outcome contracts configured.</p></section>'}</main></body></html>`;
11409
11534
  };
11410
11535
  var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
11411
11536
  var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
@@ -11421,7 +11546,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
11421
11546
  var createVoiceOutcomeContractRoutes = (options) => {
11422
11547
  const path = options.path ?? "/api/outcome-contracts";
11423
11548
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
11424
- const routes = new Elysia13({
11549
+ const routes = new Elysia14({
11425
11550
  name: options.name ?? "absolutejs-voice-outcome-contracts"
11426
11551
  }).get(path, createVoiceOutcomeContractJSONHandler(options));
11427
11552
  if (htmlPath) {
@@ -11431,7 +11556,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
11431
11556
  };
11432
11557
 
11433
11558
  // src/toolContract.ts
11434
- import { Elysia as Elysia14 } from "elysia";
11559
+ import { Elysia as Elysia15 } from "elysia";
11435
11560
 
11436
11561
  // src/toolRuntime.ts
11437
11562
  var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
@@ -11640,7 +11765,7 @@ var createDefaultTurn = (caseId) => ({
11640
11765
  });
11641
11766
  var defaultApi = {};
11642
11767
  var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
11643
- var escapeHtml17 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11768
+ var escapeHtml18 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11644
11769
  var evaluateExpectation = (input) => {
11645
11770
  const issues = [];
11646
11771
  const expect = input.expect;
@@ -11806,19 +11931,19 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
11806
11931
  const title = options.title ?? "Voice Tool Contracts";
11807
11932
  const contracts = report.contracts.map((contract) => {
11808
11933
  const cases = contract.cases.map((testCase) => `<tr>
11809
- <td>${escapeHtml17(testCase.label ?? testCase.caseId)}</td>
11934
+ <td>${escapeHtml18(testCase.label ?? testCase.caseId)}</td>
11810
11935
  <td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
11811
- <td>${escapeHtml17(testCase.status)}</td>
11936
+ <td>${escapeHtml18(testCase.status)}</td>
11812
11937
  <td>${String(testCase.attempts)}</td>
11813
11938
  <td>${String(testCase.elapsedMs)}ms</td>
11814
11939
  <td>${testCase.timedOut ? "yes" : "no"}</td>
11815
- <td>${escapeHtml17(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
11940
+ <td>${escapeHtml18(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
11816
11941
  </tr>`).join("");
11817
11942
  return `<section class="contract ${contract.pass ? "pass" : "fail"}">
11818
11943
  <div class="contract-header">
11819
11944
  <div>
11820
- <p class="eyebrow">${escapeHtml17(contract.toolName)}</p>
11821
- <h2>${escapeHtml17(contract.label ?? contract.contractId)}</h2>
11945
+ <p class="eyebrow">${escapeHtml18(contract.toolName)}</p>
11946
+ <h2>${escapeHtml18(contract.label ?? contract.contractId)}</h2>
11822
11947
  </div>
11823
11948
  <strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
11824
11949
  </div>
@@ -11828,7 +11953,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
11828
11953
  </table>
11829
11954
  </section>`;
11830
11955
  }).join("");
11831
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml17(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(245,158,11,.12))}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}h2{margin:.2rem 0 1rem}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left;vertical-align:top}th{color:#a8b0b8;font-size:.82rem}@media(max-width:800px){main{padding:18px}table{display:block;overflow:auto}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Tool Reliability</p><h1>${escapeHtml17(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml17(report.status)}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section>${contracts || '<section class="contract"><p>No tool contracts configured.</p></section>'}</main></body></html>`;
11956
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml18(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.contract{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.14),rgba(245,158,11,.12))}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.contract-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}h2{margin:.2rem 0 1rem}.pass{color:#86efac}.fail{color:#fca5a5}.contract.fail{border-color:rgba(248,113,113,.45)}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left;vertical-align:top}th{color:#a8b0b8;font-size:.82rem}@media(max-width:800px){main{padding:18px}table{display:block;overflow:auto}.contract-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Tool Reliability</p><h1>${escapeHtml18(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml18(report.status)}</span><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} contracts</span></div></section>${contracts || '<section class="contract"><p>No tool contracts configured.</p></section>'}</main></body></html>`;
11832
11957
  };
11833
11958
  var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
11834
11959
  var createVoiceToolContractHTMLHandler = (options) => async () => {
@@ -11845,7 +11970,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
11845
11970
  var createVoiceToolContractRoutes = (options) => {
11846
11971
  const path = options.path ?? "/api/tool-contracts";
11847
11972
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
11848
- const routes = new Elysia14({
11973
+ const routes = new Elysia15({
11849
11974
  name: options.name ?? "absolutejs-voice-tool-contracts"
11850
11975
  }).get(path, createVoiceToolContractJSONHandler(options));
11851
11976
  if (htmlPath) {
@@ -11855,7 +11980,7 @@ var createVoiceToolContractRoutes = (options) => {
11855
11980
  };
11856
11981
 
11857
11982
  // src/simulationSuite.ts
11858
- var escapeHtml18 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11983
+ var escapeHtml19 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11859
11984
  var summarizeSection = (report) => ({
11860
11985
  failed: report.failed,
11861
11986
  passed: report.passed,
@@ -11991,20 +12116,20 @@ var renderSection = (label, summary) => {
11991
12116
  if (!summary) {
11992
12117
  return "";
11993
12118
  }
11994
- return `<article class="${escapeHtml18(summary.status)}"><span>${escapeHtml18(label)}</span><strong>${escapeHtml18(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
12119
+ return `<article class="${escapeHtml19(summary.status)}"><span>${escapeHtml19(label)}</span><strong>${escapeHtml19(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
11995
12120
  };
11996
12121
  var renderAction = (action) => {
11997
- const content = `<strong>${escapeHtml18(action.label)}</strong><p>${escapeHtml18(action.description)}</p><span>${escapeHtml18(action.section)} / ${escapeHtml18(action.severity)}</span>`;
11998
- return action.href ? `<a class="action" href="${escapeHtml18(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
12122
+ const content = `<strong>${escapeHtml19(action.label)}</strong><p>${escapeHtml19(action.description)}</p><span>${escapeHtml19(action.section)} / ${escapeHtml19(action.severity)}</span>`;
12123
+ return action.href ? `<a class="action" href="${escapeHtml19(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
11999
12124
  };
12000
12125
  var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
12001
12126
  const title = options.title ?? "Voice Simulation Suite";
12002
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml18(title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(59,130,246,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid,.actions{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin:18px 0}.grid article,.action{background:#151d27;border:1px solid #283544;border-radius:18px;color:inherit;padding:16px;text-decoration:none}.grid span,.action span{color:#aab5c0}.grid strong{display:block;font-size:2rem;margin:.25rem 0;text-transform:uppercase}.action strong{display:block;color:#f8f3e7;margin-bottom:.35rem}.action p{color:#d8dee6;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml18(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml18(report.status)}">Status: ${escapeHtml18(report.status)}</p><section class="grid">${renderSection("Sessions", report.summary.sessions)}${renderSection("Scenarios", report.summary.scenarios)}${renderSection("Fixtures", report.summary.fixtures)}${renderSection("Tools", report.summary.tools)}${renderSection("Outcomes", report.summary.outcomes)}</section></section><h2>Actions</h2><section class="actions">${report.actions.length > 0 ? report.actions.map(renderAction).join("") : '<article class="action"><strong>No action required</strong><p>All enabled simulation sections are passing.</p></article>'}</section><pre>${escapeHtml18(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
12127
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(59,130,246,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid,.actions{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin:18px 0}.grid article,.action{background:#151d27;border:1px solid #283544;border-radius:18px;color:inherit;padding:16px;text-decoration:none}.grid span,.action span{color:#aab5c0}.grid strong{display:block;font-size:2rem;margin:.25rem 0;text-transform:uppercase}.action strong{display:block;color:#f8f3e7;margin-bottom:.35rem}.action p{color:#d8dee6;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml19(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml19(report.status)}">Status: ${escapeHtml19(report.status)}</p><section class="grid">${renderSection("Sessions", report.summary.sessions)}${renderSection("Scenarios", report.summary.scenarios)}${renderSection("Fixtures", report.summary.fixtures)}${renderSection("Tools", report.summary.tools)}${renderSection("Outcomes", report.summary.outcomes)}</section></section><h2>Actions</h2><section class="actions">${report.actions.length > 0 ? report.actions.map(renderAction).join("") : '<article class="action"><strong>No action required</strong><p>All enabled simulation sections are passing.</p></article>'}</section><pre>${escapeHtml19(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
12003
12128
  };
12004
12129
  var createVoiceSimulationSuiteRoutes = (options) => {
12005
12130
  const path = options.path ?? "/api/voice/simulations";
12006
12131
  const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
12007
- const app = new Elysia15({
12132
+ const app = new Elysia16({
12008
12133
  name: options.name ?? "absolutejs-voice-simulation-suite"
12009
12134
  }).get(path, () => runVoiceSimulationSuite(options));
12010
12135
  if (htmlPath) {
@@ -12316,9 +12441,9 @@ var createVoiceWorkflowContractHandler = (input) => {
12316
12441
  };
12317
12442
  };
12318
12443
  // src/sessionReplay.ts
12319
- import { Elysia as Elysia16 } from "elysia";
12444
+ import { Elysia as Elysia17 } from "elysia";
12320
12445
  var getString9 = (value) => typeof value === "string" ? value : undefined;
12321
- var escapeHtml19 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12446
+ var escapeHtml20 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12322
12447
  var increment4 = (record, key) => {
12323
12448
  record[key] = (record[key] ?? 0) + 1;
12324
12449
  };
@@ -12477,10 +12602,10 @@ var summarizeVoiceSessions = async (options = {}) => {
12477
12602
  var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
12478
12603
  '<div class="voice-sessions-list">',
12479
12604
  ...sessions.map((session) => [
12480
- `<article class="voice-session-card ${escapeHtml19(session.status)}">`,
12605
+ `<article class="voice-session-card ${escapeHtml20(session.status)}">`,
12481
12606
  '<div class="voice-session-card-header">',
12482
- `<strong>${escapeHtml19(session.sessionId)}</strong>`,
12483
- `<span>${escapeHtml19(session.status)}</span>`,
12607
+ `<strong>${escapeHtml20(session.sessionId)}</strong>`,
12608
+ `<span>${escapeHtml20(session.status)}</span>`,
12484
12609
  "</div>",
12485
12610
  "<dl>",
12486
12611
  `<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
@@ -12488,9 +12613,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
12488
12613
  `<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
12489
12614
  `<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
12490
12615
  "</dl>",
12491
- session.latestOutcome ? `<p>Outcome: ${escapeHtml19(session.latestOutcome)}</p>` : "",
12492
- session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml19).join(", ")}</p>` : "",
12493
- session.replayHref ? `<p><a href="${escapeHtml19(session.replayHref)}">Open replay</a></p>` : "",
12616
+ session.latestOutcome ? `<p>Outcome: ${escapeHtml20(session.latestOutcome)}</p>` : "",
12617
+ session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml20).join(", ")}</p>` : "",
12618
+ session.replayHref ? `<p><a href="${escapeHtml20(session.replayHref)}">Open replay</a></p>` : "",
12494
12619
  "</article>"
12495
12620
  ].join("")),
12496
12621
  "</div>"
@@ -12521,7 +12646,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
12521
12646
  var createVoiceSessionListRoutes = (options = {}) => {
12522
12647
  const path = options.path ?? "/api/voice-sessions";
12523
12648
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
12524
- const routes = new Elysia16({
12649
+ const routes = new Elysia17({
12525
12650
  name: options.name ?? "absolutejs-voice-session-list"
12526
12651
  }).get(path, createVoiceSessionsJSONHandler(options));
12527
12652
  if (htmlPath) {
@@ -12549,7 +12674,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
12549
12674
  var createVoiceSessionReplayRoutes = (options) => {
12550
12675
  const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
12551
12676
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
12552
- const routes = new Elysia16({
12677
+ const routes = new Elysia17({
12553
12678
  name: options.name ?? "absolutejs-voice-session-replay"
12554
12679
  }).get(path, createVoiceSessionReplayJSONHandler(options));
12555
12680
  if (htmlPath) {
@@ -12716,10 +12841,10 @@ var assertVoiceAgentSquadContract = async (options) => {
12716
12841
  return report;
12717
12842
  };
12718
12843
  // src/turnLatency.ts
12719
- import { Elysia as Elysia17 } from "elysia";
12844
+ import { Elysia as Elysia18 } from "elysia";
12720
12845
  var DEFAULT_WARN_AFTER_MS = 1800;
12721
12846
  var DEFAULT_FAIL_AFTER_MS = 3200;
12722
- var escapeHtml20 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12847
+ var escapeHtml21 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12723
12848
  var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
12724
12849
  var getString10 = (value) => typeof value === "string" && value.trim() ? value : undefined;
12725
12850
  var createTraceStageIndex = (events) => {
@@ -12833,11 +12958,11 @@ var summarizeVoiceTurnLatency = async (options) => {
12833
12958
  var formatMs = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
12834
12959
  var renderVoiceTurnLatencyHTML = (report, options = {}) => {
12835
12960
  const title = options.title ?? "Voice Turn Latency";
12836
- const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml20(turn.status)}">
12837
- <header><div><p class="eyebrow">${escapeHtml20(turn.sessionId)} \xB7 ${escapeHtml20(turn.turnId)}</p><h2>${escapeHtml20(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml20(turn.status)}</strong></header>
12838
- <dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml20(stage.label)}</dt><dd>${escapeHtml20(formatMs(stage.valueMs))}</dd></div>`).join("")}</dl>
12961
+ const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml21(turn.status)}">
12962
+ <header><div><p class="eyebrow">${escapeHtml21(turn.sessionId)} \xB7 ${escapeHtml21(turn.turnId)}</p><h2>${escapeHtml21(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml21(turn.status)}</strong></header>
12963
+ <dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml21(stage.label)}</dt><dd>${escapeHtml21(formatMs(stage.valueMs))}</dd></div>`).join("")}</dl>
12839
12964
  </article>`).join("");
12840
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml20(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(251,191,36,.1))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.turn header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{font-weight:900;margin:0}@media(max-width:800px){main{padding:18px}.turn header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">End-to-end responsiveness</p><h1>${escapeHtml20(title)}</h1><div class="summary"><span class="pill ${escapeHtml20(report.status)}">${escapeHtml20(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml20(formatMs(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
12965
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(251,191,36,.1))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.turn header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{font-weight:900;margin:0}@media(max-width:800px){main{padding:18px}.turn header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">End-to-end responsiveness</p><h1>${escapeHtml21(title)}</h1><div class="summary"><span class="pill ${escapeHtml21(report.status)}">${escapeHtml21(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml21(formatMs(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
12841
12966
  };
12842
12967
  var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
12843
12968
  var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
@@ -12854,7 +12979,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
12854
12979
  var createVoiceTurnLatencyRoutes = (options) => {
12855
12980
  const path = options.path ?? "/api/turn-latency";
12856
12981
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
12857
- const routes = new Elysia17({
12982
+ const routes = new Elysia18({
12858
12983
  name: options.name ?? "absolutejs-voice-turn-latency"
12859
12984
  }).get(path, createVoiceTurnLatencyJSONHandler(options));
12860
12985
  if (htmlPath) {
@@ -12863,8 +12988,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
12863
12988
  return routes;
12864
12989
  };
12865
12990
  // src/liveLatency.ts
12866
- import { Elysia as Elysia18 } from "elysia";
12867
- var escapeHtml21 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12991
+ import { Elysia as Elysia19 } from "elysia";
12992
+ var escapeHtml22 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12868
12993
  var percentile = (values, percentileValue) => {
12869
12994
  if (values.length === 0) {
12870
12995
  return;
@@ -12912,13 +13037,13 @@ var summarizeVoiceLiveLatency = async (options) => {
12912
13037
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
12913
13038
  var renderVoiceLiveLatencyHTML = (report, options = {}) => {
12914
13039
  const title = options.title ?? "Voice Live Latency";
12915
- const rows = report.recent.map((sample) => `<tr><td>${escapeHtml21(sample.sessionId)}</td><td>${escapeHtml21(formatMs2(sample.latencyMs))}</td><td>${escapeHtml21(sample.status ?? "unknown")}</td><td>${escapeHtml21(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
12916
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(245,158,11,.1));border:1px solid #26313d;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;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fbbf24}.fail{color:#fca5a5}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:18px 0}.metrics article,table{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #26313d;padding:12px;text-align:left}@media(max-width:760px){main{padding:20px}}</style></head><body><main><section class="hero"><p class="eyebrow">Browser proof</p><h1>${escapeHtml21(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml21(report.status)}">Status: ${escapeHtml21(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml21(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml21(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml21(formatMs2(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></section><table><thead><tr><th>Session</th><th>Latency</th><th>Status</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="4">No live latency samples yet.</td></tr>'}</tbody></table></main></body></html>`;
13040
+ const rows = report.recent.map((sample) => `<tr><td>${escapeHtml22(sample.sessionId)}</td><td>${escapeHtml22(formatMs2(sample.latencyMs))}</td><td>${escapeHtml22(sample.status ?? "unknown")}</td><td>${escapeHtml22(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
13041
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml22(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(94,234,212,.16),rgba(245,158,11,.1));border:1px solid #26313d;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;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fbbf24}.fail{color:#fca5a5}.metrics{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin:18px 0}.metrics article,table{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #26313d;padding:12px;text-align:left}@media(max-width:760px){main{padding:20px}}</style></head><body><main><section class="hero"><p class="eyebrow">Browser proof</p><h1>${escapeHtml22(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml22(report.status)}">Status: ${escapeHtml22(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml22(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml22(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml22(formatMs2(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></section><table><thead><tr><th>Session</th><th>Latency</th><th>Status</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="4">No live latency samples yet.</td></tr>'}</tbody></table></main></body></html>`;
12917
13042
  };
12918
13043
  var createVoiceLiveLatencyRoutes = (options) => {
12919
13044
  const path = options.path ?? "/api/live-latency";
12920
13045
  const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
12921
- const routes = new Elysia18({
13046
+ const routes = new Elysia19({
12922
13047
  name: options.name ?? "absolutejs-voice-live-latency"
12923
13048
  }).get(path, () => summarizeVoiceLiveLatency(options));
12924
13049
  if (htmlPath) {
@@ -12935,9 +13060,9 @@ var createVoiceLiveLatencyRoutes = (options) => {
12935
13060
  return routes;
12936
13061
  };
12937
13062
  // src/turnQuality.ts
12938
- import { Elysia as Elysia19 } from "elysia";
13063
+ import { Elysia as Elysia20 } from "elysia";
12939
13064
  var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
12940
- var escapeHtml22 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13065
+ var escapeHtml23 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12941
13066
  var getTurnLatencyMs = (turn) => {
12942
13067
  const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
12943
13068
  if (firstTranscriptAt === undefined) {
@@ -13008,24 +13133,24 @@ var summarizeVoiceTurnQuality = async (options) => {
13008
13133
  };
13009
13134
  var renderVoiceTurnQualityHTML = (report, options = {}) => {
13010
13135
  const title = options.title ?? "Voice Turn Quality";
13011
- const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml22(turn.status)}">
13136
+ const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml23(turn.status)}">
13012
13137
  <div class="turn-header">
13013
13138
  <div>
13014
- <p class="eyebrow">${escapeHtml22(turn.sessionId)} \xB7 ${escapeHtml22(turn.turnId)}</p>
13015
- <h2>${escapeHtml22(turn.text || "Empty turn")}</h2>
13139
+ <p class="eyebrow">${escapeHtml23(turn.sessionId)} \xB7 ${escapeHtml23(turn.turnId)}</p>
13140
+ <h2>${escapeHtml23(turn.text || "Empty turn")}</h2>
13016
13141
  </div>
13017
- <strong>${escapeHtml22(turn.status)}</strong>
13142
+ <strong>${escapeHtml23(turn.status)}</strong>
13018
13143
  </div>
13019
13144
  <dl>
13020
- <div><dt>Source</dt><dd>${escapeHtml22(turn.source ?? "unknown")}</dd></div>
13145
+ <div><dt>Source</dt><dd>${escapeHtml23(turn.source ?? "unknown")}</dd></div>
13021
13146
  <div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
13022
- <div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml22(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
13023
- <div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml22(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
13147
+ <div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml23(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
13148
+ <div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml23(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
13024
13149
  <div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
13025
13150
  <div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
13026
13151
  </dl>
13027
13152
  </article>`).join("");
13028
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml22(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(251,191,36,.16),rgba(34,197,94,.1))}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.turn-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.unknown{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.turn-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime STT Debugging</p><h1>${escapeHtml22(title)}</h1><div class="summary"><span class="pill ${escapeHtml22(report.status)}">${escapeHtml22(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span><span class="pill">${String(report.sessions)} sessions</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
13153
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml23(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.turn{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(251,191,36,.16),rgba(34,197,94,.1))}.eyebrow{color:#fbbf24;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.turn-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass{color:#86efac}.warn,.unknown{color:#fde68a}.fail{color:#fca5a5}.turn.fail{border-color:rgba(248,113,113,.45)}dl{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.turn-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Realtime STT Debugging</p><h1>${escapeHtml23(title)}</h1><div class="summary"><span class="pill ${escapeHtml23(report.status)}">${escapeHtml23(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span><span class="pill">${String(report.sessions)} sessions</span></div></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
13029
13154
  };
13030
13155
  var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
13031
13156
  var createVoiceTurnQualityHTMLHandler = (options) => async () => {
@@ -13042,7 +13167,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
13042
13167
  var createVoiceTurnQualityRoutes = (options) => {
13043
13168
  const path = options.path ?? "/api/turn-quality";
13044
13169
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
13045
- const routes = new Elysia19({
13170
+ const routes = new Elysia20({
13046
13171
  name: options.name ?? "absolutejs-voice-turn-quality"
13047
13172
  }).get(path, createVoiceTurnQualityJSONHandler(options));
13048
13173
  if (htmlPath) {
@@ -13051,7 +13176,7 @@ var createVoiceTurnQualityRoutes = (options) => {
13051
13176
  return routes;
13052
13177
  };
13053
13178
  // src/telephonyOutcome.ts
13054
- import { Elysia as Elysia20 } from "elysia";
13179
+ import { Elysia as Elysia21 } from "elysia";
13055
13180
  var DEFAULT_COMPLETED_STATUSES = [
13056
13181
  "answered",
13057
13182
  "completed",
@@ -13701,7 +13826,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
13701
13826
  var createVoiceTelephonyWebhookRoutes = (options = {}) => {
13702
13827
  const path = options.path ?? "/api/voice/telephony/webhook";
13703
13828
  const handler = createVoiceTelephonyWebhookHandler(options);
13704
- return new Elysia20({
13829
+ return new Elysia21({
13705
13830
  name: options.name ?? "absolutejs-voice-telephony-webhooks"
13706
13831
  }).post(path, async ({ query, request }) => {
13707
13832
  try {
@@ -13722,11 +13847,11 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
13722
13847
  });
13723
13848
  };
13724
13849
  // src/phoneAgent.ts
13725
- import { Elysia as Elysia26 } from "elysia";
13850
+ import { Elysia as Elysia27 } from "elysia";
13726
13851
 
13727
13852
  // src/telephony/plivo.ts
13728
13853
  import { Buffer as Buffer5 } from "buffer";
13729
- import { Elysia as Elysia22 } from "elysia";
13854
+ import { Elysia as Elysia23 } from "elysia";
13730
13855
 
13731
13856
  // src/telephony/contract.ts
13732
13857
  var DEFAULT_REQUIREMENTS = [
@@ -13810,7 +13935,7 @@ var evaluateVoiceTelephonyContract = (input) => {
13810
13935
 
13811
13936
  // src/telephony/twilio.ts
13812
13937
  import { Buffer as Buffer4 } from "buffer";
13813
- import { Elysia as Elysia21 } from "elysia";
13938
+ import { Elysia as Elysia22 } from "elysia";
13814
13939
  var TWILIO_MULAW_SAMPLE_RATE = 8000;
13815
13940
  var VOICE_PCM_SAMPLE_RATE = 16000;
13816
13941
  var escapeXml2 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
@@ -13840,7 +13965,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
13840
13965
  return parameters;
13841
13966
  };
13842
13967
  var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
13843
- var escapeHtml23 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
13968
+ var escapeHtml24 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
13844
13969
  var getWebhookVerificationUrl = (webhook, input) => {
13845
13970
  if (!webhook?.verificationUrl) {
13846
13971
  return;
@@ -13883,23 +14008,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
13883
14008
  };
13884
14009
  var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
13885
14010
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
13886
- <h1>${escapeHtml23(title)}</h1>
14011
+ <h1>${escapeHtml24(title)}</h1>
13887
14012
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
13888
14013
  <section>
13889
14014
  <h2>URLs</h2>
13890
14015
  <ul>
13891
- <li><strong>TwiML:</strong> <code>${escapeHtml23(status.urls.twiml)}</code></li>
13892
- <li><strong>Media stream:</strong> <code>${escapeHtml23(status.urls.stream)}</code></li>
13893
- <li><strong>Status webhook:</strong> <code>${escapeHtml23(status.urls.webhook)}</code></li>
14016
+ <li><strong>TwiML:</strong> <code>${escapeHtml24(status.urls.twiml)}</code></li>
14017
+ <li><strong>Media stream:</strong> <code>${escapeHtml24(status.urls.stream)}</code></li>
14018
+ <li><strong>Status webhook:</strong> <code>${escapeHtml24(status.urls.webhook)}</code></li>
13894
14019
  </ul>
13895
14020
  </section>
13896
14021
  <section>
13897
14022
  <h2>Signing</h2>
13898
14023
  <p>Mode: <code>${status.signing.mode}</code></p>
13899
- ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml23(status.signing.verificationUrl)}</code></p>` : ""}
14024
+ ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml24(status.signing.verificationUrl)}</code></p>` : ""}
13900
14025
  </section>
13901
- ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml23(name)}</code></li>`).join("")}</ul></section>` : ""}
13902
- ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml23(warning)}</li>`).join("")}</ul></section>` : ""}
14026
+ ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml24(name)}</code></li>`).join("")}</ul></section>` : ""}
14027
+ ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml24(warning)}</li>`).join("")}</ul></section>` : ""}
13903
14028
  </main>`;
13904
14029
  var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&amp;", "&");
13905
14030
  var createSmokeCheck = (name, status, message, details) => ({
@@ -13910,20 +14035,20 @@ var createSmokeCheck = (name, status, message, details) => ({
13910
14035
  });
13911
14036
  var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
13912
14037
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
13913
- <h1>${escapeHtml23(title)}</h1>
14038
+ <h1>${escapeHtml24(title)}</h1>
13914
14039
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
13915
14040
  <section>
13916
14041
  <h2>Checks</h2>
13917
14042
  <ul>
13918
- ${report.checks.map((check) => `<li><strong>${escapeHtml23(check.name)}</strong>: ${escapeHtml23(check.status)}${check.message ? ` - ${escapeHtml23(check.message)}` : ""}</li>`).join("")}
14043
+ ${report.checks.map((check) => `<li><strong>${escapeHtml24(check.name)}</strong>: ${escapeHtml24(check.status)}${check.message ? ` - ${escapeHtml24(check.message)}` : ""}</li>`).join("")}
13919
14044
  </ul>
13920
14045
  </section>
13921
14046
  <section>
13922
14047
  <h2>Observed URLs</h2>
13923
14048
  <ul>
13924
- <li><strong>TwiML:</strong> <code>${escapeHtml23(report.setup.urls.twiml)}</code></li>
13925
- <li><strong>Stream:</strong> <code>${escapeHtml23(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
13926
- <li><strong>Webhook:</strong> <code>${escapeHtml23(report.setup.urls.webhook)}</code></li>
14049
+ <li><strong>TwiML:</strong> <code>${escapeHtml24(report.setup.urls.twiml)}</code></li>
14050
+ <li><strong>Stream:</strong> <code>${escapeHtml24(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
14051
+ <li><strong>Webhook:</strong> <code>${escapeHtml24(report.setup.urls.webhook)}</code></li>
13927
14052
  </ul>
13928
14053
  </section>
13929
14054
  </main>`;
@@ -14383,7 +14508,7 @@ var createTwilioVoiceRoutes = (options) => {
14383
14508
  const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
14384
14509
  const bridges = new WeakMap;
14385
14510
  const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
14386
- const app = new Elysia21({
14511
+ const app = new Elysia22({
14387
14512
  name: options.name ?? "absolutejs-voice-twilio"
14388
14513
  }).get(twimlPath, async ({ query, request }) => {
14389
14514
  const streamUrl = await resolveTwilioStreamUrl(options, {
@@ -14520,7 +14645,7 @@ var createTwilioVoiceRoutes = (options) => {
14520
14645
 
14521
14646
  // src/telephony/plivo.ts
14522
14647
  var escapeXml3 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
14523
- var escapeHtml24 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
14648
+ var escapeHtml25 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
14524
14649
  var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
14525
14650
  var resolveRequestOrigin2 = (request) => {
14526
14651
  const url = new URL(request.url);
@@ -14771,21 +14896,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
14771
14896
  };
14772
14897
  var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
14773
14898
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
14774
- <h1>${escapeHtml24(title)}</h1>
14899
+ <h1>${escapeHtml25(title)}</h1>
14775
14900
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
14776
14901
  <ul>
14777
- <li><strong>Answer XML:</strong> <code>${escapeHtml24(status.urls.answer)}</code></li>
14778
- <li><strong>Audio stream:</strong> <code>${escapeHtml24(status.urls.stream)}</code></li>
14779
- <li><strong>Status webhook:</strong> <code>${escapeHtml24(status.urls.webhook)}</code></li>
14902
+ <li><strong>Answer XML:</strong> <code>${escapeHtml25(status.urls.answer)}</code></li>
14903
+ <li><strong>Audio stream:</strong> <code>${escapeHtml25(status.urls.stream)}</code></li>
14904
+ <li><strong>Status webhook:</strong> <code>${escapeHtml25(status.urls.webhook)}</code></li>
14780
14905
  </ul>
14781
- ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml24(name)}</code></li>`).join("")}</ul>` : ""}
14782
- ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml24(warning)}</li>`).join("")}</ul>` : ""}
14906
+ ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml25(name)}</code></li>`).join("")}</ul>` : ""}
14907
+ ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml25(warning)}</li>`).join("")}</ul>` : ""}
14783
14908
  </main>`;
14784
14909
  var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
14785
14910
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
14786
- <h1>${escapeHtml24(title)}</h1>
14911
+ <h1>${escapeHtml25(title)}</h1>
14787
14912
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
14788
- <ul>${report.checks.map((check) => `<li><strong>${escapeHtml24(check.name)}</strong>: ${escapeHtml24(check.status)}${check.message ? ` - ${escapeHtml24(check.message)}` : ""}</li>`).join("")}</ul>
14913
+ <ul>${report.checks.map((check) => `<li><strong>${escapeHtml25(check.name)}</strong>: ${escapeHtml25(check.status)}${check.message ? ` - ${escapeHtml25(check.message)}` : ""}</li>`).join("")}</ul>
14789
14914
  </main>`;
14790
14915
  var runPlivoSmokeTest = async (input) => {
14791
14916
  const setup = await buildPlivoVoiceSetupStatus(input.options, input);
@@ -14880,7 +15005,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
14880
15005
  request: input.request
14881
15006
  }) : verificationUrl ?? input.request.url
14882
15007
  }) : undefined);
14883
- const app = new Elysia22({
15008
+ const app = new Elysia23({
14884
15009
  name: options.name ?? "absolutejs-voice-plivo"
14885
15010
  }).get(answerPath, async ({ query, request }) => {
14886
15011
  const streamUrl = await resolvePlivoStreamUrl(options, {
@@ -14991,9 +15116,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
14991
15116
 
14992
15117
  // src/telephony/telnyx.ts
14993
15118
  import { Buffer as Buffer6 } from "buffer";
14994
- import { Elysia as Elysia23 } from "elysia";
15119
+ import { Elysia as Elysia24 } from "elysia";
14995
15120
  var escapeXml4 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
14996
- var escapeHtml25 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
15121
+ var escapeHtml26 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
14997
15122
  var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
14998
15123
  var resolveRequestOrigin3 = (request) => {
14999
15124
  const url = new URL(request.url);
@@ -15194,21 +15319,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
15194
15319
  };
15195
15320
  var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
15196
15321
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
15197
- <h1>${escapeHtml25(title)}</h1>
15322
+ <h1>${escapeHtml26(title)}</h1>
15198
15323
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
15199
15324
  <ul>
15200
- <li><strong>TeXML:</strong> <code>${escapeHtml25(status.urls.texml)}</code></li>
15201
- <li><strong>Media stream:</strong> <code>${escapeHtml25(status.urls.stream)}</code></li>
15202
- <li><strong>Status webhook:</strong> <code>${escapeHtml25(status.urls.webhook)}</code></li>
15325
+ <li><strong>TeXML:</strong> <code>${escapeHtml26(status.urls.texml)}</code></li>
15326
+ <li><strong>Media stream:</strong> <code>${escapeHtml26(status.urls.stream)}</code></li>
15327
+ <li><strong>Status webhook:</strong> <code>${escapeHtml26(status.urls.webhook)}</code></li>
15203
15328
  </ul>
15204
- ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml25(name)}</code></li>`).join("")}</ul>` : ""}
15205
- ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml25(warning)}</li>`).join("")}</ul>` : ""}
15329
+ ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml26(name)}</code></li>`).join("")}</ul>` : ""}
15330
+ ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml26(warning)}</li>`).join("")}</ul>` : ""}
15206
15331
  </main>`;
15207
15332
  var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
15208
15333
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
15209
- <h1>${escapeHtml25(title)}</h1>
15334
+ <h1>${escapeHtml26(title)}</h1>
15210
15335
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
15211
- <ul>${report.checks.map((check) => `<li><strong>${escapeHtml25(check.name)}</strong>: ${escapeHtml25(check.status)}${check.message ? ` - ${escapeHtml25(check.message)}` : ""}</li>`).join("")}</ul>
15336
+ <ul>${report.checks.map((check) => `<li><strong>${escapeHtml26(check.name)}</strong>: ${escapeHtml26(check.status)}${check.message ? ` - ${escapeHtml26(check.message)}` : ""}</li>`).join("")}</ul>
15212
15337
  </main>`;
15213
15338
  var runTelnyxSmokeTest = async (input) => {
15214
15339
  const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
@@ -15302,7 +15427,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
15302
15427
  publicKey: options.webhook?.publicKey,
15303
15428
  toleranceSeconds: options.webhook?.toleranceSeconds
15304
15429
  }) : undefined);
15305
- const app = new Elysia23({
15430
+ const app = new Elysia24({
15306
15431
  name: options.name ?? "absolutejs-voice-telnyx"
15307
15432
  }).get(texmlPath, async ({ query, request }) => {
15308
15433
  const streamUrl = await resolveTelnyxStreamUrl(options, {
@@ -15412,8 +15537,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
15412
15537
  };
15413
15538
 
15414
15539
  // src/telephony/matrix.ts
15415
- import { Elysia as Elysia24 } from "elysia";
15416
- var escapeHtml26 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
15540
+ import { Elysia as Elysia25 } from "elysia";
15541
+ var escapeHtml27 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
15417
15542
  var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
15418
15543
  var resolveEntryStatus = (contract, setup, smoke) => {
15419
15544
  if (!contract.pass || !setup.ready || smoke?.pass === false) {
@@ -15474,13 +15599,13 @@ var badgeStyles = {
15474
15599
  };
15475
15600
  var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
15476
15601
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
15477
- <h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml26(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
15602
+ <h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml27(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
15478
15603
  <p style="color:#52606d; margin: 0 0 24px;">${matrix.summary.ready}/${matrix.summary.providers} ready, ${matrix.summary.contractsPassing}/${matrix.summary.providers} contract passing, ${matrix.summary.smokePassing}/${matrix.summary.providers} smoke passing.</p>
15479
15604
  <section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
15480
15605
  ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; border-radius:18px; padding:18px; background:#fff; box-shadow:0 18px 48px rgba(15,23,42,.08);">
15481
15606
  <div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
15482
- <h2 style="margin:0; font-size:20px;">${escapeHtml26(entry.name)}</h2>
15483
- <span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml26(entry.status.toUpperCase())}</span>
15607
+ <h2 style="margin:0; font-size:20px;">${escapeHtml27(entry.name)}</h2>
15608
+ <span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml27(entry.status.toUpperCase())}</span>
15484
15609
  </div>
15485
15610
  <dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
15486
15611
  <dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
@@ -15488,15 +15613,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
15488
15613
  <dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
15489
15614
  <dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
15490
15615
  </dl>
15491
- <p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml26(entry.setup.urls.stream || "missing")}</code></p>
15492
- <p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml26(entry.setup.urls.webhook || "missing")}</code></p>
15493
- ${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml26(issue.severity)}: ${escapeHtml26(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
15616
+ <p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml27(entry.setup.urls.stream || "missing")}</code></p>
15617
+ <p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml27(entry.setup.urls.webhook || "missing")}</code></p>
15618
+ ${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml27(issue.severity)}: ${escapeHtml27(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
15494
15619
  </article>`).join("")}
15495
15620
  </section>
15496
15621
  </main>`;
15497
15622
  var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
15498
15623
  const path = options.path ?? "/api/voice/telephony/carriers";
15499
- return new Elysia24({
15624
+ return new Elysia25({
15500
15625
  name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
15501
15626
  }).get(path, async ({ query, request }) => {
15502
15627
  const providers = await options.load({ query, request });
@@ -15518,7 +15643,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
15518
15643
  };
15519
15644
 
15520
15645
  // src/phoneAgentProductionSmoke.ts
15521
- import { Elysia as Elysia25 } from "elysia";
15646
+ import { Elysia as Elysia26 } from "elysia";
15522
15647
  var defaultRequirements = [
15523
15648
  "media-started",
15524
15649
  "transcript",
@@ -15526,7 +15651,7 @@ var defaultRequirements = [
15526
15651
  "lifecycle-outcome",
15527
15652
  "no-session-error"
15528
15653
  ];
15529
- var escapeHtml27 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
15654
+ var escapeHtml28 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
15530
15655
  var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
15531
15656
  var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
15532
15657
  const value = event.payload[key];
@@ -15635,10 +15760,10 @@ var resolveHandlerOptions = async (options, input) => ({
15635
15760
  });
15636
15761
  var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
15637
15762
  const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
15638
- const issues = report.issues.map((issue) => `<li><strong>${escapeHtml27(issue.requirement)}</strong>: ${escapeHtml27(issue.message)}</li>`).join("");
15639
- const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml27(outcome)}</span>`).join("");
15640
- const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml27(requirement)}</span>`).join("");
15641
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml27(title)}</title><style>body{background:#0e141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1050px;padding:32px}.hero,.panel{background:#151d26;border:1px solid #283544;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.metric{background:#0f151d;border:1px solid #283544;border-radius:16px;padding:14px}.metric strong{display:block;font-size:1.8rem}.pill{background:#0f151d;border:1px solid #3f3f46;border-radius:999px;display:inline-flex;margin:4px;padding:7px 10px}.issues{color:#fca5a5}code{color:#fde68a}@media(max-width:720px){main{padding:18px}}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent production smoke</p><h1>${escapeHtml27(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml27(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml27(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml27(report.sessionId)}</code>` : ""}.</p></section><section class="panel"><h2>Observed Trace Evidence</h2><div class="grid"><div class="metric"><span>Media starts</span><strong>${String(report.observed.mediaStarts)}</strong></div><div class="metric"><span>Transcripts</span><strong>${String(report.observed.transcripts)}</strong></div><div class="metric"><span>Assistant responses</span><strong>${String(report.observed.assistantResponses)}</strong></div><div class="metric"><span>Session errors</span><strong>${String(report.observed.sessionErrors)}</strong></div></div><p>${outcomes || '<span class="pill">No lifecycle outcome</span>'}</p></section><section class="panel"><h2>Requirements</h2><p>${requirements}</p>${issues ? `<ul class="issues">${issues}</ul>` : '<p class="pass">All required phone-agent smoke evidence is present.</p>'}</section></main></body></html>`;
15763
+ const issues = report.issues.map((issue) => `<li><strong>${escapeHtml28(issue.requirement)}</strong>: ${escapeHtml28(issue.message)}</li>`).join("");
15764
+ const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml28(outcome)}</span>`).join("");
15765
+ const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml28(requirement)}</span>`).join("");
15766
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml28(title)}</title><style>body{background:#0e141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1050px;padding:32px}.hero,.panel{background:#151d26;border:1px solid #283544;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.metric{background:#0f151d;border:1px solid #283544;border-radius:16px;padding:14px}.metric strong{display:block;font-size:1.8rem}.pill{background:#0f151d;border:1px solid #3f3f46;border-radius:999px;display:inline-flex;margin:4px;padding:7px 10px}.issues{color:#fca5a5}code{color:#fde68a}@media(max-width:720px){main{padding:18px}}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent production smoke</p><h1>${escapeHtml28(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml28(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml28(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml28(report.sessionId)}</code>` : ""}.</p></section><section class="panel"><h2>Observed Trace Evidence</h2><div class="grid"><div class="metric"><span>Media starts</span><strong>${String(report.observed.mediaStarts)}</strong></div><div class="metric"><span>Transcripts</span><strong>${String(report.observed.transcripts)}</strong></div><div class="metric"><span>Assistant responses</span><strong>${String(report.observed.assistantResponses)}</strong></div><div class="metric"><span>Session errors</span><strong>${String(report.observed.sessionErrors)}</strong></div></div><p>${outcomes || '<span class="pill">No lifecycle outcome</span>'}</p></section><section class="panel"><h2>Requirements</h2><p>${requirements}</p>${issues ? `<ul class="issues">${issues}</ul>` : '<p class="pass">All required phone-agent smoke evidence is present.</p>'}</section></main></body></html>`;
15642
15767
  };
15643
15768
  var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
15644
15769
  query,
@@ -15661,7 +15786,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
15661
15786
  var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
15662
15787
  const path = options.path ?? "/api/voice/phone/smoke-contract";
15663
15788
  const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
15664
- const routes = new Elysia25({
15789
+ const routes = new Elysia26({
15665
15790
  name: options.name ?? "absolutejs-voice-phone-smoke-contract"
15666
15791
  }).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
15667
15792
  if (htmlPath) {
@@ -15704,7 +15829,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
15704
15829
  "completed",
15705
15830
  "failed"
15706
15831
  ];
15707
- var escapeHtml28 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
15832
+ var escapeHtml29 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
15708
15833
  var loadRouteJson = async (input) => {
15709
15834
  const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
15710
15835
  headers: {
@@ -15764,18 +15889,18 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
15764
15889
  const entry = report.matrix?.entries.find((candidate) => candidate.provider === carrier.provider && (candidate.name === carrier.name || candidate.name === (carrier.name ?? carrier.provider)));
15765
15890
  const urls = entry?.setup.urls;
15766
15891
  const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
15767
- return `<tr><td>${escapeHtml28(carrier.name ?? carrier.provider)}</td><td>${escapeHtml28(carrier.provider)}</td><td><code>${escapeHtml28(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml28(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml28(entry.status)}">${escapeHtml28(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml28(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml28(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml28(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
15892
+ return `<tr><td>${escapeHtml29(carrier.name ?? carrier.provider)}</td><td>${escapeHtml29(carrier.provider)}</td><td><code>${escapeHtml29(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml29(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml29(entry.status)}">${escapeHtml29(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml29(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml29(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml29(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
15768
15893
  }).join("");
15769
- const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml28(stage)}</code></li>`).join("");
15894
+ const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml29(stage)}</code></li>`).join("");
15770
15895
  const checklist = report.carriers.map((carrier) => {
15771
15896
  const entry = report.matrix?.entries.find((candidate) => candidate.provider === carrier.provider && (candidate.name === carrier.name || candidate.name === (carrier.name ?? carrier.provider)));
15772
15897
  const urls = entry?.setup.urls;
15773
15898
  const answerLabel = carrier.provider === "telnyx" ? "TeXML URL" : carrier.provider === "plivo" ? "Answer URL" : "TwiML URL";
15774
15899
  const answerUrl = urls?.twiml;
15775
- const issueList = entry?.issues.map((issue) => `<li>${escapeHtml28(issue.severity)}: ${escapeHtml28(issue.message)}</li>`).join("") ?? "";
15776
- return `<article><h3>${escapeHtml28(carrier.name ?? carrier.provider)}</h3><ol><li>Set ${escapeHtml28(answerLabel)} to <code>${escapeHtml28(answerUrl ?? "missing")}</code>.</li><li>Set status webhook to <code>${escapeHtml28(urls?.webhook ?? "missing")}</code>.</li><li>Allow media stream URL <code>${escapeHtml28(urls?.stream ?? "missing")}</code>.</li><li>Open setup: ${carrier.setupPath ? `<a href="${escapeHtml28(carrier.setupPath)}?format=html">${escapeHtml28(carrier.setupPath)}</a>` : '<span class="muted">disabled</span>'}.</li><li>Run smoke: ${carrier.smokePath ? `<a href="${escapeHtml28(carrier.smokePath)}?format=html">${escapeHtml28(carrier.smokePath)}</a>` : '<span class="muted">disabled</span>'}.</li>${report.productionSmokePath ? `<li>Certify production smoke traces: <a href="${escapeHtml28(report.productionSmokePath.replace("/api/", "/"))}?sessionId=">${escapeHtml28(report.productionSmokePath)}</a>.</li>` : ""}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
15900
+ const issueList = entry?.issues.map((issue) => `<li>${escapeHtml29(issue.severity)}: ${escapeHtml29(issue.message)}</li>`).join("") ?? "";
15901
+ return `<article><h3>${escapeHtml29(carrier.name ?? carrier.provider)}</h3><ol><li>Set ${escapeHtml29(answerLabel)} to <code>${escapeHtml29(answerUrl ?? "missing")}</code>.</li><li>Set status webhook to <code>${escapeHtml29(urls?.webhook ?? "missing")}</code>.</li><li>Allow media stream URL <code>${escapeHtml29(urls?.stream ?? "missing")}</code>.</li><li>Open setup: ${carrier.setupPath ? `<a href="${escapeHtml29(carrier.setupPath)}?format=html">${escapeHtml29(carrier.setupPath)}</a>` : '<span class="muted">disabled</span>'}.</li><li>Run smoke: ${carrier.smokePath ? `<a href="${escapeHtml29(carrier.smokePath)}?format=html">${escapeHtml29(carrier.smokePath)}</a>` : '<span class="muted">disabled</span>'}.</li>${report.productionSmokePath ? `<li>Certify production smoke traces: <a href="${escapeHtml29(report.productionSmokePath.replace("/api/", "/"))}?sessionId=">${escapeHtml29(report.productionSmokePath)}</a>.</li>` : ""}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
15777
15902
  }).join("");
15778
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml28(report.title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;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.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.warn{color:#fde68a}.muted{color:#aab5c0}table{background:#151d27;border:1px solid #283544;border-collapse:collapse;border-radius:18px;display:block;overflow:auto;width:100%}td,th{border-bottom:1px solid #283544;padding:12px;text-align:left;vertical-align:top}code{color:#fde68a;overflow-wrap:anywhere}.checklist{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));margin:18px 0}.checklist article{background:#151d27;border:1px solid #283544;border-radius:18px;padding:18px}.checklist ol{padding-left:20px}.issues{color:#fca5a5}.stages{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));padding-left:18px}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent setup</p><h1>${escapeHtml28(report.title)}</h1><p>One self-hosted entrypoint for carrier routes, setup reports, smoke checks, and normalized call lifecycle stages.</p><p class="badge ${report.ready ? "pass" : "fail"}">Ready: ${String(report.ready)}</p>${report.matrixPath ? `<p><a href="${escapeHtml28(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</section><h2>Carrier Setup Checklist</h2><section class="checklist">${checklist}</section><h2>Carrier URLs</h2><table><thead><tr><th>Name</th><th>Provider</th><th>Setup</th><th>Smoke</th><th>Status</th><th>Answer/TwiML/TeXML</th><th>Webhook</th><th>Stream</th></tr></thead><tbody>${carrierRows}</tbody></table><h2>Lifecycle Schema</h2><ul class="stages">${stageList}</ul></main></body></html>`;
15903
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml29(report.title)}</title><style>body{background:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;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.3rem,6vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.badge{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;padding:8px 12px}.pass{color:#86efac}.fail{color:#fca5a5}.warn{color:#fde68a}.muted{color:#aab5c0}table{background:#151d27;border:1px solid #283544;border-collapse:collapse;border-radius:18px;display:block;overflow:auto;width:100%}td,th{border-bottom:1px solid #283544;padding:12px;text-align:left;vertical-align:top}code{color:#fde68a;overflow-wrap:anywhere}.checklist{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));margin:18px 0}.checklist article{background:#151d27;border:1px solid #283544;border-radius:18px;padding:18px}.checklist ol{padding-left:20px}.issues{color:#fca5a5}.stages{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));padding-left:18px}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Phone agent setup</p><h1>${escapeHtml29(report.title)}</h1><p>One self-hosted entrypoint for carrier routes, setup reports, smoke checks, and normalized call lifecycle stages.</p><p class="badge ${report.ready ? "pass" : "fail"}">Ready: ${String(report.ready)}</p>${report.matrixPath ? `<p><a href="${escapeHtml29(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</section><h2>Carrier Setup Checklist</h2><section class="checklist">${checklist}</section><h2>Carrier URLs</h2><table><thead><tr><th>Name</th><th>Provider</th><th>Setup</th><th>Smoke</th><th>Status</th><th>Answer/TwiML/TeXML</th><th>Webhook</th><th>Stream</th></tr></thead><tbody>${carrierRows}</tbody></table><h2>Lifecycle Schema</h2><ul class="stages">${stageList}</ul></main></body></html>`;
15779
15904
  };
15780
15905
  var createVoicePhoneAgent = (options) => {
15781
15906
  const carrierSummaries = options.carriers.map((carrier) => ({
@@ -15784,7 +15909,7 @@ var createVoicePhoneAgent = (options) => {
15784
15909
  setupPath: resolveSetupPath(carrier),
15785
15910
  smokePath: resolveSmokePath(carrier)
15786
15911
  }));
15787
- const app = new Elysia26({
15912
+ const app = new Elysia27({
15788
15913
  name: options.name ?? "absolutejs-voice-phone-agent"
15789
15914
  });
15790
15915
  for (const carrier of options.carriers) {
@@ -17243,8 +17368,8 @@ var phraseHintPrompt = (options) => {
17243
17368
  hint.text,
17244
17369
  ...hint.aliases ?? []
17245
17370
  ]);
17246
- const unique = terms.filter((value, index) => terms.indexOf(value) === index);
17247
- return unique.length ? `Prioritize accurate recovery of these phrases when heard: ${unique.join(", ")}.` : undefined;
17371
+ const unique2 = terms.filter((value, index) => terms.indexOf(value) === index);
17372
+ return unique2.length ? `Prioritize accurate recovery of these phrases when heard: ${unique2.join(", ")}.` : undefined;
17248
17373
  };
17249
17374
  var lexiconPrompt = (options) => {
17250
17375
  const entries = (options.lexicon ?? []).flatMap((entry) => {
@@ -17796,8 +17921,8 @@ var createOpenAIVoiceTTS = (options) => {
17796
17921
  };
17797
17922
  };
17798
17923
  // src/providerCapabilities.ts
17799
- import { Elysia as Elysia27 } from "elysia";
17800
- var escapeHtml29 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
17924
+ import { Elysia as Elysia28 } from "elysia";
17925
+ var escapeHtml30 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
17801
17926
  var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
17802
17927
  configured: true,
17803
17928
  features: options.features?.[provider],
@@ -17860,27 +17985,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
17860
17985
  var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
17861
17986
  const title = options.title ?? "Voice Provider Capabilities";
17862
17987
  const cards = report.capabilities.map((capability) => {
17863
- const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml29(feature)}</span>`).join("");
17864
- return `<article class="card ${escapeHtml29(capability.status)}">
17988
+ const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml30(feature)}</span>`).join("");
17989
+ return `<article class="card ${escapeHtml30(capability.status)}">
17865
17990
  <div class="card-header">
17866
17991
  <div>
17867
- <p class="eyebrow">${escapeHtml29(capability.kind)}</p>
17868
- <h2>${escapeHtml29(capability.label ?? capability.provider)}</h2>
17992
+ <p class="eyebrow">${escapeHtml30(capability.kind)}</p>
17993
+ <h2>${escapeHtml30(capability.label ?? capability.provider)}</h2>
17869
17994
  </div>
17870
- <strong>${escapeHtml29(capability.status)}</strong>
17995
+ <strong>${escapeHtml30(capability.status)}</strong>
17871
17996
  </div>
17872
- ${capability.description ? `<p>${escapeHtml29(capability.description)}</p>` : ""}
17997
+ ${capability.description ? `<p>${escapeHtml30(capability.description)}</p>` : ""}
17873
17998
  <dl>
17874
17999
  <div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
17875
18000
  <div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
17876
- <div><dt>Model</dt><dd>${escapeHtml29(capability.model ?? "default")}</dd></div>
18001
+ <div><dt>Model</dt><dd>${escapeHtml30(capability.model ?? "default")}</dd></div>
17877
18002
  <div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
17878
18003
  <div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
17879
18004
  </dl>
17880
18005
  ${features ? `<div class="features">${features}</div>` : ""}
17881
18006
  </article>`;
17882
18007
  }).join("");
17883
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml29(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.16),rgba(34,197,94,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary,.features{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.selected,.healthy{color:#86efac}.unconfigured,.degraded,.rate-limited,.suppressed{color:#fca5a5}.idle,.recoverable{color:#fde68a}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Discovery</p><h1>${escapeHtml29(title)}</h1><div class="summary"><span class="pill">${String(report.configured)} configured</span><span class="pill">${String(report.selected)} selected</span><span class="pill">${String(report.unconfigured)} missing</span><span class="pill">${String(report.total)} total</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider capabilities configured.</p></article>'}</section></main></body></html>`;
18008
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml30(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#181d22;border:1px solid #2a323a;border-radius:20px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.16),rgba(34,197,94,.12))}.eyebrow{color:#7dd3fc;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0 1rem}.summary,.features{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f1217;border:1px solid #3f3f46;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.selected,.healthy{color:#86efac}.unconfigured,.degraded,.rate-limited,.suppressed{color:#fca5a5}.idle,.recoverable{color:#fde68a}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Discovery</p><h1>${escapeHtml30(title)}</h1><div class="summary"><span class="pill">${String(report.configured)} configured</span><span class="pill">${String(report.selected)} selected</span><span class="pill">${String(report.unconfigured)} missing</span><span class="pill">${String(report.total)} total</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider capabilities configured.</p></article>'}</section></main></body></html>`;
17884
18009
  };
17885
18010
  var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
17886
18011
  var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
@@ -17897,7 +18022,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
17897
18022
  var createVoiceProviderCapabilityRoutes = (options) => {
17898
18023
  const path = options.path ?? "/api/provider-capabilities";
17899
18024
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
17900
- const routes = new Elysia27({
18025
+ const routes = new Elysia28({
17901
18026
  name: options.name ?? "absolutejs-voice-provider-capabilities"
17902
18027
  }).get(path, createVoiceProviderCapabilityJSONHandler(options));
17903
18028
  if (htmlPath) {
@@ -17906,8 +18031,8 @@ var createVoiceProviderCapabilityRoutes = (options) => {
17906
18031
  return routes;
17907
18032
  };
17908
18033
  // src/resilienceRoutes.ts
17909
- import { Elysia as Elysia28 } from "elysia";
17910
- var escapeHtml30 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
18034
+ import { Elysia as Elysia29 } from "elysia";
18035
+ var escapeHtml31 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
17911
18036
  var getString11 = (value) => typeof value === "string" ? value : undefined;
17912
18037
  var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
17913
18038
  var getBoolean2 = (value) => value === true;
@@ -18054,13 +18179,13 @@ var summarizeRoutingEvents = (events) => {
18054
18179
  };
18055
18180
  var renderProviderCards = (title, providers) => {
18056
18181
  if (providers.length === 0) {
18057
- return `<p class="muted">No ${escapeHtml30(title)} provider health yet.</p>`;
18182
+ return `<p class="muted">No ${escapeHtml31(title)} provider health yet.</p>`;
18058
18183
  }
18059
18184
  return `<div class="provider-grid">${providers.map((provider) => `
18060
- <article class="card provider ${escapeHtml30(provider.status)}">
18185
+ <article class="card provider ${escapeHtml31(provider.status)}">
18061
18186
  <div class="card-header">
18062
- <strong>${escapeHtml30(provider.provider)}</strong>
18063
- <span>${escapeHtml30(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
18187
+ <strong>${escapeHtml31(provider.provider)}</strong>
18188
+ <span>${escapeHtml31(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
18064
18189
  </div>
18065
18190
  <dl>
18066
18191
  <div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
@@ -18069,7 +18194,7 @@ var renderProviderCards = (title, providers) => {
18069
18194
  <div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
18070
18195
  <div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
18071
18196
  </dl>
18072
- ${provider.lastError ? `<p class="muted">${escapeHtml30(provider.lastError)}</p>` : ""}
18197
+ ${provider.lastError ? `<p class="muted">${escapeHtml31(provider.lastError)}</p>` : ""}
18073
18198
  </article>
18074
18199
  `).join("")}</div>`;
18075
18200
  };
@@ -18078,24 +18203,24 @@ var renderTimeline2 = (events) => {
18078
18203
  return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
18079
18204
  }
18080
18205
  return `<div class="timeline">${events.slice(0, 40).map((event) => `
18081
- <article class="card event ${escapeHtml30(event.status ?? "unknown")}">
18206
+ <article class="card event ${escapeHtml31(event.status ?? "unknown")}">
18082
18207
  <div class="card-header">
18083
- <strong>${escapeHtml30(event.kind.toUpperCase())} ${escapeHtml30(event.operation ?? "generate")}</strong>
18208
+ <strong>${escapeHtml31(event.kind.toUpperCase())} ${escapeHtml31(event.operation ?? "generate")}</strong>
18084
18209
  <span>${new Date(event.at).toLocaleString()}</span>
18085
18210
  </div>
18086
18211
  <p>
18087
- <span class="pill">${escapeHtml30(event.status ?? "unknown")}</span>
18088
- <span class="pill">provider: ${escapeHtml30(event.provider ?? "unknown")}</span>
18089
- ${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml30(event.fallbackProvider)}</span>` : ""}
18212
+ <span class="pill">${escapeHtml31(event.status ?? "unknown")}</span>
18213
+ <span class="pill">provider: ${escapeHtml31(event.provider ?? "unknown")}</span>
18214
+ ${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml31(event.fallbackProvider)}</span>` : ""}
18090
18215
  ${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
18091
18216
  </p>
18092
18217
  <dl>
18093
18218
  <div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
18094
18219
  <div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
18095
18220
  <div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
18096
- <div><dt>Session</dt><dd>${escapeHtml30(event.sessionId)}</dd></div>
18221
+ <div><dt>Session</dt><dd>${escapeHtml31(event.sessionId)}</dd></div>
18097
18222
  </dl>
18098
- ${event.error ? `<p class="muted">${escapeHtml30(event.error)}</p>` : ""}
18223
+ ${event.error ? `<p class="muted">${escapeHtml31(event.error)}</p>` : ""}
18099
18224
  </article>
18100
18225
  `).join("")}</div>`;
18101
18226
  };
@@ -18105,9 +18230,9 @@ var renderSessionKind = (kind, summary) => {
18105
18230
  const status = latest?.status ?? "idle";
18106
18231
  const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
18107
18232
  return `<div>
18108
- <dt>${escapeHtml30(kind.toUpperCase())}</dt>
18109
- <dd>${escapeHtml30(provider)}${escapeHtml30(fallback)}</dd>
18110
- <small>${escapeHtml30(status)} \xB7 ${summary.runCount} event${summary.runCount === 1 ? "" : "s"} \xB7 ${summary.errorCount} error${summary.errorCount === 1 ? "" : "s"} \xB7 ${summary.fallbackCount} fallback${summary.fallbackCount === 1 ? "" : "s"}</small>
18233
+ <dt>${escapeHtml31(kind.toUpperCase())}</dt>
18234
+ <dd>${escapeHtml31(provider)}${escapeHtml31(fallback)}</dd>
18235
+ <small>${escapeHtml31(status)} \xB7 ${summary.runCount} event${summary.runCount === 1 ? "" : "s"} \xB7 ${summary.errorCount} error${summary.errorCount === 1 ? "" : "s"} \xB7 ${summary.fallbackCount} fallback${summary.fallbackCount === 1 ? "" : "s"}</small>
18111
18236
  </div>`;
18112
18237
  };
18113
18238
  var renderSessionSummaries = (sessions) => {
@@ -18115,10 +18240,10 @@ var renderSessionSummaries = (sessions) => {
18115
18240
  return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
18116
18241
  }
18117
18242
  return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
18118
- <article class="card session ${escapeHtml30(session.status)}">
18243
+ <article class="card session ${escapeHtml31(session.status)}">
18119
18244
  <div class="card-header">
18120
- <strong>${escapeHtml30(session.sessionId)}</strong>
18121
- <span>${escapeHtml30(session.status)}</span>
18245
+ <strong>${escapeHtml31(session.sessionId)}</strong>
18246
+ <span>${escapeHtml31(session.status)}</span>
18122
18247
  </div>
18123
18248
  <p>
18124
18249
  <span class="pill">${session.eventCount} routing events</span>
@@ -18145,26 +18270,26 @@ var renderSimulationControls = (kind, simulation) => {
18145
18270
  const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
18146
18271
  const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
18147
18272
  const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
18148
- return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml30(pathPrefix)}">
18149
- <p class="muted">${escapeHtml30(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
18273
+ return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml31(pathPrefix)}">
18274
+ <p class="muted">${escapeHtml31(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
18150
18275
  <div class="simulate-actions">
18151
- ${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml30(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml30(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
18152
- ${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml30(provider.provider)}">Mark ${escapeHtml30(provider.provider)} recovered</button>`).join("")}
18276
+ ${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml31(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml31(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
18277
+ ${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml31(provider.provider)}">Mark ${escapeHtml31(provider.provider)} recovered</button>`).join("")}
18153
18278
  </div>
18154
- ${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml30(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
18279
+ ${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml31(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
18155
18280
  <pre class="simulate-output" hidden></pre>
18156
18281
  </div>`;
18157
18282
  };
18158
18283
  var renderVoiceResilienceHTML = (input) => {
18159
18284
  const summary = summarizeRoutingEvents(input.routingEvents);
18160
- const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml30(kind)}: ${String(count)}</span>`).join("");
18161
- const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml30(link.href)}">${escapeHtml30(link.label)}</a>`).join(" \xB7 ") : "";
18285
+ const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml31(kind)}: ${String(count)}</span>`).join("");
18286
+ const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml31(link.href)}">${escapeHtml31(link.label)}</a>`).join(" \xB7 ") : "";
18162
18287
  return `<!doctype html>
18163
18288
  <html lang="en">
18164
18289
  <head>
18165
18290
  <meta charset="utf-8" />
18166
18291
  <meta name="viewport" content="width=device-width, initial-scale=1" />
18167
- <title>${escapeHtml30(input.title ?? "AbsoluteJS Voice Resilience")}</title>
18292
+ <title>${escapeHtml31(input.title ?? "AbsoluteJS Voice Resilience")}</title>
18168
18293
  <style>
18169
18294
  :root { color-scheme: dark; }
18170
18295
  body { background: radial-gradient(circle at top left, #172554, #09090b 36%, #050505); color: #f4f4f5; font-family: ui-sans-serif, system-ui, sans-serif; margin: 0; padding: 24px; }
@@ -18307,7 +18432,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
18307
18432
  };
18308
18433
  var createVoiceResilienceRoutes = (options) => {
18309
18434
  const path = options.path ?? "/resilience";
18310
- const routes = new Elysia28({
18435
+ const routes = new Elysia29({
18311
18436
  name: options.name ?? "absolutejs-voice-resilience"
18312
18437
  }).get(path, async () => {
18313
18438
  const events = await options.store.list();
@@ -18385,7 +18510,7 @@ var assertVoiceProviderRoutingContract = async (options) => {
18385
18510
  return report;
18386
18511
  };
18387
18512
  // src/productionReadiness.ts
18388
- import { Elysia as Elysia29 } from "elysia";
18513
+ import { Elysia as Elysia30 } from "elysia";
18389
18514
 
18390
18515
  // src/queue.ts
18391
18516
  var releaseLeaseScript = `
@@ -19328,7 +19453,7 @@ var createVoiceOpsTaskProcessorWorkerLoop = (options) => {
19328
19453
  };
19329
19454
 
19330
19455
  // src/productionReadiness.ts
19331
- var escapeHtml31 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19456
+ var escapeHtml32 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19332
19457
  var rollupStatus2 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
19333
19458
  var carrierStatus = (matrix) => matrix.summary.failing > 0 ? "fail" : matrix.summary.warnings > 0 || matrix.summary.ready < matrix.summary.providers ? "warn" : "pass";
19334
19459
  var resolveCarriers = async (options, input) => {
@@ -19834,24 +19959,24 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
19834
19959
  var renderVoiceProductionReadinessHTML = (report, options = {}) => {
19835
19960
  const title = options.title ?? "AbsoluteJS Voice Production Readiness";
19836
19961
  const checks = report.checks.map((check, index) => {
19837
- const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml31(action.href)}">${escapeHtml31(action.label)}</button>` : `<a href="${escapeHtml31(action.href)}">${escapeHtml31(action.label)}</a>`).join("");
19838
- return `<article class="check ${escapeHtml31(check.status)}">
19962
+ const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml32(action.href)}">${escapeHtml32(action.label)}</button>` : `<a href="${escapeHtml32(action.href)}">${escapeHtml32(action.label)}</a>`).join("");
19963
+ return `<article class="check ${escapeHtml32(check.status)}">
19839
19964
  <div>
19840
- <span>${escapeHtml31(check.status.toUpperCase())}</span>
19841
- <h2>${escapeHtml31(check.label)}</h2>
19842
- ${check.detail ? `<p>${escapeHtml31(check.detail)}</p>` : ""}
19965
+ <span>${escapeHtml32(check.status.toUpperCase())}</span>
19966
+ <h2>${escapeHtml32(check.label)}</h2>
19967
+ ${check.detail ? `<p>${escapeHtml32(check.detail)}</p>` : ""}
19843
19968
  ${actions ? `<p class="actions">${actions}</p>` : ""}
19844
19969
  </div>
19845
- <strong>${escapeHtml31(String(check.value ?? check.status))}</strong>
19846
- ${check.href ? `<a href="${escapeHtml31(check.href)}">Open surface</a>` : ""}
19970
+ <strong>${escapeHtml32(String(check.value ?? check.status))}</strong>
19971
+ ${check.href ? `<a href="${escapeHtml32(check.href)}">Open surface</a>` : ""}
19847
19972
  </article>`;
19848
19973
  }).join("");
19849
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml31(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#fbbf24;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{display:inline-flex;border:1px solid #3f3f46;border-radius:999px;padding:8px 12px}.status.pass,.check.pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.warn{border-color:rgba(245,158,11,.65)}.status.fail,.check.fail{border-color:rgba(239,68,68,.75)}.checks{display:grid;gap:14px}.check{align-items:center;background:#141922;border:1px solid #26313d;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.check span{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p{color:#b9c0c8;margin:.2rem 0 0}.check strong{font-size:1.5rem}.actions{display:flex;flex-wrap:wrap;gap:10px}.check a,a{color:#fbbf24}button{background:#fbbf24;border:0;border-radius:999px;color:#111827;cursor:pointer;font-weight:800;padding:9px 12px}button:disabled{cursor:wait;opacity:.65}@media(max-width:760px){main{padding:20px}.check{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted readiness</p><h1>${escapeHtml31(title)}</h1><p>One deployable pass/fail report for quality gates, provider failover, session health, handoffs, routing evidence, and optional carrier readiness.</p><p class="status ${escapeHtml31(report.status)}">Overall: ${escapeHtml31(report.status.toUpperCase())}</p><p>Checked ${escapeHtml31(new Date(report.checkedAt).toLocaleString())}</p></section><section class="checks">${checks}</section></main><script>document.querySelectorAll("[data-readiness-action]").forEach((button)=>{button.addEventListener("click",async()=>{const url=button.getAttribute("data-action-url");if(!url)return;button.disabled=true;const original=button.textContent;button.textContent="Running...";try{const response=await fetch(url,{method:"POST"});button.textContent=response.ok?"Done. Reloading...":"Failed";if(response.ok)setTimeout(()=>location.reload(),500)}catch{button.textContent="Failed"}finally{setTimeout(()=>{button.disabled=false;button.textContent=original},1500)}})});</script></body></html>`;
19974
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#fbbf24;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{display:inline-flex;border:1px solid #3f3f46;border-radius:999px;padding:8px 12px}.status.pass,.check.pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.warn{border-color:rgba(245,158,11,.65)}.status.fail,.check.fail{border-color:rgba(239,68,68,.75)}.checks{display:grid;gap:14px}.check{align-items:center;background:#141922;border:1px solid #26313d;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.check span{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p{color:#b9c0c8;margin:.2rem 0 0}.check strong{font-size:1.5rem}.actions{display:flex;flex-wrap:wrap;gap:10px}.check a,a{color:#fbbf24}button{background:#fbbf24;border:0;border-radius:999px;color:#111827;cursor:pointer;font-weight:800;padding:9px 12px}button:disabled{cursor:wait;opacity:.65}@media(max-width:760px){main{padding:20px}.check{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted readiness</p><h1>${escapeHtml32(title)}</h1><p>One deployable pass/fail report for quality gates, provider failover, session health, handoffs, routing evidence, and optional carrier readiness.</p><p class="status ${escapeHtml32(report.status)}">Overall: ${escapeHtml32(report.status.toUpperCase())}</p><p>Checked ${escapeHtml32(new Date(report.checkedAt).toLocaleString())}</p></section><section class="checks">${checks}</section></main><script>document.querySelectorAll("[data-readiness-action]").forEach((button)=>{button.addEventListener("click",async()=>{const url=button.getAttribute("data-action-url");if(!url)return;button.disabled=true;const original=button.textContent;button.textContent="Running...";try{const response=await fetch(url,{method:"POST"});button.textContent=response.ok?"Done. Reloading...":"Failed";if(response.ok)setTimeout(()=>location.reload(),500)}catch{button.textContent="Failed"}finally{setTimeout(()=>{button.disabled=false;button.textContent=original},1500)}})});</script></body></html>`;
19850
19975
  };
19851
19976
  var createVoiceProductionReadinessRoutes = (options) => {
19852
19977
  const path = options.path ?? "/api/production-readiness";
19853
19978
  const htmlPath = options.htmlPath ?? "/production-readiness";
19854
- const routes = new Elysia29({
19979
+ const routes = new Elysia30({
19855
19980
  name: options.name ?? "absolutejs-voice-production-readiness"
19856
19981
  });
19857
19982
  routes.get(path, async ({ query, request }) => buildVoiceProductionReadinessReport(options, { query, request }));
@@ -19873,7 +19998,7 @@ var createVoiceProductionReadinessRoutes = (options) => {
19873
19998
  return routes;
19874
19999
  };
19875
20000
  // src/opsConsoleRoutes.ts
19876
- import { Elysia as Elysia30 } from "elysia";
20001
+ import { Elysia as Elysia31 } from "elysia";
19877
20002
  var DEFAULT_LINKS = [
19878
20003
  {
19879
20004
  description: "Quality gates for CI, deploy checks, and production readiness.",
@@ -19908,7 +20033,7 @@ var DEFAULT_LINKS = [
19908
20033
  label: "Handoffs"
19909
20034
  }
19910
20035
  ];
19911
- var escapeHtml32 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20036
+ var escapeHtml33 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19912
20037
  var countProviderStatuses = (providers) => {
19913
20038
  const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
19914
20039
  const healthy = providers.filter((provider) => provider.status === "healthy").length;
@@ -19964,20 +20089,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
19964
20089
  trace
19965
20090
  };
19966
20091
  };
19967
- var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml32(input.label)}</span><strong>${escapeHtml32(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml32(input.status)}">${escapeHtml32(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml32(input.href)}">Open</a>` : ""}</article>`;
20092
+ var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml33(input.label)}</span><strong>${escapeHtml33(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml33(input.status)}">${escapeHtml33(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml33(input.href)}">Open</a>` : ""}</article>`;
19968
20093
  var renderVoiceOpsConsoleHTML = (report, options = {}) => {
19969
20094
  const links = report.links.map((link) => `<article class="surface">
19970
- <div><h2>${escapeHtml32(link.label)}</h2>${link.description ? `<p>${escapeHtml32(link.description)}</p>` : ""}</div>
19971
- <p><a href="${escapeHtml32(link.href)}">Open ${escapeHtml32(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml32(link.statusHref)}">Status</a>` : ""}</p>
20095
+ <div><h2>${escapeHtml33(link.label)}</h2>${link.description ? `<p>${escapeHtml33(link.description)}</p>` : ""}</div>
20096
+ <p><a href="${escapeHtml33(link.href)}">Open ${escapeHtml33(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml33(link.statusHref)}">Status</a>` : ""}</p>
19972
20097
  </article>`).join("");
19973
- const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml32(session.sessionId)}</td><td>${escapeHtml32(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml32(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
19974
- const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml32(event.kind)}</td><td>${escapeHtml32(event.provider ?? "unknown")}</td><td>${escapeHtml32(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml32(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
20098
+ const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml33(session.sessionId)}</td><td>${escapeHtml33(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml33(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
20099
+ const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml33(event.kind)}</td><td>${escapeHtml33(event.provider ?? "unknown")}</td><td>${escapeHtml33(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml33(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
19975
20100
  const title = options.title ?? "AbsoluteJS Voice Ops Console";
19976
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(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>${escapeHtml32(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 ${escapeHtml32(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>`;
20101
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml33(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>${escapeHtml33(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 ${escapeHtml33(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>`;
19977
20102
  };
19978
20103
  var createVoiceOpsConsoleRoutes = (options) => {
19979
20104
  const path = options.path ?? "/ops-console";
19980
- const routes = new Elysia30({
20105
+ const routes = new Elysia31({
19981
20106
  name: options.name ?? "absolutejs-voice-ops-console"
19982
20107
  });
19983
20108
  const getReport = () => buildVoiceOpsConsoleReport(options);
@@ -20139,19 +20264,19 @@ var summarizeVoiceOpsStatus = async (options) => {
20139
20264
  };
20140
20265
  };
20141
20266
  // src/opsStatusRoutes.ts
20142
- import { Elysia as Elysia31 } from "elysia";
20143
- var escapeHtml33 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20267
+ import { Elysia as Elysia32 } from "elysia";
20268
+ var escapeHtml34 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20144
20269
  var renderVoiceOpsStatusHTML = (report, options = {}) => {
20145
20270
  const title = options.title ?? "AbsoluteJS Voice Ops Status";
20146
20271
  const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
20147
20272
  const value = "total" in surface ? `${Math.max(surface.total - ("failed" in surface ? surface.failed : ("degraded" in surface) ? surface.degraded : 0), 0)}/${surface.total}` : surface.status;
20148
- return `<article class="surface ${escapeHtml33(surface.status)}"><span>${escapeHtml33(surface.status.toUpperCase())}</span><h2>${escapeHtml33(key)}</h2><strong>${escapeHtml33(value)}</strong></article>`;
20273
+ return `<article class="surface ${escapeHtml34(surface.status)}"><span>${escapeHtml34(surface.status.toUpperCase())}</span><h2>${escapeHtml34(key)}</h2><strong>${escapeHtml34(value)}</strong></article>`;
20149
20274
  }).join("");
20150
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml33(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>${escapeHtml33(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml33(report.status)}">Overall: ${escapeHtml33(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>`;
20275
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml34(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>${escapeHtml34(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml34(report.status)}">Overall: ${escapeHtml34(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>`;
20151
20276
  };
20152
20277
  var createVoiceOpsStatusRoutes = (options) => {
20153
20278
  const path = options.path ?? "/api/voice/ops-status";
20154
- const routes = new Elysia31({
20279
+ const routes = new Elysia32({
20155
20280
  name: options.name ?? "absolutejs-voice-ops-status"
20156
20281
  });
20157
20282
  routes.get(path, async () => summarizeVoiceOpsStatus(options));
@@ -20584,8 +20709,8 @@ var createVoiceTTSProviderRouter = (options) => {
20584
20709
  };
20585
20710
  };
20586
20711
  // src/traceDeliveryRoutes.ts
20587
- import { Elysia as Elysia32 } from "elysia";
20588
- var escapeHtml34 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20712
+ import { Elysia as Elysia33 } from "elysia";
20713
+ var escapeHtml35 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20589
20714
  var getString12 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
20590
20715
  var getNumber7 = (value) => {
20591
20716
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -20666,14 +20791,14 @@ var renderSinkResults2 = (delivery) => {
20666
20791
  if (entries.length === 0) {
20667
20792
  return "<p>No sink delivery attempts recorded yet.</p>";
20668
20793
  }
20669
- return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml34(sinkId)}</strong>: ${escapeHtml34(result.status)}${result.deliveredTo ? ` to ${escapeHtml34(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml34(result.error)})` : ""}</li>`).join("")}</ul>`;
20794
+ return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml35(sinkId)}</strong>: ${escapeHtml35(result.status)}${result.deliveredTo ? ` to ${escapeHtml35(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml35(result.error)})` : ""}</li>`).join("")}</ul>`;
20670
20795
  };
20671
- var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml34(event.type)} <small>${escapeHtml34(event.id)}</small>${event.sessionId ? ` session=${escapeHtml34(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
20796
+ var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml35(event.type)} <small>${escapeHtml35(event.id)}</small>${event.sessionId ? ` session=${escapeHtml35(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
20672
20797
  var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
20673
20798
  const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
20674
- const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml34(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
20675
- const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml34(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml34(delivery.deliveryStatus)}</span><h2>${escapeHtml34(delivery.id)}</h2><p>${escapeHtml34(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml34(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml34(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
20676
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml34(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>${escapeHtml34(title)}</h1><p>Checked ${escapeHtml34(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>`;
20799
+ const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml35(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
20800
+ const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml35(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml35(delivery.deliveryStatus)}</span><h2>${escapeHtml35(delivery.id)}</h2><p>${escapeHtml35(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml35(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml35(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
20801
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml35(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>${escapeHtml35(title)}</h1><p>Checked ${escapeHtml35(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>`;
20677
20802
  };
20678
20803
  var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
20679
20804
  var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
@@ -20693,7 +20818,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
20693
20818
  const path = options.path ?? "/api/voice-trace-deliveries";
20694
20819
  const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
20695
20820
  const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
20696
- const routes = new Elysia32({
20821
+ const routes = new Elysia33({
20697
20822
  name: options.name ?? "absolutejs-voice-trace-deliveries"
20698
20823
  }).get(path, createVoiceTraceDeliveryJSONHandler(options));
20699
20824
  if (htmlPath !== false) {
@@ -20711,8 +20836,8 @@ var createVoiceTraceDeliveryRoutes = (options) => {
20711
20836
  return routes;
20712
20837
  };
20713
20838
  // src/traceTimeline.ts
20714
- import { Elysia as Elysia33 } from "elysia";
20715
- var escapeHtml35 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20839
+ import { Elysia as Elysia34 } from "elysia";
20840
+ var escapeHtml36 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20716
20841
  var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
20717
20842
  var getNumber8 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
20718
20843
  var firstString3 = (payload, keys) => {
@@ -20880,20 +21005,20 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
20880
21005
  };
20881
21006
  };
20882
21007
  var formatMs3 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
20883
- 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>${escapeHtml35(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>`;
21008
+ 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>${escapeHtml36(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>`;
20884
21009
  var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
20885
- const events = session.events.map((event) => `<tr class="${escapeHtml35(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml35(event.type)}</td><td>${escapeHtml35(event.label)}</td><td>${escapeHtml35(event.provider ?? "")}</td><td>${escapeHtml35(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
20886
- const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml35(issue.severity)}">${escapeHtml35(issue.code)}: ${escapeHtml35(issue.message)}</li>`).join("") : "<li>none</li>";
20887
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml35(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>${escapeHtml35(session.sessionId)}</h1><p class="status ${escapeHtml35(session.status)}">${escapeHtml35(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>`;
21010
+ const events = session.events.map((event) => `<tr class="${escapeHtml36(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml36(event.type)}</td><td>${escapeHtml36(event.label)}</td><td>${escapeHtml36(event.provider ?? "")}</td><td>${escapeHtml36(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
21011
+ const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml36(issue.severity)}">${escapeHtml36(issue.code)}: ${escapeHtml36(issue.message)}</li>`).join("") : "<li>none</li>";
21012
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(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>${escapeHtml36(session.sessionId)}</h1><p class="status ${escapeHtml36(session.status)}">${escapeHtml36(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>`;
20888
21013
  };
20889
- var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml35(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml35(session.sessionId)}</a></td><td>${escapeHtml35(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) => escapeHtml35(provider.provider)).join(", ")}</td></tr>`).join("");
21014
+ var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml36(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml36(session.sessionId)}</a></td><td>${escapeHtml36(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) => escapeHtml36(provider.provider)).join(", ")}</td></tr>`).join("");
20890
21015
  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}}";
20891
- 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>${escapeHtml35(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml35(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>`;
21016
+ 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>${escapeHtml36(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml36(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>`;
20892
21017
  var createVoiceTraceTimelineRoutes = (options) => {
20893
21018
  const path = options.path ?? "/api/voice-traces";
20894
21019
  const htmlPath = options.htmlPath ?? "/traces";
20895
21020
  const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
20896
- const routes = new Elysia33({
21021
+ const routes = new Elysia34({
20897
21022
  name: options.name ?? "absolutejs-voice-trace-timelines"
20898
21023
  });
20899
21024
  const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
@@ -21546,7 +21671,7 @@ var createVoiceMemoryStore = () => {
21546
21671
  return { get, getOrCreate, list, remove, set };
21547
21672
  };
21548
21673
  // src/opsWebhook.ts
21549
- import { Elysia as Elysia34 } from "elysia";
21674
+ import { Elysia as Elysia35 } from "elysia";
21550
21675
  var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
21551
21676
  var signVoiceOpsWebhookBody = async (input) => {
21552
21677
  const encoder = new TextEncoder;
@@ -21676,7 +21801,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
21676
21801
  };
21677
21802
  var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
21678
21803
  const path = options.path ?? "/api/voice-ops/webhook";
21679
- return new Elysia34().post(path, async ({ body, request, set }) => {
21804
+ return new Elysia35().post(path, async ({ body, request, set }) => {
21680
21805
  const bodyText = typeof body === "string" ? body : JSON.stringify(body);
21681
21806
  if (options.signingSecret) {
21682
21807
  const verification = await verifyVoiceOpsWebhookSignature({
@@ -22564,6 +22689,7 @@ export {
22564
22689
  runVoiceSessionEvals,
22565
22690
  runVoiceScenarioFixtureEvals,
22566
22691
  runVoiceScenarioEvals,
22692
+ runVoiceReconnectContract,
22567
22693
  runVoiceProviderRoutingContract,
22568
22694
  runVoicePhoneAgentProductionSmokeContract,
22569
22695
  runVoiceOutcomeContractSuite,
@@ -22603,6 +22729,7 @@ export {
22603
22729
  renderVoiceScenarioFixtureEvalHTML,
22604
22730
  renderVoiceScenarioEvalHTML,
22605
22731
  renderVoiceResilienceHTML,
22732
+ renderVoiceReconnectContractHTML,
22606
22733
  renderVoiceQualityHTML,
22607
22734
  renderVoiceProviderHealthHTML,
22608
22735
  renderVoiceProviderCapabilityHTML,
@@ -22743,6 +22870,7 @@ export {
22743
22870
  createVoiceRedisTelephonyWebhookIdempotencyStore,
22744
22871
  createVoiceRedisTaskLeaseCoordinator,
22745
22872
  createVoiceRedisIdempotencyStore,
22873
+ createVoiceReconnectContractRoutes,
22746
22874
  createVoiceQualityRoutes,
22747
22875
  createVoiceProviderRouter,
22748
22876
  createVoiceProviderHealthRoutes,