@absolutejs/voice 0.0.22-beta.319 → 0.0.22-beta.320
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/angular/index.js +413 -0
- package/dist/browserMediaRoutes.d.ts +61 -0
- package/dist/client/browserMedia.d.ts +8 -0
- package/dist/client/htmxBootstrap.js +172 -1
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +414 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +587 -404
- package/dist/react/index.js +413 -0
- package/dist/svelte/index.js +413 -0
- package/dist/testing/index.js +441 -28
- package/dist/trace.d.ts +1 -1
- package/dist/types.d.ts +19 -0
- package/dist/vue/index.js +413 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11625,6 +11625,28 @@ var numericMetadata = (frame, key) => {
|
|
|
11625
11625
|
var average = (values) => values.length === 0 ? undefined : values.reduce((total, value) => total + value, 0) / values.length;
|
|
11626
11626
|
var max = (values) => values.length === 0 ? undefined : Math.max(...values);
|
|
11627
11627
|
var min = (values) => values.length === 0 ? undefined : Math.min(...values);
|
|
11628
|
+
var numericStat = (stat, key) => {
|
|
11629
|
+
const value = stat[key];
|
|
11630
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
11631
|
+
};
|
|
11632
|
+
var booleanStat = (stat, key) => {
|
|
11633
|
+
const value = stat[key];
|
|
11634
|
+
return typeof value === "boolean" ? value : undefined;
|
|
11635
|
+
};
|
|
11636
|
+
var stringStat = (stat, key) => {
|
|
11637
|
+
const value = stat[key];
|
|
11638
|
+
return typeof value === "string" ? value : undefined;
|
|
11639
|
+
};
|
|
11640
|
+
var secondsToMs = (value) => value === undefined ? undefined : value * 1000;
|
|
11641
|
+
var normalizeWebRTCStat = (stat) => {
|
|
11642
|
+
const sample = {};
|
|
11643
|
+
for (const [key, value] of Object.entries(stat)) {
|
|
11644
|
+
if (value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string") {
|
|
11645
|
+
sample[key] = value;
|
|
11646
|
+
}
|
|
11647
|
+
}
|
|
11648
|
+
return sample;
|
|
11649
|
+
};
|
|
11628
11650
|
var buildMediaResamplingPlan = (input) => {
|
|
11629
11651
|
const required = !formatMatches2(input.inputFormat, input.outputFormat);
|
|
11630
11652
|
return {
|
|
@@ -11797,6 +11819,77 @@ var buildMediaQualityReport = (input = {}) => {
|
|
|
11797
11819
|
unknownSpeechFrames
|
|
11798
11820
|
};
|
|
11799
11821
|
};
|
|
11822
|
+
var buildMediaWebRTCStatsReport = (input = {}) => {
|
|
11823
|
+
const stats = input.stats ?? [];
|
|
11824
|
+
const issues = [];
|
|
11825
|
+
const inbound = stats.filter((stat) => stat.type === "inbound-rtp" && stringStat(stat, "kind") !== "video");
|
|
11826
|
+
const outbound = stats.filter((stat) => stat.type === "outbound-rtp" && stringStat(stat, "kind") !== "video");
|
|
11827
|
+
const candidatePairs = stats.filter((stat) => stat.type === "candidate-pair");
|
|
11828
|
+
const audioTracks = stats.filter((stat) => (stat.type === "track" || stat.type === "media-source") && stringStat(stat, "kind") === "audio");
|
|
11829
|
+
const activeCandidatePairs = candidatePairs.filter((stat) => booleanStat(stat, "selected") === true || booleanStat(stat, "nominated") === true || stringStat(stat, "state") === "succeeded").length;
|
|
11830
|
+
const liveAudioTracks = audioTracks.filter((stat) => stringStat(stat, "readyState") !== "ended" && stringStat(stat, "trackState") !== "ended" && booleanStat(stat, "ended") !== true).length;
|
|
11831
|
+
const endedAudioTracks = audioTracks.filter((stat) => stringStat(stat, "readyState") === "ended" || stringStat(stat, "trackState") === "ended" || booleanStat(stat, "ended") === true).length;
|
|
11832
|
+
const inboundPackets = inbound.reduce((total, stat) => total + (numericStat(stat, "packetsReceived") ?? 0), 0);
|
|
11833
|
+
const outboundPackets = outbound.reduce((total, stat) => total + (numericStat(stat, "packetsSent") ?? 0), 0);
|
|
11834
|
+
const packetsLost = [...inbound, ...outbound].reduce((total, stat) => total + Math.max(0, numericStat(stat, "packetsLost") ?? 0), 0);
|
|
11835
|
+
const packetLossDenominator = inboundPackets + packetsLost;
|
|
11836
|
+
const packetLossRatio = packetLossDenominator === 0 ? 0 : packetsLost / packetLossDenominator;
|
|
11837
|
+
const bytesReceived = inbound.reduce((total, stat) => total + (numericStat(stat, "bytesReceived") ?? 0), 0);
|
|
11838
|
+
const bytesSent = outbound.reduce((total, stat) => total + (numericStat(stat, "bytesSent") ?? 0), 0);
|
|
11839
|
+
const roundTripTimeMs = max(candidatePairs.map((stat) => secondsToMs(numericStat(stat, "currentRoundTripTime") ?? numericStat(stat, "roundTripTime"))).filter((value) => value !== undefined));
|
|
11840
|
+
const jitterMs = max([...inbound, ...outbound].map((stat) => secondsToMs(numericStat(stat, "jitter"))).filter((value) => value !== undefined));
|
|
11841
|
+
const jitterBufferDelayMs = max(inbound.map((stat) => {
|
|
11842
|
+
const delay = numericStat(stat, "jitterBufferDelay");
|
|
11843
|
+
const emitted = numericStat(stat, "jitterBufferEmittedCount");
|
|
11844
|
+
return delay !== undefined && emitted !== undefined && emitted > 0 ? delay / emitted * 1000 : undefined;
|
|
11845
|
+
}).filter((value) => value !== undefined));
|
|
11846
|
+
const audioLevels = audioTracks.map((stat) => numericStat(stat, "audioLevel")).filter((value) => value !== undefined);
|
|
11847
|
+
if (input.requireConnectedCandidatePair && candidatePairs.length > 0 && activeCandidatePairs === 0) {
|
|
11848
|
+
pushIssue(issues, "error", "media.webrtc_candidate_pair_missing", "No active WebRTC candidate pair was observed.");
|
|
11849
|
+
}
|
|
11850
|
+
if (input.requireLiveAudioTrack && liveAudioTracks === 0) {
|
|
11851
|
+
pushIssue(issues, "error", "media.webrtc_audio_track_missing", "No live WebRTC audio track was observed.");
|
|
11852
|
+
}
|
|
11853
|
+
if (input.maxPacketLossRatio !== undefined && packetLossRatio > input.maxPacketLossRatio) {
|
|
11854
|
+
pushIssue(issues, "warning", "media.webrtc_packet_loss", `Observed WebRTC packet loss ratio ${String(packetLossRatio)} above ${String(input.maxPacketLossRatio)}.`);
|
|
11855
|
+
}
|
|
11856
|
+
if (input.maxRoundTripTimeMs !== undefined && roundTripTimeMs !== undefined && roundTripTimeMs > input.maxRoundTripTimeMs) {
|
|
11857
|
+
pushIssue(issues, "warning", "media.webrtc_round_trip_time", `Observed WebRTC RTT ${String(roundTripTimeMs)}ms above ${String(input.maxRoundTripTimeMs)}ms.`);
|
|
11858
|
+
}
|
|
11859
|
+
if (input.maxJitterMs !== undefined && jitterMs !== undefined && jitterMs > input.maxJitterMs) {
|
|
11860
|
+
pushIssue(issues, "warning", "media.webrtc_jitter", `Observed WebRTC jitter ${String(jitterMs)}ms above ${String(input.maxJitterMs)}ms.`);
|
|
11861
|
+
}
|
|
11862
|
+
return {
|
|
11863
|
+
activeCandidatePairs,
|
|
11864
|
+
audioLevelAverage: average(audioLevels),
|
|
11865
|
+
bytesReceived,
|
|
11866
|
+
bytesSent,
|
|
11867
|
+
checkedAt: Date.now(),
|
|
11868
|
+
endedAudioTracks,
|
|
11869
|
+
inboundPackets,
|
|
11870
|
+
issues,
|
|
11871
|
+
jitterBufferDelayMs,
|
|
11872
|
+
jitterMs,
|
|
11873
|
+
liveAudioTracks,
|
|
11874
|
+
outboundPackets,
|
|
11875
|
+
packetLossRatio,
|
|
11876
|
+
packetsLost,
|
|
11877
|
+
roundTripTimeMs,
|
|
11878
|
+
status: issues.some((issue) => issue.severity === "error") ? "fail" : issues.length > 0 ? "warn" : "pass",
|
|
11879
|
+
totalStats: stats.length
|
|
11880
|
+
};
|
|
11881
|
+
};
|
|
11882
|
+
var collectMediaWebRTCStats = async (input) => {
|
|
11883
|
+
const report = await input.peerConnection.getStats(input.selector ?? null);
|
|
11884
|
+
return [...report.values()].map(normalizeWebRTCStat);
|
|
11885
|
+
};
|
|
11886
|
+
var collectMediaWebRTCStatsReport = async (input) => {
|
|
11887
|
+
const stats = await collectMediaWebRTCStats(input);
|
|
11888
|
+
return buildMediaWebRTCStatsReport({
|
|
11889
|
+
...input,
|
|
11890
|
+
stats
|
|
11891
|
+
});
|
|
11892
|
+
};
|
|
11800
11893
|
var buildMediaPipelineCalibrationReport = (input = {}) => {
|
|
11801
11894
|
const frames = input.frames ?? [];
|
|
11802
11895
|
const issues = [];
|
|
@@ -12103,9 +12196,95 @@ var createVoiceMediaPipelineRoutes = (options = {}) => {
|
|
|
12103
12196
|
}
|
|
12104
12197
|
return app;
|
|
12105
12198
|
};
|
|
12106
|
-
// src/
|
|
12199
|
+
// src/browserMediaRoutes.ts
|
|
12107
12200
|
import { Elysia as Elysia13 } from "elysia";
|
|
12108
12201
|
var escapeHtml16 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12202
|
+
var isMediaWebRTCStatsReport = (value) => {
|
|
12203
|
+
const report = value;
|
|
12204
|
+
return !!report && typeof report === "object" && (report.status === "pass" || report.status === "warn" || report.status === "fail") && typeof report.activeCandidatePairs === "number" && typeof report.liveAudioTracks === "number" && typeof report.packetLossRatio === "number" && typeof report.bytesReceived === "number" && typeof report.bytesSent === "number" && Array.isArray(report.issues);
|
|
12205
|
+
};
|
|
12206
|
+
var isBrowserMediaPostBody = (value) => {
|
|
12207
|
+
const body = value;
|
|
12208
|
+
return !!body && isMediaWebRTCStatsReport(body.report);
|
|
12209
|
+
};
|
|
12210
|
+
var toBrowserMediaSample = (event) => {
|
|
12211
|
+
if (event.type !== "client.browser_media" || !isMediaWebRTCStatsReport(event.payload.report)) {
|
|
12212
|
+
return;
|
|
12213
|
+
}
|
|
12214
|
+
return {
|
|
12215
|
+
at: event.at,
|
|
12216
|
+
report: event.payload.report,
|
|
12217
|
+
scenarioId: event.scenarioId,
|
|
12218
|
+
sessionId: event.sessionId,
|
|
12219
|
+
traceId: event.traceId
|
|
12220
|
+
};
|
|
12221
|
+
};
|
|
12222
|
+
var summarizeVoiceBrowserMedia = async (options) => {
|
|
12223
|
+
const events = await options.store.list({
|
|
12224
|
+
limit: 100,
|
|
12225
|
+
type: "client.browser_media"
|
|
12226
|
+
});
|
|
12227
|
+
const recent = events.map(toBrowserMediaSample).filter((sample) => !!sample).sort((left, right) => right.at - left.at);
|
|
12228
|
+
const latest = recent[0];
|
|
12229
|
+
const maxAgeMs = options.maxAgeMs ?? 30000;
|
|
12230
|
+
const stale = latest ? Date.now() - latest.at > maxAgeMs : false;
|
|
12231
|
+
return {
|
|
12232
|
+
checkedAt: Date.now(),
|
|
12233
|
+
latest,
|
|
12234
|
+
recent,
|
|
12235
|
+
stale,
|
|
12236
|
+
status: latest ? latest.report.status === "pass" && !stale ? "pass" : stale ? "warn" : latest.report.status : "empty",
|
|
12237
|
+
total: recent.length
|
|
12238
|
+
};
|
|
12239
|
+
};
|
|
12240
|
+
var getLatestVoiceBrowserMediaReport = async (options) => {
|
|
12241
|
+
const summary = await summarizeVoiceBrowserMedia(options);
|
|
12242
|
+
return summary.latest?.report;
|
|
12243
|
+
};
|
|
12244
|
+
var renderVoiceBrowserMediaHTML = (report, options = {}) => {
|
|
12245
|
+
const title = options.title ?? "Voice Browser Media";
|
|
12246
|
+
const latest = report.latest?.report;
|
|
12247
|
+
const rows = report.recent.slice(0, 20).map((sample) => `<tr><td>${escapeHtml16(sample.sessionId)}</td><td>${escapeHtml16(sample.report.status)}</td><td>${String(sample.report.activeCandidatePairs)}</td><td>${String(sample.report.liveAudioTracks)}</td><td>${String(sample.report.roundTripTimeMs ?? "n/a")}ms</td><td>${String(sample.report.jitterMs ?? "n/a")}ms</td><td>${String(sample.report.packetLossRatio)}</td><td>${escapeHtml16(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
12248
|
+
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:#0f172a;color:#e2e8f0;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,.primitive,table{background:#111827;border:1px solid #334155;border-radius:22px;margin-bottom:16px}.hero,.primitive{padding:22px}.eyebrow{color:#93c5fd;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}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.pass{color:#86efac}.warn,.empty{color:#fde68a}.fail{color:#fecaca}.metrics{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin-top:18px}.metric{background:#0b1220;border:1px solid #263244;border-radius:16px;padding:14px}.metric span{color:#94a3b8}.metric strong{display:block;font-size:1.7rem;margin-top:4px}.primitive code{color:#bfdbfe}table{border-collapse:collapse;overflow:hidden;width:100%}td,th{border-bottom:1px solid #334155;padding:10px;text-align:left}</style></head><body><main><section class="hero"><p class="eyebrow">Browser WebRTC media proof</p><h1>${escapeHtml16(title)}</h1><p class="status ${escapeHtml16(report.status)}">Status: ${escapeHtml16(report.status)}</p><p>Recent <code>client.browser_media</code> traces from browser <code>RTCPeerConnection.getStats()</code> reports.</p><section class="metrics"><div class="metric"><span>Reports</span><strong>${String(report.total)}</strong></div><div class="metric"><span>Candidate pairs</span><strong>${String(latest?.activeCandidatePairs ?? 0)}</strong></div><div class="metric"><span>Live audio tracks</span><strong>${String(latest?.liveAudioTracks ?? 0)}</strong></div><div class="metric"><span>RTT</span><strong>${String(latest?.roundTripTimeMs ?? "n/a")}ms</strong></div><div class="metric"><span>Jitter</span><strong>${String(latest?.jitterMs ?? "n/a")}ms</strong></div><div class="metric"><span>Loss</span><strong>${String(latest?.packetLossRatio ?? "n/a")}</strong></div></section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><p><code>createVoiceBrowserMediaReporter({ peerConnection })</code> runs in the browser and posts reports here. <code>getLatestVoiceBrowserMediaReport(...)</code> can feed production readiness.</p></section><table><thead><tr><th>Session</th><th>Status</th><th>Pairs</th><th>Tracks</th><th>RTT</th><th>Jitter</th><th>Loss</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="8">No browser media reports yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
12249
|
+
};
|
|
12250
|
+
var createVoiceBrowserMediaRoutes = (options) => {
|
|
12251
|
+
const path = options.path ?? "/api/voice/browser-media";
|
|
12252
|
+
const htmlPath = options.htmlPath === undefined ? "/voice/browser-media" : options.htmlPath;
|
|
12253
|
+
const routes = new Elysia13({
|
|
12254
|
+
name: options.name ?? "absolutejs-voice-browser-media"
|
|
12255
|
+
});
|
|
12256
|
+
routes.get(path, () => summarizeVoiceBrowserMedia(options));
|
|
12257
|
+
routes.post(path, async ({ body }) => {
|
|
12258
|
+
if (!isBrowserMediaPostBody(body)) {
|
|
12259
|
+
return Response.json({ error: "Invalid browser media report." }, { status: 400 });
|
|
12260
|
+
}
|
|
12261
|
+
await options.store.append({
|
|
12262
|
+
at: typeof body.at === "number" ? body.at : Date.now(),
|
|
12263
|
+
payload: {
|
|
12264
|
+
report: body.report
|
|
12265
|
+
},
|
|
12266
|
+
scenarioId: typeof body.scenarioId === "string" ? body.scenarioId : undefined,
|
|
12267
|
+
sessionId: typeof body.sessionId === "string" ? body.sessionId : "unknown",
|
|
12268
|
+
type: "client.browser_media"
|
|
12269
|
+
});
|
|
12270
|
+
return Response.json({ ok: true });
|
|
12271
|
+
});
|
|
12272
|
+
if (htmlPath) {
|
|
12273
|
+
routes.get(htmlPath, async () => {
|
|
12274
|
+
const report = await summarizeVoiceBrowserMedia(options);
|
|
12275
|
+
return new Response(renderVoiceBrowserMediaHTML(report, options), {
|
|
12276
|
+
headers: {
|
|
12277
|
+
"content-type": "text/html; charset=utf-8",
|
|
12278
|
+
...options.headers
|
|
12279
|
+
}
|
|
12280
|
+
});
|
|
12281
|
+
});
|
|
12282
|
+
}
|
|
12283
|
+
return routes;
|
|
12284
|
+
};
|
|
12285
|
+
// src/demoReadyRoutes.ts
|
|
12286
|
+
import { Elysia as Elysia14 } from "elysia";
|
|
12287
|
+
var escapeHtml17 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12109
12288
|
var rollupStatus2 = (sections) => sections.some((section) => section.status === "fail") ? "fail" : sections.some((section) => section.status === "warn") ? "warn" : "pass";
|
|
12110
12289
|
var resolveLoader = async (loader, input) => typeof loader === "function" ? await loader(input) : loader;
|
|
12111
12290
|
var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
@@ -12189,17 +12368,17 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
12189
12368
|
};
|
|
12190
12369
|
};
|
|
12191
12370
|
var renderVoiceDemoReadyHTML = (report) => {
|
|
12192
|
-
const sections = report.sections.map((section) => `<article class="section ${
|
|
12193
|
-
<div><span>${
|
|
12194
|
-
<strong>${
|
|
12195
|
-
${section.href ? `<a href="${
|
|
12371
|
+
const sections = report.sections.map((section) => `<article class="section ${escapeHtml17(section.status)}">
|
|
12372
|
+
<div><span>${escapeHtml17(section.status.toUpperCase())}</span><h2>${escapeHtml17(section.label)}</h2>${section.description ? `<p>${escapeHtml17(section.description)}</p>` : ""}</div>
|
|
12373
|
+
<strong>${escapeHtml17(String(section.value ?? section.status))}</strong>
|
|
12374
|
+
${section.href ? `<a href="${escapeHtml17(section.href)}">Open</a>` : ""}
|
|
12196
12375
|
</article>`).join("");
|
|
12197
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12376
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml17(report.title)}</title><style>body{background:#0d141b;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.2),rgba(245,158,11,.12));border:1px solid #283544;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #3f3f46;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.sections{display:grid;gap:14px}.section{align-items:center;background:#151d26;border:1px solid #283544;border-radius:22px;display:grid;gap:16px;grid-template-columns:1fr auto auto;padding:18px}.section span{color:#aab5c0;font-size:.78rem;font-weight:900;letter-spacing:.08em}.section h2{margin:.2rem 0}.section p{color:#b9c0c8;margin:.2rem 0 0}.section strong{font-size:1.4rem}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.65)}.fail{border-color:rgba(239,68,68,.75)}a{color:#5eead4}@media(max-width:760px){main{padding:20px}.section{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Demo readiness</p><h1>${escapeHtml17(report.title)}</h1><p>One customer-facing checklist for the self-hosted voice proof surfaces: ops status, production readiness, phone setup, and phone smoke traces.</p><p class="status ${escapeHtml17(report.status)}">Overall: ${escapeHtml17(report.status.toUpperCase())}</p><p>Checked ${escapeHtml17(new Date(report.checkedAt).toLocaleString())}</p></section><section class="sections">${sections || '<article class="section warn"><div><span>WARN</span><h2>No checks configured</h2><p>Add ops status, production readiness, phone setup, or phone smoke loaders.</p></div><strong>warn</strong></article>'}</section></main></body></html>`;
|
|
12198
12377
|
};
|
|
12199
12378
|
var createVoiceDemoReadyRoutes = (options) => {
|
|
12200
12379
|
const path = options.path ?? "/api/demo-ready";
|
|
12201
12380
|
const htmlPath = options.htmlPath ?? "/demo-ready";
|
|
12202
|
-
const routes = new
|
|
12381
|
+
const routes = new Elysia14({
|
|
12203
12382
|
name: options.name ?? "absolutejs-voice-demo-ready"
|
|
12204
12383
|
});
|
|
12205
12384
|
routes.get(path, async ({ query, request }) => buildVoiceDemoReadyReport(options, { query, request }));
|
|
@@ -12218,7 +12397,7 @@ var createVoiceDemoReadyRoutes = (options) => {
|
|
|
12218
12397
|
return routes;
|
|
12219
12398
|
};
|
|
12220
12399
|
// src/deliverySinkRoutes.ts
|
|
12221
|
-
import { Elysia as
|
|
12400
|
+
import { Elysia as Elysia15 } from "elysia";
|
|
12222
12401
|
|
|
12223
12402
|
// src/queue.ts
|
|
12224
12403
|
var releaseLeaseScript = `
|
|
@@ -13161,7 +13340,7 @@ var createVoiceOpsTaskProcessorWorkerLoop = (options) => {
|
|
|
13161
13340
|
};
|
|
13162
13341
|
|
|
13163
13342
|
// src/deliverySinkRoutes.ts
|
|
13164
|
-
var
|
|
13343
|
+
var escapeHtml18 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13165
13344
|
var deliveryStatus = (summary) => {
|
|
13166
13345
|
if (!summary) {
|
|
13167
13346
|
return "warn";
|
|
@@ -13260,13 +13439,13 @@ var renderSurfaceCard = (surface) => {
|
|
|
13260
13439
|
return "";
|
|
13261
13440
|
}
|
|
13262
13441
|
const value = `${surface.summary.delivered}/${surface.summary.total}`;
|
|
13263
|
-
const body = `<span>${
|
|
13264
|
-
return `<article>${surface.href ? `<a href="${
|
|
13442
|
+
const body = `<span>${escapeHtml18(surface.label)}</span><strong>${escapeHtml18(value)}</strong><p class="muted">Delivered export records.</p>`;
|
|
13443
|
+
return `<article>${surface.href ? `<a href="${escapeHtml18(surface.href)}">${body}</a>` : body}</article>`;
|
|
13265
13444
|
};
|
|
13266
13445
|
var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
13267
13446
|
const title = options.title ?? "AbsoluteJS Voice Delivery Sinks";
|
|
13268
|
-
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${
|
|
13269
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13447
|
+
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${escapeHtml18(sink.kind)}</span><strong style="font-size:1.5rem">${escapeHtml18(sink.label)}</strong>${sink.description ? `<p class="muted">${escapeHtml18(sink.description)}</p>` : ""}${sink.mode ? `<p class="muted">Mode: ${escapeHtml18(sink.mode)}</p>` : ""}${sink.target ? `<p class="muted">Target: <code>${escapeHtml18(sink.target)}</code></p>` : ""}${sink.href ? `<p><a href="${escapeHtml18(sink.href)}">Open sink</a></p>` : ""}</article>`).join("") : '<article><span>Sink</span><strong style="font-size:1.5rem">Not described</strong><p class="muted">Pass sink descriptors to document your file, webhook, S3, SQLite, or Postgres targets.</p></article>';
|
|
13448
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml18(title)}</title><style>body{background:#11120d;color:#fbf7e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{max-width:1120px;margin:auto;padding:32px}a{color:#fde68a;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(253,230,138,.2),rgba(34,197,94,.14));border:1px solid #3a3420;border-radius:30px;margin-bottom:18px;padding:28px}.eyebrow{color:#fde68a;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #575030;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.pass{border-color:rgba(34,197,94,.65)}.status.warn{border-color:rgba(245,158,11,.65)}.status.fail{border-color:rgba(239,68,68,.75)}.muted{color:#b8b093}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#191a13;border:1px solid #33311f;border-radius:22px;padding:18px}article span{color:#b8b093;display:block;font-weight:800}article strong{display:block;font-size:2.4rem;margin-top:8px}pre{background:#0c0d09;border:1px solid #33311f;border-radius:18px;color:#fef3c7;overflow:auto;padding:16px}code{color:#fef3c7}</style></head><body><main><p><a href="/production-readiness">Production readiness</a></p><section class="hero"><p class="eyebrow">Composable sink primitive</p><h1>${escapeHtml18(title)}</h1><p class="muted">Delivery queues prove audit and trace exports without owning your infrastructure. Swap file, webhook, S3, SQLite, or Postgres sinks behind the same readiness surface.</p><p class="status ${escapeHtml18(report.status)}">Overall: ${escapeHtml18(report.status.toUpperCase())}</p><p class="muted">Checked ${escapeHtml18(new Date(report.checkedAt).toLocaleString())}</p></section><section class="grid">${renderSurfaceCard(report.auditDeliveries)}${renderSurfaceCard(report.traceDeliveries)}${sinks}</section><section class="card"><h2>Primitive shape</h2><p class="muted">Mount delivery sink routes beside audit and trace delivery queues. Production readiness can consume the same stores for pass/fail evidence.</p><pre>createVoiceDeliverySinkRoutes({
|
|
13270
13449
|
auditDeliveries: { store: runtimeStorage.auditDeliveries },
|
|
13271
13450
|
traceDeliveries: { store: runtimeStorage.traceDeliveries },
|
|
13272
13451
|
sinks: createVoiceDeliverySinkPair({
|
|
@@ -13278,7 +13457,7 @@ var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
|
13278
13457
|
var createVoiceDeliverySinkRoutes = (options) => {
|
|
13279
13458
|
const path = options.path ?? "/api/voice-delivery-sinks";
|
|
13280
13459
|
const htmlPath = options.htmlPath === undefined ? "/delivery-sinks" : options.htmlPath;
|
|
13281
|
-
const routes = new
|
|
13460
|
+
const routes = new Elysia15({
|
|
13282
13461
|
name: options.name ?? "absolutejs-voice-delivery-sinks"
|
|
13283
13462
|
}).get(path, () => buildVoiceDeliverySinkReport(options));
|
|
13284
13463
|
if (htmlPath !== false) {
|
|
@@ -13296,7 +13475,7 @@ var createVoiceDeliverySinkRoutes = (options) => {
|
|
|
13296
13475
|
return routes;
|
|
13297
13476
|
};
|
|
13298
13477
|
// src/opsActionAuditRoutes.ts
|
|
13299
|
-
import { Elysia as
|
|
13478
|
+
import { Elysia as Elysia16 } from "elysia";
|
|
13300
13479
|
var readRecordBody = (body) => {
|
|
13301
13480
|
if (!body || typeof body !== "object") {
|
|
13302
13481
|
throw new Error("Voice ops action audit requires a JSON body.");
|
|
@@ -13371,7 +13550,7 @@ var createVoiceOpsActionAuditRoutes = (options) => {
|
|
|
13371
13550
|
const path = options.path ?? "/api/voice/ops-actions/audit";
|
|
13372
13551
|
const historyPath = options.historyPath === undefined ? "/api/voice/ops-actions/history" : options.historyPath;
|
|
13373
13552
|
const historyHtmlPath = options.historyHtmlPath === undefined ? "/voice/ops-actions" : options.historyHtmlPath;
|
|
13374
|
-
const routes = new
|
|
13553
|
+
const routes = new Elysia16({
|
|
13375
13554
|
name: options.name ?? "absolutejs-voice-ops-action-audit"
|
|
13376
13555
|
}).post(path, async ({ body, request, set }) => {
|
|
13377
13556
|
try {
|
|
@@ -13421,13 +13600,13 @@ var buildVoiceOpsActionHistoryReport = async (options) => {
|
|
|
13421
13600
|
total: entries.length
|
|
13422
13601
|
};
|
|
13423
13602
|
};
|
|
13424
|
-
var
|
|
13603
|
+
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13425
13604
|
var renderVoiceOpsActionHistoryHTML = (report) => {
|
|
13426
|
-
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${
|
|
13605
|
+
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${escapeHtml19(entry.ok ? "success" : "error")}</span><strong>${escapeHtml19(entry.actionId)}</strong><p>${escapeHtml19(new Date(entry.at).toLocaleString())}${entry.status ? ` \xB7 HTTP ${String(entry.status)}` : ""}</p>${entry.error ? `<p>${escapeHtml19(entry.error)}</p>` : ""}</article>`).join("");
|
|
13427
13606
|
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>`;
|
|
13428
13607
|
};
|
|
13429
13608
|
// src/platformCoverage.ts
|
|
13430
|
-
import { Elysia as
|
|
13609
|
+
import { Elysia as Elysia17 } from "elysia";
|
|
13431
13610
|
var buildVoicePlatformCoverageSummary = (input) => {
|
|
13432
13611
|
const coverage = input.coverage ?? [];
|
|
13433
13612
|
const ok = input.ok ?? (coverage.length > 0 && coverage.every((surface) => surface.status === "pass"));
|
|
@@ -13488,7 +13667,7 @@ var assertVoicePlatformCoverage = (summary, input = {}) => {
|
|
|
13488
13667
|
var normalizeCoverageSummary = (value) => ("status" in value) && ("total" in value) && ("coverage" in value) ? value : buildVoicePlatformCoverageSummary(value);
|
|
13489
13668
|
var createVoicePlatformCoverageRoutes = (options) => {
|
|
13490
13669
|
const path = options.path ?? "/api/voice/platform-coverage";
|
|
13491
|
-
const routes = new
|
|
13670
|
+
const routes = new Elysia17({
|
|
13492
13671
|
name: options.name ?? "absolutejs-voice-platform-coverage"
|
|
13493
13672
|
});
|
|
13494
13673
|
routes.get(path, async () => {
|
|
@@ -13500,8 +13679,8 @@ var createVoicePlatformCoverageRoutes = (options) => {
|
|
|
13500
13679
|
return routes;
|
|
13501
13680
|
};
|
|
13502
13681
|
// src/competitiveCoverage.ts
|
|
13503
|
-
import { Elysia as
|
|
13504
|
-
var
|
|
13682
|
+
import { Elysia as Elysia18 } from "elysia";
|
|
13683
|
+
var escapeHtml20 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13505
13684
|
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
13506
13685
|
var resolveSurfaceStatus = (surface) => {
|
|
13507
13686
|
if (surface.status)
|
|
@@ -13669,24 +13848,24 @@ var renderVoiceCompetitiveCoverageMarkdown = (report, title = "Voice Competitive
|
|
|
13669
13848
|
`);
|
|
13670
13849
|
var renderVoiceCompetitiveCoverageHTML = (report, title = "Voice Competitive Coverage") => {
|
|
13671
13850
|
const surfaceCards = report.surfaces.map((surface) => {
|
|
13672
|
-
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${
|
|
13673
|
-
return `<article class="surface ${
|
|
13674
|
-
<header><div><p class="eyebrow">${
|
|
13675
|
-
<p>${
|
|
13851
|
+
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${escapeHtml20(item.name)}</strong>${item.kind ? ` <span>${escapeHtml20(item.kind)}</span>` : ""}${item.status ? ` <em>${escapeHtml20(item.status)}</em>` : ""}${item.href ? ` <a href="${escapeHtml20(item.href)}">open</a>` : ""}</li>`).join("");
|
|
13852
|
+
return `<article class="surface ${escapeHtml20(surface.status)} ${escapeHtml20(surface.depth)}">
|
|
13853
|
+
<header><div><p class="eyebrow">${escapeHtml20(surface.coverage)} \xB7 ${escapeHtml20(surface.depth)}</p><h2>${escapeHtml20(surface.surface)}</h2></div><strong>${escapeHtml20(surface.status)}</strong></header>
|
|
13854
|
+
<p>${escapeHtml20(surface.why)}</p>
|
|
13676
13855
|
<dl>
|
|
13677
|
-
<div><dt>Competitors</dt><dd>${
|
|
13678
|
-
<div><dt>Operations record</dt><dd>${
|
|
13679
|
-
<div><dt>Readiness gate</dt><dd>${
|
|
13680
|
-
<div><dt>Frameworks</dt><dd>${
|
|
13856
|
+
<div><dt>Competitors</dt><dd>${escapeHtml20((surface.competitors ?? []).join(", ") || "n/a")}</dd></div>
|
|
13857
|
+
<div><dt>Operations record</dt><dd>${escapeHtml20(surface.operationsRecord ?? "unknown")}</dd></div>
|
|
13858
|
+
<div><dt>Readiness gate</dt><dd>${escapeHtml20(surface.readinessGate ?? "unknown")}</dd></div>
|
|
13859
|
+
<div><dt>Frameworks</dt><dd>${escapeHtml20((surface.frameworkPrimitives ?? []).join(", ") || "n/a")}</dd></div>
|
|
13681
13860
|
</dl>
|
|
13682
|
-
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${
|
|
13683
|
-
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${
|
|
13861
|
+
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${escapeHtml20(surface.remainingGap)}</p>` : ""}
|
|
13862
|
+
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${escapeHtml20(surface.nextMove)}</p>` : ""}
|
|
13684
13863
|
${evidence ? `<h3>Evidence</h3><ul>${evidence}</ul>` : '<p class="muted">No evidence links configured.</p>'}
|
|
13685
13864
|
</article>`;
|
|
13686
13865
|
}).join(`
|
|
13687
13866
|
`);
|
|
13688
|
-
const issueList = report.issues.map((issue) => `<li class="${
|
|
13689
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13867
|
+
const issueList = report.issues.map((issue) => `<li class="${escapeHtml20(issue.severity)}"><strong>${escapeHtml20(issue.code)}</strong>${issue.surface ? ` ${escapeHtml20(issue.surface)}` : ""}: ${escapeHtml20(issue.message)}</li>`).join("");
|
|
13868
|
+
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:#0e1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.surface,.issues{background:#17201c;border:1px solid #2e3c35;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.16),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.surfaces{display:grid;gap:14px}.surface header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.surface.pass{border-color:rgba(34,197,94,.55)}.surface.warn{border-color:rgba(245,158,11,.72)}.surface.fail{border-color:rgba(239,68,68,.75)}.surface.advantage h2{color:#bbf7d0}.surface.intentional-gap h2{color:#cbd5e1}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}dt{color:#9fb0a8;font-size:.8rem;font-weight:800}dd{margin:0;overflow-wrap:anywhere}.gap{color:#fde68a}.next{color:#bfdbfe}.muted{color:#a8b5ad}a{color:#5eead4}.issues li{margin:.4rem 0}.issues .error{color:#fecaca}.issues .warning{color:#fde68a}@media(max-width:760px){main{padding:18px}.surface header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Self-hosted market proof</p><h1>${escapeHtml20(title)}</h1><p>Generated ${escapeHtml20(report.generatedAt)}. This report scores whether AbsoluteJS Voice merely covers a hosted-platform buyer surface or beats it for a code-owned/self-hosted buyer.</p><div class="summary"><span class="pill">Status ${escapeHtml20(report.status)}</span><span class="pill">Vapi-style ${escapeHtml20(report.vapiCoverageEstimate)}</span><span class="pill">Market ${escapeHtml20(report.marketCoverageEstimate)}</span><span class="pill">${String(report.summary.surfaces)} surfaces</span><span class="pill">${String(report.summary.advantage)} advantage</span><span class="pill">${String(report.summary.intentionalGaps)} intentional gaps</span></div></section><section class="issues"><h2>Issues</h2><ul>${issueList || "<li>No issues.</li>"}</ul></section><section class="surfaces">${surfaceCards || '<article class="surface"><p>No competitive surfaces configured.</p></article>'}</section></main></body></html>`;
|
|
13690
13869
|
};
|
|
13691
13870
|
var normalizeCompetitiveCoverageReport = (value) => ("status" in value) && ("summary" in value) && ("issues" in value) ? value : buildVoiceCompetitiveCoverageReport(value);
|
|
13692
13871
|
var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
@@ -13699,7 +13878,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
13699
13878
|
const value = typeof options.source === "function" ? await options.source() : options.source;
|
|
13700
13879
|
return normalizeCompetitiveCoverageReport(value);
|
|
13701
13880
|
};
|
|
13702
|
-
const app = new
|
|
13881
|
+
const app = new Elysia18({
|
|
13703
13882
|
name: options.name ?? "absolutejs-voice-competitive-coverage"
|
|
13704
13883
|
}).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
13705
13884
|
headers: {
|
|
@@ -13730,7 +13909,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
13730
13909
|
return app;
|
|
13731
13910
|
};
|
|
13732
13911
|
// src/proofTrends.ts
|
|
13733
|
-
import { Elysia as
|
|
13912
|
+
import { Elysia as Elysia19 } from "elysia";
|
|
13734
13913
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
13735
13914
|
var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
|
|
13736
13915
|
var toTimeMs = (value) => {
|
|
@@ -13881,7 +14060,7 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
13881
14060
|
};
|
|
13882
14061
|
var createVoiceProofTrendRoutes = (options) => {
|
|
13883
14062
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
13884
|
-
const routes = new
|
|
14063
|
+
const routes = new Elysia19({
|
|
13885
14064
|
name: options.name ?? "absolutejs-voice-proof-trends"
|
|
13886
14065
|
});
|
|
13887
14066
|
routes.get(path, async () => {
|
|
@@ -13914,11 +14093,11 @@ var formatVoiceProofTrendAge = (ageMs) => {
|
|
|
13914
14093
|
return `${days}d ${hours % 24}h`;
|
|
13915
14094
|
};
|
|
13916
14095
|
// src/providerDecisionTraces.ts
|
|
13917
|
-
import { Elysia as
|
|
14096
|
+
import { Elysia as Elysia21 } from "elysia";
|
|
13918
14097
|
|
|
13919
14098
|
// src/resilienceRoutes.ts
|
|
13920
|
-
import { Elysia as
|
|
13921
|
-
var
|
|
14099
|
+
import { Elysia as Elysia20 } from "elysia";
|
|
14100
|
+
var escapeHtml21 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13922
14101
|
var getString7 = (value) => typeof value === "string" ? value : undefined;
|
|
13923
14102
|
var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
13924
14103
|
var getBoolean2 = (value) => value === true;
|
|
@@ -14066,13 +14245,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
14066
14245
|
};
|
|
14067
14246
|
var renderProviderCards = (title, providers) => {
|
|
14068
14247
|
if (providers.length === 0) {
|
|
14069
|
-
return `<p class="muted">No ${
|
|
14248
|
+
return `<p class="muted">No ${escapeHtml21(title)} provider health yet.</p>`;
|
|
14070
14249
|
}
|
|
14071
14250
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
14072
|
-
<article class="card provider ${
|
|
14251
|
+
<article class="card provider ${escapeHtml21(provider.status)}">
|
|
14073
14252
|
<div class="card-header">
|
|
14074
|
-
<strong>${
|
|
14075
|
-
<span>${
|
|
14253
|
+
<strong>${escapeHtml21(provider.provider)}</strong>
|
|
14254
|
+
<span>${escapeHtml21(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
14076
14255
|
</div>
|
|
14077
14256
|
<dl>
|
|
14078
14257
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -14081,7 +14260,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
14081
14260
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
14082
14261
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
14083
14262
|
</dl>
|
|
14084
|
-
${provider.lastError ? `<p class="muted">${
|
|
14263
|
+
${provider.lastError ? `<p class="muted">${escapeHtml21(provider.lastError)}</p>` : ""}
|
|
14085
14264
|
</article>
|
|
14086
14265
|
`).join("")}</div>`;
|
|
14087
14266
|
};
|
|
@@ -14090,24 +14269,24 @@ var renderTimeline2 = (events) => {
|
|
|
14090
14269
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
14091
14270
|
}
|
|
14092
14271
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
14093
|
-
<article class="card event ${
|
|
14272
|
+
<article class="card event ${escapeHtml21(event.status ?? "unknown")}">
|
|
14094
14273
|
<div class="card-header">
|
|
14095
|
-
<strong>${
|
|
14274
|
+
<strong>${escapeHtml21(event.kind.toUpperCase())} ${escapeHtml21(event.operation ?? "generate")}</strong>
|
|
14096
14275
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
14097
14276
|
</div>
|
|
14098
14277
|
<p>
|
|
14099
|
-
<span class="pill">${
|
|
14100
|
-
<span class="pill">provider: ${
|
|
14101
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
14278
|
+
<span class="pill">${escapeHtml21(event.status ?? "unknown")}</span>
|
|
14279
|
+
<span class="pill">provider: ${escapeHtml21(event.provider ?? "unknown")}</span>
|
|
14280
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml21(event.fallbackProvider)}</span>` : ""}
|
|
14102
14281
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
14103
14282
|
</p>
|
|
14104
14283
|
<dl>
|
|
14105
14284
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
14106
14285
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
14107
14286
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
14108
|
-
<div><dt>Session</dt><dd>${
|
|
14287
|
+
<div><dt>Session</dt><dd>${escapeHtml21(event.sessionId)}</dd></div>
|
|
14109
14288
|
</dl>
|
|
14110
|
-
${event.error ? `<p class="muted">${
|
|
14289
|
+
${event.error ? `<p class="muted">${escapeHtml21(event.error)}</p>` : ""}
|
|
14111
14290
|
</article>
|
|
14112
14291
|
`).join("")}</div>`;
|
|
14113
14292
|
};
|
|
@@ -14117,9 +14296,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
14117
14296
|
const status = latest?.status ?? "idle";
|
|
14118
14297
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
14119
14298
|
return `<div>
|
|
14120
|
-
<dt>${
|
|
14121
|
-
<dd>${
|
|
14122
|
-
<small>${
|
|
14299
|
+
<dt>${escapeHtml21(kind.toUpperCase())}</dt>
|
|
14300
|
+
<dd>${escapeHtml21(provider)}${escapeHtml21(fallback)}</dd>
|
|
14301
|
+
<small>${escapeHtml21(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>
|
|
14123
14302
|
</div>`;
|
|
14124
14303
|
};
|
|
14125
14304
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -14127,10 +14306,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
14127
14306
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
14128
14307
|
}
|
|
14129
14308
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
14130
|
-
<article class="card session ${
|
|
14309
|
+
<article class="card session ${escapeHtml21(session.status)}">
|
|
14131
14310
|
<div class="card-header">
|
|
14132
|
-
<strong>${
|
|
14133
|
-
<span>${
|
|
14311
|
+
<strong>${escapeHtml21(session.sessionId)}</strong>
|
|
14312
|
+
<span>${escapeHtml21(session.status)}</span>
|
|
14134
14313
|
</div>
|
|
14135
14314
|
<p>
|
|
14136
14315
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -14157,21 +14336,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
14157
14336
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
14158
14337
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
14159
14338
|
const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
|
|
14160
|
-
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${
|
|
14161
|
-
<p class="muted">${
|
|
14339
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml21(pathPrefix)}">
|
|
14340
|
+
<p class="muted">${escapeHtml21(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
14162
14341
|
<div class="simulate-actions">
|
|
14163
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
14164
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
14342
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml21(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml21(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
14343
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml21(provider.provider)}">Mark ${escapeHtml21(provider.provider)} recovered</button>`).join("")}
|
|
14165
14344
|
</div>
|
|
14166
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
14345
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml21(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
14167
14346
|
<pre class="simulate-output" hidden></pre>
|
|
14168
14347
|
</div>`;
|
|
14169
14348
|
};
|
|
14170
14349
|
var renderVoiceResilienceHTML = (input) => {
|
|
14171
14350
|
const summary = summarizeRoutingEvents(input.routingEvents);
|
|
14172
|
-
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${
|
|
14173
|
-
const links = input.links?.length ? input.links.map((link) => `<a href="${
|
|
14174
|
-
const snippet =
|
|
14351
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml21(kind)}: ${String(count)}</span>`).join("");
|
|
14352
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml21(link.href)}">${escapeHtml21(link.label)}</a>`).join(" \xB7 ") : "";
|
|
14353
|
+
const snippet = escapeHtml21(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
14175
14354
|
kind: 'stt',
|
|
14176
14355
|
providers: ['deepgram', 'assemblyai'],
|
|
14177
14356
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -14209,7 +14388,7 @@ app.use(
|
|
|
14209
14388
|
<head>
|
|
14210
14389
|
<meta charset="utf-8" />
|
|
14211
14390
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
14212
|
-
<title>${
|
|
14391
|
+
<title>${escapeHtml21(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
14213
14392
|
<style>
|
|
14214
14393
|
:root { color-scheme: dark; }
|
|
14215
14394
|
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; }
|
|
@@ -14361,7 +14540,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
|
|
|
14361
14540
|
};
|
|
14362
14541
|
var createVoiceResilienceRoutes = (options) => {
|
|
14363
14542
|
const path = options.path ?? "/resilience";
|
|
14364
|
-
const routes = new
|
|
14543
|
+
const routes = new Elysia20({
|
|
14365
14544
|
name: options.name ?? "absolutejs-voice-resilience"
|
|
14366
14545
|
}).get(path, async () => {
|
|
14367
14546
|
const events = await options.store.list();
|
|
@@ -14402,7 +14581,7 @@ var createVoiceResilienceRoutes = (options) => {
|
|
|
14402
14581
|
};
|
|
14403
14582
|
|
|
14404
14583
|
// src/providerDecisionTraces.ts
|
|
14405
|
-
var
|
|
14584
|
+
var escapeHtml22 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14406
14585
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
14407
14586
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
14408
14587
|
var isDecisionTrace = (event) => Boolean(event && typeof event === "object" && "provider" in event && "reason" in event && "sessionId" in event && "status" in event && "surface" in event);
|
|
@@ -14643,7 +14822,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
14643
14822
|
<head>
|
|
14644
14823
|
<meta charset="utf-8" />
|
|
14645
14824
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
14646
|
-
<title>${
|
|
14825
|
+
<title>${escapeHtml22(title)}</title>
|
|
14647
14826
|
<style>
|
|
14648
14827
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
14649
14828
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -14657,8 +14836,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
14657
14836
|
</head>
|
|
14658
14837
|
<body>
|
|
14659
14838
|
<main>
|
|
14660
|
-
<p class="status ${report.status}">${
|
|
14661
|
-
<h1>${
|
|
14839
|
+
<p class="status ${report.status}">${escapeHtml22(report.status)}</p>
|
|
14840
|
+
<h1>${escapeHtml22(title)}</h1>
|
|
14662
14841
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
14663
14842
|
<section class="grid">
|
|
14664
14843
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -14669,10 +14848,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
14669
14848
|
</section>
|
|
14670
14849
|
<section class="surfaces">
|
|
14671
14850
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
14672
|
-
<header><strong>${
|
|
14851
|
+
<header><strong>${escapeHtml22(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml22(surface.status)}</span></header>
|
|
14673
14852
|
<p>${String(surface.decisions)} decision(s), ${String(surface.fallbacks)} fallback(s), ${String(surface.degraded)} degraded decision(s), ${String(surface.errors)} error(s).</p>
|
|
14674
|
-
<p class="muted">Providers: ${
|
|
14675
|
-
<p>${surface.reasons.map((reason) => `<code>${
|
|
14853
|
+
<p class="muted">Providers: ${escapeHtml22(surface.providers.join(", ") || "none")}</p>
|
|
14854
|
+
<p>${surface.reasons.map((reason) => `<code>${escapeHtml22(reason)}</code>`).join(" ")}</p>
|
|
14676
14855
|
</article>`).join(`
|
|
14677
14856
|
`)}
|
|
14678
14857
|
</section>
|
|
@@ -14686,7 +14865,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
14686
14865
|
const headers = options.headers ?? {};
|
|
14687
14866
|
const title = options.title ?? "Provider Decision Traces";
|
|
14688
14867
|
const report = () => buildVoiceProviderDecisionTraceReport(options);
|
|
14689
|
-
const app = new
|
|
14868
|
+
const app = new Elysia21({ name: options.name ?? "voice-provider-decisions" }).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
14690
14869
|
headers: {
|
|
14691
14870
|
"content-type": "application/json; charset=utf-8",
|
|
14692
14871
|
...headers
|
|
@@ -14714,7 +14893,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
14714
14893
|
return app;
|
|
14715
14894
|
};
|
|
14716
14895
|
// src/sloCalibration.ts
|
|
14717
|
-
import { Elysia as
|
|
14896
|
+
import { Elysia as Elysia22 } from "elysia";
|
|
14718
14897
|
var DEFAULT_HEADROOM_MULTIPLIER = 1.5;
|
|
14719
14898
|
var DEFAULT_WARN_RATIO = 0.8;
|
|
14720
14899
|
var DEFAULT_MIN_PASSING_RUNS = 3;
|
|
@@ -14894,7 +15073,7 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
14894
15073
|
};
|
|
14895
15074
|
};
|
|
14896
15075
|
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
14897
|
-
var
|
|
15076
|
+
var escapeHtml23 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14898
15077
|
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
14899
15078
|
var readinessThresholdRows = (report) => [
|
|
14900
15079
|
{
|
|
@@ -14985,15 +15164,15 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
14985
15164
|
};
|
|
14986
15165
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
14987
15166
|
const title = options.title ?? "Calibration -> Active Readiness Gate";
|
|
14988
|
-
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${
|
|
14989
|
-
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
14990
|
-
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${
|
|
14991
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
15167
|
+
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${escapeHtml23(row.control)}</td><td>${escapeHtml23(formatMs(row.value))}</td><td>${escapeHtml23(row.usedBy)}</td></tr>`).join("");
|
|
15168
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml23(issue)}</li>`).join("");
|
|
15169
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml23(source)}</code></li>`).join("");
|
|
15170
|
+
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:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1040px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}.status{font-size:1.6rem;font-weight:800;text-transform:uppercase}</style></head><body><main><h1>${escapeHtml23(title)}</h1><p>This page shows the calibrated thresholds currently driving production readiness gates.</p><section class="summary"><div class="card"><strong>Status</strong><br><span class="status">${escapeHtml23(report.status)}</span></div><div class="card"><strong>Live evidence max age</strong><br>${escapeHtml23(formatMs(report.liveLatencyMaxAgeMs))}</div><div class="card"><strong>Provider p95 gate</strong><br>${escapeHtml23(formatMs(report.providerSlo.llm?.maxP95ElapsedMs))}</div><div class="card"><strong>Barge-in gate</strong><br>${escapeHtml23(formatMs(report.bargeIn.thresholdMs))}</div></section><h2>Active Readiness Thresholds</h2><table><thead><tr><th>Threshold</th><th>Active value</th><th>Used by</th></tr></thead><tbody>${rows}</tbody></table><h2>Sources</h2><ul>${sources}</ul><h2>Issues</h2><ul>${issues}</ul></main></body></html>`;
|
|
14992
15171
|
};
|
|
14993
15172
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
14994
15173
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
14995
15174
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-calibration.md" : options.markdownPath;
|
|
14996
|
-
const routes = new
|
|
15175
|
+
const routes = new Elysia22({
|
|
14997
15176
|
name: options.name ?? "absolutejs-voice-slo-calibration"
|
|
14998
15177
|
});
|
|
14999
15178
|
const loadReport = async () => buildVoiceSloCalibrationReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -15017,7 +15196,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
15017
15196
|
const path = options.path ?? "/api/voice/slo-readiness-thresholds";
|
|
15018
15197
|
const htmlPath = options.htmlPath === undefined ? "/voice/slo-readiness-thresholds" : options.htmlPath;
|
|
15019
15198
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-readiness-thresholds.md" : options.markdownPath;
|
|
15020
|
-
const routes = new
|
|
15199
|
+
const routes = new Elysia22({
|
|
15021
15200
|
name: options.name ?? "absolutejs-voice-slo-readiness-thresholds"
|
|
15022
15201
|
});
|
|
15023
15202
|
const loadReport = async () => buildVoiceSloReadinessThresholdReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -15051,7 +15230,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
15051
15230
|
return routes;
|
|
15052
15231
|
};
|
|
15053
15232
|
// src/liveOps.ts
|
|
15054
|
-
import { Elysia as
|
|
15233
|
+
import { Elysia as Elysia23 } from "elysia";
|
|
15055
15234
|
var VOICE_LIVE_OPS_ACTIONS = [
|
|
15056
15235
|
"assign",
|
|
15057
15236
|
"create-task",
|
|
@@ -15361,7 +15540,7 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
15361
15540
|
const controller = createVoiceLiveOpsController(options);
|
|
15362
15541
|
const path = options.path ?? "/api/voice/live-ops/action";
|
|
15363
15542
|
const controlPath = options.controlPath ?? "/api/voice/live-ops/control/:sessionId";
|
|
15364
|
-
return new
|
|
15543
|
+
return new Elysia23({
|
|
15365
15544
|
name: options.name ?? "absolutejs-voice-live-ops"
|
|
15366
15545
|
}).post(path, async ({ request, set }) => {
|
|
15367
15546
|
try {
|
|
@@ -15383,15 +15562,15 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
15383
15562
|
});
|
|
15384
15563
|
};
|
|
15385
15564
|
// src/deliveryRuntime.ts
|
|
15386
|
-
import { Elysia as
|
|
15565
|
+
import { Elysia as Elysia24 } from "elysia";
|
|
15387
15566
|
import { mkdir } from "fs/promises";
|
|
15388
15567
|
import { dirname, join } from "path";
|
|
15389
|
-
var
|
|
15568
|
+
var escapeHtml24 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15390
15569
|
var renderSummaryCard = (label, summary) => {
|
|
15391
15570
|
if (!summary) {
|
|
15392
|
-
return `<article><span>${
|
|
15571
|
+
return `<article><span>${escapeHtml24(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
15393
15572
|
}
|
|
15394
|
-
return `<article><span>${
|
|
15573
|
+
return `<article><span>${escapeHtml24(label)}</span><strong>${String(summary.delivered)}/${String(summary.total)}</strong><p class="muted">${String(summary.pending)} pending · ${String(summary.failed)} failed · ${String(summary.deadLettered)} dead-lettered</p></article>`;
|
|
15395
15574
|
};
|
|
15396
15575
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
15397
15576
|
audit: leases,
|
|
@@ -15602,9 +15781,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
15602
15781
|
});
|
|
15603
15782
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
15604
15783
|
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
15605
|
-
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${
|
|
15606
|
-
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${
|
|
15607
|
-
const snippet =
|
|
15784
|
+
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml24(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
|
|
15785
|
+
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml24(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
|
|
15786
|
+
const snippet = escapeHtml24(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
15608
15787
|
createVoiceDeliveryRuntimePresetConfig({
|
|
15609
15788
|
audit: {
|
|
15610
15789
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -15630,14 +15809,14 @@ app.use(
|
|
|
15630
15809
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
15631
15810
|
})
|
|
15632
15811
|
);`);
|
|
15633
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
15812
|
+
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:#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}.primitive{background:#111a15;border-color:#41604a}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}.primitive p{color:#c8d8ca;line-height:1.55}.primitive code{color:#bbf7d0}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml24(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 ${escapeHtml24(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 primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceDeliveryRuntimeRoutes(...)</code> builds this control plane</h2><p>Own the audit and trace delivery queues in your app, mount one runtime route group, and pass the same runtime into production readiness so failed or dead-lettered exports block deploys.</p><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
15634
15813
|
};
|
|
15635
15814
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
15636
15815
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
15637
15816
|
const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
|
|
15638
15817
|
const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
|
|
15639
15818
|
const requeueDeadLettersPath = options.requeueDeadLettersPath === undefined ? "/api/voice-delivery-runtime/requeue-dead-letters" : options.requeueDeadLettersPath;
|
|
15640
|
-
const routes = new
|
|
15819
|
+
const routes = new Elysia24({
|
|
15641
15820
|
name: options.name ?? "absolutejs-voice-delivery-runtime"
|
|
15642
15821
|
}).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
|
|
15643
15822
|
if (tickPath !== false) {
|
|
@@ -15673,7 +15852,7 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
15673
15852
|
return routes;
|
|
15674
15853
|
};
|
|
15675
15854
|
// src/dataControl.ts
|
|
15676
|
-
import { Elysia as
|
|
15855
|
+
import { Elysia as Elysia25 } from "elysia";
|
|
15677
15856
|
var voiceComplianceRedactionDefaults = {
|
|
15678
15857
|
keys: [
|
|
15679
15858
|
"apiKey",
|
|
@@ -15912,7 +16091,7 @@ var parseRetentionScopes = (value) => {
|
|
|
15912
16091
|
const allowed = new Set(allRetentionScopes);
|
|
15913
16092
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
15914
16093
|
};
|
|
15915
|
-
var
|
|
16094
|
+
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15916
16095
|
var buildStorageSurfaces = (options) => [
|
|
15917
16096
|
{
|
|
15918
16097
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -16149,12 +16328,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
16149
16328
|
zeroRetentionAvailable: true
|
|
16150
16329
|
};
|
|
16151
16330
|
};
|
|
16152
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
16331
|
+
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${escapeHtml25(scope.scope)}</td><td>${scope.scannedCount}</td><td>${scope.deletedCount}</td><td>${escapeHtml25(scope.skippedReason ?? "")}</td><td><code>${escapeHtml25(scope.deletedIds.join(", "))}</code></td></tr>`).join("");
|
|
16153
16332
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
16154
16333
|
const title = options.title ?? "Voice Data Control";
|
|
16155
|
-
const storageRows = report.storage.map((surface) => `<tr><td>${
|
|
16156
|
-
const keyRows = report.providerKeys.map((key) => `<tr><td>${
|
|
16157
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
16334
|
+
const storageRows = report.storage.map((surface) => `<tr><td>${escapeHtml25(surface.name)}</td><td>${surface.configured ? "Configured" : "Missing"}</td><td>${escapeHtml25(surface.control)}</td><td>${surface.selfHosted ? "Yes" : "No"}</td></tr>`).join("");
|
|
16335
|
+
const keyRows = report.providerKeys.map((key) => `<tr><td>${escapeHtml25(key.name)}</td><td><code>${escapeHtml25(key.env ?? "n/a")}</code></td><td>${key.required ? "Required" : "Optional"}</td><td>${escapeHtml25(key.recommendation)}</td></tr>`).join("");
|
|
16336
|
+
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:#f8f7f2;color:#181713;font-family:ui-sans-serif,system-ui,sans-serif;line-height:1.45;margin:2rem}main{max-width:1120px;margin:auto}.summary{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:1rem 0}.card,table{background:white;border:1px solid #ddd6c8;border-radius:14px}.card{padding:1rem}table{border-collapse:collapse;width:100%;overflow:hidden}td,th{border-bottom:1px solid #eee8dc;padding:.7rem;text-align:left;vertical-align:top}code{white-space:pre-wrap;word-break:break-word}a{color:#9a3412}</style></head><body><main><h1>${escapeHtml25(title)}</h1><p>Self-hosted data-control proof for retention, redaction, audit export, deletion planning, customer-owned storage, and provider key handling.</p><section class="summary"><div class="card"><strong>Redaction</strong><br>${report.redaction.enabled ? "enabled" : "disabled"}</div><div class="card"><strong>Retention dry-run deletes</strong><br>${report.retentionPlan.deletedCount}</div><div class="card"><strong>Audit export events</strong><br>${report.auditExport?.events.length ?? 0}</div><div class="card"><strong>Zero retention recipe</strong><br>${report.zeroRetentionAvailable ? "available" : "missing"}</div></section><h2>Customer-Owned Storage</h2><table><thead><tr><th>Surface</th><th>Status</th><th>Control</th><th>Self-hosted</th></tr></thead><tbody>${storageRows}</tbody></table><h2>Retention Plan</h2><table><thead><tr><th>Scope</th><th>Scanned</th><th>Would delete</th><th>Skipped</th><th>Ids</th></tr></thead><tbody>${renderDataRetentionReportRows(report.retentionPlan)}</tbody></table><h2>Provider Keys</h2><table><thead><tr><th>Provider</th><th>Env</th><th>Required</th><th>Recommendation</th></tr></thead><tbody>${keyRows}</tbody></table><p><a href="./data-control/audit.md">Redacted audit Markdown</a> \xB7 <a href="./data-control/audit.html">Redacted audit HTML</a></p></main></body></html>`;
|
|
16158
16337
|
};
|
|
16159
16338
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
16160
16339
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -16212,7 +16391,7 @@ var parseRetentionPolicyBody = (body, options, dryRun) => {
|
|
|
16212
16391
|
var createVoiceDataControlRoutes = (options) => {
|
|
16213
16392
|
const path = options.path ?? "/data-control";
|
|
16214
16393
|
const title = options.title ?? "AbsoluteJS Voice Data Control";
|
|
16215
|
-
const routes = new
|
|
16394
|
+
const routes = new Elysia25({
|
|
16216
16395
|
name: options.name ?? "absolutejs-voice-data-control"
|
|
16217
16396
|
});
|
|
16218
16397
|
routes.get(path, async ({ query }) => {
|
|
@@ -16288,16 +16467,16 @@ var createVoiceDataControlRoutes = (options) => {
|
|
|
16288
16467
|
return routes;
|
|
16289
16468
|
};
|
|
16290
16469
|
// src/evalRoutes.ts
|
|
16291
|
-
import { Elysia as
|
|
16470
|
+
import { Elysia as Elysia28 } from "elysia";
|
|
16292
16471
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
16293
16472
|
import { dirname as dirname2 } from "path";
|
|
16294
16473
|
|
|
16295
16474
|
// src/qualityRoutes.ts
|
|
16296
|
-
import { Elysia as
|
|
16475
|
+
import { Elysia as Elysia27 } from "elysia";
|
|
16297
16476
|
|
|
16298
16477
|
// src/handoffHealth.ts
|
|
16299
|
-
import { Elysia as
|
|
16300
|
-
var
|
|
16478
|
+
import { Elysia as Elysia26 } from "elysia";
|
|
16479
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16301
16480
|
var getString9 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
16302
16481
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
16303
16482
|
var increment3 = (record, key) => {
|
|
@@ -16415,10 +16594,10 @@ var renderActionSummary = (summary) => {
|
|
|
16415
16594
|
return [
|
|
16416
16595
|
'<section class="voice-handoff-health-columns">',
|
|
16417
16596
|
"<article><h3>Actions</h3>",
|
|
16418
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
16597
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml26(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
16419
16598
|
"</article>",
|
|
16420
16599
|
"<article><h3>Adapters</h3>",
|
|
16421
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
16600
|
+
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml26(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
|
|
16422
16601
|
"</article>",
|
|
16423
16602
|
"</section>"
|
|
16424
16603
|
].join("");
|
|
@@ -16432,22 +16611,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
16432
16611
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
16433
16612
|
'<div class="voice-handoff-health-events">',
|
|
16434
16613
|
...summary.events.map((event) => [
|
|
16435
|
-
`<article class="${
|
|
16614
|
+
`<article class="${escapeHtml26(event.status)}">`,
|
|
16436
16615
|
'<div class="voice-handoff-health-event-header">',
|
|
16437
|
-
`<strong>${
|
|
16438
|
-
`<span>${
|
|
16616
|
+
`<strong>${escapeHtml26(event.action ?? "handoff")}</strong>`,
|
|
16617
|
+
`<span>${escapeHtml26(event.status)}</span>`,
|
|
16439
16618
|
"</div>",
|
|
16440
|
-
`<p><small>${
|
|
16441
|
-
event.target ? `<p>Target: ${
|
|
16442
|
-
event.reason ? `<p>Reason: ${
|
|
16619
|
+
`<p><small>${escapeHtml26(event.sessionId)}</small></p>`,
|
|
16620
|
+
event.target ? `<p>Target: ${escapeHtml26(event.target)}</p>` : "",
|
|
16621
|
+
event.reason ? `<p>Reason: ${escapeHtml26(event.reason)}</p>` : "",
|
|
16443
16622
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
16444
16623
|
"<li>",
|
|
16445
|
-
`${
|
|
16446
|
-
delivery.deliveredTo ? ` to ${
|
|
16447
|
-
delivery.error ? ` (${
|
|
16624
|
+
`${escapeHtml26(delivery.adapterId)}: ${escapeHtml26(delivery.status)}`,
|
|
16625
|
+
delivery.deliveredTo ? ` to ${escapeHtml26(delivery.deliveredTo)}` : "",
|
|
16626
|
+
delivery.error ? ` (${escapeHtml26(delivery.error)})` : "",
|
|
16448
16627
|
"</li>"
|
|
16449
16628
|
].join("")).join("")}</ul>` : "",
|
|
16450
|
-
event.replayHref ? `<p><a href="${
|
|
16629
|
+
event.replayHref ? `<p><a href="${escapeHtml26(event.replayHref)}">Open replay</a></p>` : "",
|
|
16451
16630
|
"</article>"
|
|
16452
16631
|
].join("")),
|
|
16453
16632
|
"</div>"
|
|
@@ -16479,7 +16658,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
|
|
|
16479
16658
|
var createVoiceHandoffHealthRoutes = (options = {}) => {
|
|
16480
16659
|
const path = options.path ?? "/api/voice-handoffs";
|
|
16481
16660
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
16482
|
-
const routes = new
|
|
16661
|
+
const routes = new Elysia26({
|
|
16483
16662
|
name: options.name ?? "absolutejs-voice-handoff-health"
|
|
16484
16663
|
}).get(path, createVoiceHandoffHealthJSONHandler(options));
|
|
16485
16664
|
if (htmlPath) {
|
|
@@ -16600,17 +16779,17 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
16600
16779
|
thresholds
|
|
16601
16780
|
};
|
|
16602
16781
|
};
|
|
16603
|
-
var
|
|
16782
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16604
16783
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
16605
16784
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
16606
16785
|
var renderVoiceQualityHTML = (report, options = {}) => {
|
|
16607
|
-
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${
|
|
16608
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16786
|
+
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml27(metric.label)}</td><td>${escapeHtml27(formatMetricValue(metric))}</td><td>${escapeHtml27(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml27(key)}</code></td></tr>`).join("");
|
|
16787
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml27(link.href)}">${escapeHtml27(link.label)}</a>`).join("")}</nav>` : "";
|
|
16609
16788
|
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>`;
|
|
16610
16789
|
};
|
|
16611
16790
|
var createVoiceQualityRoutes = (options) => {
|
|
16612
16791
|
const path = options.path ?? "/quality";
|
|
16613
|
-
const routes = new
|
|
16792
|
+
const routes = new Elysia27({
|
|
16614
16793
|
name: options.name ?? "absolutejs-voice-quality"
|
|
16615
16794
|
});
|
|
16616
16795
|
const getReport = () => evaluateVoiceQuality({
|
|
@@ -16639,7 +16818,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
16639
16818
|
};
|
|
16640
16819
|
|
|
16641
16820
|
// src/evalRoutes.ts
|
|
16642
|
-
var
|
|
16821
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16643
16822
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
16644
16823
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
16645
16824
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -16961,7 +17140,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
16961
17140
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
16962
17141
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
16963
17142
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
16964
|
-
const snippet =
|
|
17143
|
+
const snippet = escapeHtml28(`app.use(
|
|
16965
17144
|
createVoiceEvalRoutes({
|
|
16966
17145
|
path: '/evals',
|
|
16967
17146
|
store: traceStore,
|
|
@@ -16982,48 +17161,48 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
16982
17161
|
};
|
|
16983
17162
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
16984
17163
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
16985
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16986
|
-
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${
|
|
17164
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml28(link.href)}">${escapeHtml28(link.label)}</a>`).join("")}</nav>` : "";
|
|
17165
|
+
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml28(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>';
|
|
16987
17166
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
16988
17167
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
16989
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
16990
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
17168
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml28(session.operationsRecordHref)}">${escapeHtml28(session.sessionId)}</a>` : escapeHtml28(session.sessionId);
|
|
17169
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml28(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml28(formatTime(session.endedAt))}</td><td>${escapeHtml28(failedMetrics || "none")}</td></tr>`;
|
|
16991
17170
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
16992
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17171
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml28(title)}</title><style>body{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}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.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,.primitive{background:white;border:1px solid #e7e5e4;border-radius:1rem;padding:1rem}.primitive{background:#fffdf7;border-color:#d6c7a3;margin:1rem 0}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.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>${escapeHtml28(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>${renderVoiceEvalPrimitiveCopy()}<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>`;
|
|
16993
17172
|
};
|
|
16994
17173
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
16995
17174
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
16996
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
16997
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
16998
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
16999
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
17000
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17175
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml28(link.href)}">${escapeHtml28(link.label)}</a>`).join("")}</nav>` : "";
|
|
17176
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml28(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
17177
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml28(id)}</li>`).join("") : "<li>none</li>";
|
|
17178
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml28(id)}</li>`).join("") : "<li>none</li>";
|
|
17179
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml28(title)}</title><style>body{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>${escapeHtml28(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml28(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml28(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>${escapeHtml28(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>`;
|
|
17001
17180
|
};
|
|
17002
17181
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
17003
17182
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
17004
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17183
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml28(link.href)}">${escapeHtml28(link.label)}</a>`).join("")}</nav>` : "";
|
|
17005
17184
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
17006
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
17185
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml28(issue)}</li>`).join("")}</ul>` : "";
|
|
17007
17186
|
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => {
|
|
17008
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
17009
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
17187
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml28(session.operationsRecordHref)}">${escapeHtml28(session.sessionId)}</a>` : escapeHtml28(session.sessionId);
|
|
17188
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml28(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml28(session.issues.join(", ") || "none")}</td></tr>`;
|
|
17010
17189
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
17011
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
17190
|
+
return `<section class="scenario ${scenario.status}"><h2>${escapeHtml28(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml28(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>`;
|
|
17012
17191
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
17013
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17192
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml28(title)}</title><style>body{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}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.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}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.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>${escapeHtml28(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>${renderVoiceEvalPrimitiveCopy()}${scenarios}</main></body></html>`;
|
|
17014
17193
|
};
|
|
17015
17194
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
17016
17195
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
17017
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17196
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml28(link.href)}">${escapeHtml28(link.label)}</a>`).join("")}</nav>` : "";
|
|
17018
17197
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
17019
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
17020
|
-
return `<section class="${fixture.status}"><h2>${
|
|
17198
|
+
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml28(scenario.label)}</td><td>${escapeHtml28(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml28([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
|
|
17199
|
+
return `<section class="${fixture.status}"><h2>${escapeHtml28(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml28(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>`;
|
|
17021
17200
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
17022
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17201
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml28(title)}</title><style>body{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}.eyebrow{font-size:.78rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase}.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}.primitive{background:#fffdf7;border-color:#d6c7a3}.primitive p{line-height:1.55}.primitive pre{background:#181713;border-radius:.85rem;color:#fef3c7;overflow:auto;padding:1rem}.primitive code{color:#fef3c7}.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>${escapeHtml28(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>${renderVoiceEvalPrimitiveCopy()}${fixtures}</main></body></html>`;
|
|
17023
17202
|
};
|
|
17024
17203
|
var createVoiceEvalRoutes = (options) => {
|
|
17025
17204
|
const path = options.path ?? "/evals";
|
|
17026
|
-
const routes = new
|
|
17205
|
+
const routes = new Elysia28({
|
|
17027
17206
|
name: options.name ?? "absolutejs-voice-evals"
|
|
17028
17207
|
});
|
|
17029
17208
|
const getReport = () => runVoiceSessionEvals({
|
|
@@ -17160,11 +17339,11 @@ var createVoiceEvalRoutes = (options) => {
|
|
|
17160
17339
|
return routes;
|
|
17161
17340
|
};
|
|
17162
17341
|
// src/simulationSuite.ts
|
|
17163
|
-
import { Elysia as
|
|
17342
|
+
import { Elysia as Elysia31 } from "elysia";
|
|
17164
17343
|
|
|
17165
17344
|
// src/outcomeContract.ts
|
|
17166
|
-
import { Elysia as
|
|
17167
|
-
var
|
|
17345
|
+
import { Elysia as Elysia29 } from "elysia";
|
|
17346
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17168
17347
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
17169
17348
|
if (value === false) {
|
|
17170
17349
|
return;
|
|
@@ -17375,13 +17554,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
17375
17554
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
17376
17555
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
17377
17556
|
const contracts = report.contracts.map((contract) => {
|
|
17378
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
17557
|
+
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${escapeHtml29(href)}">${escapeHtml29(contract.sessionIds[index] ?? href)}</a>`).join(" \xB7 ")}</p>` : "";
|
|
17379
17558
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
17380
17559
|
<div class="contract-header">
|
|
17381
17560
|
<div>
|
|
17382
|
-
<p class="eyebrow">${
|
|
17383
|
-
<h2>${
|
|
17384
|
-
${contract.description ? `<p>${
|
|
17561
|
+
<p class="eyebrow">${escapeHtml29(contract.contractId)}</p>
|
|
17562
|
+
<h2>${escapeHtml29(contract.label ?? contract.contractId)}</h2>
|
|
17563
|
+
${contract.description ? `<p>${escapeHtml29(contract.description)}</p>` : ""}
|
|
17385
17564
|
${sessionLinks}
|
|
17386
17565
|
</div>
|
|
17387
17566
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -17393,10 +17572,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
17393
17572
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
17394
17573
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
17395
17574
|
</div>
|
|
17396
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
17575
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml29(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
17397
17576
|
</section>`;
|
|
17398
17577
|
}).join("");
|
|
17399
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17578
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml29(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.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>${escapeHtml29(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>`;
|
|
17400
17579
|
};
|
|
17401
17580
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
17402
17581
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -17412,7 +17591,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
|
17412
17591
|
var createVoiceOutcomeContractRoutes = (options) => {
|
|
17413
17592
|
const path = options.path ?? "/api/outcome-contracts";
|
|
17414
17593
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17415
|
-
const routes = new
|
|
17594
|
+
const routes = new Elysia29({
|
|
17416
17595
|
name: options.name ?? "absolutejs-voice-outcome-contracts"
|
|
17417
17596
|
}).get(path, createVoiceOutcomeContractJSONHandler(options));
|
|
17418
17597
|
if (htmlPath) {
|
|
@@ -17422,7 +17601,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
|
|
|
17422
17601
|
};
|
|
17423
17602
|
|
|
17424
17603
|
// src/toolContract.ts
|
|
17425
|
-
import { Elysia as
|
|
17604
|
+
import { Elysia as Elysia30 } from "elysia";
|
|
17426
17605
|
|
|
17427
17606
|
// src/toolRuntime.ts
|
|
17428
17607
|
var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -17631,7 +17810,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
17631
17810
|
});
|
|
17632
17811
|
var defaultApi = {};
|
|
17633
17812
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
17634
|
-
var
|
|
17813
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17635
17814
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
17636
17815
|
if (value === false) {
|
|
17637
17816
|
return;
|
|
@@ -17880,7 +18059,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
17880
18059
|
};
|
|
17881
18060
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
17882
18061
|
const title = options.title ?? "Voice Tool Contracts";
|
|
17883
|
-
const snippet =
|
|
18062
|
+
const snippet = escapeHtml30(`app.use(
|
|
17884
18063
|
createVoiceToolContractRoutes({
|
|
17885
18064
|
htmlPath: '/tool-contracts',
|
|
17886
18065
|
path: '/api/tool-contracts',
|
|
@@ -17906,20 +18085,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
17906
18085
|
);`);
|
|
17907
18086
|
const contracts = report.contracts.map((contract) => {
|
|
17908
18087
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
17909
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
18088
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml30(testCase.operationsRecordHref)}">${escapeHtml30(testCase.label ?? testCase.caseId)}</a>` : escapeHtml30(testCase.label ?? testCase.caseId)}</td>
|
|
17910
18089
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
17911
|
-
<td>${
|
|
17912
|
-
<td>${
|
|
18090
|
+
<td>${escapeHtml30(testCase.status)}</td>
|
|
18091
|
+
<td>${escapeHtml30(testCase.sessionId)}</td>
|
|
17913
18092
|
<td>${String(testCase.attempts)}</td>
|
|
17914
18093
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
17915
18094
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
17916
|
-
<td>${
|
|
18095
|
+
<td>${escapeHtml30(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
17917
18096
|
</tr>`).join("");
|
|
17918
18097
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
17919
18098
|
<div class="contract-header">
|
|
17920
18099
|
<div>
|
|
17921
|
-
<p class="eyebrow">${
|
|
17922
|
-
<h2>${
|
|
18100
|
+
<p class="eyebrow">${escapeHtml30(contract.toolName)}</p>
|
|
18101
|
+
<h2>${escapeHtml30(contract.label ?? contract.contractId)}</h2>
|
|
17923
18102
|
</div>
|
|
17924
18103
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
17925
18104
|
</div>
|
|
@@ -17929,7 +18108,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
17929
18108
|
</table>
|
|
17930
18109
|
</section>`;
|
|
17931
18110
|
}).join("");
|
|
17932
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18111
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml30(title)}</title><style>body{background:#101316;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.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))}.primitive{background:#151b20;border-color:#5a4421}.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)}.primitive p{color:#d8dee6;line-height:1.55}.primitive pre{background:#0f1217;border:1px solid #2a323a;border-radius:16px;color:#fef3c7;overflow:auto;padding:14px}.primitive code{color:#fef3c7}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>${escapeHtml30(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml30(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><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceToolContractRoutes(...)</code> certifies tool behavior</h2><p>Define deterministic tool cases for retries, idempotency, timeouts, result shape, and error handling so assistant tools fail in pre-production instead of live calls.</p><pre><code>${snippet}</code></pre></section>${contracts || '<section class="contract"><p>No tool contracts configured.</p></section>'}</main></body></html>`;
|
|
17933
18112
|
};
|
|
17934
18113
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
17935
18114
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -17946,7 +18125,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
|
17946
18125
|
var createVoiceToolContractRoutes = (options) => {
|
|
17947
18126
|
const path = options.path ?? "/api/tool-contracts";
|
|
17948
18127
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17949
|
-
const routes = new
|
|
18128
|
+
const routes = new Elysia30({
|
|
17950
18129
|
name: options.name ?? "absolutejs-voice-tool-contracts"
|
|
17951
18130
|
}).get(path, createVoiceToolContractJSONHandler(options));
|
|
17952
18131
|
if (htmlPath) {
|
|
@@ -17956,7 +18135,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
17956
18135
|
};
|
|
17957
18136
|
|
|
17958
18137
|
// src/simulationSuite.ts
|
|
17959
|
-
var
|
|
18138
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17960
18139
|
var summarizeSection = (report) => ({
|
|
17961
18140
|
failed: report.failed,
|
|
17962
18141
|
passed: report.passed,
|
|
@@ -18152,15 +18331,15 @@ var renderSection = (label, summary) => {
|
|
|
18152
18331
|
if (!summary) {
|
|
18153
18332
|
return "";
|
|
18154
18333
|
}
|
|
18155
|
-
return `<article class="${
|
|
18334
|
+
return `<article class="${escapeHtml31(summary.status)}"><span>${escapeHtml31(label)}</span><strong>${escapeHtml31(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
|
|
18156
18335
|
};
|
|
18157
18336
|
var renderAction = (action) => {
|
|
18158
|
-
const content = `<strong>${
|
|
18159
|
-
return action.href ? `<a class="action" href="${
|
|
18337
|
+
const content = `<strong>${escapeHtml31(action.label)}</strong><p>${escapeHtml31(action.description)}</p><span>${escapeHtml31(action.section)} / ${escapeHtml31(action.severity)}</span>`;
|
|
18338
|
+
return action.href ? `<a class="action" href="${escapeHtml31(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
18160
18339
|
};
|
|
18161
18340
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
18162
18341
|
const title = options.title ?? "Voice Simulation Suite";
|
|
18163
|
-
const snippet =
|
|
18342
|
+
const snippet = escapeHtml31(`app.use(
|
|
18164
18343
|
createVoiceSimulationSuiteRoutes({
|
|
18165
18344
|
htmlPath: '/voice/simulations',
|
|
18166
18345
|
path: '/api/voice/simulations',
|
|
@@ -18193,12 +18372,12 @@ app.use(
|
|
|
18193
18372
|
store: traceStore
|
|
18194
18373
|
})
|
|
18195
18374
|
);`);
|
|
18196
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18375
|
+
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:#10151c;color:#f8f3e7;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}.hero,.primitive{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}.primitive{background:#151d27;border-color:#355078}.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,.primitive p{color:#d8dee6;line-height:1.55;margin:.3rem 0 .6rem}pre{background:#151d27;border:1px solid #283544;border-radius:18px;overflow:auto;padding:16px}.primitive pre{background:#0b1118;color:#dbeafe}.primitive code{color:#bfdbfe}</style></head><body><main><section class="hero"><p class="eyebrow">Pre-production proof</p><h1>${escapeHtml31(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml31(report.status)}">Status: ${escapeHtml31(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><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceSimulationSuiteRoutes(...)</code> builds this pre-production proof surface</h2><p>Run session quality checks, scenario evals, fixture-backed simulations, tool contracts, and outcome contracts from one route group before live traffic sees a regression.</p><pre><code>${snippet}</code></pre></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>${escapeHtml31(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
|
|
18197
18376
|
};
|
|
18198
18377
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
18199
18378
|
const path = options.path ?? "/api/voice/simulations";
|
|
18200
18379
|
const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
|
|
18201
|
-
const app = new
|
|
18380
|
+
const app = new Elysia31({
|
|
18202
18381
|
name: options.name ?? "absolutejs-voice-simulation-suite"
|
|
18203
18382
|
}).get(path, () => runVoiceSimulationSuite(options));
|
|
18204
18383
|
if (htmlPath) {
|
|
@@ -18510,9 +18689,9 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
18510
18689
|
};
|
|
18511
18690
|
};
|
|
18512
18691
|
// src/sessionReplay.ts
|
|
18513
|
-
import { Elysia as
|
|
18692
|
+
import { Elysia as Elysia32 } from "elysia";
|
|
18514
18693
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
18515
|
-
var
|
|
18694
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18516
18695
|
var increment4 = (record, key) => {
|
|
18517
18696
|
record[key] = (record[key] ?? 0) + 1;
|
|
18518
18697
|
};
|
|
@@ -18706,10 +18885,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
18706
18885
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
18707
18886
|
'<div class="voice-sessions-list">',
|
|
18708
18887
|
...sessions.map((session) => [
|
|
18709
|
-
`<article class="voice-session-card ${
|
|
18888
|
+
`<article class="voice-session-card ${escapeHtml32(session.status)}">`,
|
|
18710
18889
|
'<div class="voice-session-card-header">',
|
|
18711
|
-
`<strong>${
|
|
18712
|
-
`<span>${
|
|
18890
|
+
`<strong>${escapeHtml32(session.sessionId)}</strong>`,
|
|
18891
|
+
`<span>${escapeHtml32(session.status)}</span>`,
|
|
18713
18892
|
"</div>",
|
|
18714
18893
|
"<dl>",
|
|
18715
18894
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -18717,9 +18896,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
18717
18896
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
18718
18897
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
18719
18898
|
"</dl>",
|
|
18720
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
18721
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
18722
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
18899
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml32(session.latestOutcome)}</p>` : "",
|
|
18900
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml32).join(", ")}</p>` : "",
|
|
18901
|
+
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml32(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml32(session.replayHref)}">Open replay</a></p>` : "",
|
|
18723
18902
|
"</article>"
|
|
18724
18903
|
].join("")),
|
|
18725
18904
|
"</div>"
|
|
@@ -18750,7 +18929,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
|
|
|
18750
18929
|
var createVoiceSessionListRoutes = (options = {}) => {
|
|
18751
18930
|
const path = options.path ?? "/api/voice-sessions";
|
|
18752
18931
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18753
|
-
const routes = new
|
|
18932
|
+
const routes = new Elysia32({
|
|
18754
18933
|
name: options.name ?? "absolutejs-voice-session-list"
|
|
18755
18934
|
}).get(path, createVoiceSessionsJSONHandler(options));
|
|
18756
18935
|
if (htmlPath) {
|
|
@@ -18778,7 +18957,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
|
|
|
18778
18957
|
var createVoiceSessionReplayRoutes = (options) => {
|
|
18779
18958
|
const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
|
|
18780
18959
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18781
|
-
const routes = new
|
|
18960
|
+
const routes = new Elysia32({
|
|
18782
18961
|
name: options.name ?? "absolutejs-voice-session-replay"
|
|
18783
18962
|
}).get(path, createVoiceSessionReplayJSONHandler(options));
|
|
18784
18963
|
if (htmlPath) {
|
|
@@ -19092,10 +19271,10 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
19092
19271
|
return report;
|
|
19093
19272
|
};
|
|
19094
19273
|
// src/turnLatency.ts
|
|
19095
|
-
import { Elysia as
|
|
19274
|
+
import { Elysia as Elysia33 } from "elysia";
|
|
19096
19275
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
19097
19276
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
19098
|
-
var
|
|
19277
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19099
19278
|
var firstNumber = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
19100
19279
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
19101
19280
|
var createTraceStageIndex = (events) => {
|
|
@@ -19227,11 +19406,11 @@ await traceStore.append({
|
|
|
19227
19406
|
turnId,
|
|
19228
19407
|
type: 'turn_latency.stage'
|
|
19229
19408
|
});`;
|
|
19230
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
19231
|
-
<header><div><p class="eyebrow">${
|
|
19232
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
19409
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml33(turn.status)}">
|
|
19410
|
+
<header><div><p class="eyebrow">${escapeHtml33(turn.sessionId)} \xB7 ${escapeHtml33(turn.turnId)}</p><h2>${escapeHtml33(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml33(turn.status)}</strong></header>
|
|
19411
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml33(stage.label)}</dt><dd>${escapeHtml33(formatMs2(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
19233
19412
|
</article>`).join("");
|
|
19234
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
19413
|
+
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,.turn,.primitive{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}.primitive p{color:#cbd5e1}.primitive pre{background:#0a0d10;border:1px solid #2a323a;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}.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>${escapeHtml33(title)}</h1><div class="summary"><span class="pill ${escapeHtml33(report.status)}">${escapeHtml33(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml33(formatMs2(report.averageTotalMs))}</span><span class="pill">${String(report.warnings)} warnings</span><span class="pill">${String(report.failed)} failed</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTurnLatencyRoutes(...)</code> exposes the full turn waterfall</h2><p>Attach stage traces for speech detection, commit, model response, TTS send, and first audio so teams can prove where latency actually comes from.</p><pre><code>${escapeHtml33(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
19235
19414
|
};
|
|
19236
19415
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
19237
19416
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -19248,7 +19427,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
19248
19427
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
19249
19428
|
const path = options.path ?? "/api/turn-latency";
|
|
19250
19429
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
19251
|
-
const routes = new
|
|
19430
|
+
const routes = new Elysia33({
|
|
19252
19431
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
19253
19432
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
19254
19433
|
if (htmlPath) {
|
|
@@ -19257,8 +19436,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
19257
19436
|
return routes;
|
|
19258
19437
|
};
|
|
19259
19438
|
// src/liveLatency.ts
|
|
19260
|
-
import { Elysia as
|
|
19261
|
-
var
|
|
19439
|
+
import { Elysia as Elysia34 } from "elysia";
|
|
19440
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19262
19441
|
var percentile3 = (values, percentileValue) => {
|
|
19263
19442
|
if (values.length === 0) {
|
|
19264
19443
|
return;
|
|
@@ -19325,13 +19504,13 @@ await traceStore.append({
|
|
|
19325
19504
|
sessionId,
|
|
19326
19505
|
type: 'client.live_latency'
|
|
19327
19506
|
});`;
|
|
19328
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
19329
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
19507
|
+
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml34(sample.sessionId)}</td><td>${escapeHtml34(formatMs3(sample.latencyMs))}</td><td>${escapeHtml34(sample.status ?? "unknown")}</td><td>${escapeHtml34(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
19508
|
+
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(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,.primitive{background:#141922;border:1px solid #26313d;border-radius:18px}.metrics article,.primitive{padding:16px}.metrics span{color:#a8b0b8}.metrics strong{display:block;font-size:2rem;margin-top:.25rem}.primitive{margin:0 0 18px}.primitive h2{margin:.2rem 0 .5rem}.primitive p{color:#cbd5e1}.primitive pre{background:#080b10;border:1px solid #26313d;border-radius:16px;color:#d9fff7;overflow:auto;padding:16px}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>${escapeHtml34(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml34(report.status)}">Status: ${escapeHtml34(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml34(formatMs3(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml34(formatMs3(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml34(formatMs3(report.averageLatencyMs))}</strong></article><article><span>Samples</span><strong>${String(report.total)}</strong></article></section></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceLiveLatencyRoutes(...)</code> turns real browser timing into a release gate</h2><p>Persist live timing samples into the trace store so readiness, simulations, and trace timelines all point at the same self-hosted proof.</p><pre><code>${escapeHtml34(snippet)}</code></pre></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>`;
|
|
19330
19509
|
};
|
|
19331
19510
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
19332
19511
|
const path = options.path ?? "/api/live-latency";
|
|
19333
19512
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
19334
|
-
const routes = new
|
|
19513
|
+
const routes = new Elysia34({
|
|
19335
19514
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
19336
19515
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
19337
19516
|
if (htmlPath) {
|
|
@@ -19650,9 +19829,9 @@ None.
|
|
|
19650
19829
|
`}`;
|
|
19651
19830
|
};
|
|
19652
19831
|
// src/turnQuality.ts
|
|
19653
|
-
import { Elysia as
|
|
19832
|
+
import { Elysia as Elysia35 } from "elysia";
|
|
19654
19833
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
19655
|
-
var
|
|
19834
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19656
19835
|
var getTurnLatencyMs = (turn) => {
|
|
19657
19836
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
19658
19837
|
if (firstTranscriptAt === undefined) {
|
|
@@ -19723,24 +19902,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
19723
19902
|
};
|
|
19724
19903
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
19725
19904
|
const title = options.title ?? "Voice Turn Quality";
|
|
19726
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
19905
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml35(turn.status)}">
|
|
19727
19906
|
<div class="turn-header">
|
|
19728
19907
|
<div>
|
|
19729
|
-
<p class="eyebrow">${
|
|
19730
|
-
<h2>${
|
|
19908
|
+
<p class="eyebrow">${escapeHtml35(turn.sessionId)} \xB7 ${escapeHtml35(turn.turnId)}</p>
|
|
19909
|
+
<h2>${escapeHtml35(turn.text || "Empty turn")}</h2>
|
|
19731
19910
|
</div>
|
|
19732
|
-
<strong>${
|
|
19911
|
+
<strong>${escapeHtml35(turn.status)}</strong>
|
|
19733
19912
|
</div>
|
|
19734
19913
|
<dl>
|
|
19735
|
-
<div><dt>Source</dt><dd>${
|
|
19914
|
+
<div><dt>Source</dt><dd>${escapeHtml35(turn.source ?? "unknown")}</dd></div>
|
|
19736
19915
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
19737
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
19738
|
-
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${
|
|
19916
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml35(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
19917
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml35(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
19739
19918
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
19740
19919
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
19741
19920
|
</dl>
|
|
19742
19921
|
</article>`).join("");
|
|
19743
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
19922
|
+
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:#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>${escapeHtml35(title)}</h1><div class="summary"><span class="pill ${escapeHtml35(report.status)}">${escapeHtml35(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>`;
|
|
19744
19923
|
};
|
|
19745
19924
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
19746
19925
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -19757,7 +19936,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
19757
19936
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
19758
19937
|
const path = options.path ?? "/api/turn-quality";
|
|
19759
19938
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
19760
|
-
const routes = new
|
|
19939
|
+
const routes = new Elysia35({
|
|
19761
19940
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
19762
19941
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
19763
19942
|
if (htmlPath) {
|
|
@@ -19766,7 +19945,7 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
19766
19945
|
return routes;
|
|
19767
19946
|
};
|
|
19768
19947
|
// src/telephonyOutcome.ts
|
|
19769
|
-
import { Elysia as
|
|
19948
|
+
import { Elysia as Elysia36 } from "elysia";
|
|
19770
19949
|
var DEFAULT_COMPLETED_STATUSES = [
|
|
19771
19950
|
"answered",
|
|
19772
19951
|
"completed",
|
|
@@ -20527,7 +20706,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
|
|
|
20527
20706
|
var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
20528
20707
|
const path = options.path ?? "/api/voice/telephony/webhook";
|
|
20529
20708
|
const handler = createVoiceTelephonyWebhookHandler(options);
|
|
20530
|
-
return new
|
|
20709
|
+
return new Elysia36({
|
|
20531
20710
|
name: options.name ?? "absolutejs-voice-telephony-webhooks"
|
|
20532
20711
|
}).post(path, async ({ query, request }) => {
|
|
20533
20712
|
try {
|
|
@@ -20548,12 +20727,12 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
|
20548
20727
|
});
|
|
20549
20728
|
};
|
|
20550
20729
|
// src/phoneAgent.ts
|
|
20551
|
-
import { Elysia as
|
|
20730
|
+
import { Elysia as Elysia42 } from "elysia";
|
|
20552
20731
|
|
|
20553
20732
|
// src/telephony/plivo.ts
|
|
20554
20733
|
import { Buffer as Buffer5 } from "buffer";
|
|
20555
20734
|
import { Database } from "bun:sqlite";
|
|
20556
|
-
import { Elysia as
|
|
20735
|
+
import { Elysia as Elysia38 } from "elysia";
|
|
20557
20736
|
|
|
20558
20737
|
// src/telephony/contract.ts
|
|
20559
20738
|
var DEFAULT_REQUIREMENTS = [
|
|
@@ -20637,7 +20816,7 @@ var evaluateVoiceTelephonyContract = (input) => {
|
|
|
20637
20816
|
|
|
20638
20817
|
// src/telephony/twilio.ts
|
|
20639
20818
|
import { Buffer as Buffer4 } from "buffer";
|
|
20640
|
-
import { Elysia as
|
|
20819
|
+
import { Elysia as Elysia37 } from "elysia";
|
|
20641
20820
|
var TWILIO_MULAW_SAMPLE_RATE = 8000;
|
|
20642
20821
|
var VOICE_PCM_SAMPLE_RATE = 16000;
|
|
20643
20822
|
var escapeXml2 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
@@ -20667,7 +20846,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
20667
20846
|
return parameters;
|
|
20668
20847
|
};
|
|
20669
20848
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
20670
|
-
var
|
|
20849
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20671
20850
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
20672
20851
|
if (!webhook?.verificationUrl) {
|
|
20673
20852
|
return;
|
|
@@ -20710,23 +20889,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
20710
20889
|
};
|
|
20711
20890
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20712
20891
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
20713
|
-
<h1>${
|
|
20892
|
+
<h1>${escapeHtml36(title)}</h1>
|
|
20714
20893
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
20715
20894
|
<section>
|
|
20716
20895
|
<h2>URLs</h2>
|
|
20717
20896
|
<ul>
|
|
20718
|
-
<li><strong>TwiML:</strong> <code>${
|
|
20719
|
-
<li><strong>Media stream:</strong> <code>${
|
|
20720
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
20897
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml36(status.urls.twiml)}</code></li>
|
|
20898
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml36(status.urls.stream)}</code></li>
|
|
20899
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml36(status.urls.webhook)}</code></li>
|
|
20721
20900
|
</ul>
|
|
20722
20901
|
</section>
|
|
20723
20902
|
<section>
|
|
20724
20903
|
<h2>Signing</h2>
|
|
20725
20904
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
20726
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
20905
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml36(status.signing.verificationUrl)}</code></p>` : ""}
|
|
20727
20906
|
</section>
|
|
20728
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
20729
|
-
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
20907
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml36(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
20908
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml36(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
20730
20909
|
</main>`;
|
|
20731
20910
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
20732
20911
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -20737,20 +20916,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
20737
20916
|
});
|
|
20738
20917
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20739
20918
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
20740
|
-
<h1>${
|
|
20919
|
+
<h1>${escapeHtml36(title)}</h1>
|
|
20741
20920
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
20742
20921
|
<section>
|
|
20743
20922
|
<h2>Checks</h2>
|
|
20744
20923
|
<ul>
|
|
20745
|
-
${report.checks.map((check) => `<li><strong>${
|
|
20924
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml36(check.name)}</strong>: ${escapeHtml36(check.status)}${check.message ? ` - ${escapeHtml36(check.message)}` : ""}</li>`).join("")}
|
|
20746
20925
|
</ul>
|
|
20747
20926
|
</section>
|
|
20748
20927
|
<section>
|
|
20749
20928
|
<h2>Observed URLs</h2>
|
|
20750
20929
|
<ul>
|
|
20751
|
-
<li><strong>TwiML:</strong> <code>${
|
|
20752
|
-
<li><strong>Stream:</strong> <code>${
|
|
20753
|
-
<li><strong>Webhook:</strong> <code>${
|
|
20930
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml36(report.setup.urls.twiml)}</code></li>
|
|
20931
|
+
<li><strong>Stream:</strong> <code>${escapeHtml36(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
20932
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml36(report.setup.urls.webhook)}</code></li>
|
|
20754
20933
|
</ul>
|
|
20755
20934
|
</section>
|
|
20756
20935
|
</main>`;
|
|
@@ -21210,7 +21389,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
21210
21389
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
|
|
21211
21390
|
const bridges = new WeakMap;
|
|
21212
21391
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
21213
|
-
const app = new
|
|
21392
|
+
const app = new Elysia37({
|
|
21214
21393
|
name: options.name ?? "absolutejs-voice-twilio"
|
|
21215
21394
|
}).get(twimlPath, async ({ query, request }) => {
|
|
21216
21395
|
const streamUrl = await resolveTwilioStreamUrl(options, {
|
|
@@ -21347,7 +21526,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
21347
21526
|
|
|
21348
21527
|
// src/telephony/plivo.ts
|
|
21349
21528
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21350
|
-
var
|
|
21529
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21351
21530
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
21352
21531
|
var resolveRequestOrigin2 = (request) => {
|
|
21353
21532
|
const url = new URL(request.url);
|
|
@@ -21777,21 +21956,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
21777
21956
|
};
|
|
21778
21957
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21779
21958
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
21780
|
-
<h1>${
|
|
21959
|
+
<h1>${escapeHtml37(title)}</h1>
|
|
21781
21960
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21782
21961
|
<ul>
|
|
21783
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
21784
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
21785
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21962
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml37(status.urls.answer)}</code></li>
|
|
21963
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml37(status.urls.stream)}</code></li>
|
|
21964
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml37(status.urls.webhook)}</code></li>
|
|
21786
21965
|
</ul>
|
|
21787
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
21788
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
21966
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml37(name)}</code></li>`).join("")}</ul>` : ""}
|
|
21967
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml37(warning)}</li>`).join("")}</ul>` : ""}
|
|
21789
21968
|
</main>`;
|
|
21790
21969
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21791
21970
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
21792
|
-
<h1>${
|
|
21971
|
+
<h1>${escapeHtml37(title)}</h1>
|
|
21793
21972
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21794
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
21973
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml37(check.name)}</strong>: ${escapeHtml37(check.status)}${check.message ? ` - ${escapeHtml37(check.message)}` : ""}</li>`).join("")}</ul>
|
|
21795
21974
|
</main>`;
|
|
21796
21975
|
var runPlivoSmokeTest = async (input) => {
|
|
21797
21976
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -21881,7 +22060,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
21881
22060
|
nonceStore: options.webhook.nonceStore,
|
|
21882
22061
|
verificationUrl: options.webhook.verificationUrl
|
|
21883
22062
|
}) : undefined);
|
|
21884
|
-
const app = new
|
|
22063
|
+
const app = new Elysia38({
|
|
21885
22064
|
name: options.name ?? "absolutejs-voice-plivo"
|
|
21886
22065
|
}).get(answerPath, async ({ query, request }) => {
|
|
21887
22066
|
const streamUrl = await resolvePlivoStreamUrl(options, {
|
|
@@ -21993,9 +22172,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
21993
22172
|
// src/telephony/telnyx.ts
|
|
21994
22173
|
import { Buffer as Buffer6 } from "buffer";
|
|
21995
22174
|
import { Database as Database2 } from "bun:sqlite";
|
|
21996
|
-
import { Elysia as
|
|
22175
|
+
import { Elysia as Elysia39 } from "elysia";
|
|
21997
22176
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21998
|
-
var
|
|
22177
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21999
22178
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
22000
22179
|
var resolveRequestOrigin3 = (request) => {
|
|
22001
22180
|
const url = new URL(request.url);
|
|
@@ -22388,21 +22567,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
22388
22567
|
};
|
|
22389
22568
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22390
22569
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
22391
|
-
<h1>${
|
|
22570
|
+
<h1>${escapeHtml38(title)}</h1>
|
|
22392
22571
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
22393
22572
|
<ul>
|
|
22394
|
-
<li><strong>TeXML:</strong> <code>${
|
|
22395
|
-
<li><strong>Media stream:</strong> <code>${
|
|
22396
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
22573
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml38(status.urls.texml)}</code></li>
|
|
22574
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml38(status.urls.stream)}</code></li>
|
|
22575
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml38(status.urls.webhook)}</code></li>
|
|
22397
22576
|
</ul>
|
|
22398
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
22399
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
22577
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml38(name)}</code></li>`).join("")}</ul>` : ""}
|
|
22578
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml38(warning)}</li>`).join("")}</ul>` : ""}
|
|
22400
22579
|
</main>`;
|
|
22401
22580
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22402
22581
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
22403
|
-
<h1>${
|
|
22582
|
+
<h1>${escapeHtml38(title)}</h1>
|
|
22404
22583
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
22405
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
22584
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml38(check.name)}</strong>: ${escapeHtml38(check.status)}${check.message ? ` - ${escapeHtml38(check.message)}` : ""}</li>`).join("")}</ul>
|
|
22406
22585
|
</main>`;
|
|
22407
22586
|
var runTelnyxSmokeTest = async (input) => {
|
|
22408
22587
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -22495,7 +22674,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
22495
22674
|
publicKey: options.webhook.publicKey,
|
|
22496
22675
|
toleranceSeconds: options.webhook.toleranceSeconds
|
|
22497
22676
|
}) : undefined);
|
|
22498
|
-
const app = new
|
|
22677
|
+
const app = new Elysia39({
|
|
22499
22678
|
name: options.name ?? "absolutejs-voice-telnyx"
|
|
22500
22679
|
}).get(texmlPath, async ({ query, request }) => {
|
|
22501
22680
|
const streamUrl = await resolveTelnyxStreamUrl(options, {
|
|
@@ -22605,8 +22784,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
22605
22784
|
};
|
|
22606
22785
|
|
|
22607
22786
|
// src/telephony/matrix.ts
|
|
22608
|
-
import { Elysia as
|
|
22609
|
-
var
|
|
22787
|
+
import { Elysia as Elysia40 } from "elysia";
|
|
22788
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22610
22789
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
22611
22790
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
22612
22791
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -22667,13 +22846,13 @@ var badgeStyles = {
|
|
|
22667
22846
|
};
|
|
22668
22847
|
var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
|
|
22669
22848
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
22670
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
22849
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml39(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
22671
22850
|
<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>
|
|
22672
22851
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
22673
22852
|
${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);">
|
|
22674
22853
|
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
|
|
22675
|
-
<h2 style="margin:0; font-size:20px;">${
|
|
22676
|
-
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${
|
|
22854
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml39(entry.name)}</h2>
|
|
22855
|
+
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml39(entry.status.toUpperCase())}</span>
|
|
22677
22856
|
</div>
|
|
22678
22857
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
22679
22858
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -22681,15 +22860,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
22681
22860
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
22682
22861
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
22683
22862
|
</dl>
|
|
22684
|
-
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${
|
|
22685
|
-
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${
|
|
22686
|
-
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${
|
|
22863
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml39(entry.setup.urls.stream || "missing")}</code></p>
|
|
22864
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml39(entry.setup.urls.webhook || "missing")}</code></p>
|
|
22865
|
+
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml39(issue.severity)}: ${escapeHtml39(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
|
|
22687
22866
|
</article>`).join("")}
|
|
22688
22867
|
</section>
|
|
22689
22868
|
</main>`;
|
|
22690
22869
|
var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
22691
22870
|
const path = options.path ?? "/api/voice/telephony/carriers";
|
|
22692
|
-
return new
|
|
22871
|
+
return new Elysia40({
|
|
22693
22872
|
name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
|
|
22694
22873
|
}).get(path, async ({ query, request }) => {
|
|
22695
22874
|
const providers = await options.load({ query, request });
|
|
@@ -22711,7 +22890,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
|
22711
22890
|
};
|
|
22712
22891
|
|
|
22713
22892
|
// src/phoneAgentProductionSmoke.ts
|
|
22714
|
-
import { Elysia as
|
|
22893
|
+
import { Elysia as Elysia41 } from "elysia";
|
|
22715
22894
|
var defaultRequirements = [
|
|
22716
22895
|
"media-started",
|
|
22717
22896
|
"transcript",
|
|
@@ -22719,7 +22898,7 @@ var defaultRequirements = [
|
|
|
22719
22898
|
"lifecycle-outcome",
|
|
22720
22899
|
"no-session-error"
|
|
22721
22900
|
];
|
|
22722
|
-
var
|
|
22901
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
22723
22902
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
22724
22903
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
22725
22904
|
const value = event.payload[key];
|
|
@@ -22828,10 +23007,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
22828
23007
|
});
|
|
22829
23008
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
22830
23009
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
22831
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
22832
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
22833
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
22834
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
23010
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml40(issue.requirement)}</strong>: ${escapeHtml40(issue.message)}</li>`).join("");
|
|
23011
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml40(outcome)}</span>`).join("");
|
|
23012
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml40(requirement)}</span>`).join("");
|
|
23013
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml40(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>${escapeHtml40(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml40(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml40(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml40(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>`;
|
|
22835
23014
|
};
|
|
22836
23015
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
22837
23016
|
query,
|
|
@@ -22854,7 +23033,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
22854
23033
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
22855
23034
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
22856
23035
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
22857
|
-
const routes = new
|
|
23036
|
+
const routes = new Elysia41({
|
|
22858
23037
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
22859
23038
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
22860
23039
|
if (htmlPath) {
|
|
@@ -22897,7 +23076,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
22897
23076
|
"completed",
|
|
22898
23077
|
"failed"
|
|
22899
23078
|
];
|
|
22900
|
-
var
|
|
23079
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22901
23080
|
var loadRouteJson = async (input) => {
|
|
22902
23081
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
22903
23082
|
headers: {
|
|
@@ -23135,10 +23314,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
23135
23314
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
23136
23315
|
const urls = entry?.setup.urls;
|
|
23137
23316
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
23138
|
-
return `<tr><td>${
|
|
23317
|
+
return `<tr><td>${escapeHtml41(carrier.name ?? carrier.provider)}</td><td>${escapeHtml41(carrier.provider)}</td><td><code>${escapeHtml41(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml41(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml41(entry.status)}">${escapeHtml41(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml41(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml41(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml41(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
|
|
23139
23318
|
}).join("");
|
|
23140
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
23141
|
-
const snippet =
|
|
23319
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml41(stage)}</code></li>`).join("");
|
|
23320
|
+
const snippet = escapeHtml41(`const phoneAgent = createVoicePhoneAgent({
|
|
23142
23321
|
carriers: [
|
|
23143
23322
|
{
|
|
23144
23323
|
provider: 'twilio',
|
|
@@ -23172,11 +23351,11 @@ app.use(
|
|
|
23172
23351
|
);`);
|
|
23173
23352
|
const checklist = report.carriers.map((carrier) => {
|
|
23174
23353
|
const instruction = report.setupInstructions.find((candidate) => candidate.provider === carrier.provider && candidate.carrierName === (carrier.name ?? carrier.provider));
|
|
23175
|
-
const issueList = instruction?.issues.map((issue) => `<li>${
|
|
23176
|
-
const steps = instruction?.steps.map((step) => `<li>${
|
|
23177
|
-
return `<article><h3>${
|
|
23354
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml41(issue)}</li>`).join("") ?? "";
|
|
23355
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml41(step)}</li>`).join("") ?? "";
|
|
23356
|
+
return `<article><h3>${escapeHtml41(carrier.name ?? carrier.provider)}</h3><ol>${steps}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
|
|
23178
23357
|
}).join("");
|
|
23179
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
23358
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml41(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,.primitive{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}.primitive{background:#151d27;border-color:#365a60}.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}.primitive p{color:#cbd5de;line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #283544;border-radius:18px;color:#fef3c7;overflow:auto;padding:16px}.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>${escapeHtml41(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="${escapeHtml41(report.matrixPath)}?format=html">Open carrier matrix</a></p>` : ""}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoicePhoneAgent(...)</code> builds this carrier control plane</h2><p>Mount carrier routes once, expose setup and smoke proof, then feed the same carrier matrix and phone-agent smoke reports into production readiness so carrier regressions block deploys.</p><pre><code>${snippet}</code></pre></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>`;
|
|
23180
23359
|
};
|
|
23181
23360
|
var createVoicePhoneAgent = (options) => {
|
|
23182
23361
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -23185,7 +23364,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
23185
23364
|
setupPath: resolveSetupPath(carrier),
|
|
23186
23365
|
smokePath: resolveSmokePath(carrier)
|
|
23187
23366
|
}));
|
|
23188
|
-
const app = new
|
|
23367
|
+
const app = new Elysia42({
|
|
23189
23368
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
23190
23369
|
});
|
|
23191
23370
|
for (const carrier of options.carriers) {
|
|
@@ -24815,8 +24994,8 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
24815
24994
|
};
|
|
24816
24995
|
};
|
|
24817
24996
|
// src/providerCapabilities.ts
|
|
24818
|
-
import { Elysia as
|
|
24819
|
-
var
|
|
24997
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
24998
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24820
24999
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
24821
25000
|
configured: true,
|
|
24822
25001
|
features: options.features?.[provider],
|
|
@@ -24879,27 +25058,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
24879
25058
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
24880
25059
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
24881
25060
|
const cards = report.capabilities.map((capability) => {
|
|
24882
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
24883
|
-
return `<article class="card ${
|
|
25061
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml42(feature)}</span>`).join("");
|
|
25062
|
+
return `<article class="card ${escapeHtml42(capability.status)}">
|
|
24884
25063
|
<div class="card-header">
|
|
24885
25064
|
<div>
|
|
24886
|
-
<p class="eyebrow">${
|
|
24887
|
-
<h2>${
|
|
25065
|
+
<p class="eyebrow">${escapeHtml42(capability.kind)}</p>
|
|
25066
|
+
<h2>${escapeHtml42(capability.label ?? capability.provider)}</h2>
|
|
24888
25067
|
</div>
|
|
24889
|
-
<strong>${
|
|
25068
|
+
<strong>${escapeHtml42(capability.status)}</strong>
|
|
24890
25069
|
</div>
|
|
24891
|
-
${capability.description ? `<p>${
|
|
25070
|
+
${capability.description ? `<p>${escapeHtml42(capability.description)}</p>` : ""}
|
|
24892
25071
|
<dl>
|
|
24893
25072
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
24894
25073
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
24895
|
-
<div><dt>Model</dt><dd>${
|
|
25074
|
+
<div><dt>Model</dt><dd>${escapeHtml42(capability.model ?? "default")}</dd></div>
|
|
24896
25075
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
24897
25076
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
24898
25077
|
</dl>
|
|
24899
25078
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
24900
25079
|
</article>`;
|
|
24901
25080
|
}).join("");
|
|
24902
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25081
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml42(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>${escapeHtml42(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>`;
|
|
24903
25082
|
};
|
|
24904
25083
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
24905
25084
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -24916,7 +25095,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
24916
25095
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
24917
25096
|
const path = options.path ?? "/api/provider-capabilities";
|
|
24918
25097
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
24919
|
-
const routes = new
|
|
25098
|
+
const routes = new Elysia43({
|
|
24920
25099
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
24921
25100
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
24922
25101
|
if (htmlPath) {
|
|
@@ -24925,7 +25104,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
24925
25104
|
return routes;
|
|
24926
25105
|
};
|
|
24927
25106
|
// src/providerOrchestration.ts
|
|
24928
|
-
import { Elysia as
|
|
25107
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
24929
25108
|
var defaultRequirement = {
|
|
24930
25109
|
minProviders: 1,
|
|
24931
25110
|
requireBudgetPolicy: false,
|
|
@@ -24938,7 +25117,7 @@ var statusRank4 = {
|
|
|
24938
25117
|
warn: 1,
|
|
24939
25118
|
fail: 2
|
|
24940
25119
|
};
|
|
24941
|
-
var
|
|
25120
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24942
25121
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
24943
25122
|
var uniqueSorted6 = (values) => [
|
|
24944
25123
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -25081,27 +25260,27 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
25081
25260
|
};
|
|
25082
25261
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
25083
25262
|
const title = options.title ?? "Voice Provider Orchestration";
|
|
25084
|
-
const cards = report.surfaces.map((surface) => `<article class="card ${
|
|
25085
|
-
<div class="card-header"><div><p class="eyebrow">${
|
|
25263
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml43(surface.status)}">
|
|
25264
|
+
<div class="card-header"><div><p class="eyebrow">${escapeHtml43(surface.surface)}</p><h2>${escapeHtml43(surface.strategy ?? "default policy")}</h2></div><strong>${escapeHtml43(surface.status)}</strong></div>
|
|
25086
25265
|
<dl>
|
|
25087
|
-
<div><dt>Providers</dt><dd>${
|
|
25088
|
-
<div><dt>Fallback</dt><dd>${
|
|
25266
|
+
<div><dt>Providers</dt><dd>${escapeHtml43(surface.providers.join(", ") || "none")}</dd></div>
|
|
25267
|
+
<div><dt>Fallback</dt><dd>${escapeHtml43(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
25089
25268
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
25090
25269
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
25091
25270
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
25092
25271
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
25093
25272
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
25094
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
25273
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml43(surface.fallbackMode || "default")}</dd></div>
|
|
25095
25274
|
</dl>
|
|
25096
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
25275
|
+
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${escapeHtml43(issue.status)}</strong> ${escapeHtml43(issue.message)}</li>`).join("")}</ul>` : "<p>No orchestration issues.</p>"}
|
|
25097
25276
|
</article>`).join("");
|
|
25098
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25277
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml43(title)}</title><style>body{background:#111827;color:#f9fafb;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.card{background:#172033;border:1px solid #2d3b55;border-radius:22px;margin-bottom:16px;padding:20px}.hero{background:linear-gradient(135deg,rgba(59,130,246,.18),rgba(20,184,166,.12))}.eyebrow{color:#93c5fd;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{display:flex;flex-wrap:wrap;gap:10px}.pill{background:#0f172a;border:1px solid #334155;border-radius:999px;padding:7px 10px}.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}.card-header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between}.pass strong{color:#86efac}.warn strong{color:#fde68a}.fail strong{color:#fca5a5}dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}dt{color:#a8b0b8;font-size:.8rem}dd{margin:0;overflow-wrap:anywhere}li{margin:.35rem 0}@media(max-width:800px){main{padding:18px}.card-header{display:block}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider Policy Proof</p><h1>${escapeHtml43(title)}</h1><div class="summary"><span class="pill">${escapeHtml43(report.profileId)}</span><span class="pill">${escapeHtml43(report.status)}</span><span class="pill">${String(report.summary.surfaces)} surfaces</span><span class="pill">${String(report.summary.providers)} providers</span><span class="pill">${String(report.issues.length)} issues</span></div></section><section class="grid">${cards || '<article class="card"><p>No provider orchestration surfaces configured.</p></article>'}</section></main></body></html>`;
|
|
25099
25278
|
};
|
|
25100
25279
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
25101
25280
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
25102
25281
|
const htmlPath = options.htmlPath === undefined ? "/voice/provider-orchestration" : options.htmlPath;
|
|
25103
25282
|
const markdownPath = options.markdownPath === undefined ? "/voice/provider-orchestration.md" : options.markdownPath;
|
|
25104
|
-
const routes = new
|
|
25283
|
+
const routes = new Elysia44({
|
|
25105
25284
|
name: options.name ?? "absolutejs-voice-provider-orchestration"
|
|
25106
25285
|
}).get(path, () => buildVoiceProviderOrchestrationReport(options));
|
|
25107
25286
|
if (htmlPath) {
|
|
@@ -25272,7 +25451,7 @@ var assertVoiceProviderRoutingContractEvidence = (reports, input = {}) => {
|
|
|
25272
25451
|
return report;
|
|
25273
25452
|
};
|
|
25274
25453
|
// src/providerSlo.ts
|
|
25275
|
-
import { Elysia as
|
|
25454
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
25276
25455
|
var defaultThresholds = {
|
|
25277
25456
|
llm: {
|
|
25278
25457
|
maxAverageElapsedMs: 2500,
|
|
@@ -25305,7 +25484,7 @@ var statusRank5 = {
|
|
|
25305
25484
|
warn: 1,
|
|
25306
25485
|
fail: 2
|
|
25307
25486
|
};
|
|
25308
|
-
var
|
|
25487
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25309
25488
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
25310
25489
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
25311
25490
|
var uniqueSorted7 = (values) => [
|
|
@@ -25601,11 +25780,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25601
25780
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
25602
25781
|
const kindCards = providerKinds.map((kind) => {
|
|
25603
25782
|
const kindReport = report.kinds[kind];
|
|
25604
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
25783
|
+
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${escapeHtml44(metric.label)}</dt><dd>${escapeHtml44(formatMetricValue2(metric))}</dd><small>budget ${escapeHtml44(formatMetricThreshold(metric))}</small></div>`).join("");
|
|
25605
25784
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
25606
|
-
return `<article class="${
|
|
25785
|
+
return `<article class="${escapeHtml44(kindReport.status)}"><h2>${kind.toUpperCase()} <span>${escapeHtml44(kindReport.status)}</span></h2><p>${kindReport.events} routing event(s), ${kindReport.eventsWithLatency} latency sample(s), providers: ${escapeHtml44(providers)}.</p><dl>${metrics}</dl></article>`;
|
|
25607
25786
|
}).join("");
|
|
25608
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
25787
|
+
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${escapeHtml44(issue.status)}"><strong>${escapeHtml44(issue.kind ? `${issue.kind.toUpperCase()} ${issue.label}` : issue.label)}</strong><span>${escapeHtml44(issue.detail ?? "")}</span></li>`).join("")}</ul>` : "<p>No provider SLO issues.</p>";
|
|
25609
25788
|
const snippet = `createVoiceProviderSloRoutes({
|
|
25610
25789
|
store: runtimeStorage.traces,
|
|
25611
25790
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -25615,7 +25794,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25615
25794
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
25616
25795
|
}
|
|
25617
25796
|
})`;
|
|
25618
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25797
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml44(title)}</title><style>body{background:#101318;color:#f8f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,article,.primitive{background:#171b22;border:1px solid #2c3340;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(14,165,233,.2),rgba(245,158,11,.12))}.eyebrow{color:#7dd3fc;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.3rem,6vw,4.9rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.status,article h2 span{border:1px solid #475569;border-radius:999px;display:inline-flex;font-size:.85rem;padding:6px 10px}.pass{border-color:rgba(34,197,94,.65)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}dl{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}dt{color:#cbd5e1;font-size:.78rem;text-transform:uppercase}dd{font-size:1.7rem;font-weight:900;margin:0}small{color:#a8b3c2}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#101318;border:1px solid #2c3340;border-radius:16px;padding:12px}li span{color:#cbd5e1;display:block;margin-top:4px}.primitive{background:#11161d}.primitive code{color:#bae6fd}.primitive pre{background:#070b10;border:1px solid #243041;border-radius:16px;color:#e0f2fe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Provider latency and fallback proof</p><h1>${escapeHtml44(title)}</h1><p class="status ${escapeHtml44(report.status)}">${escapeHtml44(report.status)}</p><p>${report.events} provider routing event(s), ${report.eventsWithLatency} latency sample(s).</p></section><section class="grid">${kindCards}</section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderSloRoutes(...)</code> turns provider speed into release evidence</h2><p>Pair this report with production readiness so LLM/STT/TTS latency, timeout, fallback, and unresolved error regressions block deploys.</p><pre><code>${escapeHtml44(snippet)}</code></pre></section><section><h2>Issues</h2>${issues}</section></main></body></html>`;
|
|
25619
25798
|
};
|
|
25620
25799
|
var createVoiceProviderSloRoutes = (options) => {
|
|
25621
25800
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -25626,7 +25805,7 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25626
25805
|
...options.headers ?? {}
|
|
25627
25806
|
};
|
|
25628
25807
|
const buildReport = () => buildVoiceProviderSloReport(options);
|
|
25629
|
-
const app = new
|
|
25808
|
+
const app = new Elysia45({ name: options.name ?? "absolute-voice-provider-slos" });
|
|
25630
25809
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
25631
25810
|
if (markdownPath !== false) {
|
|
25632
25811
|
app.get(markdownPath, async () => {
|
|
@@ -25656,10 +25835,10 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25656
25835
|
return app;
|
|
25657
25836
|
};
|
|
25658
25837
|
// src/productionReadiness.ts
|
|
25659
|
-
import { Elysia as
|
|
25838
|
+
import { Elysia as Elysia51 } from "elysia";
|
|
25660
25839
|
|
|
25661
25840
|
// src/telephony/security.ts
|
|
25662
|
-
import { Elysia as
|
|
25841
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
25663
25842
|
|
|
25664
25843
|
// src/postgresStore.ts
|
|
25665
25844
|
var normalizeIdentifierSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
|
|
@@ -26397,7 +26576,7 @@ var assertVoiceTelephonyWebhookSecurityEvidence = (report, input = {}) => {
|
|
|
26397
26576
|
};
|
|
26398
26577
|
var createVoiceTelephonyWebhookSecurityRoutes = (options) => {
|
|
26399
26578
|
const path = options.path ?? "/api/voice/telephony/webhook-security";
|
|
26400
|
-
return new
|
|
26579
|
+
return new Elysia46({
|
|
26401
26580
|
name: options.name ?? "absolutejs-voice-telephony-webhook-security"
|
|
26402
26581
|
}).get(path, () => buildVoiceTelephonyWebhookSecurityReport(options.options));
|
|
26403
26582
|
};
|
|
@@ -26454,8 +26633,8 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
26454
26633
|
};
|
|
26455
26634
|
|
|
26456
26635
|
// src/opsRecovery.ts
|
|
26457
|
-
import { Elysia as
|
|
26458
|
-
var
|
|
26636
|
+
import { Elysia as Elysia47 } from "elysia";
|
|
26637
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26459
26638
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
26460
26639
|
var hrefForSession = (value, sessionId) => {
|
|
26461
26640
|
if (typeof value === "function") {
|
|
@@ -26669,19 +26848,19 @@ ${failedSessions || "None."}
|
|
|
26669
26848
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
26670
26849
|
`;
|
|
26671
26850
|
};
|
|
26672
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
26851
|
+
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${escapeHtml45(label)}</span><strong>${String(summary.failed + summary.deadLettered)} failed</strong><small>${String(summary.pending)} pending \xB7 ${String(summary.retryEligible)} retry eligible \xB7 ${String(summary.total)} total</small></article>` : `<article><span>${escapeHtml45(label)}</span><strong>not configured</strong></article>`;
|
|
26673
26852
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
26674
26853
|
const title = options.title ?? "Voice Ops Recovery";
|
|
26675
|
-
const issues = report.issues.map((issue) => `<tr><td>${
|
|
26676
|
-
const providers = report.providers.providers.map((provider) => `<tr><td>${
|
|
26677
|
-
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${
|
|
26678
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26854
|
+
const issues = report.issues.map((issue) => `<tr><td>${escapeHtml45(issue.severity)}</td><td><code>${escapeHtml45(issue.code)}</code></td><td>${issue.href ? `<a href="${escapeHtml45(issue.href)}">${escapeHtml45(issue.label)}</a>` : escapeHtml45(issue.label)}</td><td>${escapeHtml45(String(issue.value ?? ""))}</td><td>${escapeHtml45(issue.detail ?? "")}</td></tr>`).join("");
|
|
26855
|
+
const providers = report.providers.providers.map((provider) => `<tr><td>${escapeHtml45(provider.provider)}</td><td>${escapeHtml45(provider.status)}</td><td>${String(provider.runCount)}</td><td>${String(provider.errorCount)}</td><td>${String(provider.fallbackCount)}</td><td>${escapeHtml45(provider.lastError ?? "")}</td></tr>`).join("");
|
|
26856
|
+
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${escapeHtml45(session.operationsRecordHref)}">${escapeHtml45(session.sessionId)}</a>` : escapeHtml45(session.sessionId)}${session.provider ? ` via ${escapeHtml45(session.provider)}` : ""}${session.error ? `: ${escapeHtml45(session.error)}` : ""}</li>`).join("");
|
|
26857
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml45(title)}</title><style>body{font-family:ui-sans-serif,system-ui,sans-serif;background:#f8fafc;color:#172033;margin:2rem;line-height:1.45}main{max-width:1180px;margin:auto}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.75rem;margin:1rem 0}article{background:white;border:1px solid #dbe3ef;border-radius:14px;padding:1rem;box-shadow:0 10px 28px rgba(15,23,42,.05)}article span{display:block;color:#64748b;font-size:.85rem}article strong{display:block;font-size:1.5rem;margin:.2rem 0}article small{color:#64748b}table{border-collapse:collapse;width:100%;background:white;border:1px solid #dbe3ef;border-radius:14px;overflow:hidden}th,td{border-bottom:1px solid #e2e8f0;padding:.7rem;text-align:left;vertical-align:top}code{font-size:.85em}.status{display:inline-flex;border-radius:999px;padding:.35rem .7rem;background:${report.status === "fail" ? "#fee2e2" : report.status === "warn" ? "#fef3c7" : "#dcfce7"};color:${report.status === "fail" ? "#991b1b" : report.status === "warn" ? "#92400e" : "#166534"};font-weight:700}</style></head><body><main><h1>${escapeHtml45(title)}</h1><p><span class="status">${escapeHtml45(report.status)}</span> Checked ${escapeHtml45(new Date(report.checkedAt).toLocaleString())}</p><section class="grid"><article><span>Recovered fallbacks</span><strong>${String(report.providers.recoveredFallbacks)}</strong></article><article><span>Unresolved providers</span><strong>${String(report.providers.unresolvedFailures)}</strong></article><article><span>Operator interventions</span><strong>${String(report.interventions.total)}</strong></article><article><span>Latency status</span><strong>${escapeHtml45(report.latency?.status ?? "disabled")}</strong></article>${renderDeliverySummary("Audit delivery", report.auditDeliveries)}${renderDeliverySummary("Trace delivery", report.traceDeliveries)}${renderDeliverySummary("Handoff delivery", report.handoffDeliveries)}</section><h2>Issues</h2><table><thead><tr><th>Severity</th><th>Code</th><th>Label</th><th>Value</th><th>Detail</th></tr></thead><tbody>${issues || '<tr><td colspan="5">No recovery issues.</td></tr>'}</tbody></table><h2>Providers</h2><table><thead><tr><th>Provider</th><th>Status</th><th>Runs</th><th>Errors</th><th>Fallbacks</th><th>Last error</th></tr></thead><tbody>${providers || '<tr><td colspan="6">No provider activity.</td></tr>'}</tbody></table><h2>Failed Sessions</h2><ul>${failedSessions || "<li>None.</li>"}</ul></main></body></html>`;
|
|
26679
26858
|
};
|
|
26680
26859
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
26681
26860
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
26682
26861
|
const htmlPath = options.htmlPath === undefined ? "/ops-recovery" : options.htmlPath;
|
|
26683
26862
|
const markdownPath = options.markdownPath === undefined ? `${path}.md` : options.markdownPath;
|
|
26684
|
-
const routes = new
|
|
26863
|
+
const routes = new Elysia47({
|
|
26685
26864
|
name: options.name ?? "absolutejs-voice-ops-recovery"
|
|
26686
26865
|
}).get(path, async () => buildVoiceOpsRecoveryReport(options));
|
|
26687
26866
|
if (htmlPath) {
|
|
@@ -26711,18 +26890,18 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
|
26711
26890
|
};
|
|
26712
26891
|
|
|
26713
26892
|
// src/observabilityExport.ts
|
|
26714
|
-
import { Elysia as
|
|
26893
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
26715
26894
|
import { Database as Database4 } from "bun:sqlite";
|
|
26716
26895
|
import { createHash } from "crypto";
|
|
26717
26896
|
import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
|
|
26718
26897
|
import { join as join3 } from "path";
|
|
26719
26898
|
|
|
26720
26899
|
// src/operationsRecord.ts
|
|
26721
|
-
import { Elysia as
|
|
26900
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
26722
26901
|
|
|
26723
26902
|
// src/traceTimeline.ts
|
|
26724
|
-
import { Elysia as
|
|
26725
|
-
var
|
|
26903
|
+
import { Elysia as Elysia48 } from "elysia";
|
|
26904
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26726
26905
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
26727
26906
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
26728
26907
|
var firstString3 = (payload, keys) => {
|
|
@@ -26905,17 +27084,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
26905
27084
|
};
|
|
26906
27085
|
};
|
|
26907
27086
|
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
26908
|
-
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>${
|
|
27087
|
+
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>${escapeHtml46(provider.provider)}</strong><dl><div><dt>Events</dt><dd>${String(provider.eventCount)}</dd></div><div><dt>Avg</dt><dd>${formatMs4(provider.averageElapsedMs)}</dd></div><div><dt>Max</dt><dd>${formatMs4(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>`;
|
|
26909
27088
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
26910
|
-
const events = session.events.map((event) => `<tr class="${
|
|
26911
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
26912
|
-
const supportLinks = session.operationsRecordHref ? `<p><a href="${
|
|
26913
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27089
|
+
const events = session.events.map((event) => `<tr class="${escapeHtml46(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml46(event.type)}</td><td>${escapeHtml46(event.label)}</td><td>${escapeHtml46(event.provider ?? "")}</td><td>${escapeHtml46(event.status ?? "")}</td><td>${formatMs4(event.elapsedMs)}</td></tr>`).join("");
|
|
27090
|
+
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml46(issue.severity)}">${escapeHtml46(issue.code)}: ${escapeHtml46(issue.message)}</li>`).join("") : "<li>none</li>";
|
|
27091
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml46(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
27092
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml46(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>${escapeHtml46(session.sessionId)}</h1><p class="status ${escapeHtml46(session.status)}">${escapeHtml46(session.status)}</p>${supportLinks}</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>${formatMs4(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>`;
|
|
26914
27093
|
};
|
|
26915
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
27094
|
+
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml46(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml46(session.operationsRecordHref)}">${escapeHtml46(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml46(session.sessionId)}</a>`}</td><td>${escapeHtml46(session.status)}</td><td>${String(session.summary.eventCount)}</td><td>${String(session.summary.turnCount)}</td><td>${String(session.summary.errorCount)}</td><td>${formatMs4(session.summary.callDurationMs)}</td><td>${session.providers.map((provider) => escapeHtml46(provider.provider)).join(", ")}</td></tr>`).join("");
|
|
26916
27095
|
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}}";
|
|
26917
27096
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
26918
|
-
const snippet =
|
|
27097
|
+
const snippet = escapeHtml46(`const traceStore = createVoiceTraceSinkStore({
|
|
26919
27098
|
store: runtimeStorage.traces,
|
|
26920
27099
|
sinks: [
|
|
26921
27100
|
createVoiceTraceHTTPSink({
|
|
@@ -26941,13 +27120,13 @@ app.use(
|
|
|
26941
27120
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
26942
27121
|
})
|
|
26943
27122
|
);`);
|
|
26944
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27123
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml46(options.title ?? "Voice Trace Timelines")}</title><style>${timelineCSS}.primitive{background:#181f27;border:1px solid #334155;border-radius:20px;margin:20px 0;padding:18px}.primitive p{line-height:1.55}.primitive pre{background:#0b1118;border:1px solid #2b3642;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.primitive code{color:#bfdbfe}</style></head><body><main><header><p class="eyebrow">Self-hosted voice debugging</p><h1>${escapeHtml46(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><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceTraceTimelineRoutes(...)</code> makes traces the proof backbone</h2><p class="muted">Mount trace timelines from the same trace store used by readiness, simulations, provider recovery, delivery sinks, and phone-agent smoke proof.</p><pre><code>${snippet}</code></pre></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>`;
|
|
26945
27124
|
};
|
|
26946
27125
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
26947
27126
|
const path = options.path ?? "/api/voice-traces";
|
|
26948
27127
|
const htmlPath = options.htmlPath ?? "/traces";
|
|
26949
27128
|
const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
|
|
26950
|
-
const routes = new
|
|
27129
|
+
const routes = new Elysia48({
|
|
26951
27130
|
name: options.name ?? "absolutejs-voice-trace-timelines"
|
|
26952
27131
|
});
|
|
26953
27132
|
const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
|
|
@@ -27376,7 +27555,7 @@ var assertVoiceOperationsRecordProviderRecovery = (record, input = {}) => {
|
|
|
27376
27555
|
}
|
|
27377
27556
|
return report;
|
|
27378
27557
|
};
|
|
27379
|
-
var
|
|
27558
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27380
27559
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
27381
27560
|
var outcomeLabels = (outcome) => [
|
|
27382
27561
|
outcome.complete ? "complete" : undefined,
|
|
@@ -27456,20 +27635,20 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
27456
27635
|
`);
|
|
27457
27636
|
};
|
|
27458
27637
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
27459
|
-
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${
|
|
27460
|
-
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${
|
|
27461
|
-
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${
|
|
27638
|
+
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml47(provider.provider)}</strong><span>${String(provider.eventCount)} events</span><span>${formatMs5(provider.averageElapsedMs)} avg</span><span>${String(provider.errorCount)} errors</span></article>`).join("") : '<p class="muted">No provider events recorded.</p>';
|
|
27639
|
+
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml47(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml47(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml47(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml47(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
27640
|
+
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml47(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml47(decision.status ?? decision.type)}</span> ${formatMs5(decision.elapsedMs)}${decision.surface ? `<p><span class="label">Surface</span>${escapeHtml47(decision.surface)}</p>` : ""}${decision.kind ? `<p><span class="label">Kind</span>${escapeHtml47(decision.kind)}</p>` : ""}${decision.selectedProvider ? `<p>Selected: ${escapeHtml47(decision.selectedProvider)}</p>` : ""}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml47(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml47(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml47(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
27462
27641
|
const providerDecisionSummary = record.providerDecisionSummary;
|
|
27463
|
-
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${
|
|
27464
|
-
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${
|
|
27465
|
-
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${
|
|
27466
|
-
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${
|
|
27467
|
-
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${
|
|
27642
|
+
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml47(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml47(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml47(handoff.status ?? "")}</span><p>${escapeHtml47(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
|
|
27643
|
+
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml47(tool.toolName ?? "tool")}</strong> <span>${escapeHtml47(tool.status ?? "")}</span> ${formatMs5(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml47(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
|
|
27644
|
+
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml47(review.title)}</strong> <span>${escapeHtml47(review.summary.outcome ?? "")}</span><p>${escapeHtml47(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
27645
|
+
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml47(task.title)}</strong> <span>${escapeHtml47(task.status)}</span><p>${escapeHtml47(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
|
|
27646
|
+
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml47(event.type)}</strong> <span>${escapeHtml47(event.deliveryStatus ?? "local")}</span><p>${escapeHtml47(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
|
|
27468
27647
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
27469
27648
|
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
27470
|
-
return `<li><strong>assistant.guardrail ${
|
|
27649
|
+
return `<li><strong>assistant.guardrail ${escapeHtml47(decision.stage ?? "unknown")}</strong> <span>${escapeHtml47(decision.status ?? "")}</span><p>Allowed: ${escapeHtml47(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml47(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml47(decision.turnId)}` : ""}</p><p>${escapeHtml47(findings)}</p></li>`;
|
|
27471
27650
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
27472
|
-
const snippet =
|
|
27651
|
+
const snippet = escapeHtml47(`app.use(
|
|
27473
27652
|
createVoiceOperationsRecordRoutes({
|
|
27474
27653
|
audit: auditStore,
|
|
27475
27654
|
integrationEvents: opsEvents,
|
|
@@ -27483,16 +27662,16 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
27483
27662
|
tasks: opsTasks
|
|
27484
27663
|
})
|
|
27485
27664
|
);`);
|
|
27486
|
-
const incidentMarkdown =
|
|
27487
|
-
const incidentLink = options.incidentHref ? `<a href="${
|
|
27488
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27665
|
+
const incidentMarkdown = escapeHtml47(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
27666
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml47(options.incidentHref)}">Download incident.md</a>` : "";
|
|
27667
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml47(options.title ?? "Voice Operations Record")}</title><style>body{background:#101417;color:#f9f4e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.eyebrow{color:#fbbf24;font-size:.8rem;font-weight:900;letter-spacing:.14em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,4.8rem);line-height:.9;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}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));margin:20px 0}.card,.primitive{background:#182025;border:1px solid #2d3a43;border-radius:20px;padding:16px}.card span,.muted,.label{color:#a9b4bd}.label{display:block;font-size:.72rem;font-weight:900;letter-spacing:.12em;text-transform:uppercase}.card strong{display:block;font-size:2rem}section{margin-top:28px}article{display:grid;gap:8px}ul{display:grid;gap:10px;list-style:none;padding:0}li{background:#182025;border:1px solid #2d3a43;border-radius:16px;padding:14px}pre{background:#080d10;border:1px solid #2d3a43;border-radius:16px;color:#dbeafe;overflow:auto;padding:14px}.hero-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}.hero-actions a{background:#fbbf24;border-radius:999px;color:#111827;font-weight:900;padding:10px 14px;text-decoration:none}.two-column{display:grid;gap:18px;grid-template-columns:minmax(0,1.15fr) minmax(280px,.85fr)}@media(max-width:860px){main{padding:20px}.two-column{grid-template-columns:1fr}}</style></head><body><main><p class="eyebrow">Call log replacement</p><h1>${escapeHtml47(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml47(record.status)}">${escapeHtml47(record.status)}</p><div class="hero-actions"><a href="#transcript">Transcript</a><a href="#provider-decisions">Provider decisions</a><a href="#guardrails">Guardrails</a><a href="#incident-handoff">Incident handoff</a>${incidentLink}</div><section class="grid"><div class="card"><span>Events</span><strong>${String(record.summary.eventCount)}</strong></div><div class="card"><span>Turns</span><strong>${String(record.summary.turnCount)}</strong></div><div class="card"><span>Errors</span><strong>${String(record.summary.errorCount)}</strong></div><div class="card"><span>Duration</span><strong>${formatMs5(record.summary.callDurationMs)}</strong></div><div class="card"><span>Provider recovery</span><strong>${escapeHtml47(providerDecisionSummary.recoveryStatus)}</strong><span>${String(providerDecisionSummary.fallbacks)} fallback / ${String(providerDecisionSummary.degraded)} degraded / ${String(providerDecisionSummary.errors)} errors</span></div><div class="card"><span>Guardrails</span><strong>${String(record.guardrails.blocked)}</strong></div><div class="card"><span>Audit</span><strong>${String(record.audit?.total ?? 0)}</strong></div><div class="card"><span>Reviews</span><strong>${String(record.reviews?.total ?? 0)}</strong></div><div class="card"><span>Tasks</span><strong>${String(record.tasks?.total ?? 0)}</strong></div><div class="card"><span>Integrations</span><strong>${String(record.integrationEvents?.total ?? 0)}</strong></div></section><section class="two-column"><div><h2 id="transcript">Transcript</h2><ul>${transcript}</ul></div><div><h2 id="provider-decisions">Provider Decisions</h2><ul>${providerDecisions}</ul></div></section><section id="guardrails"><h2>Guardrail Evidence</h2><p class="muted">Live <code>assistant.guardrail</code> decisions attached to this session.</p><ul>${guardrails}</ul></section><section id="incident-handoff"><h2>Copyable Incident Handoff</h2><p class="muted">Paste this into Slack, Linear, Zendesk, or an incident review. ${incidentLink}</p><pre><code>${incidentMarkdown}</code></pre></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceOperationsRecordRoutes(...)</code> gives every call one debuggable object</h2><p class="muted">Use this as the support/debug payload across traces, provider routing, tools, handoffs, guardrails, audit, latency, replay, reviews, tasks, and webhook delivery.</p><pre><code>${snippet}</code></pre></section><section><h2>Provider Summary</h2><div class="grid">${providers}</div></section><section><h2>Handoffs</h2><ul>${handoffs}</ul></section><section><h2>Tools</h2><ul>${tools}</ul></section><section><h2>Reviews</h2><ul>${reviews}</ul></section><section><h2>Tasks</h2><ul>${tasks}</ul></section><section><h2>Integration Events</h2><ul>${integrationEvents}</ul></section></main></body></html>`;
|
|
27489
27668
|
};
|
|
27490
27669
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
27491
27670
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
27492
27671
|
const htmlPath = options.htmlPath === undefined ? "/voice-operations/:sessionId" : options.htmlPath;
|
|
27493
27672
|
const incidentPath = options.incidentPath === undefined ? `${path}/incident.md` : options.incidentPath;
|
|
27494
27673
|
const incidentHtmlPath = options.incidentHtmlPath === undefined && htmlPath ? `${htmlPath}/incident.md` : options.incidentHtmlPath;
|
|
27495
|
-
const routes = new
|
|
27674
|
+
const routes = new Elysia49({
|
|
27496
27675
|
name: options.name ?? "absolutejs-voice-operations-record"
|
|
27497
27676
|
});
|
|
27498
27677
|
const buildRecord = (sessionId) => buildVoiceOperationsRecord({
|
|
@@ -28143,7 +28322,7 @@ var createVoiceObservabilityExportReplayRoutes = (options) => {
|
|
|
28143
28322
|
...options.headers ?? {}
|
|
28144
28323
|
};
|
|
28145
28324
|
const buildReport = () => resolveVoiceObservabilityExportReplayReport(options.source);
|
|
28146
|
-
const app = new
|
|
28325
|
+
const app = new Elysia50({
|
|
28147
28326
|
name: options.name ?? "absolute-voice-observability-export-replay"
|
|
28148
28327
|
});
|
|
28149
28328
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28952,7 +29131,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
28952
29131
|
artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
|
|
28953
29132
|
}
|
|
28954
29133
|
});
|
|
28955
|
-
const app = new
|
|
29134
|
+
const app = new Elysia50({
|
|
28956
29135
|
name: options.name ?? "absolute-voice-observability-export"
|
|
28957
29136
|
});
|
|
28958
29137
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -29029,7 +29208,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
29029
29208
|
};
|
|
29030
29209
|
|
|
29031
29210
|
// src/productionReadiness.ts
|
|
29032
|
-
var
|
|
29211
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29033
29212
|
var rollupStatus4 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
29034
29213
|
var readinessGateCodes = {
|
|
29035
29214
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
@@ -30598,25 +30777,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30598
30777
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
30599
30778
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
30600
30779
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
30601
|
-
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${
|
|
30602
|
-
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${
|
|
30780
|
+
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${escapeHtml48(report.links.sloReadinessThresholds)}">Open Calibration -> Active Readiness Gate</a> to inspect the thresholds currently driving calibrated provider, latency, interruption, reconnect, and monitoring gates.</p>` : "";
|
|
30781
|
+
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml48(report.profile.name)}</h2><p>${escapeHtml48(report.profile.description)}</p><p>${escapeHtml48(report.profile.purpose)}</p><div class="profile-surfaces">${report.profile.surfaces.map((surface) => `<article class="${surface.configured ? "pass" : "warn"}"><span>${surface.configured ? "CONFIGURED" : "EXPECTED"}</span><strong>${surface.href ? `<a href="${escapeHtml48(surface.href)}">${escapeHtml48(surface.label)}</a>` : escapeHtml48(surface.label)}</strong></article>`).join("")}</div></section>` : "";
|
|
30603
30782
|
const checks = report.checks.map((check, index) => {
|
|
30604
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
30605
|
-
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${
|
|
30606
|
-
return `<article class="check ${
|
|
30783
|
+
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml48(action.href)}">${escapeHtml48(action.label)}</button>` : `<a href="${escapeHtml48(action.href)}">${escapeHtml48(action.label)}</a>`).join("");
|
|
30784
|
+
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${escapeHtml48(check.status)}: observed ${escapeHtml48(String(check.gateExplanation.observed ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml48(check.gateExplanation.unit)}` : ""}; threshold ${escapeHtml48(String(check.gateExplanation.threshold ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml48(check.gateExplanation.unit)}` : ""}. ${escapeHtml48(check.gateExplanation.remediation)} ${check.gateExplanation.sourceHref ? `<a href="${escapeHtml48(check.gateExplanation.sourceHref)}">Open threshold source</a>` : ""}</p>` : "";
|
|
30785
|
+
return `<article class="check ${escapeHtml48(check.status)}">
|
|
30607
30786
|
<div>
|
|
30608
|
-
<span>${
|
|
30609
|
-
<h2>${
|
|
30610
|
-
${check.detail ? `<p>${
|
|
30787
|
+
<span>${escapeHtml48(check.status.toUpperCase())}</span>
|
|
30788
|
+
<h2>${escapeHtml48(check.label)}</h2>
|
|
30789
|
+
${check.detail ? `<p>${escapeHtml48(check.detail)}</p>` : ""}
|
|
30611
30790
|
${explanation}
|
|
30612
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
30791
|
+
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml48(check.proofSource.href)}">${escapeHtml48(check.proofSource.sourceLabel)}</a>` : escapeHtml48(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml48(check.proofSource.detail)}` : ""}</p>` : ""}
|
|
30613
30792
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
30614
30793
|
</div>
|
|
30615
|
-
<strong>${
|
|
30616
|
-
${check.href ? `<a href="${
|
|
30794
|
+
<strong>${escapeHtml48(String(check.value ?? check.status))}</strong>
|
|
30795
|
+
${check.href ? `<a href="${escapeHtml48(check.href)}">Open surface</a>` : ""}
|
|
30617
30796
|
</article>`;
|
|
30618
30797
|
}).join("");
|
|
30619
|
-
const snippet =
|
|
30798
|
+
const snippet = escapeHtml48(`createVoiceProductionReadinessRoutes({
|
|
30620
30799
|
htmlPath: '/production-readiness',
|
|
30621
30800
|
path: '/api/production-readiness',
|
|
30622
30801
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -30632,13 +30811,13 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
30632
30811
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
30633
30812
|
store: traceStore
|
|
30634
30813
|
});`);
|
|
30635
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
30814
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml48(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,.primitive,.profile{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}.primitive,.profile{background:#111722}.primitive{border-color:#3a3f2d}.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}.primitive code{color:#fde68a}.primitive p{color:#c8ccd3;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#0b0f16;border:1px solid #2c3440;border-radius:18px;color:#fef3c7;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.check.pass,.profile-surfaces .pass{border-color:rgba(34,197,94,.55)}.status.warn,.check.warn,.profile-surfaces .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,.profile-surfaces span{color:#a8b0b8;font-size:.78rem;font-weight:900;letter-spacing:.08em}.check h2{margin:.2rem 0}.check p,.profile p{color:#b9c0c8;margin:.2rem 0 0}.check .proof-source{color:#f9d77e;font-weight:800}.check .gate-explanation{background:#0b0f16;border:1px solid #2c3440;border-radius:14px;color:#fef3c7;margin-top:10px;padding:10px}.check strong{font-size:1.5rem}.profile-surfaces{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));margin-top:16px}.profile-surfaces article{background:#141922;border:1px solid #26313d;border-radius:16px;padding:14px}.profile-surfaces strong{display:block;margin-top:6px}.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>${escapeHtml48(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 ${escapeHtml48(report.status)}">Overall: ${escapeHtml48(report.status.toUpperCase())}</p><p>Checked ${escapeHtml48(new Date(report.checkedAt).toLocaleString())}</p>${thresholdLink}</section>${profile}<section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProductionReadinessRoutes(...)</code> builds this deploy gate</h2><p>Mount one package primitive to expose JSON readiness, HTML readiness, and a machine-readable gate route. Feed it the proof stores and contract reports your app already owns.</p><pre><code>${snippet}</code></pre></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>`;
|
|
30636
30815
|
};
|
|
30637
30816
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
30638
30817
|
const path = options.path ?? "/api/production-readiness";
|
|
30639
30818
|
const gatePath = options.gatePath === undefined ? "/api/production-readiness/gate" : options.gatePath;
|
|
30640
30819
|
const htmlPath = options.htmlPath ?? "/production-readiness";
|
|
30641
|
-
const routes = new
|
|
30820
|
+
const routes = new Elysia51({
|
|
30642
30821
|
name: options.name ?? "absolutejs-voice-production-readiness"
|
|
30643
30822
|
});
|
|
30644
30823
|
const resolveOptions = async (input) => {
|
|
@@ -30686,8 +30865,8 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
30686
30865
|
return routes;
|
|
30687
30866
|
};
|
|
30688
30867
|
// src/voiceMonitoring.ts
|
|
30689
|
-
import { Elysia as
|
|
30690
|
-
var
|
|
30868
|
+
import { Elysia as Elysia52 } from "elysia";
|
|
30869
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30691
30870
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
30692
30871
|
var rollupStatus5 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
30693
30872
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
@@ -30940,14 +31119,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
30940
31119
|
};
|
|
30941
31120
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
30942
31121
|
const title = options.title ?? "Voice Monitors";
|
|
30943
|
-
const runs = report.runs.map((run) => `<tr><td>${
|
|
30944
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
30945
|
-
const snippet =
|
|
31122
|
+
const runs = report.runs.map((run) => `<tr><td>${escapeHtml49(run.label)}</td><td class="${escapeHtml49(run.status)}">${escapeHtml49(run.status)}</td><td>${escapeHtml49(run.severity)}</td><td>${escapeHtml49(String(run.value ?? ""))}</td><td>${escapeHtml49(String(run.threshold ?? ""))}</td><td>${escapeHtml49(run.detail ?? "")}</td></tr>`).join("");
|
|
31123
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml49(issue.label)}</strong> <span class="${escapeHtml49(issue.status)}">${escapeHtml49(issue.status)}</span> ${escapeHtml49(issue.detail ?? "")}</li>`).join("");
|
|
31124
|
+
const snippet = escapeHtml49(`app.use(createVoiceMonitorRoutes({
|
|
30946
31125
|
evidence,
|
|
30947
31126
|
issueStore,
|
|
30948
31127
|
monitors: [defineVoiceMonitor(...)]
|
|
30949
31128
|
}));`);
|
|
30950
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31129
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml49(title)}</title><style>body{background:#10141b;color:#f8f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero,.card{background:#171f2b;border:1px solid #2e3a4b;border-radius:24px;margin-bottom:16px;padding:22px}.eyebrow{color:#93c5fd;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);line-height:.92;margin:.2rem 0 1rem}.pill{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;margin-right:8px;padding:8px 12px}.pass{color:#86efac}.warn,.acknowledged{color:#fde68a}.fail,.open{color:#fca5a5}.resolved,.muted{color:#cbd5e1}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid #2e3a4b;padding:12px;text-align:left;vertical-align:top}pre{background:#0c1118;border:1px solid #2e3a4b;border-radius:16px;color:#dbeafe;overflow:auto;padding:16px}</style></head><body><main><section class="hero"><p class="eyebrow">Code-owned monitoring</p><h1>${escapeHtml49(title)}</h1><p class="pill ${escapeHtml49(report.status)}">Status: ${escapeHtml49(report.status)}</p><p class="pill">Open issues: ${String(report.summary.open)}</p><p class="pill">Critical: ${String(report.summary.criticalOpen)}</p></section><section class="card"><h2>Monitor Runs</h2><table><thead><tr><th>Monitor</th><th>Status</th><th>Severity</th><th>Value</th><th>Threshold</th><th>Detail</th></tr></thead><tbody>${runs}</tbody></table></section><section class="card"><h2>Issues</h2>${issues ? `<ul>${issues}</ul>` : '<p class="pass">No monitor issues.</p>'}</section><section class="card"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceMonitorRoutes(...)</code></h2><pre><code>${snippet}</code></pre></section></main></body></html>`;
|
|
30951
31130
|
};
|
|
30952
31131
|
var actorFromRequest = async (request) => {
|
|
30953
31132
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -30971,7 +31150,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
30971
31150
|
monitors: options.monitors,
|
|
30972
31151
|
now: options.now
|
|
30973
31152
|
});
|
|
30974
|
-
const routes = new
|
|
31153
|
+
const routes = new Elysia52({
|
|
30975
31154
|
name: options.name ?? "absolutejs-voice-monitoring"
|
|
30976
31155
|
}).get(path, report).get(`${path}.md`, async () => {
|
|
30977
31156
|
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
@@ -31018,7 +31197,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
31018
31197
|
};
|
|
31019
31198
|
var createVoiceMonitorRunnerRoutes = (options) => {
|
|
31020
31199
|
const path = options.path ?? "/api/voice/monitor-runner";
|
|
31021
|
-
return new
|
|
31200
|
+
return new Elysia52({
|
|
31022
31201
|
name: options.name ?? "absolutejs-voice-monitor-runner"
|
|
31023
31202
|
}).get(path, () => ({
|
|
31024
31203
|
isRunning: options.runner.isRunning()
|
|
@@ -31394,8 +31573,8 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
31394
31573
|
};
|
|
31395
31574
|
};
|
|
31396
31575
|
// src/providerStackRecommendations.ts
|
|
31397
|
-
import { Elysia as
|
|
31398
|
-
var
|
|
31576
|
+
import { Elysia as Elysia53 } from "elysia";
|
|
31577
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31399
31578
|
var profileProviderPriorities = {
|
|
31400
31579
|
"meeting-recorder": {
|
|
31401
31580
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -31714,17 +31893,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
31714
31893
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
31715
31894
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
31716
31895
|
const rows = report.rows.map((row) => {
|
|
31717
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
31718
|
-
return `<article class="row ${
|
|
31896
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml50(check.status)}"><strong>${escapeHtml50(check.label)}</strong><span>${escapeHtml50(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml50(check.remediation.href)}">${escapeHtml50(check.remediation.label)}</a>` : escapeHtml50(check.remediation.label)}: ${escapeHtml50(check.remediation.detail)}</em>` : ""}</li>`).join("");
|
|
31897
|
+
return `<article class="row ${escapeHtml50(row.status)}">
|
|
31719
31898
|
<div>
|
|
31720
|
-
<p class="eyebrow">${
|
|
31721
|
-
<h2>${
|
|
31722
|
-
<p class="status ${
|
|
31899
|
+
<p class="eyebrow">${escapeHtml50(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
31900
|
+
<h2>${escapeHtml50(row.provider)}</h2>
|
|
31901
|
+
<p class="status ${escapeHtml50(row.status)}">${escapeHtml50(row.status.toUpperCase())}</p>
|
|
31723
31902
|
</div>
|
|
31724
31903
|
<ul>${checks}</ul>
|
|
31725
31904
|
</article>`;
|
|
31726
31905
|
}).join("");
|
|
31727
|
-
const snippet =
|
|
31906
|
+
const snippet = escapeHtml50(`const providerContracts = () =>
|
|
31728
31907
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
31729
31908
|
env: process.env,
|
|
31730
31909
|
providers: {
|
|
@@ -31745,7 +31924,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
31745
31924
|
providerContractMatrix: () =>
|
|
31746
31925
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
31747
31926
|
});`);
|
|
31748
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31927
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml50(title)}</title><style>body{background:#0f1412;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1180px;padding:32px}.hero,.primitive,.row{background:#17201b;border:1px solid #2d3b32;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(34,197,94,.16),rgba(125,211,252,.12))}.primitive{background:#111814;border-color:#41604a}.eyebrow{color:#86efac;font-size:.78rem;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}h2{margin:.2rem 0}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill,.status{border:1px solid #3f4f45;border-radius:999px;display:inline-flex;padding:8px 12px}.primitive code{color:#bbf7d0}.primitive p{color:#c8d8ca;line-height:1.55;margin:.45rem 0 0}.primitive pre{background:#08110d;border:1px solid #294132;border-radius:18px;color:#d9f99d;margin:16px 0 0;overflow:auto;padding:16px}.status.pass,.row.pass,.pass{border-color:rgba(34,197,94,.65)}.status.warn,.row.warn,.warn{border-color:rgba(245,158,11,.7)}.status.fail,.row.fail,.fail{border-color:rgba(239,68,68,.75)}.row{display:grid;gap:20px;grid-template-columns:minmax(180px,.45fr) 1fr}.row ul{display:grid;gap:10px;list-style:none;margin:0;padding:0}.row li{background:#111814;border:1px solid #2d3b32;border-radius:16px;display:grid;gap:4px;padding:12px}.row li span{color:#b8c2ba}.row li em{color:#f9d77e;font-style:normal}.row li a{color:#86efac}@media(max-width:760px){main{padding:18px}.row{grid-template-columns:1fr}}</style></head><body><main><section class="hero"><p class="eyebrow">Provider contracts</p><h1>${escapeHtml50(title)}</h1><p>Self-hosted provider proof for configured state, required env, latency budgets, fallback, streaming, and declared capabilities.</p><div class="summary"><span class="pill">${String(report.passed)} passing</span><span class="pill">${String(report.warned)} warning</span><span class="pill">${String(report.failed)} failing</span><span class="pill">${String(report.total)} total</span></div></section><section class="primitive"><p class="eyebrow">Copy into your app</p><h2><code>createVoiceProviderContractMatrixPreset(...)</code> builds this matrix</h2><p>Give AbsoluteJS your configured LLM, STT, and TTS providers once. It turns them into deploy-checkable proof for env, fallback, streaming, latency budgets, selected providers, and profile-required capabilities without a hosted dashboard.</p><pre><code>${snippet}</code></pre></section>${rows || '<article class="row"><p>No provider contracts configured.</p></article>'}</main></body></html>`;
|
|
31749
31928
|
};
|
|
31750
31929
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
31751
31930
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -31760,7 +31939,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
31760
31939
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
31761
31940
|
const path = options.path ?? "/api/provider-contracts";
|
|
31762
31941
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
31763
|
-
const routes = new
|
|
31942
|
+
const routes = new Elysia53({
|
|
31764
31943
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
31765
31944
|
});
|
|
31766
31945
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -31878,7 +32057,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
31878
32057
|
return assertion;
|
|
31879
32058
|
};
|
|
31880
32059
|
// src/opsConsoleRoutes.ts
|
|
31881
|
-
import { Elysia as
|
|
32060
|
+
import { Elysia as Elysia54 } from "elysia";
|
|
31882
32061
|
var DEFAULT_LINKS = [
|
|
31883
32062
|
{
|
|
31884
32063
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -31913,7 +32092,7 @@ var DEFAULT_LINKS = [
|
|
|
31913
32092
|
label: "Handoffs"
|
|
31914
32093
|
}
|
|
31915
32094
|
];
|
|
31916
|
-
var
|
|
32095
|
+
var escapeHtml51 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31917
32096
|
var countProviderStatuses = (providers) => {
|
|
31918
32097
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
31919
32098
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -31982,20 +32161,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
31982
32161
|
trace
|
|
31983
32162
|
};
|
|
31984
32163
|
};
|
|
31985
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
32164
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml51(input.label)}</span><strong>${escapeHtml51(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml51(input.status)}">${escapeHtml51(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml51(input.href)}">Open</a>` : ""}</article>`;
|
|
31986
32165
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
31987
32166
|
const links = report.links.map((link) => `<article class="surface">
|
|
31988
|
-
<div><h2>${
|
|
31989
|
-
<p><a href="${
|
|
32167
|
+
<div><h2>${escapeHtml51(link.label)}</h2>${link.description ? `<p>${escapeHtml51(link.description)}</p>` : ""}</div>
|
|
32168
|
+
<p><a href="${escapeHtml51(link.href)}">Open ${escapeHtml51(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml51(link.statusHref)}">Status</a>` : ""}</p>
|
|
31990
32169
|
</article>`).join("");
|
|
31991
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
31992
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
32170
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml51(session.sessionId)}</td><td>${escapeHtml51(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml51(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
32171
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml51(event.kind)}</td><td>${escapeHtml51(event.provider ?? "unknown")}</td><td>${escapeHtml51(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml51(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
31993
32172
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
31994
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32173
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml51(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>${escapeHtml51(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 ${escapeHtml51(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>`;
|
|
31995
32174
|
};
|
|
31996
32175
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
31997
32176
|
const path = options.path ?? "/ops-console";
|
|
31998
|
-
const routes = new
|
|
32177
|
+
const routes = new Elysia54({
|
|
31999
32178
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
32000
32179
|
});
|
|
32001
32180
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -32012,7 +32191,7 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
32012
32191
|
return routes;
|
|
32013
32192
|
};
|
|
32014
32193
|
// src/incidentBundle.ts
|
|
32015
|
-
import { Elysia as
|
|
32194
|
+
import { Elysia as Elysia55 } from "elysia";
|
|
32016
32195
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
32017
32196
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
32018
32197
|
return false;
|
|
@@ -32213,7 +32392,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
32213
32392
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
32214
32393
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
32215
32394
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
32216
|
-
const routes = new
|
|
32395
|
+
const routes = new Elysia55({
|
|
32217
32396
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
32218
32397
|
});
|
|
32219
32398
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -32414,19 +32593,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
32414
32593
|
};
|
|
32415
32594
|
};
|
|
32416
32595
|
// src/opsStatusRoutes.ts
|
|
32417
|
-
import { Elysia as
|
|
32418
|
-
var
|
|
32596
|
+
import { Elysia as Elysia56 } from "elysia";
|
|
32597
|
+
var escapeHtml52 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32419
32598
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
32420
32599
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
32421
32600
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
32422
32601
|
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;
|
|
32423
|
-
return `<article class="surface ${
|
|
32602
|
+
return `<article class="surface ${escapeHtml52(surface.status)}"><span>${escapeHtml52(surface.status.toUpperCase())}</span><h2>${escapeHtml52(key)}</h2><strong>${escapeHtml52(value)}</strong></article>`;
|
|
32424
32603
|
}).join("");
|
|
32425
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32604
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml52(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>${escapeHtml52(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml52(report.status)}">Overall: ${escapeHtml52(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>`;
|
|
32426
32605
|
};
|
|
32427
32606
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
32428
32607
|
const path = options.path ?? "/api/voice/ops-status";
|
|
32429
|
-
const routes = new
|
|
32608
|
+
const routes = new Elysia56({
|
|
32430
32609
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
32431
32610
|
});
|
|
32432
32611
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -32859,8 +33038,8 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
32859
33038
|
};
|
|
32860
33039
|
};
|
|
32861
33040
|
// src/traceDeliveryRoutes.ts
|
|
32862
|
-
import { Elysia as
|
|
32863
|
-
var
|
|
33041
|
+
import { Elysia as Elysia57 } from "elysia";
|
|
33042
|
+
var escapeHtml53 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32864
33043
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
32865
33044
|
var getNumber12 = (value) => {
|
|
32866
33045
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -32941,14 +33120,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
32941
33120
|
if (entries.length === 0) {
|
|
32942
33121
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
32943
33122
|
}
|
|
32944
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
33123
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml53(sinkId)}</strong>: ${escapeHtml53(result.status)}${result.deliveredTo ? ` to ${escapeHtml53(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml53(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
32945
33124
|
};
|
|
32946
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
33125
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml53(event.type)} <small>${escapeHtml53(event.id)}</small>${event.sessionId ? ` session=${escapeHtml53(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
32947
33126
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
32948
33127
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
32949
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
32950
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
32951
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33128
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml53(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
33129
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml53(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml53(delivery.deliveryStatus)}</span><h2>${escapeHtml53(delivery.id)}</h2><p>${escapeHtml53(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml53(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml53(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
33130
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml53(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>${escapeHtml53(title)}</h1><p>Checked ${escapeHtml53(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>`;
|
|
32952
33131
|
};
|
|
32953
33132
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
32954
33133
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -32968,7 +33147,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
32968
33147
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
32969
33148
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
32970
33149
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
32971
|
-
const routes = new
|
|
33150
|
+
const routes = new Elysia57({
|
|
32972
33151
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
32973
33152
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
32974
33153
|
if (htmlPath !== false) {
|
|
@@ -33065,7 +33244,7 @@ var createVoiceMemoryStore = () => {
|
|
|
33065
33244
|
return { get, getOrCreate, list, remove, set };
|
|
33066
33245
|
};
|
|
33067
33246
|
// src/opsWebhook.ts
|
|
33068
|
-
import { Elysia as
|
|
33247
|
+
import { Elysia as Elysia58 } from "elysia";
|
|
33069
33248
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
33070
33249
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
33071
33250
|
const encoder = new TextEncoder;
|
|
@@ -33195,7 +33374,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
33195
33374
|
};
|
|
33196
33375
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
33197
33376
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
33198
|
-
return new
|
|
33377
|
+
return new Elysia58().post(path, async ({ body, request, set }) => {
|
|
33199
33378
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
33200
33379
|
if (options.signingSecret) {
|
|
33201
33380
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -33650,7 +33829,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
33650
33829
|
};
|
|
33651
33830
|
};
|
|
33652
33831
|
// src/postCallAnalysis.ts
|
|
33653
|
-
import { Elysia as
|
|
33832
|
+
import { Elysia as Elysia59 } from "elysia";
|
|
33654
33833
|
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
33655
33834
|
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
33656
33835
|
var getPathValue3 = (source, path) => {
|
|
@@ -33829,7 +34008,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
|
|
|
33829
34008
|
};
|
|
33830
34009
|
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
33831
34010
|
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
33832
|
-
const routes = new
|
|
34011
|
+
const routes = new Elysia59({
|
|
33833
34012
|
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
33834
34013
|
});
|
|
33835
34014
|
routes.get(path, async ({ query }) => {
|
|
@@ -33854,7 +34033,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
|
33854
34033
|
return routes;
|
|
33855
34034
|
};
|
|
33856
34035
|
// src/guardrails.ts
|
|
33857
|
-
import { Elysia as
|
|
34036
|
+
import { Elysia as Elysia60 } from "elysia";
|
|
33858
34037
|
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
33859
34038
|
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
33860
34039
|
var matchesRule = async (rule, input) => {
|
|
@@ -34156,7 +34335,7 @@ var resolveGuardrailReport = async (options, input) => {
|
|
|
34156
34335
|
};
|
|
34157
34336
|
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
34158
34337
|
const path = options.path ?? "/api/voice/guardrails";
|
|
34159
|
-
const routes = new
|
|
34338
|
+
const routes = new Elysia60({
|
|
34160
34339
|
name: options.name ?? "absolutejs-voice-guardrails"
|
|
34161
34340
|
});
|
|
34162
34341
|
routes.all(path, async ({ request }) => {
|
|
@@ -34616,6 +34795,7 @@ export {
|
|
|
34616
34795
|
summarizeVoiceHandoffHealth,
|
|
34617
34796
|
summarizeVoiceHandoffDeliveries,
|
|
34618
34797
|
summarizeVoiceCampaigns,
|
|
34798
|
+
summarizeVoiceBrowserMedia,
|
|
34619
34799
|
summarizeVoiceBargeIn,
|
|
34620
34800
|
summarizeVoiceAuditTrail,
|
|
34621
34801
|
summarizeVoiceAuditSinkDeliveries,
|
|
@@ -34728,6 +34908,7 @@ export {
|
|
|
34728
34908
|
renderVoiceCampaignObservabilityHTML,
|
|
34729
34909
|
renderVoiceCallReviewMarkdown,
|
|
34730
34910
|
renderVoiceCallReviewHTML,
|
|
34911
|
+
renderVoiceBrowserMediaHTML,
|
|
34731
34912
|
renderVoiceBargeInHTML,
|
|
34732
34913
|
renderVoiceAuditTrailHTML,
|
|
34733
34914
|
renderVoiceAuditMarkdown,
|
|
@@ -34768,6 +34949,7 @@ export {
|
|
|
34768
34949
|
hasVoiceOpsTaskSLABreach,
|
|
34769
34950
|
getVoiceLiveOpsControlStatus,
|
|
34770
34951
|
getVoiceCampaignDialerProofStatus,
|
|
34952
|
+
getLatestVoiceBrowserMediaReport,
|
|
34771
34953
|
formatVoiceProofTrendAge,
|
|
34772
34954
|
filterVoiceTraceEvents,
|
|
34773
34955
|
filterVoiceAuditEvents,
|
|
@@ -35059,6 +35241,7 @@ export {
|
|
|
35059
35241
|
createVoiceCallReviewFromLiveTelephonyReport,
|
|
35060
35242
|
createVoiceCallCompletedEvent,
|
|
35061
35243
|
createVoiceCRMActivitySink,
|
|
35244
|
+
createVoiceBrowserMediaRoutes,
|
|
35062
35245
|
createVoiceBargeInRoutes,
|
|
35063
35246
|
createVoiceAuditTrailRoutes,
|
|
35064
35247
|
createVoiceAuditSinkStore,
|