@absolutejs/voice 0.0.22-beta.154 → 0.0.22-beta.156

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
@@ -11564,16 +11564,147 @@ var createVoiceDeliverySinkRoutes = (options) => {
11564
11564
  }
11565
11565
  return routes;
11566
11566
  };
11567
- // src/deliveryRuntime.ts
11567
+ // src/opsActionAuditRoutes.ts
11568
11568
  import { Elysia as Elysia12 } from "elysia";
11569
+ var readRecord = async (request) => {
11570
+ const body = await request.json().catch(() => null);
11571
+ if (!body || typeof body !== "object") {
11572
+ throw new Error("Voice ops action audit requires a JSON body.");
11573
+ }
11574
+ const record = body;
11575
+ if (!record.actionId || typeof record.actionId !== "string") {
11576
+ throw new Error("Voice ops action audit requires actionId.");
11577
+ }
11578
+ return {
11579
+ actionId: record.actionId,
11580
+ body: record.body,
11581
+ error: record.error,
11582
+ ok: Boolean(record.ok),
11583
+ ranAt: typeof record.ranAt === "number" ? record.ranAt : Date.now(),
11584
+ status: typeof record.status === "number" ? record.status : 0
11585
+ };
11586
+ };
11587
+ var recordVoiceOpsActionAudit = async (record, options) => {
11588
+ const traceId = `voice-ops-action:${record.actionId}:${record.ranAt}`;
11589
+ const outcome = record.ok ? "success" : "error";
11590
+ const [audit, trace] = await Promise.all([
11591
+ options.audit?.append(createVoiceAuditEvent({
11592
+ action: record.actionId,
11593
+ actor: {
11594
+ id: "voice-ops-action-center",
11595
+ kind: "operator",
11596
+ name: "Voice Ops Action Center"
11597
+ },
11598
+ at: record.ranAt,
11599
+ metadata: {
11600
+ source: "voice-ops-action-center"
11601
+ },
11602
+ outcome,
11603
+ payload: {
11604
+ body: record.body,
11605
+ error: record.error,
11606
+ status: record.status
11607
+ },
11608
+ resource: {
11609
+ id: record.actionId,
11610
+ type: "voice.ops.action"
11611
+ },
11612
+ sessionId: "voice-ops-action-center",
11613
+ traceId,
11614
+ type: "operator.action"
11615
+ })),
11616
+ options.trace?.append(createVoiceTraceEvent({
11617
+ at: record.ranAt,
11618
+ metadata: {
11619
+ source: "voice-ops-action-center"
11620
+ },
11621
+ payload: {
11622
+ actionId: record.actionId,
11623
+ body: record.body,
11624
+ error: record.error,
11625
+ ok: record.ok,
11626
+ status: record.status
11627
+ },
11628
+ sessionId: "voice-ops-action-center",
11629
+ traceId,
11630
+ type: "operator.action"
11631
+ }))
11632
+ ]);
11633
+ return {
11634
+ audit,
11635
+ ok: true,
11636
+ trace
11637
+ };
11638
+ };
11639
+ var createVoiceOpsActionAuditRoutes = (options) => {
11640
+ const path = options.path ?? "/api/voice/ops-actions/audit";
11641
+ const historyPath = options.historyPath === undefined ? "/api/voice/ops-actions/history" : options.historyPath;
11642
+ const historyHtmlPath = options.historyHtmlPath === undefined ? "/voice/ops-actions" : options.historyHtmlPath;
11643
+ const routes = new Elysia12({
11644
+ name: options.name ?? "absolutejs-voice-ops-action-audit"
11645
+ }).post(path, async ({ request, set }) => {
11646
+ try {
11647
+ const record = await readRecord(request);
11648
+ return await recordVoiceOpsActionAudit(record, options);
11649
+ } catch (error) {
11650
+ set.status = 400;
11651
+ return {
11652
+ error: error instanceof Error ? error.message : String(error),
11653
+ ok: false
11654
+ };
11655
+ }
11656
+ });
11657
+ if (historyPath !== false) {
11658
+ routes.get(historyPath, async () => buildVoiceOpsActionHistoryReport(options));
11659
+ }
11660
+ if (historyHtmlPath !== false) {
11661
+ routes.get(historyHtmlPath, async () => new Response(renderVoiceOpsActionHistoryHTML(await buildVoiceOpsActionHistoryReport(options)), {
11662
+ headers: {
11663
+ "Content-Type": "text/html; charset=utf-8"
11664
+ }
11665
+ }));
11666
+ }
11667
+ return routes;
11668
+ };
11669
+ var toHistoryEntry = (event) => ({
11670
+ actionId: event.action,
11671
+ at: event.at,
11672
+ error: event.payload && typeof event.payload === "object" && "error" in event.payload && typeof event.payload.error === "string" ? event.payload.error : undefined,
11673
+ eventId: event.id,
11674
+ ok: event.outcome !== "error",
11675
+ status: event.payload && typeof event.payload === "object" && "status" in event.payload && typeof event.payload.status === "number" ? event.payload.status : undefined,
11676
+ traceId: event.traceId
11677
+ });
11678
+ var buildVoiceOpsActionHistoryReport = async (options) => {
11679
+ const events = options.audit ? await options.audit.list({
11680
+ limit: 25,
11681
+ resourceType: "voice.ops.action",
11682
+ type: "operator.action"
11683
+ }) : [];
11684
+ const entries = events.map(toHistoryEntry).sort((left, right) => right.at - left.at);
11685
+ return {
11686
+ checkedAt: Date.now(),
11687
+ entries,
11688
+ failed: entries.filter((entry) => !entry.ok).length,
11689
+ passed: entries.filter((entry) => entry.ok).length,
11690
+ total: entries.length
11691
+ };
11692
+ };
11693
+ var escapeHtml15 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11694
+ var renderVoiceOpsActionHistoryHTML = (report) => {
11695
+ const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${escapeHtml15(entry.ok ? "success" : "error")}</span><strong>${escapeHtml15(entry.actionId)}</strong><p>${escapeHtml15(new Date(entry.at).toLocaleString())}${entry.status ? ` \xB7 HTTP ${String(entry.status)}` : ""}</p>${entry.error ? `<p>${escapeHtml15(entry.error)}</p>` : ""}</article>`).join("");
11696
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>Voice Ops Action History</title><style>body{background:#11140f;color:#f7f1df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,article{background:#181d15;border:1px solid #2c3327;border-radius:24px;padding:20px}.hero{margin-bottom:16px}h1{font-size:clamp(2rem,6vw,4rem);line-height:.95}section{display:grid;gap:12px}article.ok{border-color:rgba(34,197,94,.55)}article.fail{border-color:rgba(239,68,68,.75)}span{color:#facc15;font-weight:900;text-transform:uppercase}p{color:#c8ccb8}</style></head><body><main><section class="hero"><span>Operator proof</span><h1>Voice Ops Action History</h1><p>${String(report.total)} action(s), ${String(report.failed)} failed.</p></section><section>${rows || "<p>No operator actions have been recorded.</p>"}</section></main></body></html>`;
11697
+ };
11698
+ // src/deliveryRuntime.ts
11699
+ import { Elysia as Elysia13 } from "elysia";
11569
11700
  import { mkdir } from "fs/promises";
11570
11701
  import { dirname, join } from "path";
11571
- var escapeHtml15 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11702
+ var escapeHtml16 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
11572
11703
  var renderSummaryCard = (label, summary) => {
11573
11704
  if (!summary) {
11574
- return `<article><span>${escapeHtml15(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
11705
+ return `<article><span>${escapeHtml16(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
11575
11706
  }
11576
- return `<article><span>${escapeHtml15(label)}</span><strong>${String(summary.delivered)}/${String(summary.total)}</strong><p class="muted">${String(summary.pending)} pending &middot; ${String(summary.failed)} failed &middot; ${String(summary.deadLettered)} dead-lettered</p></article>`;
11707
+ return `<article><span>${escapeHtml16(label)}</span><strong>${String(summary.delivered)}/${String(summary.total)}</strong><p class="muted">${String(summary.pending)} pending &middot; ${String(summary.failed)} failed &middot; ${String(summary.deadLettered)} dead-lettered</p></article>`;
11577
11708
  };
11578
11709
  var resolvePresetLeases = (leases) => ("claim" in leases) ? {
11579
11710
  audit: leases,
@@ -11784,9 +11915,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
11784
11915
  });
11785
11916
  var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
11786
11917
  const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
11787
- const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml15(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
11788
- const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml15(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
11789
- 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{background:#0f1411;color:#f7f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}a{color:#86efac;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(14,165,233,.13));border:1px solid #263a30;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}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.running{border-color:rgba(34,197,94,.7);color:#bbf7d0}.muted{color:#b9c3b4}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#151d18;border:1px solid #263a30;border-radius:22px;padding:18px}article span{color:#b9c3b4;display:block;font-weight:800}article strong{display:block;font-size:2.3rem;margin-top:8px}.actions{display:flex;flex-wrap:wrap;gap:10px}button{background:#86efac;border:0;border-radius:999px;color:#07120b;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}pre{background:#09100c;border:1px solid #263a30;border-radius:18px;color:#dcfce7;overflow:auto;padding:16px}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml15(title)}</h1><p class="muted">Inspect queue summaries, manually tick failed/pending audit and trace deliveries, and requeue dead letters after operator review.</p><p class="status ${report.isRunning ? "running" : ""}">${report.isRunning ? "Running" : "Stopped"}</p><p class="muted">Checked ${escapeHtml15(new Date(report.checkedAt).toLocaleString())}</p><div class="actions">${tickForm}${requeueForm}</div></section><section class="grid">${renderSummaryCard("Audit", report.summary.audit)}${renderSummaryCard("Trace", report.summary.trace)}</section><section class="card"><h2>Runtime shape</h2><pre>const runtime = createVoiceDeliveryRuntime({ audit, trace })
11918
+ const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml16(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
11919
+ const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml16(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
11920
+ 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:#0f1411;color:#f7f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}a{color:#86efac;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(14,165,233,.13));border:1px solid #263a30;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}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.running{border-color:rgba(34,197,94,.7);color:#bbf7d0}.muted{color:#b9c3b4}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#151d18;border:1px solid #263a30;border-radius:22px;padding:18px}article span{color:#b9c3b4;display:block;font-weight:800}article strong{display:block;font-size:2.3rem;margin-top:8px}.actions{display:flex;flex-wrap:wrap;gap:10px}button{background:#86efac;border:0;border-radius:999px;color:#07120b;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}pre{background:#09100c;border:1px solid #263a30;border-radius:18px;color:#dcfce7;overflow:auto;padding:16px}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml16(title)}</h1><p class="muted">Inspect queue summaries, manually tick failed/pending audit and trace deliveries, and requeue dead letters after operator review.</p><p class="status ${report.isRunning ? "running" : ""}">${report.isRunning ? "Running" : "Stopped"}</p><p class="muted">Checked ${escapeHtml16(new Date(report.checkedAt).toLocaleString())}</p><div class="actions">${tickForm}${requeueForm}</div></section><section class="grid">${renderSummaryCard("Audit", report.summary.audit)}${renderSummaryCard("Trace", report.summary.trace)}</section><section class="card"><h2>Runtime shape</h2><pre>const runtime = createVoiceDeliveryRuntime({ audit, trace })
11790
11921
 
11791
11922
  await runtime.tick()
11792
11923
  await runtime.requeueDeadLetters()
@@ -11797,7 +11928,7 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
11797
11928
  const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
11798
11929
  const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
11799
11930
  const requeueDeadLettersPath = options.requeueDeadLettersPath === undefined ? "/api/voice-delivery-runtime/requeue-dead-letters" : options.requeueDeadLettersPath;
11800
- const routes = new Elysia12({
11931
+ const routes = new Elysia13({
11801
11932
  name: options.name ?? "absolutejs-voice-delivery-runtime"
11802
11933
  }).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
11803
11934
  if (tickPath !== false) {
@@ -12035,16 +12166,16 @@ var applyVoiceDataRetentionPolicy = async (options) => {
12035
12166
  };
12036
12167
  var buildVoiceDataRetentionPlan = (options) => applyVoiceDataRetentionPolicy({ ...options, dryRun: true });
12037
12168
  // src/evalRoutes.ts
12038
- import { Elysia as Elysia15 } from "elysia";
12169
+ import { Elysia as Elysia16 } from "elysia";
12039
12170
  import { mkdir as mkdir2 } from "fs/promises";
12040
12171
  import { dirname as dirname2 } from "path";
12041
12172
 
12042
12173
  // src/qualityRoutes.ts
12043
- import { Elysia as Elysia14 } from "elysia";
12174
+ import { Elysia as Elysia15 } from "elysia";
12044
12175
 
12045
12176
  // src/handoffHealth.ts
12046
- import { Elysia as Elysia13 } from "elysia";
12047
- var escapeHtml16 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12177
+ import { Elysia as Elysia14 } from "elysia";
12178
+ var escapeHtml17 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12048
12179
  var getString6 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
12049
12180
  var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
12050
12181
  var increment3 = (record, key) => {
@@ -12162,10 +12293,10 @@ var renderActionSummary = (summary) => {
12162
12293
  return [
12163
12294
  '<section class="voice-handoff-health-columns">',
12164
12295
  "<article><h3>Actions</h3>",
12165
- actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml16(action)}: ${String(count)}</li>`).join("")}</ul>`,
12296
+ actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml17(action)}: ${String(count)}</li>`).join("")}</ul>`,
12166
12297
  "</article>",
12167
12298
  "<article><h3>Adapters</h3>",
12168
- adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml16(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
12299
+ adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml17(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
12169
12300
  "</article>",
12170
12301
  "</section>"
12171
12302
  ].join("");
@@ -12179,22 +12310,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
12179
12310
  summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
12180
12311
  '<div class="voice-handoff-health-events">',
12181
12312
  ...summary.events.map((event) => [
12182
- `<article class="${escapeHtml16(event.status)}">`,
12313
+ `<article class="${escapeHtml17(event.status)}">`,
12183
12314
  '<div class="voice-handoff-health-event-header">',
12184
- `<strong>${escapeHtml16(event.action ?? "handoff")}</strong>`,
12185
- `<span>${escapeHtml16(event.status)}</span>`,
12315
+ `<strong>${escapeHtml17(event.action ?? "handoff")}</strong>`,
12316
+ `<span>${escapeHtml17(event.status)}</span>`,
12186
12317
  "</div>",
12187
- `<p><small>${escapeHtml16(event.sessionId)}</small></p>`,
12188
- event.target ? `<p>Target: ${escapeHtml16(event.target)}</p>` : "",
12189
- event.reason ? `<p>Reason: ${escapeHtml16(event.reason)}</p>` : "",
12318
+ `<p><small>${escapeHtml17(event.sessionId)}</small></p>`,
12319
+ event.target ? `<p>Target: ${escapeHtml17(event.target)}</p>` : "",
12320
+ event.reason ? `<p>Reason: ${escapeHtml17(event.reason)}</p>` : "",
12190
12321
  event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
12191
12322
  "<li>",
12192
- `${escapeHtml16(delivery.adapterId)}: ${escapeHtml16(delivery.status)}`,
12193
- delivery.deliveredTo ? ` to ${escapeHtml16(delivery.deliveredTo)}` : "",
12194
- delivery.error ? ` (${escapeHtml16(delivery.error)})` : "",
12323
+ `${escapeHtml17(delivery.adapterId)}: ${escapeHtml17(delivery.status)}`,
12324
+ delivery.deliveredTo ? ` to ${escapeHtml17(delivery.deliveredTo)}` : "",
12325
+ delivery.error ? ` (${escapeHtml17(delivery.error)})` : "",
12195
12326
  "</li>"
12196
12327
  ].join("")).join("")}</ul>` : "",
12197
- event.replayHref ? `<p><a href="${escapeHtml16(event.replayHref)}">Open replay</a></p>` : "",
12328
+ event.replayHref ? `<p><a href="${escapeHtml17(event.replayHref)}">Open replay</a></p>` : "",
12198
12329
  "</article>"
12199
12330
  ].join("")),
12200
12331
  "</div>"
@@ -12226,7 +12357,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
12226
12357
  var createVoiceHandoffHealthRoutes = (options = {}) => {
12227
12358
  const path = options.path ?? "/api/voice-handoffs";
12228
12359
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
12229
- const routes = new Elysia13({
12360
+ const routes = new Elysia14({
12230
12361
  name: options.name ?? "absolutejs-voice-handoff-health"
12231
12362
  }).get(path, createVoiceHandoffHealthJSONHandler(options));
12232
12363
  if (htmlPath) {
@@ -12347,17 +12478,17 @@ var evaluateVoiceQuality = async (input) => {
12347
12478
  thresholds
12348
12479
  };
12349
12480
  };
12350
- var escapeHtml17 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12481
+ var escapeHtml18 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12351
12482
  var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
12352
12483
  var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
12353
12484
  var renderVoiceQualityHTML = (report, options = {}) => {
12354
- const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml17(metric.label)}</td><td>${escapeHtml17(formatMetricValue(metric))}</td><td>${escapeHtml17(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml17(key)}</code></td></tr>`).join("");
12355
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml17(link.href)}">${escapeHtml17(link.label)}</a>`).join("")}</nav>` : "";
12485
+ const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml18(metric.label)}</td><td>${escapeHtml18(formatMetricValue(metric))}</td><td>${escapeHtml18(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml18(key)}</code></td></tr>`).join("");
12486
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
12356
12487
  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>`;
12357
12488
  };
12358
12489
  var createVoiceQualityRoutes = (options) => {
12359
12490
  const path = options.path ?? "/quality";
12360
- const routes = new Elysia14({
12491
+ const routes = new Elysia15({
12361
12492
  name: options.name ?? "absolutejs-voice-quality"
12362
12493
  });
12363
12494
  const getReport = () => evaluateVoiceQuality({
@@ -12386,7 +12517,7 @@ var createVoiceQualityRoutes = (options) => {
12386
12517
  };
12387
12518
 
12388
12519
  // src/evalRoutes.ts
12389
- var escapeHtml18 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12520
+ var escapeHtml19 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12390
12521
  var rate2 = (count, total) => count / Math.max(1, total);
12391
12522
  var normalizeSearchText = (value) => value.trim().toLowerCase();
12392
12523
  var getString8 = (value) => typeof value === "string" ? value : undefined;
@@ -12695,44 +12826,44 @@ var formatTime = (value) => value === undefined ? "unknown" : new Date(value).to
12695
12826
  var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
12696
12827
  var renderVoiceEvalHTML = (report, options = {}) => {
12697
12828
  const title = options.title ?? "AbsoluteJS Voice Evals";
12698
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
12699
- const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml18(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>';
12829
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
12830
+ const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml19(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>';
12700
12831
  const sessions = report.sessions.length ? report.sessions.map((session) => {
12701
12832
  const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
12702
- return `<tr class="${session.status}"><td>${escapeHtml18(session.sessionId)}</td><td>${escapeHtml18(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml18(formatTime(session.endedAt))}</td><td>${escapeHtml18(failedMetrics || "none")}</td></tr>`;
12833
+ return `<tr class="${session.status}"><td>${escapeHtml19(session.sessionId)}</td><td>${escapeHtml19(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml19(formatTime(session.endedAt))}</td><td>${escapeHtml19(failedMetrics || "none")}</td></tr>`;
12703
12834
  }).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
12704
- 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{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>${escapeHtml18(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>`;
12835
+ 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{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>${escapeHtml19(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>`;
12705
12836
  };
12706
12837
  var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
12707
12838
  const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
12708
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
12709
- const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml18(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
12710
- const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml18(id)}</li>`).join("") : "<li>none</li>";
12711
- const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml18(id)}</li>`).join("") : "<li>none</li>";
12712
- 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{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>${escapeHtml18(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml18(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml18(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>${escapeHtml18(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>`;
12839
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
12840
+ const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml19(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
12841
+ const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml19(id)}</li>`).join("") : "<li>none</li>";
12842
+ const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml19(id)}</li>`).join("") : "<li>none</li>";
12843
+ 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{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>${escapeHtml19(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml19(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml19(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>${escapeHtml19(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>`;
12713
12844
  };
12714
12845
  var renderVoiceScenarioEvalHTML = (report, options = {}) => {
12715
12846
  const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
12716
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
12847
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
12717
12848
  const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
12718
- const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml18(issue)}</li>`).join("")}</ul>` : "";
12719
- const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml18(session.sessionId)}</td><td>${escapeHtml18(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml18(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
12720
- return `<section class="scenario ${scenario.status}"><h2>${escapeHtml18(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml18(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>`;
12849
+ const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml19(issue)}</li>`).join("")}</ul>` : "";
12850
+ const sessions = scenario.sessions.length ? scenario.sessions.map((session) => `<tr class="${session.status}"><td>${escapeHtml19(session.sessionId)}</td><td>${escapeHtml19(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml19(session.issues.join(", ") || "none")}</td></tr>`).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
12851
+ return `<section class="scenario ${scenario.status}"><h2>${escapeHtml19(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml19(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>`;
12721
12852
  }).join("") : "<section><p>No scenarios configured.</p></section>";
12722
- 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{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>${escapeHtml18(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>`;
12853
+ 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{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>${escapeHtml19(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>`;
12723
12854
  };
12724
12855
  var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
12725
12856
  const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
12726
- const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml18(link.href)}">${escapeHtml18(link.label)}</a>`).join("")}</nav>` : "";
12857
+ const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml19(link.href)}">${escapeHtml19(link.label)}</a>`).join("")}</nav>` : "";
12727
12858
  const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
12728
- const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml18(scenario.label)}</td><td>${escapeHtml18(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml18([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
12729
- return `<section class="${fixture.status}"><h2>${escapeHtml18(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml18(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>`;
12859
+ const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml19(scenario.label)}</td><td>${escapeHtml19(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml19([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
12860
+ return `<section class="${fixture.status}"><h2>${escapeHtml19(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml19(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>`;
12730
12861
  }).join("") : "<section><p>No scenario fixtures configured.</p></section>";
12731
- 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{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>${escapeHtml18(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>`;
12862
+ 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{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>${escapeHtml19(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>`;
12732
12863
  };
12733
12864
  var createVoiceEvalRoutes = (options) => {
12734
12865
  const path = options.path ?? "/evals";
12735
- const routes = new Elysia15({
12866
+ const routes = new Elysia16({
12736
12867
  name: options.name ?? "absolutejs-voice-evals"
12737
12868
  });
12738
12869
  const getReport = () => runVoiceSessionEvals({
@@ -12866,11 +12997,11 @@ var createVoiceEvalRoutes = (options) => {
12866
12997
  return routes;
12867
12998
  };
12868
12999
  // src/simulationSuite.ts
12869
- import { Elysia as Elysia18 } from "elysia";
13000
+ import { Elysia as Elysia19 } from "elysia";
12870
13001
 
12871
13002
  // src/outcomeContract.ts
12872
- import { Elysia as Elysia16 } from "elysia";
12873
- var escapeHtml19 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13003
+ import { Elysia as Elysia17 } from "elysia";
13004
+ var escapeHtml20 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
12874
13005
  var getPayloadString = (event, key) => typeof event.payload[key] === "string" ? event.payload[key] : undefined;
12875
13006
  var toList = async (input) => Array.isArray(input) ? input : await input?.list() ?? [];
12876
13007
  var hydrateSessions = async (input) => {
@@ -12978,9 +13109,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
12978
13109
  const contracts = report.contracts.map((contract) => `<section class="contract ${contract.pass ? "pass" : "fail"}">
12979
13110
  <div class="contract-header">
12980
13111
  <div>
12981
- <p class="eyebrow">${escapeHtml19(contract.contractId)}</p>
12982
- <h2>${escapeHtml19(contract.label ?? contract.contractId)}</h2>
12983
- ${contract.description ? `<p>${escapeHtml19(contract.description)}</p>` : ""}
13112
+ <p class="eyebrow">${escapeHtml20(contract.contractId)}</p>
13113
+ <h2>${escapeHtml20(contract.label ?? contract.contractId)}</h2>
13114
+ ${contract.description ? `<p>${escapeHtml20(contract.description)}</p>` : ""}
12984
13115
  </div>
12985
13116
  <strong>${contract.pass ? "pass" : "fail"}</strong>
12986
13117
  </div>
@@ -12991,9 +13122,9 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
12991
13122
  <span>handoffs ${String(contract.matched.handoffs)}</span>
12992
13123
  <span>events ${String(contract.matched.integrationEvents)}</span>
12993
13124
  </div>
12994
- ${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml19(issue.message)}</li>`).join("")}</ul>` : ""}
13125
+ ${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml20(issue.message)}</li>`).join("")}</ul>` : ""}
12995
13126
  </section>`).join("");
12996
- 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:#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>${escapeHtml19(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>`;
13127
+ 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,.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>${escapeHtml20(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>`;
12997
13128
  };
12998
13129
  var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
12999
13130
  var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
@@ -13009,7 +13140,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
13009
13140
  var createVoiceOutcomeContractRoutes = (options) => {
13010
13141
  const path = options.path ?? "/api/outcome-contracts";
13011
13142
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
13012
- const routes = new Elysia16({
13143
+ const routes = new Elysia17({
13013
13144
  name: options.name ?? "absolutejs-voice-outcome-contracts"
13014
13145
  }).get(path, createVoiceOutcomeContractJSONHandler(options));
13015
13146
  if (htmlPath) {
@@ -13019,7 +13150,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
13019
13150
  };
13020
13151
 
13021
13152
  // src/toolContract.ts
13022
- import { Elysia as Elysia17 } from "elysia";
13153
+ import { Elysia as Elysia18 } from "elysia";
13023
13154
 
13024
13155
  // src/toolRuntime.ts
13025
13156
  var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
@@ -13228,7 +13359,7 @@ var createDefaultTurn = (caseId) => ({
13228
13359
  });
13229
13360
  var defaultApi = {};
13230
13361
  var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
13231
- var escapeHtml20 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13362
+ var escapeHtml21 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13232
13363
  var evaluateExpectation = (input) => {
13233
13364
  const issues = [];
13234
13365
  const expect = input.expect;
@@ -13394,19 +13525,19 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
13394
13525
  const title = options.title ?? "Voice Tool Contracts";
13395
13526
  const contracts = report.contracts.map((contract) => {
13396
13527
  const cases = contract.cases.map((testCase) => `<tr>
13397
- <td>${escapeHtml20(testCase.label ?? testCase.caseId)}</td>
13528
+ <td>${escapeHtml21(testCase.label ?? testCase.caseId)}</td>
13398
13529
  <td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
13399
- <td>${escapeHtml20(testCase.status)}</td>
13530
+ <td>${escapeHtml21(testCase.status)}</td>
13400
13531
  <td>${String(testCase.attempts)}</td>
13401
13532
  <td>${String(testCase.elapsedMs)}ms</td>
13402
13533
  <td>${testCase.timedOut ? "yes" : "no"}</td>
13403
- <td>${escapeHtml20(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
13534
+ <td>${escapeHtml21(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
13404
13535
  </tr>`).join("");
13405
13536
  return `<section class="contract ${contract.pass ? "pass" : "fail"}">
13406
13537
  <div class="contract-header">
13407
13538
  <div>
13408
- <p class="eyebrow">${escapeHtml20(contract.toolName)}</p>
13409
- <h2>${escapeHtml20(contract.label ?? contract.contractId)}</h2>
13539
+ <p class="eyebrow">${escapeHtml21(contract.toolName)}</p>
13540
+ <h2>${escapeHtml21(contract.label ?? contract.contractId)}</h2>
13410
13541
  </div>
13411
13542
  <strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
13412
13543
  </div>
@@ -13416,7 +13547,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
13416
13547
  </table>
13417
13548
  </section>`;
13418
13549
  }).join("");
13419
- 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,.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>${escapeHtml20(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml20(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>`;
13550
+ 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,.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>${escapeHtml21(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml21(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>`;
13420
13551
  };
13421
13552
  var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
13422
13553
  var createVoiceToolContractHTMLHandler = (options) => async () => {
@@ -13433,7 +13564,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
13433
13564
  var createVoiceToolContractRoutes = (options) => {
13434
13565
  const path = options.path ?? "/api/tool-contracts";
13435
13566
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
13436
- const routes = new Elysia17({
13567
+ const routes = new Elysia18({
13437
13568
  name: options.name ?? "absolutejs-voice-tool-contracts"
13438
13569
  }).get(path, createVoiceToolContractJSONHandler(options));
13439
13570
  if (htmlPath) {
@@ -13443,7 +13574,7 @@ var createVoiceToolContractRoutes = (options) => {
13443
13574
  };
13444
13575
 
13445
13576
  // src/simulationSuite.ts
13446
- var escapeHtml21 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13577
+ var escapeHtml22 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13447
13578
  var summarizeSection = (report) => ({
13448
13579
  failed: report.failed,
13449
13580
  passed: report.passed,
@@ -13579,20 +13710,20 @@ var renderSection = (label, summary) => {
13579
13710
  if (!summary) {
13580
13711
  return "";
13581
13712
  }
13582
- return `<article class="${escapeHtml21(summary.status)}"><span>${escapeHtml21(label)}</span><strong>${escapeHtml21(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
13713
+ return `<article class="${escapeHtml22(summary.status)}"><span>${escapeHtml22(label)}</span><strong>${escapeHtml22(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
13583
13714
  };
13584
13715
  var renderAction = (action) => {
13585
- const content = `<strong>${escapeHtml21(action.label)}</strong><p>${escapeHtml21(action.description)}</p><span>${escapeHtml21(action.section)} / ${escapeHtml21(action.severity)}</span>`;
13586
- return action.href ? `<a class="action" href="${escapeHtml21(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
13716
+ const content = `<strong>${escapeHtml22(action.label)}</strong><p>${escapeHtml22(action.description)}</p><span>${escapeHtml22(action.section)} / ${escapeHtml22(action.severity)}</span>`;
13717
+ return action.href ? `<a class="action" href="${escapeHtml22(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
13587
13718
  };
13588
13719
  var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
13589
13720
  const title = options.title ?? "Voice Simulation Suite";
13590
- 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:#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>${escapeHtml21(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml21(report.status)}">Status: ${escapeHtml21(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>${escapeHtml21(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
13721
+ 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:#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>${escapeHtml22(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml22(report.status)}">Status: ${escapeHtml22(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>${escapeHtml22(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
13591
13722
  };
13592
13723
  var createVoiceSimulationSuiteRoutes = (options) => {
13593
13724
  const path = options.path ?? "/api/voice/simulations";
13594
13725
  const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
13595
- const app = new Elysia18({
13726
+ const app = new Elysia19({
13596
13727
  name: options.name ?? "absolutejs-voice-simulation-suite"
13597
13728
  }).get(path, () => runVoiceSimulationSuite(options));
13598
13729
  if (htmlPath) {
@@ -13904,9 +14035,9 @@ var createVoiceWorkflowContractHandler = (input) => {
13904
14035
  };
13905
14036
  };
13906
14037
  // src/sessionReplay.ts
13907
- import { Elysia as Elysia19 } from "elysia";
14038
+ import { Elysia as Elysia20 } from "elysia";
13908
14039
  var getString9 = (value) => typeof value === "string" ? value : undefined;
13909
- var escapeHtml22 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14040
+ var escapeHtml23 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
13910
14041
  var increment4 = (record, key) => {
13911
14042
  record[key] = (record[key] ?? 0) + 1;
13912
14043
  };
@@ -14086,10 +14217,10 @@ var summarizeVoiceSessions = async (options = {}) => {
14086
14217
  var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
14087
14218
  '<div class="voice-sessions-list">',
14088
14219
  ...sessions.map((session) => [
14089
- `<article class="voice-session-card ${escapeHtml22(session.status)}">`,
14220
+ `<article class="voice-session-card ${escapeHtml23(session.status)}">`,
14090
14221
  '<div class="voice-session-card-header">',
14091
- `<strong>${escapeHtml22(session.sessionId)}</strong>`,
14092
- `<span>${escapeHtml22(session.status)}</span>`,
14222
+ `<strong>${escapeHtml23(session.sessionId)}</strong>`,
14223
+ `<span>${escapeHtml23(session.status)}</span>`,
14093
14224
  "</div>",
14094
14225
  "<dl>",
14095
14226
  `<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
@@ -14097,9 +14228,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
14097
14228
  `<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
14098
14229
  `<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
14099
14230
  "</dl>",
14100
- session.latestOutcome ? `<p>Outcome: ${escapeHtml22(session.latestOutcome)}</p>` : "",
14101
- session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml22).join(", ")}</p>` : "",
14102
- session.replayHref ? `<p><a href="${escapeHtml22(session.replayHref)}">Open replay</a></p>` : "",
14231
+ session.latestOutcome ? `<p>Outcome: ${escapeHtml23(session.latestOutcome)}</p>` : "",
14232
+ session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml23).join(", ")}</p>` : "",
14233
+ session.replayHref ? `<p><a href="${escapeHtml23(session.replayHref)}">Open replay</a></p>` : "",
14103
14234
  "</article>"
14104
14235
  ].join("")),
14105
14236
  "</div>"
@@ -14130,7 +14261,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
14130
14261
  var createVoiceSessionListRoutes = (options = {}) => {
14131
14262
  const path = options.path ?? "/api/voice-sessions";
14132
14263
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
14133
- const routes = new Elysia19({
14264
+ const routes = new Elysia20({
14134
14265
  name: options.name ?? "absolutejs-voice-session-list"
14135
14266
  }).get(path, createVoiceSessionsJSONHandler(options));
14136
14267
  if (htmlPath) {
@@ -14158,7 +14289,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
14158
14289
  var createVoiceSessionReplayRoutes = (options) => {
14159
14290
  const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
14160
14291
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
14161
- const routes = new Elysia19({
14292
+ const routes = new Elysia20({
14162
14293
  name: options.name ?? "absolutejs-voice-session-replay"
14163
14294
  }).get(path, createVoiceSessionReplayJSONHandler(options));
14164
14295
  if (htmlPath) {
@@ -14325,10 +14456,10 @@ var assertVoiceAgentSquadContract = async (options) => {
14325
14456
  return report;
14326
14457
  };
14327
14458
  // src/turnLatency.ts
14328
- import { Elysia as Elysia20 } from "elysia";
14459
+ import { Elysia as Elysia21 } from "elysia";
14329
14460
  var DEFAULT_WARN_AFTER_MS = 1800;
14330
14461
  var DEFAULT_FAIL_AFTER_MS = 3200;
14331
- var escapeHtml23 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14462
+ var escapeHtml24 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14332
14463
  var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
14333
14464
  var getString10 = (value) => typeof value === "string" && value.trim() ? value : undefined;
14334
14465
  var createTraceStageIndex = (events) => {
@@ -14442,11 +14573,11 @@ var summarizeVoiceTurnLatency = async (options) => {
14442
14573
  var formatMs = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
14443
14574
  var renderVoiceTurnLatencyHTML = (report, options = {}) => {
14444
14575
  const title = options.title ?? "Voice Turn Latency";
14445
- const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml23(turn.status)}">
14446
- <header><div><p class="eyebrow">${escapeHtml23(turn.sessionId)} \xB7 ${escapeHtml23(turn.turnId)}</p><h2>${escapeHtml23(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml23(turn.status)}</strong></header>
14447
- <dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml23(stage.label)}</dt><dd>${escapeHtml23(formatMs(stage.valueMs))}</dd></div>`).join("")}</dl>
14576
+ const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml24(turn.status)}">
14577
+ <header><div><p class="eyebrow">${escapeHtml24(turn.sessionId)} \xB7 ${escapeHtml24(turn.turnId)}</p><h2>${escapeHtml24(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml24(turn.status)}</strong></header>
14578
+ <dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml24(stage.label)}</dt><dd>${escapeHtml24(formatMs(stage.valueMs))}</dd></div>`).join("")}</dl>
14448
14579
  </article>`).join("");
14449
- 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(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>${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">avg ${escapeHtml23(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>`;
14580
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml24(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>${escapeHtml24(title)}</h1><div class="summary"><span class="pill ${escapeHtml24(report.status)}">${escapeHtml24(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml24(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>`;
14450
14581
  };
14451
14582
  var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
14452
14583
  var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
@@ -14463,7 +14594,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
14463
14594
  var createVoiceTurnLatencyRoutes = (options) => {
14464
14595
  const path = options.path ?? "/api/turn-latency";
14465
14596
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
14466
- const routes = new Elysia20({
14597
+ const routes = new Elysia21({
14467
14598
  name: options.name ?? "absolutejs-voice-turn-latency"
14468
14599
  }).get(path, createVoiceTurnLatencyJSONHandler(options));
14469
14600
  if (htmlPath) {
@@ -14472,8 +14603,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
14472
14603
  return routes;
14473
14604
  };
14474
14605
  // src/liveLatency.ts
14475
- import { Elysia as Elysia21 } from "elysia";
14476
- var escapeHtml24 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14606
+ import { Elysia as Elysia22 } from "elysia";
14607
+ var escapeHtml25 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14477
14608
  var percentile = (values, percentileValue) => {
14478
14609
  if (values.length === 0) {
14479
14610
  return;
@@ -14521,13 +14652,13 @@ var summarizeVoiceLiveLatency = async (options) => {
14521
14652
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
14522
14653
  var renderVoiceLiveLatencyHTML = (report, options = {}) => {
14523
14654
  const title = options.title ?? "Voice Live Latency";
14524
- const rows = report.recent.map((sample) => `<tr><td>${escapeHtml24(sample.sessionId)}</td><td>${escapeHtml24(formatMs2(sample.latencyMs))}</td><td>${escapeHtml24(sample.status ?? "unknown")}</td><td>${escapeHtml24(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
14525
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml24(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>${escapeHtml24(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml24(report.status)}">Status: ${escapeHtml24(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml24(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml24(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml24(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>`;
14655
+ const rows = report.recent.map((sample) => `<tr><td>${escapeHtml25(sample.sessionId)}</td><td>${escapeHtml25(formatMs2(sample.latencyMs))}</td><td>${escapeHtml25(sample.status ?? "unknown")}</td><td>${escapeHtml25(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
14656
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(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>${escapeHtml25(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml25(report.status)}">Status: ${escapeHtml25(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml25(formatMs2(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml25(formatMs2(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml25(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>`;
14526
14657
  };
14527
14658
  var createVoiceLiveLatencyRoutes = (options) => {
14528
14659
  const path = options.path ?? "/api/live-latency";
14529
14660
  const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
14530
- const routes = new Elysia21({
14661
+ const routes = new Elysia22({
14531
14662
  name: options.name ?? "absolutejs-voice-live-latency"
14532
14663
  }).get(path, () => summarizeVoiceLiveLatency(options));
14533
14664
  if (htmlPath) {
@@ -14544,9 +14675,9 @@ var createVoiceLiveLatencyRoutes = (options) => {
14544
14675
  return routes;
14545
14676
  };
14546
14677
  // src/turnQuality.ts
14547
- import { Elysia as Elysia22 } from "elysia";
14678
+ import { Elysia as Elysia23 } from "elysia";
14548
14679
  var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
14549
- var escapeHtml25 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14680
+ var escapeHtml26 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
14550
14681
  var getTurnLatencyMs = (turn) => {
14551
14682
  const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
14552
14683
  if (firstTranscriptAt === undefined) {
@@ -14617,24 +14748,24 @@ var summarizeVoiceTurnQuality = async (options) => {
14617
14748
  };
14618
14749
  var renderVoiceTurnQualityHTML = (report, options = {}) => {
14619
14750
  const title = options.title ?? "Voice Turn Quality";
14620
- const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml25(turn.status)}">
14751
+ const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml26(turn.status)}">
14621
14752
  <div class="turn-header">
14622
14753
  <div>
14623
- <p class="eyebrow">${escapeHtml25(turn.sessionId)} \xB7 ${escapeHtml25(turn.turnId)}</p>
14624
- <h2>${escapeHtml25(turn.text || "Empty turn")}</h2>
14754
+ <p class="eyebrow">${escapeHtml26(turn.sessionId)} \xB7 ${escapeHtml26(turn.turnId)}</p>
14755
+ <h2>${escapeHtml26(turn.text || "Empty turn")}</h2>
14625
14756
  </div>
14626
- <strong>${escapeHtml25(turn.status)}</strong>
14757
+ <strong>${escapeHtml26(turn.status)}</strong>
14627
14758
  </div>
14628
14759
  <dl>
14629
- <div><dt>Source</dt><dd>${escapeHtml25(turn.source ?? "unknown")}</dd></div>
14760
+ <div><dt>Source</dt><dd>${escapeHtml26(turn.source ?? "unknown")}</dd></div>
14630
14761
  <div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
14631
- <div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml25(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
14632
- <div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml25(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
14762
+ <div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml26(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
14763
+ <div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml26(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
14633
14764
  <div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
14634
14765
  <div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
14635
14766
  </dl>
14636
14767
  </article>`).join("");
14637
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml25(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>${escapeHtml25(title)}</h1><div class="summary"><span class="pill ${escapeHtml25(report.status)}">${escapeHtml25(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>`;
14768
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml26(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>${escapeHtml26(title)}</h1><div class="summary"><span class="pill ${escapeHtml26(report.status)}">${escapeHtml26(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>`;
14638
14769
  };
14639
14770
  var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
14640
14771
  var createVoiceTurnQualityHTMLHandler = (options) => async () => {
@@ -14651,7 +14782,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
14651
14782
  var createVoiceTurnQualityRoutes = (options) => {
14652
14783
  const path = options.path ?? "/api/turn-quality";
14653
14784
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
14654
- const routes = new Elysia22({
14785
+ const routes = new Elysia23({
14655
14786
  name: options.name ?? "absolutejs-voice-turn-quality"
14656
14787
  }).get(path, createVoiceTurnQualityJSONHandler(options));
14657
14788
  if (htmlPath) {
@@ -14660,7 +14791,7 @@ var createVoiceTurnQualityRoutes = (options) => {
14660
14791
  return routes;
14661
14792
  };
14662
14793
  // src/telephonyOutcome.ts
14663
- import { Elysia as Elysia23 } from "elysia";
14794
+ import { Elysia as Elysia24 } from "elysia";
14664
14795
  var DEFAULT_COMPLETED_STATUSES = [
14665
14796
  "answered",
14666
14797
  "completed",
@@ -15310,7 +15441,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
15310
15441
  var createVoiceTelephonyWebhookRoutes = (options = {}) => {
15311
15442
  const path = options.path ?? "/api/voice/telephony/webhook";
15312
15443
  const handler = createVoiceTelephonyWebhookHandler(options);
15313
- return new Elysia23({
15444
+ return new Elysia24({
15314
15445
  name: options.name ?? "absolutejs-voice-telephony-webhooks"
15315
15446
  }).post(path, async ({ query, request }) => {
15316
15447
  try {
@@ -15331,11 +15462,11 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
15331
15462
  });
15332
15463
  };
15333
15464
  // src/phoneAgent.ts
15334
- import { Elysia as Elysia29 } from "elysia";
15465
+ import { Elysia as Elysia30 } from "elysia";
15335
15466
 
15336
15467
  // src/telephony/plivo.ts
15337
15468
  import { Buffer as Buffer5 } from "buffer";
15338
- import { Elysia as Elysia25 } from "elysia";
15469
+ import { Elysia as Elysia26 } from "elysia";
15339
15470
 
15340
15471
  // src/telephony/contract.ts
15341
15472
  var DEFAULT_REQUIREMENTS = [
@@ -15419,7 +15550,7 @@ var evaluateVoiceTelephonyContract = (input) => {
15419
15550
 
15420
15551
  // src/telephony/twilio.ts
15421
15552
  import { Buffer as Buffer4 } from "buffer";
15422
- import { Elysia as Elysia24 } from "elysia";
15553
+ import { Elysia as Elysia25 } from "elysia";
15423
15554
  var TWILIO_MULAW_SAMPLE_RATE = 8000;
15424
15555
  var VOICE_PCM_SAMPLE_RATE = 16000;
15425
15556
  var escapeXml2 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
@@ -15449,7 +15580,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
15449
15580
  return parameters;
15450
15581
  };
15451
15582
  var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
15452
- var escapeHtml26 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
15583
+ var escapeHtml27 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
15453
15584
  var getWebhookVerificationUrl = (webhook, input) => {
15454
15585
  if (!webhook?.verificationUrl) {
15455
15586
  return;
@@ -15492,23 +15623,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
15492
15623
  };
15493
15624
  var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
15494
15625
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
15495
- <h1>${escapeHtml26(title)}</h1>
15626
+ <h1>${escapeHtml27(title)}</h1>
15496
15627
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
15497
15628
  <section>
15498
15629
  <h2>URLs</h2>
15499
15630
  <ul>
15500
- <li><strong>TwiML:</strong> <code>${escapeHtml26(status.urls.twiml)}</code></li>
15501
- <li><strong>Media stream:</strong> <code>${escapeHtml26(status.urls.stream)}</code></li>
15502
- <li><strong>Status webhook:</strong> <code>${escapeHtml26(status.urls.webhook)}</code></li>
15631
+ <li><strong>TwiML:</strong> <code>${escapeHtml27(status.urls.twiml)}</code></li>
15632
+ <li><strong>Media stream:</strong> <code>${escapeHtml27(status.urls.stream)}</code></li>
15633
+ <li><strong>Status webhook:</strong> <code>${escapeHtml27(status.urls.webhook)}</code></li>
15503
15634
  </ul>
15504
15635
  </section>
15505
15636
  <section>
15506
15637
  <h2>Signing</h2>
15507
15638
  <p>Mode: <code>${status.signing.mode}</code></p>
15508
- ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml26(status.signing.verificationUrl)}</code></p>` : ""}
15639
+ ${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml27(status.signing.verificationUrl)}</code></p>` : ""}
15509
15640
  </section>
15510
- ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml26(name)}</code></li>`).join("")}</ul></section>` : ""}
15511
- ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml26(warning)}</li>`).join("")}</ul></section>` : ""}
15641
+ ${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml27(name)}</code></li>`).join("")}</ul></section>` : ""}
15642
+ ${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml27(warning)}</li>`).join("")}</ul></section>` : ""}
15512
15643
  </main>`;
15513
15644
  var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&amp;", "&");
15514
15645
  var createSmokeCheck = (name, status, message, details) => ({
@@ -15519,20 +15650,20 @@ var createSmokeCheck = (name, status, message, details) => ({
15519
15650
  });
15520
15651
  var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
15521
15652
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
15522
- <h1>${escapeHtml26(title)}</h1>
15653
+ <h1>${escapeHtml27(title)}</h1>
15523
15654
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
15524
15655
  <section>
15525
15656
  <h2>Checks</h2>
15526
15657
  <ul>
15527
- ${report.checks.map((check) => `<li><strong>${escapeHtml26(check.name)}</strong>: ${escapeHtml26(check.status)}${check.message ? ` - ${escapeHtml26(check.message)}` : ""}</li>`).join("")}
15658
+ ${report.checks.map((check) => `<li><strong>${escapeHtml27(check.name)}</strong>: ${escapeHtml27(check.status)}${check.message ? ` - ${escapeHtml27(check.message)}` : ""}</li>`).join("")}
15528
15659
  </ul>
15529
15660
  </section>
15530
15661
  <section>
15531
15662
  <h2>Observed URLs</h2>
15532
15663
  <ul>
15533
- <li><strong>TwiML:</strong> <code>${escapeHtml26(report.setup.urls.twiml)}</code></li>
15534
- <li><strong>Stream:</strong> <code>${escapeHtml26(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
15535
- <li><strong>Webhook:</strong> <code>${escapeHtml26(report.setup.urls.webhook)}</code></li>
15664
+ <li><strong>TwiML:</strong> <code>${escapeHtml27(report.setup.urls.twiml)}</code></li>
15665
+ <li><strong>Stream:</strong> <code>${escapeHtml27(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
15666
+ <li><strong>Webhook:</strong> <code>${escapeHtml27(report.setup.urls.webhook)}</code></li>
15536
15667
  </ul>
15537
15668
  </section>
15538
15669
  </main>`;
@@ -15992,7 +16123,7 @@ var createTwilioVoiceRoutes = (options) => {
15992
16123
  const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
15993
16124
  const bridges = new WeakMap;
15994
16125
  const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
15995
- const app = new Elysia24({
16126
+ const app = new Elysia25({
15996
16127
  name: options.name ?? "absolutejs-voice-twilio"
15997
16128
  }).get(twimlPath, async ({ query, request }) => {
15998
16129
  const streamUrl = await resolveTwilioStreamUrl(options, {
@@ -16129,7 +16260,7 @@ var createTwilioVoiceRoutes = (options) => {
16129
16260
 
16130
16261
  // src/telephony/plivo.ts
16131
16262
  var escapeXml3 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16132
- var escapeHtml27 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16263
+ var escapeHtml28 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16133
16264
  var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
16134
16265
  var resolveRequestOrigin2 = (request) => {
16135
16266
  const url = new URL(request.url);
@@ -16380,21 +16511,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
16380
16511
  };
16381
16512
  var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16382
16513
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
16383
- <h1>${escapeHtml27(title)}</h1>
16514
+ <h1>${escapeHtml28(title)}</h1>
16384
16515
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
16385
16516
  <ul>
16386
- <li><strong>Answer XML:</strong> <code>${escapeHtml27(status.urls.answer)}</code></li>
16387
- <li><strong>Audio stream:</strong> <code>${escapeHtml27(status.urls.stream)}</code></li>
16388
- <li><strong>Status webhook:</strong> <code>${escapeHtml27(status.urls.webhook)}</code></li>
16517
+ <li><strong>Answer XML:</strong> <code>${escapeHtml28(status.urls.answer)}</code></li>
16518
+ <li><strong>Audio stream:</strong> <code>${escapeHtml28(status.urls.stream)}</code></li>
16519
+ <li><strong>Status webhook:</strong> <code>${escapeHtml28(status.urls.webhook)}</code></li>
16389
16520
  </ul>
16390
- ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml27(name)}</code></li>`).join("")}</ul>` : ""}
16391
- ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml27(warning)}</li>`).join("")}</ul>` : ""}
16521
+ ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml28(name)}</code></li>`).join("")}</ul>` : ""}
16522
+ ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml28(warning)}</li>`).join("")}</ul>` : ""}
16392
16523
  </main>`;
16393
16524
  var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16394
16525
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
16395
- <h1>${escapeHtml27(title)}</h1>
16526
+ <h1>${escapeHtml28(title)}</h1>
16396
16527
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
16397
- <ul>${report.checks.map((check) => `<li><strong>${escapeHtml27(check.name)}</strong>: ${escapeHtml27(check.status)}${check.message ? ` - ${escapeHtml27(check.message)}` : ""}</li>`).join("")}</ul>
16528
+ <ul>${report.checks.map((check) => `<li><strong>${escapeHtml28(check.name)}</strong>: ${escapeHtml28(check.status)}${check.message ? ` - ${escapeHtml28(check.message)}` : ""}</li>`).join("")}</ul>
16398
16529
  </main>`;
16399
16530
  var runPlivoSmokeTest = async (input) => {
16400
16531
  const setup = await buildPlivoVoiceSetupStatus(input.options, input);
@@ -16489,7 +16620,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
16489
16620
  request: input.request
16490
16621
  }) : verificationUrl ?? input.request.url
16491
16622
  }) : undefined);
16492
- const app = new Elysia25({
16623
+ const app = new Elysia26({
16493
16624
  name: options.name ?? "absolutejs-voice-plivo"
16494
16625
  }).get(answerPath, async ({ query, request }) => {
16495
16626
  const streamUrl = await resolvePlivoStreamUrl(options, {
@@ -16600,9 +16731,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
16600
16731
 
16601
16732
  // src/telephony/telnyx.ts
16602
16733
  import { Buffer as Buffer6 } from "buffer";
16603
- import { Elysia as Elysia26 } from "elysia";
16734
+ import { Elysia as Elysia27 } from "elysia";
16604
16735
  var escapeXml4 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&apos;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16605
- var escapeHtml28 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16736
+ var escapeHtml29 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
16606
16737
  var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
16607
16738
  var resolveRequestOrigin3 = (request) => {
16608
16739
  const url = new URL(request.url);
@@ -16803,21 +16934,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
16803
16934
  };
16804
16935
  var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16805
16936
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
16806
- <h1>${escapeHtml28(title)}</h1>
16937
+ <h1>${escapeHtml29(title)}</h1>
16807
16938
  <p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
16808
16939
  <ul>
16809
- <li><strong>TeXML:</strong> <code>${escapeHtml28(status.urls.texml)}</code></li>
16810
- <li><strong>Media stream:</strong> <code>${escapeHtml28(status.urls.stream)}</code></li>
16811
- <li><strong>Status webhook:</strong> <code>${escapeHtml28(status.urls.webhook)}</code></li>
16940
+ <li><strong>TeXML:</strong> <code>${escapeHtml29(status.urls.texml)}</code></li>
16941
+ <li><strong>Media stream:</strong> <code>${escapeHtml29(status.urls.stream)}</code></li>
16942
+ <li><strong>Status webhook:</strong> <code>${escapeHtml29(status.urls.webhook)}</code></li>
16812
16943
  </ul>
16813
- ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml28(name)}</code></li>`).join("")}</ul>` : ""}
16814
- ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml28(warning)}</li>`).join("")}</ul>` : ""}
16944
+ ${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml29(name)}</code></li>`).join("")}</ul>` : ""}
16945
+ ${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml29(warning)}</li>`).join("")}</ul>` : ""}
16815
16946
  </main>`;
16816
16947
  var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
16817
16948
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
16818
- <h1>${escapeHtml28(title)}</h1>
16949
+ <h1>${escapeHtml29(title)}</h1>
16819
16950
  <p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
16820
- <ul>${report.checks.map((check) => `<li><strong>${escapeHtml28(check.name)}</strong>: ${escapeHtml28(check.status)}${check.message ? ` - ${escapeHtml28(check.message)}` : ""}</li>`).join("")}</ul>
16951
+ <ul>${report.checks.map((check) => `<li><strong>${escapeHtml29(check.name)}</strong>: ${escapeHtml29(check.status)}${check.message ? ` - ${escapeHtml29(check.message)}` : ""}</li>`).join("")}</ul>
16821
16952
  </main>`;
16822
16953
  var runTelnyxSmokeTest = async (input) => {
16823
16954
  const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
@@ -16911,7 +17042,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
16911
17042
  publicKey: options.webhook?.publicKey,
16912
17043
  toleranceSeconds: options.webhook?.toleranceSeconds
16913
17044
  }) : undefined);
16914
- const app = new Elysia26({
17045
+ const app = new Elysia27({
16915
17046
  name: options.name ?? "absolutejs-voice-telnyx"
16916
17047
  }).get(texmlPath, async ({ query, request }) => {
16917
17048
  const streamUrl = await resolveTelnyxStreamUrl(options, {
@@ -17021,8 +17152,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
17021
17152
  };
17022
17153
 
17023
17154
  // src/telephony/matrix.ts
17024
- import { Elysia as Elysia27 } from "elysia";
17025
- var escapeHtml29 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17155
+ import { Elysia as Elysia28 } from "elysia";
17156
+ var escapeHtml30 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17026
17157
  var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
17027
17158
  var resolveEntryStatus = (contract, setup, smoke) => {
17028
17159
  if (!contract.pass || !setup.ready || smoke?.pass === false) {
@@ -17083,13 +17214,13 @@ var badgeStyles = {
17083
17214
  };
17084
17215
  var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
17085
17216
  <p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
17086
- <h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml29(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
17217
+ <h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml30(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
17087
17218
  <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>
17088
17219
  <section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
17089
17220
  ${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);">
17090
17221
  <div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
17091
- <h2 style="margin:0; font-size:20px;">${escapeHtml29(entry.name)}</h2>
17092
- <span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml29(entry.status.toUpperCase())}</span>
17222
+ <h2 style="margin:0; font-size:20px;">${escapeHtml30(entry.name)}</h2>
17223
+ <span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml30(entry.status.toUpperCase())}</span>
17093
17224
  </div>
17094
17225
  <dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
17095
17226
  <dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
@@ -17097,15 +17228,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
17097
17228
  <dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
17098
17229
  <dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
17099
17230
  </dl>
17100
- <p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml29(entry.setup.urls.stream || "missing")}</code></p>
17101
- <p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml29(entry.setup.urls.webhook || "missing")}</code></p>
17102
- ${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml29(issue.severity)}: ${escapeHtml29(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
17231
+ <p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml30(entry.setup.urls.stream || "missing")}</code></p>
17232
+ <p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml30(entry.setup.urls.webhook || "missing")}</code></p>
17233
+ ${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml30(issue.severity)}: ${escapeHtml30(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
17103
17234
  </article>`).join("")}
17104
17235
  </section>
17105
17236
  </main>`;
17106
17237
  var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
17107
17238
  const path = options.path ?? "/api/voice/telephony/carriers";
17108
- return new Elysia27({
17239
+ return new Elysia28({
17109
17240
  name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
17110
17241
  }).get(path, async ({ query, request }) => {
17111
17242
  const providers = await options.load({ query, request });
@@ -17127,7 +17258,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
17127
17258
  };
17128
17259
 
17129
17260
  // src/phoneAgentProductionSmoke.ts
17130
- import { Elysia as Elysia28 } from "elysia";
17261
+ import { Elysia as Elysia29 } from "elysia";
17131
17262
  var defaultRequirements = [
17132
17263
  "media-started",
17133
17264
  "transcript",
@@ -17135,7 +17266,7 @@ var defaultRequirements = [
17135
17266
  "lifecycle-outcome",
17136
17267
  "no-session-error"
17137
17268
  ];
17138
- var escapeHtml30 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
17269
+ var escapeHtml31 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
17139
17270
  var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
17140
17271
  var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
17141
17272
  const value = event.payload[key];
@@ -17244,10 +17375,10 @@ var resolveHandlerOptions = async (options, input) => ({
17244
17375
  });
17245
17376
  var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
17246
17377
  const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
17247
- const issues = report.issues.map((issue) => `<li><strong>${escapeHtml30(issue.requirement)}</strong>: ${escapeHtml30(issue.message)}</li>`).join("");
17248
- const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml30(outcome)}</span>`).join("");
17249
- const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml30(requirement)}</span>`).join("");
17250
- 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:#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>${escapeHtml30(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml30(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml30(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml30(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>`;
17378
+ const issues = report.issues.map((issue) => `<li><strong>${escapeHtml31(issue.requirement)}</strong>: ${escapeHtml31(issue.message)}</li>`).join("");
17379
+ const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml31(outcome)}</span>`).join("");
17380
+ const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml31(requirement)}</span>`).join("");
17381
+ 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:#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>${escapeHtml31(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml31(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml31(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml31(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>`;
17251
17382
  };
17252
17383
  var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
17253
17384
  query,
@@ -17270,7 +17401,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
17270
17401
  var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
17271
17402
  const path = options.path ?? "/api/voice/phone/smoke-contract";
17272
17403
  const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
17273
- const routes = new Elysia28({
17404
+ const routes = new Elysia29({
17274
17405
  name: options.name ?? "absolutejs-voice-phone-smoke-contract"
17275
17406
  }).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
17276
17407
  if (htmlPath) {
@@ -17313,7 +17444,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
17313
17444
  "completed",
17314
17445
  "failed"
17315
17446
  ];
17316
- var escapeHtml31 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17447
+ var escapeHtml32 = (value) => value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
17317
17448
  var loadRouteJson = async (input) => {
17318
17449
  const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
17319
17450
  headers: {
@@ -17373,18 +17504,18 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
17373
17504
  const entry = report.matrix?.entries.find((candidate) => candidate.provider === carrier.provider && (candidate.name === carrier.name || candidate.name === (carrier.name ?? carrier.provider)));
17374
17505
  const urls = entry?.setup.urls;
17375
17506
  const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
17376
- return `<tr><td>${escapeHtml31(carrier.name ?? carrier.provider)}</td><td>${escapeHtml31(carrier.provider)}</td><td><code>${escapeHtml31(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml31(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml31(entry.status)}">${escapeHtml31(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml31(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml31(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml31(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
17507
+ return `<tr><td>${escapeHtml32(carrier.name ?? carrier.provider)}</td><td>${escapeHtml32(carrier.provider)}</td><td><code>${escapeHtml32(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml32(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml32(entry.status)}">${escapeHtml32(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml32(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml32(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml32(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
17377
17508
  }).join("");
17378
- const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml31(stage)}</code></li>`).join("");
17509
+ const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml32(stage)}</code></li>`).join("");
17379
17510
  const checklist = report.carriers.map((carrier) => {
17380
17511
  const entry = report.matrix?.entries.find((candidate) => candidate.provider === carrier.provider && (candidate.name === carrier.name || candidate.name === (carrier.name ?? carrier.provider)));
17381
17512
  const urls = entry?.setup.urls;
17382
17513
  const answerLabel = carrier.provider === "telnyx" ? "TeXML URL" : carrier.provider === "plivo" ? "Answer URL" : "TwiML URL";
17383
17514
  const answerUrl = urls?.twiml;
17384
- const issueList = entry?.issues.map((issue) => `<li>${escapeHtml31(issue.severity)}: ${escapeHtml31(issue.message)}</li>`).join("") ?? "";
17385
- return `<article><h3>${escapeHtml31(carrier.name ?? carrier.provider)}</h3><ol><li>Set ${escapeHtml31(answerLabel)} to <code>${escapeHtml31(answerUrl ?? "missing")}</code>.</li><li>Set status webhook to <code>${escapeHtml31(urls?.webhook ?? "missing")}</code>.</li><li>Allow media stream URL <code>${escapeHtml31(urls?.stream ?? "missing")}</code>.</li><li>Open setup: ${carrier.setupPath ? `<a href="${escapeHtml31(carrier.setupPath)}?format=html">${escapeHtml31(carrier.setupPath)}</a>` : '<span class="muted">disabled</span>'}.</li><li>Run smoke: ${carrier.smokePath ? `<a href="${escapeHtml31(carrier.smokePath)}?format=html">${escapeHtml31(carrier.smokePath)}</a>` : '<span class="muted">disabled</span>'}.</li>${report.productionSmokePath ? `<li>Certify production smoke traces: <a href="${escapeHtml31(report.productionSmokePath.replace("/api/", "/"))}?sessionId=">${escapeHtml31(report.productionSmokePath)}</a>.</li>` : ""}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
17515
+ const issueList = entry?.issues.map((issue) => `<li>${escapeHtml32(issue.severity)}: ${escapeHtml32(issue.message)}</li>`).join("") ?? "";
17516
+ return `<article><h3>${escapeHtml32(carrier.name ?? carrier.provider)}</h3><ol><li>Set ${escapeHtml32(answerLabel)} to <code>${escapeHtml32(answerUrl ?? "missing")}</code>.</li><li>Set status webhook to <code>${escapeHtml32(urls?.webhook ?? "missing")}</code>.</li><li>Allow media stream URL <code>${escapeHtml32(urls?.stream ?? "missing")}</code>.</li><li>Open setup: ${carrier.setupPath ? `<a href="${escapeHtml32(carrier.setupPath)}?format=html">${escapeHtml32(carrier.setupPath)}</a>` : '<span class="muted">disabled</span>'}.</li><li>Run smoke: ${carrier.smokePath ? `<a href="${escapeHtml32(carrier.smokePath)}?format=html">${escapeHtml32(carrier.smokePath)}</a>` : '<span class="muted">disabled</span>'}.</li>${report.productionSmokePath ? `<li>Certify production smoke traces: <a href="${escapeHtml32(report.productionSmokePath.replace("/api/", "/"))}?sessionId=">${escapeHtml32(report.productionSmokePath)}</a>.</li>` : ""}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
17386
17517
  }).join("");
17387
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml31(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>${escapeHtml31(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="${escapeHtml31(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>`;
17518
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(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>${escapeHtml32(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="${escapeHtml32(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>`;
17388
17519
  };
17389
17520
  var createVoicePhoneAgent = (options) => {
17390
17521
  const carrierSummaries = options.carriers.map((carrier) => ({
@@ -17393,7 +17524,7 @@ var createVoicePhoneAgent = (options) => {
17393
17524
  setupPath: resolveSetupPath(carrier),
17394
17525
  smokePath: resolveSmokePath(carrier)
17395
17526
  }));
17396
- const app = new Elysia29({
17527
+ const app = new Elysia30({
17397
17528
  name: options.name ?? "absolutejs-voice-phone-agent"
17398
17529
  });
17399
17530
  for (const carrier of options.carriers) {
@@ -19405,8 +19536,8 @@ var createOpenAIVoiceTTS = (options) => {
19405
19536
  };
19406
19537
  };
19407
19538
  // src/providerCapabilities.ts
19408
- import { Elysia as Elysia30 } from "elysia";
19409
- var escapeHtml32 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19539
+ import { Elysia as Elysia31 } from "elysia";
19540
+ var escapeHtml33 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19410
19541
  var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
19411
19542
  configured: true,
19412
19543
  features: options.features?.[provider],
@@ -19469,27 +19600,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
19469
19600
  var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
19470
19601
  const title = options.title ?? "Voice Provider Capabilities";
19471
19602
  const cards = report.capabilities.map((capability) => {
19472
- const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml32(feature)}</span>`).join("");
19473
- return `<article class="card ${escapeHtml32(capability.status)}">
19603
+ const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml33(feature)}</span>`).join("");
19604
+ return `<article class="card ${escapeHtml33(capability.status)}">
19474
19605
  <div class="card-header">
19475
19606
  <div>
19476
- <p class="eyebrow">${escapeHtml32(capability.kind)}</p>
19477
- <h2>${escapeHtml32(capability.label ?? capability.provider)}</h2>
19607
+ <p class="eyebrow">${escapeHtml33(capability.kind)}</p>
19608
+ <h2>${escapeHtml33(capability.label ?? capability.provider)}</h2>
19478
19609
  </div>
19479
- <strong>${escapeHtml32(capability.status)}</strong>
19610
+ <strong>${escapeHtml33(capability.status)}</strong>
19480
19611
  </div>
19481
- ${capability.description ? `<p>${escapeHtml32(capability.description)}</p>` : ""}
19612
+ ${capability.description ? `<p>${escapeHtml33(capability.description)}</p>` : ""}
19482
19613
  <dl>
19483
19614
  <div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
19484
19615
  <div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
19485
- <div><dt>Model</dt><dd>${escapeHtml32(capability.model ?? "default")}</dd></div>
19616
+ <div><dt>Model</dt><dd>${escapeHtml33(capability.model ?? "default")}</dd></div>
19486
19617
  <div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
19487
19618
  <div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
19488
19619
  </dl>
19489
19620
  ${features ? `<div class="features">${features}</div>` : ""}
19490
19621
  </article>`;
19491
19622
  }).join("");
19492
- 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:#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>${escapeHtml32(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>`;
19623
+ 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:#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>${escapeHtml33(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>`;
19493
19624
  };
19494
19625
  var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
19495
19626
  var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
@@ -19506,7 +19637,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
19506
19637
  var createVoiceProviderCapabilityRoutes = (options) => {
19507
19638
  const path = options.path ?? "/api/provider-capabilities";
19508
19639
  const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
19509
- const routes = new Elysia30({
19640
+ const routes = new Elysia31({
19510
19641
  name: options.name ?? "absolutejs-voice-provider-capabilities"
19511
19642
  }).get(path, createVoiceProviderCapabilityJSONHandler(options));
19512
19643
  if (htmlPath) {
@@ -19515,8 +19646,8 @@ var createVoiceProviderCapabilityRoutes = (options) => {
19515
19646
  return routes;
19516
19647
  };
19517
19648
  // src/resilienceRoutes.ts
19518
- import { Elysia as Elysia31 } from "elysia";
19519
- var escapeHtml33 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19649
+ import { Elysia as Elysia32 } from "elysia";
19650
+ var escapeHtml34 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19520
19651
  var getString11 = (value) => typeof value === "string" ? value : undefined;
19521
19652
  var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
19522
19653
  var getBoolean2 = (value) => value === true;
@@ -19663,13 +19794,13 @@ var summarizeRoutingEvents = (events) => {
19663
19794
  };
19664
19795
  var renderProviderCards = (title, providers) => {
19665
19796
  if (providers.length === 0) {
19666
- return `<p class="muted">No ${escapeHtml33(title)} provider health yet.</p>`;
19797
+ return `<p class="muted">No ${escapeHtml34(title)} provider health yet.</p>`;
19667
19798
  }
19668
19799
  return `<div class="provider-grid">${providers.map((provider) => `
19669
- <article class="card provider ${escapeHtml33(provider.status)}">
19800
+ <article class="card provider ${escapeHtml34(provider.status)}">
19670
19801
  <div class="card-header">
19671
- <strong>${escapeHtml33(provider.provider)}</strong>
19672
- <span>${escapeHtml33(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
19802
+ <strong>${escapeHtml34(provider.provider)}</strong>
19803
+ <span>${escapeHtml34(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
19673
19804
  </div>
19674
19805
  <dl>
19675
19806
  <div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
@@ -19678,7 +19809,7 @@ var renderProviderCards = (title, providers) => {
19678
19809
  <div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
19679
19810
  <div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
19680
19811
  </dl>
19681
- ${provider.lastError ? `<p class="muted">${escapeHtml33(provider.lastError)}</p>` : ""}
19812
+ ${provider.lastError ? `<p class="muted">${escapeHtml34(provider.lastError)}</p>` : ""}
19682
19813
  </article>
19683
19814
  `).join("")}</div>`;
19684
19815
  };
@@ -19687,24 +19818,24 @@ var renderTimeline2 = (events) => {
19687
19818
  return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
19688
19819
  }
19689
19820
  return `<div class="timeline">${events.slice(0, 40).map((event) => `
19690
- <article class="card event ${escapeHtml33(event.status ?? "unknown")}">
19821
+ <article class="card event ${escapeHtml34(event.status ?? "unknown")}">
19691
19822
  <div class="card-header">
19692
- <strong>${escapeHtml33(event.kind.toUpperCase())} ${escapeHtml33(event.operation ?? "generate")}</strong>
19823
+ <strong>${escapeHtml34(event.kind.toUpperCase())} ${escapeHtml34(event.operation ?? "generate")}</strong>
19693
19824
  <span>${new Date(event.at).toLocaleString()}</span>
19694
19825
  </div>
19695
19826
  <p>
19696
- <span class="pill">${escapeHtml33(event.status ?? "unknown")}</span>
19697
- <span class="pill">provider: ${escapeHtml33(event.provider ?? "unknown")}</span>
19698
- ${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml33(event.fallbackProvider)}</span>` : ""}
19827
+ <span class="pill">${escapeHtml34(event.status ?? "unknown")}</span>
19828
+ <span class="pill">provider: ${escapeHtml34(event.provider ?? "unknown")}</span>
19829
+ ${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml34(event.fallbackProvider)}</span>` : ""}
19699
19830
  ${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
19700
19831
  </p>
19701
19832
  <dl>
19702
19833
  <div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
19703
19834
  <div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
19704
19835
  <div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
19705
- <div><dt>Session</dt><dd>${escapeHtml33(event.sessionId)}</dd></div>
19836
+ <div><dt>Session</dt><dd>${escapeHtml34(event.sessionId)}</dd></div>
19706
19837
  </dl>
19707
- ${event.error ? `<p class="muted">${escapeHtml33(event.error)}</p>` : ""}
19838
+ ${event.error ? `<p class="muted">${escapeHtml34(event.error)}</p>` : ""}
19708
19839
  </article>
19709
19840
  `).join("")}</div>`;
19710
19841
  };
@@ -19714,9 +19845,9 @@ var renderSessionKind = (kind, summary) => {
19714
19845
  const status = latest?.status ?? "idle";
19715
19846
  const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
19716
19847
  return `<div>
19717
- <dt>${escapeHtml33(kind.toUpperCase())}</dt>
19718
- <dd>${escapeHtml33(provider)}${escapeHtml33(fallback)}</dd>
19719
- <small>${escapeHtml33(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>
19848
+ <dt>${escapeHtml34(kind.toUpperCase())}</dt>
19849
+ <dd>${escapeHtml34(provider)}${escapeHtml34(fallback)}</dd>
19850
+ <small>${escapeHtml34(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>
19720
19851
  </div>`;
19721
19852
  };
19722
19853
  var renderSessionSummaries = (sessions) => {
@@ -19724,10 +19855,10 @@ var renderSessionSummaries = (sessions) => {
19724
19855
  return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
19725
19856
  }
19726
19857
  return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
19727
- <article class="card session ${escapeHtml33(session.status)}">
19858
+ <article class="card session ${escapeHtml34(session.status)}">
19728
19859
  <div class="card-header">
19729
- <strong>${escapeHtml33(session.sessionId)}</strong>
19730
- <span>${escapeHtml33(session.status)}</span>
19860
+ <strong>${escapeHtml34(session.sessionId)}</strong>
19861
+ <span>${escapeHtml34(session.status)}</span>
19731
19862
  </div>
19732
19863
  <p>
19733
19864
  <span class="pill">${session.eventCount} routing events</span>
@@ -19754,26 +19885,26 @@ var renderSimulationControls = (kind, simulation) => {
19754
19885
  const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
19755
19886
  const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
19756
19887
  const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
19757
- return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml33(pathPrefix)}">
19758
- <p class="muted">${escapeHtml33(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
19888
+ return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml34(pathPrefix)}">
19889
+ <p class="muted">${escapeHtml34(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
19759
19890
  <div class="simulate-actions">
19760
- ${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml33(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml33(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
19761
- ${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml33(provider.provider)}">Mark ${escapeHtml33(provider.provider)} recovered</button>`).join("")}
19891
+ ${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml34(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml34(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
19892
+ ${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml34(provider.provider)}">Mark ${escapeHtml34(provider.provider)} recovered</button>`).join("")}
19762
19893
  </div>
19763
- ${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml33(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
19894
+ ${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml34(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
19764
19895
  <pre class="simulate-output" hidden></pre>
19765
19896
  </div>`;
19766
19897
  };
19767
19898
  var renderVoiceResilienceHTML = (input) => {
19768
19899
  const summary = summarizeRoutingEvents(input.routingEvents);
19769
- const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml33(kind)}: ${String(count)}</span>`).join("");
19770
- const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml33(link.href)}">${escapeHtml33(link.label)}</a>`).join(" \xB7 ") : "";
19900
+ const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml34(kind)}: ${String(count)}</span>`).join("");
19901
+ const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml34(link.href)}">${escapeHtml34(link.label)}</a>`).join(" \xB7 ") : "";
19771
19902
  return `<!doctype html>
19772
19903
  <html lang="en">
19773
19904
  <head>
19774
19905
  <meta charset="utf-8" />
19775
19906
  <meta name="viewport" content="width=device-width, initial-scale=1" />
19776
- <title>${escapeHtml33(input.title ?? "AbsoluteJS Voice Resilience")}</title>
19907
+ <title>${escapeHtml34(input.title ?? "AbsoluteJS Voice Resilience")}</title>
19777
19908
  <style>
19778
19909
  :root { color-scheme: dark; }
19779
19910
  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; }
@@ -19916,7 +20047,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
19916
20047
  };
19917
20048
  var createVoiceResilienceRoutes = (options) => {
19918
20049
  const path = options.path ?? "/resilience";
19919
- const routes = new Elysia31({
20050
+ const routes = new Elysia32({
19920
20051
  name: options.name ?? "absolutejs-voice-resilience"
19921
20052
  }).get(path, async () => {
19922
20053
  const events = await options.store.list();
@@ -19994,8 +20125,8 @@ var assertVoiceProviderRoutingContract = async (options) => {
19994
20125
  return report;
19995
20126
  };
19996
20127
  // src/productionReadiness.ts
19997
- import { Elysia as Elysia32 } from "elysia";
19998
- var escapeHtml34 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20128
+ import { Elysia as Elysia33 } from "elysia";
20129
+ var escapeHtml35 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
19999
20130
  var rollupStatus2 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
20000
20131
  var carrierStatus = (matrix) => matrix.summary.failing > 0 ? "fail" : matrix.summary.warnings > 0 || matrix.summary.ready < matrix.summary.providers ? "warn" : "pass";
20001
20132
  var resolveCarriers = async (options, input) => {
@@ -20670,25 +20801,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
20670
20801
  var renderVoiceProductionReadinessHTML = (report, options = {}) => {
20671
20802
  const title = options.title ?? "AbsoluteJS Voice Production Readiness";
20672
20803
  const checks = report.checks.map((check, index) => {
20673
- const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml34(action.href)}">${escapeHtml34(action.label)}</button>` : `<a href="${escapeHtml34(action.href)}">${escapeHtml34(action.label)}</a>`).join("");
20674
- return `<article class="check ${escapeHtml34(check.status)}">
20804
+ const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml35(action.href)}">${escapeHtml35(action.label)}</button>` : `<a href="${escapeHtml35(action.href)}">${escapeHtml35(action.label)}</a>`).join("");
20805
+ return `<article class="check ${escapeHtml35(check.status)}">
20675
20806
  <div>
20676
- <span>${escapeHtml34(check.status.toUpperCase())}</span>
20677
- <h2>${escapeHtml34(check.label)}</h2>
20678
- ${check.detail ? `<p>${escapeHtml34(check.detail)}</p>` : ""}
20679
- ${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml34(check.proofSource.href)}">${escapeHtml34(check.proofSource.sourceLabel)}</a>` : escapeHtml34(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml34(check.proofSource.detail)}` : ""}</p>` : ""}
20807
+ <span>${escapeHtml35(check.status.toUpperCase())}</span>
20808
+ <h2>${escapeHtml35(check.label)}</h2>
20809
+ ${check.detail ? `<p>${escapeHtml35(check.detail)}</p>` : ""}
20810
+ ${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml35(check.proofSource.href)}">${escapeHtml35(check.proofSource.sourceLabel)}</a>` : escapeHtml35(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml35(check.proofSource.detail)}` : ""}</p>` : ""}
20680
20811
  ${actions ? `<p class="actions">${actions}</p>` : ""}
20681
20812
  </div>
20682
- <strong>${escapeHtml34(String(check.value ?? check.status))}</strong>
20683
- ${check.href ? `<a href="${escapeHtml34(check.href)}">Open surface</a>` : ""}
20813
+ <strong>${escapeHtml35(String(check.value ?? check.status))}</strong>
20814
+ ${check.href ? `<a href="${escapeHtml35(check.href)}">Open surface</a>` : ""}
20684
20815
  </article>`;
20685
20816
  }).join("");
20686
- 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:#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 .proof-source{color:#f9d77e;font-weight:800}.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>${escapeHtml34(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 ${escapeHtml34(report.status)}">Overall: ${escapeHtml34(report.status.toUpperCase())}</p><p>Checked ${escapeHtml34(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>`;
20817
+ 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:#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 .proof-source{color:#f9d77e;font-weight:800}.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>${escapeHtml35(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 ${escapeHtml35(report.status)}">Overall: ${escapeHtml35(report.status.toUpperCase())}</p><p>Checked ${escapeHtml35(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>`;
20687
20818
  };
20688
20819
  var createVoiceProductionReadinessRoutes = (options) => {
20689
20820
  const path = options.path ?? "/api/production-readiness";
20690
20821
  const htmlPath = options.htmlPath ?? "/production-readiness";
20691
- const routes = new Elysia32({
20822
+ const routes = new Elysia33({
20692
20823
  name: options.name ?? "absolutejs-voice-production-readiness"
20693
20824
  });
20694
20825
  routes.get(path, async ({ query, request }) => buildVoiceProductionReadinessReport(options, { query, request }));
@@ -20710,7 +20841,7 @@ var createVoiceProductionReadinessRoutes = (options) => {
20710
20841
  return routes;
20711
20842
  };
20712
20843
  // src/opsConsoleRoutes.ts
20713
- import { Elysia as Elysia33 } from "elysia";
20844
+ import { Elysia as Elysia34 } from "elysia";
20714
20845
  var DEFAULT_LINKS = [
20715
20846
  {
20716
20847
  description: "Quality gates for CI, deploy checks, and production readiness.",
@@ -20745,7 +20876,7 @@ var DEFAULT_LINKS = [
20745
20876
  label: "Handoffs"
20746
20877
  }
20747
20878
  ];
20748
- var escapeHtml35 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20879
+ var escapeHtml36 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
20749
20880
  var countProviderStatuses = (providers) => {
20750
20881
  const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
20751
20882
  const healthy = providers.filter((provider) => provider.status === "healthy").length;
@@ -20814,20 +20945,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
20814
20945
  trace
20815
20946
  };
20816
20947
  };
20817
- var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml35(input.label)}</span><strong>${escapeHtml35(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml35(input.status)}">${escapeHtml35(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml35(input.href)}">Open</a>` : ""}</article>`;
20948
+ var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml36(input.label)}</span><strong>${escapeHtml36(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml36(input.status)}">${escapeHtml36(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml36(input.href)}">Open</a>` : ""}</article>`;
20818
20949
  var renderVoiceOpsConsoleHTML = (report, options = {}) => {
20819
20950
  const links = report.links.map((link) => `<article class="surface">
20820
- <div><h2>${escapeHtml35(link.label)}</h2>${link.description ? `<p>${escapeHtml35(link.description)}</p>` : ""}</div>
20821
- <p><a href="${escapeHtml35(link.href)}">Open ${escapeHtml35(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml35(link.statusHref)}">Status</a>` : ""}</p>
20951
+ <div><h2>${escapeHtml36(link.label)}</h2>${link.description ? `<p>${escapeHtml36(link.description)}</p>` : ""}</div>
20952
+ <p><a href="${escapeHtml36(link.href)}">Open ${escapeHtml36(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml36(link.statusHref)}">Status</a>` : ""}</p>
20822
20953
  </article>`).join("");
20823
- const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml35(session.sessionId)}</td><td>${escapeHtml35(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml35(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
20824
- const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml35(event.kind)}</td><td>${escapeHtml35(event.provider ?? "unknown")}</td><td>${escapeHtml35(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml35(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
20954
+ const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml36(session.sessionId)}</td><td>${escapeHtml36(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml36(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
20955
+ const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml36(event.kind)}</td><td>${escapeHtml36(event.provider ?? "unknown")}</td><td>${escapeHtml36(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml36(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
20825
20956
  const title = options.title ?? "AbsoluteJS Voice Ops Console";
20826
- 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{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>${escapeHtml35(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 ${escapeHtml35(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>`;
20957
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#101316;color:#f6f2e8;margin:0}main{max-width:1180px;margin:auto;padding:32px}a{color:#fbbf24}header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;margin-bottom:24px}.eyebrow{color:#fbbf24;font-weight:800;letter-spacing:.08em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.5rem);line-height:.95;margin:.2rem 0 1rem}.muted{color:#a8b0b8}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.metric,.surface{background:#181d22;border:1px solid #2a323a;border-radius:20px;padding:18px}.metric strong{display:block;font-size:2.2rem;margin:.25rem 0}.pass,.healthy{color:#86efac}.fail,.failed,.degraded{color:#fca5a5}.surfaces{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:24px 0}table{width:100%;border-collapse:collapse;background:#181d22;border-radius:16px;overflow:hidden;margin:12px 0 28px}td,th{border-bottom:1px solid #2a323a;padding:12px;text-align:left}section{margin-top:30px}@media(max-width:700px){main{padding:20px}header{display:block}}</style></head><body><main><header><div><p class="eyebrow">Self-hosted voice operations</p><h1>${escapeHtml36(title)}</h1><p class="muted">One deployable control plane for quality gates, failover, traces, sessions, handoffs, and provider health.</p></div><p class="muted">Checked ${escapeHtml36(new Date(report.checkedAt).toLocaleString())}</p></header><div class="grid">${renderMetricCard({ label: "Quality", value: report.quality.status, status: report.quality.status, href: "/quality" })}${renderMetricCard({ label: "Events", value: report.eventCount, href: "/diagnostics" })}${renderMetricCard({ label: "Sessions", value: report.sessions.total, status: report.sessions.failed > 0 ? "failed" : "healthy", href: "/sessions" })}${renderMetricCard({ label: "Handoffs failed", value: report.handoffs.failed, status: report.handoffs.failed > 0 ? "failed" : "healthy", href: "/handoffs" })}${renderMetricCard({ label: "Providers degraded", value: report.providers.degraded, status: report.providers.degraded > 0 ? "degraded" : "healthy", href: "/resilience" })}</div><section><h2>Operational Surfaces</h2><div class="surfaces">${links}</div></section><section><h2>Recent Sessions</h2><table><thead><tr><th>Session</th><th>Status</th><th>Turns</th><th>Errors</th><th>Replay</th></tr></thead><tbody>${sessions}</tbody></table></section><section><h2>Recent Provider Routing</h2><table><thead><tr><th>Kind</th><th>Provider</th><th>Status</th><th>Elapsed</th><th>Session</th></tr></thead><tbody>${routing}</tbody></table></section></main></body></html>`;
20827
20958
  };
20828
20959
  var createVoiceOpsConsoleRoutes = (options) => {
20829
20960
  const path = options.path ?? "/ops-console";
20830
- const routes = new Elysia33({
20961
+ const routes = new Elysia34({
20831
20962
  name: options.name ?? "absolutejs-voice-ops-console"
20832
20963
  });
20833
20964
  const getReport = () => buildVoiceOpsConsoleReport(options);
@@ -21015,19 +21146,19 @@ var summarizeVoiceOpsStatus = async (options) => {
21015
21146
  };
21016
21147
  };
21017
21148
  // src/opsStatusRoutes.ts
21018
- import { Elysia as Elysia34 } from "elysia";
21019
- var escapeHtml36 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21149
+ import { Elysia as Elysia35 } from "elysia";
21150
+ var escapeHtml37 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21020
21151
  var renderVoiceOpsStatusHTML = (report, options = {}) => {
21021
21152
  const title = options.title ?? "AbsoluteJS Voice Ops Status";
21022
21153
  const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
21023
21154
  const value = "recovered" in surface ? surface.total === 0 ? "0 events" : `${surface.recovered}/${surface.total}` : ("auditTotal" in surface) ? `${surface.auditTotal + surface.traceTotal} deliveries` : ("total" in surface) ? `${Math.max(surface.total - ("failed" in surface ? surface.failed : ("degraded" in surface) ? surface.degraded : 0), 0)}/${surface.total}` : surface.status;
21024
- return `<article class="surface ${escapeHtml36(surface.status)}"><span>${escapeHtml36(surface.status.toUpperCase())}</span><h2>${escapeHtml36(key)}</h2><strong>${escapeHtml36(value)}</strong></article>`;
21155
+ return `<article class="surface ${escapeHtml37(surface.status)}"><span>${escapeHtml37(surface.status.toUpperCase())}</span><h2>${escapeHtml37(key)}</h2><strong>${escapeHtml37(value)}</strong></article>`;
21025
21156
  }).join("");
21026
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(title)}</title><style>body{background:#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>${escapeHtml36(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml36(report.status)}">Overall: ${escapeHtml36(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>`;
21157
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml37(title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.surfaces{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.surface{background:#151d26;border:1px solid #283544;border-radius:20px;padding:18px}.surface span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.surface strong{font-size:1.5rem}.pass{border-color:rgba(34,197,94,.55)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Ops status</p><h1>${escapeHtml37(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml37(report.status)}">Overall: ${escapeHtml37(report.status.toUpperCase())}</p><p>${report.passed}/${report.total} checks passing</p></section><section class="surfaces">${surfaces || '<article class="surface pass"><span>PASS</span><h2>No checks configured</h2><strong>0/0</strong></article>'}</section></main></body></html>`;
21027
21158
  };
21028
21159
  var createVoiceOpsStatusRoutes = (options) => {
21029
21160
  const path = options.path ?? "/api/voice/ops-status";
21030
- const routes = new Elysia34({
21161
+ const routes = new Elysia35({
21031
21162
  name: options.name ?? "absolutejs-voice-ops-status"
21032
21163
  });
21033
21164
  routes.get(path, async () => summarizeVoiceOpsStatus(options));
@@ -21460,8 +21591,8 @@ var createVoiceTTSProviderRouter = (options) => {
21460
21591
  };
21461
21592
  };
21462
21593
  // src/traceDeliveryRoutes.ts
21463
- import { Elysia as Elysia35 } from "elysia";
21464
- var escapeHtml37 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21594
+ import { Elysia as Elysia36 } from "elysia";
21595
+ var escapeHtml38 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21465
21596
  var getString12 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
21466
21597
  var getNumber7 = (value) => {
21467
21598
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -21542,14 +21673,14 @@ var renderSinkResults2 = (delivery) => {
21542
21673
  if (entries.length === 0) {
21543
21674
  return "<p>No sink delivery attempts recorded yet.</p>";
21544
21675
  }
21545
- return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml37(sinkId)}</strong>: ${escapeHtml37(result.status)}${result.deliveredTo ? ` to ${escapeHtml37(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml37(result.error)})` : ""}</li>`).join("")}</ul>`;
21676
+ return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml38(sinkId)}</strong>: ${escapeHtml38(result.status)}${result.deliveredTo ? ` to ${escapeHtml38(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml38(result.error)})` : ""}</li>`).join("")}</ul>`;
21546
21677
  };
21547
- var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml37(event.type)} <small>${escapeHtml37(event.id)}</small>${event.sessionId ? ` session=${escapeHtml37(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
21678
+ var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml38(event.type)} <small>${escapeHtml38(event.id)}</small>${event.sessionId ? ` session=${escapeHtml38(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
21548
21679
  var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
21549
21680
  const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
21550
- const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml37(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
21551
- const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml37(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml37(delivery.deliveryStatus)}</span><h2>${escapeHtml37(delivery.id)}</h2><p>${escapeHtml37(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml37(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml37(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
21552
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml37(title)}</title><style>body{background:#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>${escapeHtml37(title)}</h1><p>Checked ${escapeHtml37(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>`;
21681
+ const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml38(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
21682
+ const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml38(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml38(delivery.deliveryStatus)}</span><h2>${escapeHtml38(delivery.id)}</h2><p>${escapeHtml38(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml38(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml38(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
21683
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(title)}</title><style>body{background:#0f1318;color:#f4efe1;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(14,165,233,.14));border:1px solid #26313d;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.grid{display:grid;gap:12px;grid-template-columns:repeat(4,1fr);margin-bottom:16px}.grid article,.delivery{background:#151b22;border:1px solid #26313d;border-radius:22px;padding:18px}.grid span,.delivery span{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.grid strong{display:block;font-size:2rem}.deliveries{display:grid;gap:14px}.delivery.failed{border-color:rgba(239,68,68,.75)}.delivery.pending{border-color:rgba(245,158,11,.7)}.delivery.delivered{border-color:rgba(34,197,94,.55)}.delivery.skipped{border-color:rgba(148,163,184,.6)}.head{align-items:start;display:flex;gap:14px;justify-content:space-between}.delivery h2{font-size:1.05rem;margin:.3rem 0;overflow-wrap:anywhere}.delivery h3{margin:1rem 0 .3rem}.delivery p,.delivery li{color:#c8d0d8}.error{color:#fecaca!important}button{background:#86efac;border:0;border-radius:999px;color:#07111f;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}@media(max-width:760px){main{padding:20px}.grid{grid-template-columns:1fr 1fr}.head{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Trace export health</p><h1>${escapeHtml38(title)}</h1><p>Checked ${escapeHtml38(new Date(report.checkedAt).toLocaleString())}. Showing ${String(report.deliveries.length)} delivery item(s).</p>${drainAction}</section>${renderMetricGrid3(report)}<section class="deliveries">${rows || "<p>No trace deliveries match this filter.</p>"}</section></main></body></html>`;
21553
21684
  };
21554
21685
  var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
21555
21686
  var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
@@ -21569,7 +21700,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
21569
21700
  const path = options.path ?? "/api/voice-trace-deliveries";
21570
21701
  const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
21571
21702
  const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
21572
- const routes = new Elysia35({
21703
+ const routes = new Elysia36({
21573
21704
  name: options.name ?? "absolutejs-voice-trace-deliveries"
21574
21705
  }).get(path, createVoiceTraceDeliveryJSONHandler(options));
21575
21706
  if (htmlPath !== false) {
@@ -21587,8 +21718,8 @@ var createVoiceTraceDeliveryRoutes = (options) => {
21587
21718
  return routes;
21588
21719
  };
21589
21720
  // src/traceTimeline.ts
21590
- import { Elysia as Elysia36 } from "elysia";
21591
- var escapeHtml38 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21721
+ import { Elysia as Elysia37 } from "elysia";
21722
+ var escapeHtml39 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
21592
21723
  var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
21593
21724
  var getNumber8 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
21594
21725
  var firstString3 = (payload, keys) => {
@@ -21756,20 +21887,20 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
21756
21887
  };
21757
21888
  };
21758
21889
  var formatMs3 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
21759
- 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>${escapeHtml38(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>`;
21890
+ var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${escapeHtml39(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs3(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs3(provider.maxElapsedMs)}</dd></div><div><dt>Errors</dt><dd>${String(provider.errorCount)}</dd></div><div><dt>Fallbacks</dt><dd>${String(provider.fallbackCount)}</dd></div><div><dt>Timeouts</dt><dd>${String(provider.timeoutCount)}</dd></div></dl></article>`).join("")}</div>`;
21760
21891
  var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
21761
- const events = session.events.map((event) => `<tr class="${escapeHtml38(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml38(event.type)}</td><td>${escapeHtml38(event.label)}</td><td>${escapeHtml38(event.provider ?? "")}</td><td>${escapeHtml38(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
21762
- const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml38(issue.severity)}">${escapeHtml38(issue.code)}: ${escapeHtml38(issue.message)}</li>`).join("") : "<li>none</li>";
21763
- return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml38(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>${escapeHtml38(session.sessionId)}</h1><p class="status ${escapeHtml38(session.status)}">${escapeHtml38(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>`;
21892
+ const events = session.events.map((event) => `<tr class="${escapeHtml39(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml39(event.type)}</td><td>${escapeHtml39(event.label)}</td><td>${escapeHtml39(event.provider ?? "")}</td><td>${escapeHtml39(event.status ?? "")}</td><td>${formatMs3(event.elapsedMs)}</td></tr>`).join("");
21893
+ const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml39(issue.severity)}">${escapeHtml39(issue.code)}: ${escapeHtml39(issue.message)}</li>`).join("") : "<li>none</li>";
21894
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml39(session.sessionId)}</h1><p class="status ${escapeHtml39(session.status)}">${escapeHtml39(session.status)}</p></header><section class="metrics"><article><span>Events</span><strong>${String(session.summary.eventCount)}</strong></article><article><span>Turns</span><strong>${String(session.summary.turnCount)}</strong></article><article><span>Errors</span><strong>${String(session.summary.errorCount)}</strong></article><article><span>Duration</span><strong>${formatMs3(session.summary.callDurationMs)}</strong></article></section><section><h2>Providers</h2>${renderProviderCards2(session)}</section><section><h2>Issues</h2><ul>${issues}</ul></section><section><h2>Timeline</h2><table><thead><tr><th>Offset</th><th>Type</th><th>Event</th><th>Provider</th><th>Status</th><th>Latency</th></tr></thead><tbody>${events}</tbody></table></section></main></body></html>`;
21764
21895
  };
21765
- var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml38(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml38(session.sessionId)}</a></td><td>${escapeHtml38(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) => escapeHtml38(provider.provider)).join(", ")}</td></tr>`).join("");
21896
+ var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml39(session.status)}"><td><a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml39(session.sessionId)}</a></td><td>${escapeHtml39(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs3(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml39(provider.provider)).join(", ")}</td></tr>`).join("");
21766
21897
  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}}";
21767
- 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>${escapeHtml38(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml38(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>`;
21898
+ var renderVoiceTraceTimelineHTML = (report, options = {}) => `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml39(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml39(options.title ?? "Voice Trace Timelines")}</h1><p class="muted">Per-call event timelines with provider latency, fallback, timeout, handoff, and error context.</p></header><section class="metrics"><article><span>Sessions</span><strong>${String(report.total)}</strong></article><article><span>Failed</span><strong>${String(report.failed)}</strong></article><article><span>Warnings</span><strong>${String(report.warnings)}</strong></article></section><table><thead><tr><th>Session</th><th>Status</th><th>Events</th><th>Turns</th><th>Errors</th><th>Duration</th><th>Providers</th></tr></thead><tbody>${renderSessionRows(report)}</tbody></table></main></body></html>`;
21768
21899
  var createVoiceTraceTimelineRoutes = (options) => {
21769
21900
  const path = options.path ?? "/api/voice-traces";
21770
21901
  const htmlPath = options.htmlPath ?? "/traces";
21771
21902
  const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
21772
- const routes = new Elysia36({
21903
+ const routes = new Elysia37({
21773
21904
  name: options.name ?? "absolutejs-voice-trace-timelines"
21774
21905
  });
21775
21906
  const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
@@ -22422,7 +22553,7 @@ var createVoiceMemoryStore = () => {
22422
22553
  return { get, getOrCreate, list, remove, set };
22423
22554
  };
22424
22555
  // src/opsWebhook.ts
22425
- import { Elysia as Elysia37 } from "elysia";
22556
+ import { Elysia as Elysia38 } from "elysia";
22426
22557
  var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
22427
22558
  var signVoiceOpsWebhookBody = async (input) => {
22428
22559
  const encoder = new TextEncoder;
@@ -22552,7 +22683,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
22552
22683
  };
22553
22684
  var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
22554
22685
  const path = options.path ?? "/api/voice-ops/webhook";
22555
- return new Elysia37().post(path, async ({ body, request, set }) => {
22686
+ return new Elysia38().post(path, async ({ body, request, set }) => {
22556
22687
  const bodyText = typeof body === "string" ? body : JSON.stringify(body);
22557
22688
  if (options.signingSecret) {
22558
22689
  const verification = await verifyVoiceOpsWebhookSignature({
@@ -23491,6 +23622,7 @@ export {
23491
23622
  renderVoiceOutcomeContractHTML,
23492
23623
  renderVoiceOpsStatusHTML,
23493
23624
  renderVoiceOpsConsoleHTML,
23625
+ renderVoiceOpsActionHistoryHTML,
23494
23626
  renderVoiceLiveLatencyHTML,
23495
23627
  renderVoiceHandoffHealthHTML,
23496
23628
  renderVoiceEvalHTML,
@@ -23518,6 +23650,7 @@ export {
23518
23650
  recordVoiceRuntimeOps,
23519
23651
  recordVoiceRetentionAuditEvent,
23520
23652
  recordVoiceProviderAuditEvent,
23653
+ recordVoiceOpsActionAudit,
23521
23654
  recordVoiceOperatorAuditEvent,
23522
23655
  recordVoiceHandoffAuditEvent,
23523
23656
  recordVoiceAuditEvent,
@@ -23669,6 +23802,7 @@ export {
23669
23802
  createVoiceOpsStatusRoutes,
23670
23803
  createVoiceOpsRuntime,
23671
23804
  createVoiceOpsConsoleRoutes,
23805
+ createVoiceOpsActionAuditRoutes,
23672
23806
  createVoiceMemoryTraceSinkDeliveryStore,
23673
23807
  createVoiceMemoryTraceEventStore,
23674
23808
  createVoiceMemoryStore,
@@ -23790,6 +23924,7 @@ export {
23790
23924
  buildVoiceOpsTaskFromSLABreach,
23791
23925
  buildVoiceOpsTaskFromReview,
23792
23926
  buildVoiceOpsConsoleReport,
23927
+ buildVoiceOpsActionHistoryReport,
23793
23928
  buildVoiceDiagnosticsMarkdown,
23794
23929
  buildVoiceDemoReadyReport,
23795
23930
  buildVoiceDeliverySinkReport,