@absolutejs/voice 0.0.22-beta.322 → 0.0.22-beta.323
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 +164 -0
- package/dist/client/index.js +164 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +730 -437
- package/dist/react/index.js +164 -0
- package/dist/svelte/index.js +164 -0
- package/dist/telephonyMediaRoutes.d.ts +63 -0
- package/dist/testing/index.js +177 -13
- package/dist/vue/index.js +164 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -11639,6 +11639,63 @@ var stringStat = (stat, key) => {
|
|
|
11639
11639
|
};
|
|
11640
11640
|
var statKey = (stat) => String(stat.id ?? stringStat(stat, "ssrc") ?? numericStat(stat, "ssrc") ?? stringStat(stat, "trackIdentifier") ?? stringStat(stat, "mid") ?? "unknown");
|
|
11641
11641
|
var secondsToMs = (value) => value === undefined ? undefined : value * 1000;
|
|
11642
|
+
var DEFAULT_TELEPHONY_FORMAT = {
|
|
11643
|
+
channels: 1,
|
|
11644
|
+
container: "raw",
|
|
11645
|
+
encoding: "mulaw",
|
|
11646
|
+
sampleRateHz: 8000
|
|
11647
|
+
};
|
|
11648
|
+
var bytesToBase64 = (audio) => {
|
|
11649
|
+
const bytes = audio instanceof ArrayBuffer ? new Uint8Array(audio) : new Uint8Array(audio.buffer, audio.byteOffset, audio.byteLength);
|
|
11650
|
+
return Buffer.from(bytes).toString("base64");
|
|
11651
|
+
};
|
|
11652
|
+
var base64ToBytes = (value) => new Uint8Array(Buffer.from(value, "base64"));
|
|
11653
|
+
var unknownRecord = (value) => value && typeof value === "object" ? value : {};
|
|
11654
|
+
var firstString2 = (records, keys) => {
|
|
11655
|
+
for (const record of records) {
|
|
11656
|
+
for (const key of keys) {
|
|
11657
|
+
const value = record[key];
|
|
11658
|
+
if (typeof value === "string" && value.length > 0) {
|
|
11659
|
+
return value;
|
|
11660
|
+
}
|
|
11661
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
11662
|
+
return String(value);
|
|
11663
|
+
}
|
|
11664
|
+
}
|
|
11665
|
+
}
|
|
11666
|
+
return;
|
|
11667
|
+
};
|
|
11668
|
+
var firstNumber = (records, keys) => {
|
|
11669
|
+
for (const record of records) {
|
|
11670
|
+
for (const key of keys) {
|
|
11671
|
+
const value = record[key];
|
|
11672
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
11673
|
+
return value;
|
|
11674
|
+
}
|
|
11675
|
+
if (typeof value === "string") {
|
|
11676
|
+
const parsed = Number(value);
|
|
11677
|
+
if (Number.isFinite(parsed)) {
|
|
11678
|
+
return parsed;
|
|
11679
|
+
}
|
|
11680
|
+
}
|
|
11681
|
+
}
|
|
11682
|
+
}
|
|
11683
|
+
return;
|
|
11684
|
+
};
|
|
11685
|
+
var telephonyDirection = (track) => {
|
|
11686
|
+
const normalized = track?.toLowerCase();
|
|
11687
|
+
if (!normalized) {
|
|
11688
|
+
return "unknown";
|
|
11689
|
+
}
|
|
11690
|
+
if (normalized.includes("inbound") || normalized.includes("caller") || normalized.includes("in")) {
|
|
11691
|
+
return "inbound";
|
|
11692
|
+
}
|
|
11693
|
+
if (normalized.includes("outbound") || normalized.includes("assistant") || normalized.includes("out")) {
|
|
11694
|
+
return "outbound";
|
|
11695
|
+
}
|
|
11696
|
+
return "unknown";
|
|
11697
|
+
};
|
|
11698
|
+
var telephonyFrameKind = (direction) => direction === "outbound" ? "assistant-audio" : "input-audio";
|
|
11642
11699
|
var normalizeWebRTCStat = (stat) => {
|
|
11643
11700
|
const sample = {};
|
|
11644
11701
|
for (const [key, value] of Object.entries(stat)) {
|
|
@@ -11648,6 +11705,113 @@ var normalizeWebRTCStat = (stat) => {
|
|
|
11648
11705
|
}
|
|
11649
11706
|
return sample;
|
|
11650
11707
|
};
|
|
11708
|
+
var parseTelephonyMediaFrame = (input) => {
|
|
11709
|
+
const envelope = input.envelope;
|
|
11710
|
+
const media = unknownRecord(envelope.media);
|
|
11711
|
+
const payload = firstString2([media, envelope], ["payload", "audio", "data"]) ?? firstString2([unknownRecord(envelope.message)], ["payload"]);
|
|
11712
|
+
if (!payload) {
|
|
11713
|
+
return;
|
|
11714
|
+
}
|
|
11715
|
+
const carrier = input.carrier ?? firstString2([envelope], ["provider"]) ?? "telephony";
|
|
11716
|
+
const streamId = firstString2([media, envelope], ["streamSid", "stream_id", "streamId", "streamId", "callSid", "call_id"]);
|
|
11717
|
+
const sequenceNumber = firstString2([media, envelope], ["sequenceNumber", "sequence_number", "chunk"]);
|
|
11718
|
+
const track = firstString2([media, envelope], ["track", "direction"]);
|
|
11719
|
+
const direction = telephonyDirection(track);
|
|
11720
|
+
const timestamp = firstNumber([media, envelope], ["timestamp", "time", "startedAt"]);
|
|
11721
|
+
return {
|
|
11722
|
+
at: timestamp,
|
|
11723
|
+
audio: base64ToBytes(payload),
|
|
11724
|
+
format: input.format ?? DEFAULT_TELEPHONY_FORMAT,
|
|
11725
|
+
id: [
|
|
11726
|
+
carrier,
|
|
11727
|
+
streamId ?? input.sessionId ?? "stream",
|
|
11728
|
+
sequenceNumber ?? timestamp ?? Date.now()
|
|
11729
|
+
].join(":"),
|
|
11730
|
+
kind: telephonyFrameKind(direction),
|
|
11731
|
+
metadata: {
|
|
11732
|
+
carrier,
|
|
11733
|
+
direction,
|
|
11734
|
+
event: firstString2([envelope], ["event", "type"]),
|
|
11735
|
+
sequenceNumber,
|
|
11736
|
+
streamId,
|
|
11737
|
+
track
|
|
11738
|
+
},
|
|
11739
|
+
sessionId: input.sessionId ?? streamId,
|
|
11740
|
+
source: "telephony"
|
|
11741
|
+
};
|
|
11742
|
+
};
|
|
11743
|
+
var serializeTelephonyMediaFrame = (input) => {
|
|
11744
|
+
const carrier = input.carrier ?? input.frame.metadata?.carrier ?? "telephony";
|
|
11745
|
+
const streamId = input.streamId ?? (typeof input.frame.metadata?.streamId === "string" ? input.frame.metadata.streamId : input.frame.sessionId);
|
|
11746
|
+
const sequenceNumber = input.sequenceNumber ?? (typeof input.frame.metadata?.sequenceNumber === "string" || typeof input.frame.metadata?.sequenceNumber === "number" ? input.frame.metadata.sequenceNumber : undefined);
|
|
11747
|
+
const direction = input.frame.kind === "assistant-audio" ? "outbound" : "inbound";
|
|
11748
|
+
const payload = input.frame.audio ? bytesToBase64(input.frame.audio) : "";
|
|
11749
|
+
if (carrier === "twilio") {
|
|
11750
|
+
return {
|
|
11751
|
+
event: "media",
|
|
11752
|
+
sequenceNumber,
|
|
11753
|
+
streamSid: streamId,
|
|
11754
|
+
media: {
|
|
11755
|
+
payload,
|
|
11756
|
+
timestamp: input.frame.at,
|
|
11757
|
+
track: direction
|
|
11758
|
+
}
|
|
11759
|
+
};
|
|
11760
|
+
}
|
|
11761
|
+
if (carrier === "telnyx") {
|
|
11762
|
+
return {
|
|
11763
|
+
event: "media",
|
|
11764
|
+
stream_id: streamId,
|
|
11765
|
+
sequence_number: sequenceNumber,
|
|
11766
|
+
media: {
|
|
11767
|
+
payload,
|
|
11768
|
+
timestamp: input.frame.at,
|
|
11769
|
+
track: direction
|
|
11770
|
+
}
|
|
11771
|
+
};
|
|
11772
|
+
}
|
|
11773
|
+
if (carrier === "plivo") {
|
|
11774
|
+
return {
|
|
11775
|
+
event: "media",
|
|
11776
|
+
streamId,
|
|
11777
|
+
sequenceNumber,
|
|
11778
|
+
media: {
|
|
11779
|
+
payload,
|
|
11780
|
+
timestamp: input.frame.at,
|
|
11781
|
+
track: direction
|
|
11782
|
+
}
|
|
11783
|
+
};
|
|
11784
|
+
}
|
|
11785
|
+
return {
|
|
11786
|
+
event: "media",
|
|
11787
|
+
provider: carrier,
|
|
11788
|
+
sequenceNumber,
|
|
11789
|
+
streamId,
|
|
11790
|
+
media: {
|
|
11791
|
+
payload,
|
|
11792
|
+
timestamp: input.frame.at,
|
|
11793
|
+
track: direction
|
|
11794
|
+
}
|
|
11795
|
+
};
|
|
11796
|
+
};
|
|
11797
|
+
var createTelephonyMediaSerializer = (input) => {
|
|
11798
|
+
const format = input.format ?? DEFAULT_TELEPHONY_FORMAT;
|
|
11799
|
+
return {
|
|
11800
|
+
carrier: input.carrier,
|
|
11801
|
+
format,
|
|
11802
|
+
parse: (envelope) => parseTelephonyMediaFrame({
|
|
11803
|
+
carrier: input.carrier,
|
|
11804
|
+
envelope,
|
|
11805
|
+
format,
|
|
11806
|
+
sessionId: input.sessionId ?? input.streamId
|
|
11807
|
+
}),
|
|
11808
|
+
serialize: (frame) => serializeTelephonyMediaFrame({
|
|
11809
|
+
carrier: input.carrier,
|
|
11810
|
+
frame,
|
|
11811
|
+
streamId: input.streamId
|
|
11812
|
+
})
|
|
11813
|
+
};
|
|
11814
|
+
};
|
|
11651
11815
|
var buildMediaResamplingPlan = (input) => {
|
|
11652
11816
|
const required = !formatMatches2(input.inputFormat, input.outputFormat);
|
|
11653
11817
|
return {
|
|
@@ -12249,9 +12413,135 @@ var createVoiceMediaPipelineRoutes = (options = {}) => {
|
|
|
12249
12413
|
}
|
|
12250
12414
|
return app;
|
|
12251
12415
|
};
|
|
12252
|
-
// src/
|
|
12416
|
+
// src/telephonyMediaRoutes.ts
|
|
12253
12417
|
import { Elysia as Elysia13 } from "elysia";
|
|
12418
|
+
var demoPayload = Buffer.from(new Uint8Array([1, 2, 3, 4])).toString("base64");
|
|
12419
|
+
var demoEnvelope = (carrier) => {
|
|
12420
|
+
if (carrier === "twilio") {
|
|
12421
|
+
return {
|
|
12422
|
+
event: "media",
|
|
12423
|
+
media: {
|
|
12424
|
+
chunk: "1",
|
|
12425
|
+
payload: demoPayload,
|
|
12426
|
+
timestamp: "1000",
|
|
12427
|
+
track: "inbound"
|
|
12428
|
+
},
|
|
12429
|
+
sequenceNumber: "1",
|
|
12430
|
+
streamSid: "proof-twilio-media"
|
|
12431
|
+
};
|
|
12432
|
+
}
|
|
12433
|
+
if (carrier === "telnyx") {
|
|
12434
|
+
return {
|
|
12435
|
+
event: "media",
|
|
12436
|
+
media: {
|
|
12437
|
+
payload: demoPayload,
|
|
12438
|
+
timestamp: 1000,
|
|
12439
|
+
track: "inbound"
|
|
12440
|
+
},
|
|
12441
|
+
sequence_number: 1,
|
|
12442
|
+
stream_id: "proof-telnyx-media"
|
|
12443
|
+
};
|
|
12444
|
+
}
|
|
12445
|
+
return {
|
|
12446
|
+
event: "media",
|
|
12447
|
+
media: {
|
|
12448
|
+
payload: demoPayload,
|
|
12449
|
+
timestamp: 1000,
|
|
12450
|
+
track: "inbound"
|
|
12451
|
+
},
|
|
12452
|
+
sequenceNumber: 1,
|
|
12453
|
+
streamId: "proof-plivo-media"
|
|
12454
|
+
};
|
|
12455
|
+
};
|
|
12456
|
+
var byteLength = (audio) => {
|
|
12457
|
+
if (!audio) {
|
|
12458
|
+
return 0;
|
|
12459
|
+
}
|
|
12460
|
+
return audio instanceof ArrayBuffer ? audio.byteLength : audio.byteLength;
|
|
12461
|
+
};
|
|
12254
12462
|
var escapeHtml16 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12463
|
+
var buildVoiceTelephonyMediaReport = (input = {}) => {
|
|
12464
|
+
const carriers = input.carriers ?? [
|
|
12465
|
+
{ carrier: "twilio" },
|
|
12466
|
+
{ carrier: "telnyx" },
|
|
12467
|
+
{ carrier: "plivo" }
|
|
12468
|
+
];
|
|
12469
|
+
const reports = carriers.map((entry) => {
|
|
12470
|
+
const serializer = createTelephonyMediaSerializer({
|
|
12471
|
+
carrier: entry.carrier
|
|
12472
|
+
});
|
|
12473
|
+
const frame = serializer.parse(entry.envelope ?? demoEnvelope(entry.carrier)) ?? parseTelephonyMediaFrame({
|
|
12474
|
+
carrier: entry.carrier,
|
|
12475
|
+
envelope: entry.envelope ?? demoEnvelope(entry.carrier)
|
|
12476
|
+
});
|
|
12477
|
+
const serialized = frame ? serializer.serialize(frame) ?? serializeTelephonyMediaFrame({
|
|
12478
|
+
carrier: entry.carrier,
|
|
12479
|
+
frame
|
|
12480
|
+
}) : undefined;
|
|
12481
|
+
const audioBytes = byteLength(frame?.audio);
|
|
12482
|
+
const issues2 = [];
|
|
12483
|
+
if (!frame) {
|
|
12484
|
+
issues2.push("Carrier media envelope did not produce a MediaFrame.");
|
|
12485
|
+
}
|
|
12486
|
+
if (frame && frame.source !== "telephony") {
|
|
12487
|
+
issues2.push("Parsed MediaFrame source is not telephony.");
|
|
12488
|
+
}
|
|
12489
|
+
if (frame && frame.kind !== "input-audio" && frame.kind !== "assistant-audio") {
|
|
12490
|
+
issues2.push("Parsed MediaFrame is not an audio frame.");
|
|
12491
|
+
}
|
|
12492
|
+
if (audioBytes === 0) {
|
|
12493
|
+
issues2.push("Parsed MediaFrame has no audio bytes.");
|
|
12494
|
+
}
|
|
12495
|
+
if (!serialized || typeof serialized !== "object") {
|
|
12496
|
+
issues2.push("MediaFrame did not serialize back into a carrier envelope.");
|
|
12497
|
+
}
|
|
12498
|
+
return {
|
|
12499
|
+
audioBytes,
|
|
12500
|
+
carrier: entry.carrier,
|
|
12501
|
+
frame,
|
|
12502
|
+
issues: issues2,
|
|
12503
|
+
serialized,
|
|
12504
|
+
status: issues2.length === 0 ? "pass" : "fail"
|
|
12505
|
+
};
|
|
12506
|
+
});
|
|
12507
|
+
const issues = reports.flatMap((report) => report.issues.map((issue) => `${report.carrier}: ${issue}`));
|
|
12508
|
+
return {
|
|
12509
|
+
carriers: reports,
|
|
12510
|
+
checkedAt: Date.now(),
|
|
12511
|
+
issues,
|
|
12512
|
+
status: issues.length === 0 ? "pass" : "fail"
|
|
12513
|
+
};
|
|
12514
|
+
};
|
|
12515
|
+
var renderVoiceTelephonyMediaHTML = (report, options = {}) => {
|
|
12516
|
+
const title = options.title ?? "Voice Telephony Media Proof";
|
|
12517
|
+
const rows = report.carriers.map((carrier) => `<tr><td>${escapeHtml16(carrier.carrier)}</td><td>${escapeHtml16(carrier.status)}</td><td>${String(carrier.audioBytes)}</td><td>${escapeHtml16(carrier.frame?.kind ?? "missing")}</td><td>${escapeHtml16(carrier.frame?.format?.encoding ?? "missing")}</td><td>${escapeHtml16(carrier.issues.join(" ") || "none")}</td></tr>`).join("");
|
|
12518
|
+
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:#111827;color:#e5e7eb;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:980px;padding:32px}.hero,table{background:#0f172a;border:1px solid #334155;border-radius:20px;margin-bottom:16px}.hero{padding:22px}.eyebrow{color:#67e8f9;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.5rem);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}.fail{color:#fecaca}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">Carrier media serializer proof</p><h1>${escapeHtml16(title)}</h1><p class="status ${escapeHtml16(report.status)}">Status: ${escapeHtml16(report.status)}</p><p>Twilio, Telnyx, and Plivo media payload envelopes are parsed into generic <code>MediaFrame</code> objects and serialized back into carrier envelopes by <code>@absolutejs/media</code>.</p></section><table><thead><tr><th>Carrier</th><th>Status</th><th>Audio bytes</th><th>Frame kind</th><th>Encoding</th><th>Issues</th></tr></thead><tbody>${rows}</tbody></table></main></body></html>`;
|
|
12519
|
+
};
|
|
12520
|
+
var createVoiceTelephonyMediaRoutes = (options = {}) => {
|
|
12521
|
+
const path = options.path ?? "/api/voice/telephony/media";
|
|
12522
|
+
const htmlPath = options.htmlPath === undefined ? "/voice/telephony-media" : options.htmlPath;
|
|
12523
|
+
const routes = new Elysia13({
|
|
12524
|
+
name: options.name ?? "absolutejs-voice-telephony-media"
|
|
12525
|
+
});
|
|
12526
|
+
routes.get(path, () => buildVoiceTelephonyMediaReport({ carriers: options.carriers }));
|
|
12527
|
+
if (htmlPath) {
|
|
12528
|
+
routes.get(htmlPath, () => {
|
|
12529
|
+
const report = buildVoiceTelephonyMediaReport({
|
|
12530
|
+
carriers: options.carriers
|
|
12531
|
+
});
|
|
12532
|
+
return new Response(renderVoiceTelephonyMediaHTML(report, options), {
|
|
12533
|
+
headers: {
|
|
12534
|
+
"content-type": "text/html; charset=utf-8",
|
|
12535
|
+
...options.headers
|
|
12536
|
+
}
|
|
12537
|
+
});
|
|
12538
|
+
});
|
|
12539
|
+
}
|
|
12540
|
+
return routes;
|
|
12541
|
+
};
|
|
12542
|
+
// src/browserMediaRoutes.ts
|
|
12543
|
+
import { Elysia as Elysia14 } from "elysia";
|
|
12544
|
+
var escapeHtml17 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12255
12545
|
var isMediaWebRTCStatsReport = (value) => {
|
|
12256
12546
|
const report = value;
|
|
12257
12547
|
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);
|
|
@@ -12321,14 +12611,14 @@ var renderVoiceBrowserMediaHTML = (report, options = {}) => {
|
|
|
12321
12611
|
const latestContinuity = report.latest?.continuity;
|
|
12322
12612
|
const rows = report.recent.slice(0, 20).map((sample) => {
|
|
12323
12613
|
const stalledStreams = (sample.continuity?.stalledInboundStreams ?? 0) + (sample.continuity?.stalledOutboundStreams ?? 0);
|
|
12324
|
-
return `<tr><td>${
|
|
12614
|
+
return `<tr><td>${escapeHtml17(sample.sessionId)}</td><td>${escapeHtml17(mergeIssues(sample.report, sample.continuity).status)}</td><td>${String(sample.report.activeCandidatePairs)}</td><td>${String(sample.report.liveAudioTracks)}</td><td>${String(sample.continuity?.inboundAudioStreams ?? "n/a")}</td><td>${String(sample.continuity?.outboundAudioStreams ?? "n/a")}</td><td>${String(stalledStreams)}</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>${escapeHtml17(new Date(sample.at).toLocaleString())}</td></tr>`;
|
|
12325
12615
|
}).join("");
|
|
12326
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12616
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml17(title)}</title><style>body{background:#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>${escapeHtml17(title)}</h1><p class="status ${escapeHtml17(report.status)}">Status: ${escapeHtml17(report.status)}</p><p>Recent <code>client.browser_media</code> traces from browser <code>RTCPeerConnection.getStats()</code> reports, including aggregate transport stats and per-stream continuity.</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>Inbound streams</span><strong>${String(latestContinuity?.inboundAudioStreams ?? "n/a")}</strong></div><div class="metric"><span>Outbound streams</span><strong>${String(latestContinuity?.outboundAudioStreams ?? "n/a")}</strong></div><div class="metric"><span>Stalled streams</span><strong>${String((latestContinuity?.stalledInboundStreams ?? 0) + (latestContinuity?.stalledOutboundStreams ?? 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, continuity })</code> runs in the browser and posts reports here. <code>getLatestVoiceBrowserMediaReport(...)</code> can feed production readiness with aggregate and continuity issues merged.</p></section><table><thead><tr><th>Session</th><th>Status</th><th>Pairs</th><th>Tracks</th><th>Inbound</th><th>Outbound</th><th>Stalled</th><th>RTT</th><th>Jitter</th><th>Loss</th><th>Measured</th></tr></thead><tbody>${rows || '<tr><td colspan="11">No browser media reports yet.</td></tr>'}</tbody></table></main></body></html>`;
|
|
12327
12617
|
};
|
|
12328
12618
|
var createVoiceBrowserMediaRoutes = (options) => {
|
|
12329
12619
|
const path = options.path ?? "/api/voice/browser-media";
|
|
12330
12620
|
const htmlPath = options.htmlPath === undefined ? "/voice/browser-media" : options.htmlPath;
|
|
12331
|
-
const routes = new
|
|
12621
|
+
const routes = new Elysia14({
|
|
12332
12622
|
name: options.name ?? "absolutejs-voice-browser-media"
|
|
12333
12623
|
});
|
|
12334
12624
|
routes.get(path, () => summarizeVoiceBrowserMedia(options));
|
|
@@ -12362,8 +12652,8 @@ var createVoiceBrowserMediaRoutes = (options) => {
|
|
|
12362
12652
|
return routes;
|
|
12363
12653
|
};
|
|
12364
12654
|
// src/demoReadyRoutes.ts
|
|
12365
|
-
import { Elysia as
|
|
12366
|
-
var
|
|
12655
|
+
import { Elysia as Elysia15 } from "elysia";
|
|
12656
|
+
var escapeHtml18 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12367
12657
|
var rollupStatus2 = (sections) => sections.some((section) => section.status === "fail") ? "fail" : sections.some((section) => section.status === "warn") ? "warn" : "pass";
|
|
12368
12658
|
var resolveLoader = async (loader, input) => typeof loader === "function" ? await loader(input) : loader;
|
|
12369
12659
|
var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
@@ -12447,17 +12737,17 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
12447
12737
|
};
|
|
12448
12738
|
};
|
|
12449
12739
|
var renderVoiceDemoReadyHTML = (report) => {
|
|
12450
|
-
const sections = report.sections.map((section) => `<article class="section ${
|
|
12451
|
-
<div><span>${
|
|
12452
|
-
<strong>${
|
|
12453
|
-
${section.href ? `<a href="${
|
|
12740
|
+
const sections = report.sections.map((section) => `<article class="section ${escapeHtml18(section.status)}">
|
|
12741
|
+
<div><span>${escapeHtml18(section.status.toUpperCase())}</span><h2>${escapeHtml18(section.label)}</h2>${section.description ? `<p>${escapeHtml18(section.description)}</p>` : ""}</div>
|
|
12742
|
+
<strong>${escapeHtml18(String(section.value ?? section.status))}</strong>
|
|
12743
|
+
${section.href ? `<a href="${escapeHtml18(section.href)}">Open</a>` : ""}
|
|
12454
12744
|
</article>`).join("");
|
|
12455
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
12745
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml18(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>${escapeHtml18(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 ${escapeHtml18(report.status)}">Overall: ${escapeHtml18(report.status.toUpperCase())}</p><p>Checked ${escapeHtml18(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>`;
|
|
12456
12746
|
};
|
|
12457
12747
|
var createVoiceDemoReadyRoutes = (options) => {
|
|
12458
12748
|
const path = options.path ?? "/api/demo-ready";
|
|
12459
12749
|
const htmlPath = options.htmlPath ?? "/demo-ready";
|
|
12460
|
-
const routes = new
|
|
12750
|
+
const routes = new Elysia15({
|
|
12461
12751
|
name: options.name ?? "absolutejs-voice-demo-ready"
|
|
12462
12752
|
});
|
|
12463
12753
|
routes.get(path, async ({ query, request }) => buildVoiceDemoReadyReport(options, { query, request }));
|
|
@@ -12476,7 +12766,7 @@ var createVoiceDemoReadyRoutes = (options) => {
|
|
|
12476
12766
|
return routes;
|
|
12477
12767
|
};
|
|
12478
12768
|
// src/deliverySinkRoutes.ts
|
|
12479
|
-
import { Elysia as
|
|
12769
|
+
import { Elysia as Elysia16 } from "elysia";
|
|
12480
12770
|
|
|
12481
12771
|
// src/queue.ts
|
|
12482
12772
|
var releaseLeaseScript = `
|
|
@@ -13419,7 +13709,7 @@ var createVoiceOpsTaskProcessorWorkerLoop = (options) => {
|
|
|
13419
13709
|
};
|
|
13420
13710
|
|
|
13421
13711
|
// src/deliverySinkRoutes.ts
|
|
13422
|
-
var
|
|
13712
|
+
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13423
13713
|
var deliveryStatus = (summary) => {
|
|
13424
13714
|
if (!summary) {
|
|
13425
13715
|
return "warn";
|
|
@@ -13518,13 +13808,13 @@ var renderSurfaceCard = (surface) => {
|
|
|
13518
13808
|
return "";
|
|
13519
13809
|
}
|
|
13520
13810
|
const value = `${surface.summary.delivered}/${surface.summary.total}`;
|
|
13521
|
-
const body = `<span>${
|
|
13522
|
-
return `<article>${surface.href ? `<a href="${
|
|
13811
|
+
const body = `<span>${escapeHtml19(surface.label)}</span><strong>${escapeHtml19(value)}</strong><p class="muted">Delivered export records.</p>`;
|
|
13812
|
+
return `<article>${surface.href ? `<a href="${escapeHtml19(surface.href)}">${body}</a>` : body}</article>`;
|
|
13523
13813
|
};
|
|
13524
13814
|
var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
13525
13815
|
const title = options.title ?? "AbsoluteJS Voice Delivery Sinks";
|
|
13526
|
-
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${
|
|
13527
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
13816
|
+
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${escapeHtml19(sink.kind)}</span><strong style="font-size:1.5rem">${escapeHtml19(sink.label)}</strong>${sink.description ? `<p class="muted">${escapeHtml19(sink.description)}</p>` : ""}${sink.mode ? `<p class="muted">Mode: ${escapeHtml19(sink.mode)}</p>` : ""}${sink.target ? `<p class="muted">Target: <code>${escapeHtml19(sink.target)}</code></p>` : ""}${sink.href ? `<p><a href="${escapeHtml19(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>';
|
|
13817
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml19(title)}</title><style>body{background:#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>${escapeHtml19(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 ${escapeHtml19(report.status)}">Overall: ${escapeHtml19(report.status.toUpperCase())}</p><p class="muted">Checked ${escapeHtml19(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({
|
|
13528
13818
|
auditDeliveries: { store: runtimeStorage.auditDeliveries },
|
|
13529
13819
|
traceDeliveries: { store: runtimeStorage.traceDeliveries },
|
|
13530
13820
|
sinks: createVoiceDeliverySinkPair({
|
|
@@ -13536,7 +13826,7 @@ var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
|
13536
13826
|
var createVoiceDeliverySinkRoutes = (options) => {
|
|
13537
13827
|
const path = options.path ?? "/api/voice-delivery-sinks";
|
|
13538
13828
|
const htmlPath = options.htmlPath === undefined ? "/delivery-sinks" : options.htmlPath;
|
|
13539
|
-
const routes = new
|
|
13829
|
+
const routes = new Elysia16({
|
|
13540
13830
|
name: options.name ?? "absolutejs-voice-delivery-sinks"
|
|
13541
13831
|
}).get(path, () => buildVoiceDeliverySinkReport(options));
|
|
13542
13832
|
if (htmlPath !== false) {
|
|
@@ -13554,7 +13844,7 @@ var createVoiceDeliverySinkRoutes = (options) => {
|
|
|
13554
13844
|
return routes;
|
|
13555
13845
|
};
|
|
13556
13846
|
// src/opsActionAuditRoutes.ts
|
|
13557
|
-
import { Elysia as
|
|
13847
|
+
import { Elysia as Elysia17 } from "elysia";
|
|
13558
13848
|
var readRecordBody = (body) => {
|
|
13559
13849
|
if (!body || typeof body !== "object") {
|
|
13560
13850
|
throw new Error("Voice ops action audit requires a JSON body.");
|
|
@@ -13629,7 +13919,7 @@ var createVoiceOpsActionAuditRoutes = (options) => {
|
|
|
13629
13919
|
const path = options.path ?? "/api/voice/ops-actions/audit";
|
|
13630
13920
|
const historyPath = options.historyPath === undefined ? "/api/voice/ops-actions/history" : options.historyPath;
|
|
13631
13921
|
const historyHtmlPath = options.historyHtmlPath === undefined ? "/voice/ops-actions" : options.historyHtmlPath;
|
|
13632
|
-
const routes = new
|
|
13922
|
+
const routes = new Elysia17({
|
|
13633
13923
|
name: options.name ?? "absolutejs-voice-ops-action-audit"
|
|
13634
13924
|
}).post(path, async ({ body, request, set }) => {
|
|
13635
13925
|
try {
|
|
@@ -13679,13 +13969,13 @@ var buildVoiceOpsActionHistoryReport = async (options) => {
|
|
|
13679
13969
|
total: entries.length
|
|
13680
13970
|
};
|
|
13681
13971
|
};
|
|
13682
|
-
var
|
|
13972
|
+
var escapeHtml20 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13683
13973
|
var renderVoiceOpsActionHistoryHTML = (report) => {
|
|
13684
|
-
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${
|
|
13974
|
+
const rows = report.entries.map((entry) => `<article class="${entry.ok ? "ok" : "fail"}"><span>${escapeHtml20(entry.ok ? "success" : "error")}</span><strong>${escapeHtml20(entry.actionId)}</strong><p>${escapeHtml20(new Date(entry.at).toLocaleString())}${entry.status ? ` \xB7 HTTP ${String(entry.status)}` : ""}</p>${entry.error ? `<p>${escapeHtml20(entry.error)}</p>` : ""}</article>`).join("");
|
|
13685
13975
|
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>`;
|
|
13686
13976
|
};
|
|
13687
13977
|
// src/platformCoverage.ts
|
|
13688
|
-
import { Elysia as
|
|
13978
|
+
import { Elysia as Elysia18 } from "elysia";
|
|
13689
13979
|
var buildVoicePlatformCoverageSummary = (input) => {
|
|
13690
13980
|
const coverage = input.coverage ?? [];
|
|
13691
13981
|
const ok = input.ok ?? (coverage.length > 0 && coverage.every((surface) => surface.status === "pass"));
|
|
@@ -13746,7 +14036,7 @@ var assertVoicePlatformCoverage = (summary, input = {}) => {
|
|
|
13746
14036
|
var normalizeCoverageSummary = (value) => ("status" in value) && ("total" in value) && ("coverage" in value) ? value : buildVoicePlatformCoverageSummary(value);
|
|
13747
14037
|
var createVoicePlatformCoverageRoutes = (options) => {
|
|
13748
14038
|
const path = options.path ?? "/api/voice/platform-coverage";
|
|
13749
|
-
const routes = new
|
|
14039
|
+
const routes = new Elysia18({
|
|
13750
14040
|
name: options.name ?? "absolutejs-voice-platform-coverage"
|
|
13751
14041
|
});
|
|
13752
14042
|
routes.get(path, async () => {
|
|
@@ -13758,8 +14048,8 @@ var createVoicePlatformCoverageRoutes = (options) => {
|
|
|
13758
14048
|
return routes;
|
|
13759
14049
|
};
|
|
13760
14050
|
// src/competitiveCoverage.ts
|
|
13761
|
-
import { Elysia as
|
|
13762
|
-
var
|
|
14051
|
+
import { Elysia as Elysia19 } from "elysia";
|
|
14052
|
+
var escapeHtml21 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13763
14053
|
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
13764
14054
|
var resolveSurfaceStatus = (surface) => {
|
|
13765
14055
|
if (surface.status)
|
|
@@ -13927,24 +14217,24 @@ var renderVoiceCompetitiveCoverageMarkdown = (report, title = "Voice Competitive
|
|
|
13927
14217
|
`);
|
|
13928
14218
|
var renderVoiceCompetitiveCoverageHTML = (report, title = "Voice Competitive Coverage") => {
|
|
13929
14219
|
const surfaceCards = report.surfaces.map((surface) => {
|
|
13930
|
-
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${
|
|
13931
|
-
return `<article class="surface ${
|
|
13932
|
-
<header><div><p class="eyebrow">${
|
|
13933
|
-
<p>${
|
|
14220
|
+
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${escapeHtml21(item.name)}</strong>${item.kind ? ` <span>${escapeHtml21(item.kind)}</span>` : ""}${item.status ? ` <em>${escapeHtml21(item.status)}</em>` : ""}${item.href ? ` <a href="${escapeHtml21(item.href)}">open</a>` : ""}</li>`).join("");
|
|
14221
|
+
return `<article class="surface ${escapeHtml21(surface.status)} ${escapeHtml21(surface.depth)}">
|
|
14222
|
+
<header><div><p class="eyebrow">${escapeHtml21(surface.coverage)} \xB7 ${escapeHtml21(surface.depth)}</p><h2>${escapeHtml21(surface.surface)}</h2></div><strong>${escapeHtml21(surface.status)}</strong></header>
|
|
14223
|
+
<p>${escapeHtml21(surface.why)}</p>
|
|
13934
14224
|
<dl>
|
|
13935
|
-
<div><dt>Competitors</dt><dd>${
|
|
13936
|
-
<div><dt>Operations record</dt><dd>${
|
|
13937
|
-
<div><dt>Readiness gate</dt><dd>${
|
|
13938
|
-
<div><dt>Frameworks</dt><dd>${
|
|
14225
|
+
<div><dt>Competitors</dt><dd>${escapeHtml21((surface.competitors ?? []).join(", ") || "n/a")}</dd></div>
|
|
14226
|
+
<div><dt>Operations record</dt><dd>${escapeHtml21(surface.operationsRecord ?? "unknown")}</dd></div>
|
|
14227
|
+
<div><dt>Readiness gate</dt><dd>${escapeHtml21(surface.readinessGate ?? "unknown")}</dd></div>
|
|
14228
|
+
<div><dt>Frameworks</dt><dd>${escapeHtml21((surface.frameworkPrimitives ?? []).join(", ") || "n/a")}</dd></div>
|
|
13939
14229
|
</dl>
|
|
13940
|
-
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${
|
|
13941
|
-
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${
|
|
14230
|
+
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${escapeHtml21(surface.remainingGap)}</p>` : ""}
|
|
14231
|
+
${surface.nextMove ? `<p class="next"><strong>Next:</strong> ${escapeHtml21(surface.nextMove)}</p>` : ""}
|
|
13942
14232
|
${evidence ? `<h3>Evidence</h3><ul>${evidence}</ul>` : '<p class="muted">No evidence links configured.</p>'}
|
|
13943
14233
|
</article>`;
|
|
13944
14234
|
}).join(`
|
|
13945
14235
|
`);
|
|
13946
|
-
const issueList = report.issues.map((issue) => `<li class="${
|
|
13947
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
14236
|
+
const issueList = report.issues.map((issue) => `<li class="${escapeHtml21(issue.severity)}"><strong>${escapeHtml21(issue.code)}</strong>${issue.surface ? ` ${escapeHtml21(issue.surface)}` : ""}: ${escapeHtml21(issue.message)}</li>`).join("");
|
|
14237
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml21(title)}</title><style>body{background:#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>${escapeHtml21(title)}</h1><p>Generated ${escapeHtml21(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 ${escapeHtml21(report.status)}</span><span class="pill">Vapi-style ${escapeHtml21(report.vapiCoverageEstimate)}</span><span class="pill">Market ${escapeHtml21(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>`;
|
|
13948
14238
|
};
|
|
13949
14239
|
var normalizeCompetitiveCoverageReport = (value) => ("status" in value) && ("summary" in value) && ("issues" in value) ? value : buildVoiceCompetitiveCoverageReport(value);
|
|
13950
14240
|
var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
@@ -13957,7 +14247,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
13957
14247
|
const value = typeof options.source === "function" ? await options.source() : options.source;
|
|
13958
14248
|
return normalizeCompetitiveCoverageReport(value);
|
|
13959
14249
|
};
|
|
13960
|
-
const app = new
|
|
14250
|
+
const app = new Elysia19({
|
|
13961
14251
|
name: options.name ?? "absolutejs-voice-competitive-coverage"
|
|
13962
14252
|
}).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
13963
14253
|
headers: {
|
|
@@ -13988,7 +14278,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
13988
14278
|
return app;
|
|
13989
14279
|
};
|
|
13990
14280
|
// src/proofTrends.ts
|
|
13991
|
-
import { Elysia as
|
|
14281
|
+
import { Elysia as Elysia20 } from "elysia";
|
|
13992
14282
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
13993
14283
|
var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
|
|
13994
14284
|
var toTimeMs = (value) => {
|
|
@@ -14139,7 +14429,7 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
14139
14429
|
};
|
|
14140
14430
|
var createVoiceProofTrendRoutes = (options) => {
|
|
14141
14431
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
14142
|
-
const routes = new
|
|
14432
|
+
const routes = new Elysia20({
|
|
14143
14433
|
name: options.name ?? "absolutejs-voice-proof-trends"
|
|
14144
14434
|
});
|
|
14145
14435
|
routes.get(path, async () => {
|
|
@@ -14172,11 +14462,11 @@ var formatVoiceProofTrendAge = (ageMs) => {
|
|
|
14172
14462
|
return `${days}d ${hours % 24}h`;
|
|
14173
14463
|
};
|
|
14174
14464
|
// src/providerDecisionTraces.ts
|
|
14175
|
-
import { Elysia as
|
|
14465
|
+
import { Elysia as Elysia22 } from "elysia";
|
|
14176
14466
|
|
|
14177
14467
|
// src/resilienceRoutes.ts
|
|
14178
|
-
import { Elysia as
|
|
14179
|
-
var
|
|
14468
|
+
import { Elysia as Elysia21 } from "elysia";
|
|
14469
|
+
var escapeHtml22 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14180
14470
|
var getString7 = (value) => typeof value === "string" ? value : undefined;
|
|
14181
14471
|
var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
14182
14472
|
var getBoolean2 = (value) => value === true;
|
|
@@ -14324,13 +14614,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
14324
14614
|
};
|
|
14325
14615
|
var renderProviderCards = (title, providers) => {
|
|
14326
14616
|
if (providers.length === 0) {
|
|
14327
|
-
return `<p class="muted">No ${
|
|
14617
|
+
return `<p class="muted">No ${escapeHtml22(title)} provider health yet.</p>`;
|
|
14328
14618
|
}
|
|
14329
14619
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
14330
|
-
<article class="card provider ${
|
|
14620
|
+
<article class="card provider ${escapeHtml22(provider.status)}">
|
|
14331
14621
|
<div class="card-header">
|
|
14332
|
-
<strong>${
|
|
14333
|
-
<span>${
|
|
14622
|
+
<strong>${escapeHtml22(provider.provider)}</strong>
|
|
14623
|
+
<span>${escapeHtml22(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
14334
14624
|
</div>
|
|
14335
14625
|
<dl>
|
|
14336
14626
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -14339,7 +14629,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
14339
14629
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
14340
14630
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
14341
14631
|
</dl>
|
|
14342
|
-
${provider.lastError ? `<p class="muted">${
|
|
14632
|
+
${provider.lastError ? `<p class="muted">${escapeHtml22(provider.lastError)}</p>` : ""}
|
|
14343
14633
|
</article>
|
|
14344
14634
|
`).join("")}</div>`;
|
|
14345
14635
|
};
|
|
@@ -14348,24 +14638,24 @@ var renderTimeline2 = (events) => {
|
|
|
14348
14638
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
14349
14639
|
}
|
|
14350
14640
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
14351
|
-
<article class="card event ${
|
|
14641
|
+
<article class="card event ${escapeHtml22(event.status ?? "unknown")}">
|
|
14352
14642
|
<div class="card-header">
|
|
14353
|
-
<strong>${
|
|
14643
|
+
<strong>${escapeHtml22(event.kind.toUpperCase())} ${escapeHtml22(event.operation ?? "generate")}</strong>
|
|
14354
14644
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
14355
14645
|
</div>
|
|
14356
14646
|
<p>
|
|
14357
|
-
<span class="pill">${
|
|
14358
|
-
<span class="pill">provider: ${
|
|
14359
|
-
${event.fallbackProvider ? `<span class="pill">fallback: ${
|
|
14647
|
+
<span class="pill">${escapeHtml22(event.status ?? "unknown")}</span>
|
|
14648
|
+
<span class="pill">provider: ${escapeHtml22(event.provider ?? "unknown")}</span>
|
|
14649
|
+
${event.fallbackProvider ? `<span class="pill">fallback: ${escapeHtml22(event.fallbackProvider)}</span>` : ""}
|
|
14360
14650
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
14361
14651
|
</p>
|
|
14362
14652
|
<dl>
|
|
14363
14653
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
14364
14654
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
14365
14655
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
14366
|
-
<div><dt>Session</dt><dd>${
|
|
14656
|
+
<div><dt>Session</dt><dd>${escapeHtml22(event.sessionId)}</dd></div>
|
|
14367
14657
|
</dl>
|
|
14368
|
-
${event.error ? `<p class="muted">${
|
|
14658
|
+
${event.error ? `<p class="muted">${escapeHtml22(event.error)}</p>` : ""}
|
|
14369
14659
|
</article>
|
|
14370
14660
|
`).join("")}</div>`;
|
|
14371
14661
|
};
|
|
@@ -14375,9 +14665,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
14375
14665
|
const status = latest?.status ?? "idle";
|
|
14376
14666
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
14377
14667
|
return `<div>
|
|
14378
|
-
<dt>${
|
|
14379
|
-
<dd>${
|
|
14380
|
-
<small>${
|
|
14668
|
+
<dt>${escapeHtml22(kind.toUpperCase())}</dt>
|
|
14669
|
+
<dd>${escapeHtml22(provider)}${escapeHtml22(fallback)}</dd>
|
|
14670
|
+
<small>${escapeHtml22(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>
|
|
14381
14671
|
</div>`;
|
|
14382
14672
|
};
|
|
14383
14673
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -14385,10 +14675,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
14385
14675
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
14386
14676
|
}
|
|
14387
14677
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
14388
|
-
<article class="card session ${
|
|
14678
|
+
<article class="card session ${escapeHtml22(session.status)}">
|
|
14389
14679
|
<div class="card-header">
|
|
14390
|
-
<strong>${
|
|
14391
|
-
<span>${
|
|
14680
|
+
<strong>${escapeHtml22(session.sessionId)}</strong>
|
|
14681
|
+
<span>${escapeHtml22(session.status)}</span>
|
|
14392
14682
|
</div>
|
|
14393
14683
|
<p>
|
|
14394
14684
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -14415,21 +14705,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
14415
14705
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
14416
14706
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
14417
14707
|
const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
|
|
14418
|
-
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${
|
|
14419
|
-
<p class="muted">${
|
|
14708
|
+
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${escapeHtml22(pathPrefix)}">
|
|
14709
|
+
<p class="muted">${escapeHtml22(simulation.failureMessage ?? `Simulate ${kind.toUpperCase()} provider failure without changing provider credentials.`)}</p>
|
|
14420
14710
|
<div class="simulate-actions">
|
|
14421
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
14422
|
-
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${
|
|
14711
|
+
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${escapeHtml22(provider)}"${canFail(provider) ? "" : " disabled"}>Simulate ${escapeHtml22(provider)} ${kind.toUpperCase()} failure</button>`).join("")}
|
|
14712
|
+
${configuredProviders.map((provider) => `<button type="button" data-provider-recover="${escapeHtml22(provider.provider)}">Mark ${escapeHtml22(provider.provider)} recovered</button>`).join("")}
|
|
14423
14713
|
</div>
|
|
14424
|
-
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${
|
|
14714
|
+
${simulation.fallbackRequiredProvider && !configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider) ? `<p class="muted">${escapeHtml22(simulation.fallbackRequiredMessage ?? `Configure ${simulation.fallbackRequiredProvider} to enable fallback simulation.`)}</p>` : ""}
|
|
14425
14715
|
<pre class="simulate-output" hidden></pre>
|
|
14426
14716
|
</div>`;
|
|
14427
14717
|
};
|
|
14428
14718
|
var renderVoiceResilienceHTML = (input) => {
|
|
14429
14719
|
const summary = summarizeRoutingEvents(input.routingEvents);
|
|
14430
|
-
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${
|
|
14431
|
-
const links = input.links?.length ? input.links.map((link) => `<a href="${
|
|
14432
|
-
const snippet =
|
|
14720
|
+
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${escapeHtml22(kind)}: ${String(count)}</span>`).join("");
|
|
14721
|
+
const links = input.links?.length ? input.links.map((link) => `<a href="${escapeHtml22(link.href)}">${escapeHtml22(link.label)}</a>`).join(" \xB7 ") : "";
|
|
14722
|
+
const snippet = escapeHtml22(`const sttSimulator = createVoiceIOProviderFailureSimulator({
|
|
14433
14723
|
kind: 'stt',
|
|
14434
14724
|
providers: ['deepgram', 'assemblyai'],
|
|
14435
14725
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -14467,7 +14757,7 @@ app.use(
|
|
|
14467
14757
|
<head>
|
|
14468
14758
|
<meta charset="utf-8" />
|
|
14469
14759
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
14470
|
-
<title>${
|
|
14760
|
+
<title>${escapeHtml22(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
14471
14761
|
<style>
|
|
14472
14762
|
:root { color-scheme: dark; }
|
|
14473
14763
|
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; }
|
|
@@ -14619,7 +14909,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
|
|
|
14619
14909
|
};
|
|
14620
14910
|
var createVoiceResilienceRoutes = (options) => {
|
|
14621
14911
|
const path = options.path ?? "/resilience";
|
|
14622
|
-
const routes = new
|
|
14912
|
+
const routes = new Elysia21({
|
|
14623
14913
|
name: options.name ?? "absolutejs-voice-resilience"
|
|
14624
14914
|
}).get(path, async () => {
|
|
14625
14915
|
const events = await options.store.list();
|
|
@@ -14660,7 +14950,7 @@ var createVoiceResilienceRoutes = (options) => {
|
|
|
14660
14950
|
};
|
|
14661
14951
|
|
|
14662
14952
|
// src/providerDecisionTraces.ts
|
|
14663
|
-
var
|
|
14953
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14664
14954
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
14665
14955
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
14666
14956
|
var isDecisionTrace = (event) => Boolean(event && typeof event === "object" && "provider" in event && "reason" in event && "sessionId" in event && "status" in event && "surface" in event);
|
|
@@ -14901,7 +15191,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
14901
15191
|
<head>
|
|
14902
15192
|
<meta charset="utf-8" />
|
|
14903
15193
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
14904
|
-
<title>${
|
|
15194
|
+
<title>${escapeHtml23(title)}</title>
|
|
14905
15195
|
<style>
|
|
14906
15196
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
14907
15197
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -14915,8 +15205,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
14915
15205
|
</head>
|
|
14916
15206
|
<body>
|
|
14917
15207
|
<main>
|
|
14918
|
-
<p class="status ${report.status}">${
|
|
14919
|
-
<h1>${
|
|
15208
|
+
<p class="status ${report.status}">${escapeHtml23(report.status)}</p>
|
|
15209
|
+
<h1>${escapeHtml23(title)}</h1>
|
|
14920
15210
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
14921
15211
|
<section class="grid">
|
|
14922
15212
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -14927,10 +15217,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
14927
15217
|
</section>
|
|
14928
15218
|
<section class="surfaces">
|
|
14929
15219
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
14930
|
-
<header><strong>${
|
|
15220
|
+
<header><strong>${escapeHtml23(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml23(surface.status)}</span></header>
|
|
14931
15221
|
<p>${String(surface.decisions)} decision(s), ${String(surface.fallbacks)} fallback(s), ${String(surface.degraded)} degraded decision(s), ${String(surface.errors)} error(s).</p>
|
|
14932
|
-
<p class="muted">Providers: ${
|
|
14933
|
-
<p>${surface.reasons.map((reason) => `<code>${
|
|
15222
|
+
<p class="muted">Providers: ${escapeHtml23(surface.providers.join(", ") || "none")}</p>
|
|
15223
|
+
<p>${surface.reasons.map((reason) => `<code>${escapeHtml23(reason)}</code>`).join(" ")}</p>
|
|
14934
15224
|
</article>`).join(`
|
|
14935
15225
|
`)}
|
|
14936
15226
|
</section>
|
|
@@ -14944,7 +15234,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
14944
15234
|
const headers = options.headers ?? {};
|
|
14945
15235
|
const title = options.title ?? "Provider Decision Traces";
|
|
14946
15236
|
const report = () => buildVoiceProviderDecisionTraceReport(options);
|
|
14947
|
-
const app = new
|
|
15237
|
+
const app = new Elysia22({ name: options.name ?? "voice-provider-decisions" }).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
14948
15238
|
headers: {
|
|
14949
15239
|
"content-type": "application/json; charset=utf-8",
|
|
14950
15240
|
...headers
|
|
@@ -14972,7 +15262,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
14972
15262
|
return app;
|
|
14973
15263
|
};
|
|
14974
15264
|
// src/sloCalibration.ts
|
|
14975
|
-
import { Elysia as
|
|
15265
|
+
import { Elysia as Elysia23 } from "elysia";
|
|
14976
15266
|
var DEFAULT_HEADROOM_MULTIPLIER = 1.5;
|
|
14977
15267
|
var DEFAULT_WARN_RATIO = 0.8;
|
|
14978
15268
|
var DEFAULT_MIN_PASSING_RUNS = 3;
|
|
@@ -15152,7 +15442,7 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
15152
15442
|
};
|
|
15153
15443
|
};
|
|
15154
15444
|
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
15155
|
-
var
|
|
15445
|
+
var escapeHtml24 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15156
15446
|
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
15157
15447
|
var readinessThresholdRows = (report) => [
|
|
15158
15448
|
{
|
|
@@ -15243,15 +15533,15 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
15243
15533
|
};
|
|
15244
15534
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
15245
15535
|
const title = options.title ?? "Calibration -> Active Readiness Gate";
|
|
15246
|
-
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${
|
|
15247
|
-
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
15248
|
-
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${
|
|
15249
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
15536
|
+
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${escapeHtml24(row.control)}</td><td>${escapeHtml24(formatMs(row.value))}</td><td>${escapeHtml24(row.usedBy)}</td></tr>`).join("");
|
|
15537
|
+
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml24(issue)}</li>`).join("");
|
|
15538
|
+
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${escapeHtml24(source)}</code></li>`).join("");
|
|
15539
|
+
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:#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>${escapeHtml24(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">${escapeHtml24(report.status)}</span></div><div class="card"><strong>Live evidence max age</strong><br>${escapeHtml24(formatMs(report.liveLatencyMaxAgeMs))}</div><div class="card"><strong>Provider p95 gate</strong><br>${escapeHtml24(formatMs(report.providerSlo.llm?.maxP95ElapsedMs))}</div><div class="card"><strong>Barge-in gate</strong><br>${escapeHtml24(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>`;
|
|
15250
15540
|
};
|
|
15251
15541
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
15252
15542
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
15253
15543
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-calibration.md" : options.markdownPath;
|
|
15254
|
-
const routes = new
|
|
15544
|
+
const routes = new Elysia23({
|
|
15255
15545
|
name: options.name ?? "absolutejs-voice-slo-calibration"
|
|
15256
15546
|
});
|
|
15257
15547
|
const loadReport = async () => buildVoiceSloCalibrationReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -15275,7 +15565,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
15275
15565
|
const path = options.path ?? "/api/voice/slo-readiness-thresholds";
|
|
15276
15566
|
const htmlPath = options.htmlPath === undefined ? "/voice/slo-readiness-thresholds" : options.htmlPath;
|
|
15277
15567
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-readiness-thresholds.md" : options.markdownPath;
|
|
15278
|
-
const routes = new
|
|
15568
|
+
const routes = new Elysia23({
|
|
15279
15569
|
name: options.name ?? "absolutejs-voice-slo-readiness-thresholds"
|
|
15280
15570
|
});
|
|
15281
15571
|
const loadReport = async () => buildVoiceSloReadinessThresholdReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -15309,7 +15599,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
15309
15599
|
return routes;
|
|
15310
15600
|
};
|
|
15311
15601
|
// src/liveOps.ts
|
|
15312
|
-
import { Elysia as
|
|
15602
|
+
import { Elysia as Elysia24 } from "elysia";
|
|
15313
15603
|
var VOICE_LIVE_OPS_ACTIONS = [
|
|
15314
15604
|
"assign",
|
|
15315
15605
|
"create-task",
|
|
@@ -15619,7 +15909,7 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
15619
15909
|
const controller = createVoiceLiveOpsController(options);
|
|
15620
15910
|
const path = options.path ?? "/api/voice/live-ops/action";
|
|
15621
15911
|
const controlPath = options.controlPath ?? "/api/voice/live-ops/control/:sessionId";
|
|
15622
|
-
return new
|
|
15912
|
+
return new Elysia24({
|
|
15623
15913
|
name: options.name ?? "absolutejs-voice-live-ops"
|
|
15624
15914
|
}).post(path, async ({ request, set }) => {
|
|
15625
15915
|
try {
|
|
@@ -15641,15 +15931,15 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
15641
15931
|
});
|
|
15642
15932
|
};
|
|
15643
15933
|
// src/deliveryRuntime.ts
|
|
15644
|
-
import { Elysia as
|
|
15934
|
+
import { Elysia as Elysia25 } from "elysia";
|
|
15645
15935
|
import { mkdir } from "fs/promises";
|
|
15646
15936
|
import { dirname, join } from "path";
|
|
15647
|
-
var
|
|
15937
|
+
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15648
15938
|
var renderSummaryCard = (label, summary) => {
|
|
15649
15939
|
if (!summary) {
|
|
15650
|
-
return `<article><span>${
|
|
15940
|
+
return `<article><span>${escapeHtml25(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
15651
15941
|
}
|
|
15652
|
-
return `<article><span>${
|
|
15942
|
+
return `<article><span>${escapeHtml25(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>`;
|
|
15653
15943
|
};
|
|
15654
15944
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
15655
15945
|
audit: leases,
|
|
@@ -15860,9 +16150,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
15860
16150
|
});
|
|
15861
16151
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
15862
16152
|
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
15863
|
-
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${
|
|
15864
|
-
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${
|
|
15865
|
-
const snippet =
|
|
16153
|
+
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml25(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
|
|
16154
|
+
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml25(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
|
|
16155
|
+
const snippet = escapeHtml25(`const deliveryRuntime = createVoiceDeliveryRuntime(
|
|
15866
16156
|
createVoiceDeliveryRuntimePresetConfig({
|
|
15867
16157
|
audit: {
|
|
15868
16158
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -15888,14 +16178,14 @@ app.use(
|
|
|
15888
16178
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
15889
16179
|
})
|
|
15890
16180
|
);`);
|
|
15891
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
16181
|
+
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:#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>${escapeHtml25(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 ${escapeHtml25(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>`;
|
|
15892
16182
|
};
|
|
15893
16183
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
15894
16184
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
15895
16185
|
const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
|
|
15896
16186
|
const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
|
|
15897
16187
|
const requeueDeadLettersPath = options.requeueDeadLettersPath === undefined ? "/api/voice-delivery-runtime/requeue-dead-letters" : options.requeueDeadLettersPath;
|
|
15898
|
-
const routes = new
|
|
16188
|
+
const routes = new Elysia25({
|
|
15899
16189
|
name: options.name ?? "absolutejs-voice-delivery-runtime"
|
|
15900
16190
|
}).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
|
|
15901
16191
|
if (tickPath !== false) {
|
|
@@ -15931,7 +16221,7 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
15931
16221
|
return routes;
|
|
15932
16222
|
};
|
|
15933
16223
|
// src/dataControl.ts
|
|
15934
|
-
import { Elysia as
|
|
16224
|
+
import { Elysia as Elysia26 } from "elysia";
|
|
15935
16225
|
var voiceComplianceRedactionDefaults = {
|
|
15936
16226
|
keys: [
|
|
15937
16227
|
"apiKey",
|
|
@@ -16170,7 +16460,7 @@ var parseRetentionScopes = (value) => {
|
|
|
16170
16460
|
const allowed = new Set(allRetentionScopes);
|
|
16171
16461
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
16172
16462
|
};
|
|
16173
|
-
var
|
|
16463
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16174
16464
|
var buildStorageSurfaces = (options) => [
|
|
16175
16465
|
{
|
|
16176
16466
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -16407,12 +16697,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
16407
16697
|
zeroRetentionAvailable: true
|
|
16408
16698
|
};
|
|
16409
16699
|
};
|
|
16410
|
-
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${
|
|
16700
|
+
var renderDataRetentionReportRows = (report) => report.scopes.map((scope) => `<tr><td>${escapeHtml26(scope.scope)}</td><td>${scope.scannedCount}</td><td>${scope.deletedCount}</td><td>${escapeHtml26(scope.skippedReason ?? "")}</td><td><code>${escapeHtml26(scope.deletedIds.join(", "))}</code></td></tr>`).join("");
|
|
16411
16701
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
16412
16702
|
const title = options.title ?? "Voice Data Control";
|
|
16413
|
-
const storageRows = report.storage.map((surface) => `<tr><td>${
|
|
16414
|
-
const keyRows = report.providerKeys.map((key) => `<tr><td>${
|
|
16415
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${
|
|
16703
|
+
const storageRows = report.storage.map((surface) => `<tr><td>${escapeHtml26(surface.name)}</td><td>${surface.configured ? "Configured" : "Missing"}</td><td>${escapeHtml26(surface.control)}</td><td>${surface.selfHosted ? "Yes" : "No"}</td></tr>`).join("");
|
|
16704
|
+
const keyRows = report.providerKeys.map((key) => `<tr><td>${escapeHtml26(key.name)}</td><td><code>${escapeHtml26(key.env ?? "n/a")}</code></td><td>${key.required ? "Required" : "Optional"}</td><td>${escapeHtml26(key.recommendation)}</td></tr>`).join("");
|
|
16705
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml26(title)}</title><style>body{background:#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>${escapeHtml26(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>`;
|
|
16416
16706
|
};
|
|
16417
16707
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
16418
16708
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -16470,7 +16760,7 @@ var parseRetentionPolicyBody = (body, options, dryRun) => {
|
|
|
16470
16760
|
var createVoiceDataControlRoutes = (options) => {
|
|
16471
16761
|
const path = options.path ?? "/data-control";
|
|
16472
16762
|
const title = options.title ?? "AbsoluteJS Voice Data Control";
|
|
16473
|
-
const routes = new
|
|
16763
|
+
const routes = new Elysia26({
|
|
16474
16764
|
name: options.name ?? "absolutejs-voice-data-control"
|
|
16475
16765
|
});
|
|
16476
16766
|
routes.get(path, async ({ query }) => {
|
|
@@ -16546,16 +16836,16 @@ var createVoiceDataControlRoutes = (options) => {
|
|
|
16546
16836
|
return routes;
|
|
16547
16837
|
};
|
|
16548
16838
|
// src/evalRoutes.ts
|
|
16549
|
-
import { Elysia as
|
|
16839
|
+
import { Elysia as Elysia29 } from "elysia";
|
|
16550
16840
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
16551
16841
|
import { dirname as dirname2 } from "path";
|
|
16552
16842
|
|
|
16553
16843
|
// src/qualityRoutes.ts
|
|
16554
|
-
import { Elysia as
|
|
16844
|
+
import { Elysia as Elysia28 } from "elysia";
|
|
16555
16845
|
|
|
16556
16846
|
// src/handoffHealth.ts
|
|
16557
|
-
import { Elysia as
|
|
16558
|
-
var
|
|
16847
|
+
import { Elysia as Elysia27 } from "elysia";
|
|
16848
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16559
16849
|
var getString9 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
16560
16850
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
16561
16851
|
var increment3 = (record, key) => {
|
|
@@ -16673,10 +16963,10 @@ var renderActionSummary = (summary) => {
|
|
|
16673
16963
|
return [
|
|
16674
16964
|
'<section class="voice-handoff-health-columns">',
|
|
16675
16965
|
"<article><h3>Actions</h3>",
|
|
16676
|
-
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${
|
|
16966
|
+
actions.length === 0 ? "<p>No handoff actions yet.</p>" : `<ul>${actions.map(([action, count]) => `<li>${escapeHtml27(action)}: ${String(count)}</li>`).join("")}</ul>`,
|
|
16677
16967
|
"</article>",
|
|
16678
16968
|
"<article><h3>Adapters</h3>",
|
|
16679
|
-
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${
|
|
16969
|
+
adapters.length === 0 ? "<p>No adapter deliveries yet.</p>" : `<ul>${adapters.map(([adapterId, counts]) => `<li>${escapeHtml27(adapterId)}: ${String(counts.delivered)} delivered / ${String(counts.failed)} failed / ${String(counts.skipped)} skipped</li>`).join("")}</ul>`,
|
|
16680
16970
|
"</article>",
|
|
16681
16971
|
"</section>"
|
|
16682
16972
|
].join("");
|
|
@@ -16690,22 +16980,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
16690
16980
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
16691
16981
|
'<div class="voice-handoff-health-events">',
|
|
16692
16982
|
...summary.events.map((event) => [
|
|
16693
|
-
`<article class="${
|
|
16983
|
+
`<article class="${escapeHtml27(event.status)}">`,
|
|
16694
16984
|
'<div class="voice-handoff-health-event-header">',
|
|
16695
|
-
`<strong>${
|
|
16696
|
-
`<span>${
|
|
16985
|
+
`<strong>${escapeHtml27(event.action ?? "handoff")}</strong>`,
|
|
16986
|
+
`<span>${escapeHtml27(event.status)}</span>`,
|
|
16697
16987
|
"</div>",
|
|
16698
|
-
`<p><small>${
|
|
16699
|
-
event.target ? `<p>Target: ${
|
|
16700
|
-
event.reason ? `<p>Reason: ${
|
|
16988
|
+
`<p><small>${escapeHtml27(event.sessionId)}</small></p>`,
|
|
16989
|
+
event.target ? `<p>Target: ${escapeHtml27(event.target)}</p>` : "",
|
|
16990
|
+
event.reason ? `<p>Reason: ${escapeHtml27(event.reason)}</p>` : "",
|
|
16701
16991
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
16702
16992
|
"<li>",
|
|
16703
|
-
`${
|
|
16704
|
-
delivery.deliveredTo ? ` to ${
|
|
16705
|
-
delivery.error ? ` (${
|
|
16993
|
+
`${escapeHtml27(delivery.adapterId)}: ${escapeHtml27(delivery.status)}`,
|
|
16994
|
+
delivery.deliveredTo ? ` to ${escapeHtml27(delivery.deliveredTo)}` : "",
|
|
16995
|
+
delivery.error ? ` (${escapeHtml27(delivery.error)})` : "",
|
|
16706
16996
|
"</li>"
|
|
16707
16997
|
].join("")).join("")}</ul>` : "",
|
|
16708
|
-
event.replayHref ? `<p><a href="${
|
|
16998
|
+
event.replayHref ? `<p><a href="${escapeHtml27(event.replayHref)}">Open replay</a></p>` : "",
|
|
16709
16999
|
"</article>"
|
|
16710
17000
|
].join("")),
|
|
16711
17001
|
"</div>"
|
|
@@ -16737,7 +17027,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
|
|
|
16737
17027
|
var createVoiceHandoffHealthRoutes = (options = {}) => {
|
|
16738
17028
|
const path = options.path ?? "/api/voice-handoffs";
|
|
16739
17029
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
16740
|
-
const routes = new
|
|
17030
|
+
const routes = new Elysia27({
|
|
16741
17031
|
name: options.name ?? "absolutejs-voice-handoff-health"
|
|
16742
17032
|
}).get(path, createVoiceHandoffHealthJSONHandler(options));
|
|
16743
17033
|
if (htmlPath) {
|
|
@@ -16858,17 +17148,17 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
16858
17148
|
thresholds
|
|
16859
17149
|
};
|
|
16860
17150
|
};
|
|
16861
|
-
var
|
|
17151
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16862
17152
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
16863
17153
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
16864
17154
|
var renderVoiceQualityHTML = (report, options = {}) => {
|
|
16865
|
-
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${
|
|
16866
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17155
|
+
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${escapeHtml28(metric.label)}</td><td>${escapeHtml28(formatMetricValue(metric))}</td><td>${escapeHtml28(formatThreshold(metric))}</td><td>${metric.pass ? "pass" : "fail"}</td><td><code>${escapeHtml28(key)}</code></td></tr>`).join("");
|
|
17156
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml28(link.href)}">${escapeHtml28(link.label)}</a>`).join("")}</nav>` : "";
|
|
16867
17157
|
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>`;
|
|
16868
17158
|
};
|
|
16869
17159
|
var createVoiceQualityRoutes = (options) => {
|
|
16870
17160
|
const path = options.path ?? "/quality";
|
|
16871
|
-
const routes = new
|
|
17161
|
+
const routes = new Elysia28({
|
|
16872
17162
|
name: options.name ?? "absolutejs-voice-quality"
|
|
16873
17163
|
});
|
|
16874
17164
|
const getReport = () => evaluateVoiceQuality({
|
|
@@ -16897,7 +17187,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
16897
17187
|
};
|
|
16898
17188
|
|
|
16899
17189
|
// src/evalRoutes.ts
|
|
16900
|
-
var
|
|
17190
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16901
17191
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
16902
17192
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
16903
17193
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -17219,7 +17509,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
17219
17509
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
17220
17510
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
17221
17511
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
17222
|
-
const snippet =
|
|
17512
|
+
const snippet = escapeHtml29(`app.use(
|
|
17223
17513
|
createVoiceEvalRoutes({
|
|
17224
17514
|
path: '/evals',
|
|
17225
17515
|
store: traceStore,
|
|
@@ -17240,48 +17530,48 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
17240
17530
|
};
|
|
17241
17531
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
17242
17532
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
17243
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17244
|
-
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${
|
|
17533
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml29(link.href)}">${escapeHtml29(link.label)}</a>`).join("")}</nav>` : "";
|
|
17534
|
+
const trend = report.trend.length ? report.trend.map((bucket) => `<tr><td>${escapeHtml29(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>';
|
|
17245
17535
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
17246
17536
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
17247
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
17248
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
17537
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml29(session.operationsRecordHref)}">${escapeHtml29(session.sessionId)}</a>` : escapeHtml29(session.sessionId);
|
|
17538
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml29(session.status)}</td><td>${session.eventCount}</td><td>${session.summary.turnCount}</td><td>${session.summary.errorCount}</td><td>${escapeHtml29(formatTime(session.endedAt))}</td><td>${escapeHtml29(failedMetrics || "none")}</td></tr>`;
|
|
17249
17539
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
17250
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17540
|
+
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{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>${escapeHtml29(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>`;
|
|
17251
17541
|
};
|
|
17252
17542
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
17253
17543
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
17254
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17255
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
17256
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
17257
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
17258
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17544
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml29(link.href)}">${escapeHtml29(link.label)}</a>`).join("")}</nav>` : "";
|
|
17545
|
+
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${escapeHtml29(reason)}</li>`).join("") : "<li>No baseline regressions detected.</li>";
|
|
17546
|
+
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${escapeHtml29(id)}</li>`).join("") : "<li>none</li>";
|
|
17547
|
+
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${escapeHtml29(id)}</li>`).join("") : "<li>none</li>";
|
|
17548
|
+
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{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>${escapeHtml29(title)}</h1><p class="status ${comparison.status}">${comparison.status}</p><div class="grid"><article class="card"><span>Baseline pass rate</span><strong>${escapeHtml29(formatPercent(comparison.baseline.passRate))}</strong></article><article class="card"><span>Current pass rate</span><strong>${escapeHtml29(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>${escapeHtml29(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>`;
|
|
17259
17549
|
};
|
|
17260
17550
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
17261
17551
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
17262
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17552
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml29(link.href)}">${escapeHtml29(link.label)}</a>`).join("")}</nav>` : "";
|
|
17263
17553
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
17264
|
-
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${
|
|
17554
|
+
const scenarioIssues = scenario.issues.length ? `<ul>${scenario.issues.map((issue) => `<li>${escapeHtml29(issue)}</li>`).join("")}</ul>` : "";
|
|
17265
17555
|
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => {
|
|
17266
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
17267
|
-
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${
|
|
17556
|
+
const sessionLabel = session.operationsRecordHref ? `<a href="${escapeHtml29(session.operationsRecordHref)}">${escapeHtml29(session.sessionId)}</a>` : escapeHtml29(session.sessionId);
|
|
17557
|
+
return `<tr class="${session.status}"><td>${sessionLabel}</td><td>${escapeHtml29(session.status)}</td><td>${session.eventCount}</td><td>${escapeHtml29(session.issues.join(", ") || "none")}</td></tr>`;
|
|
17268
17558
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
17269
|
-
return `<section class="scenario ${scenario.status}"><h2>${
|
|
17559
|
+
return `<section class="scenario ${scenario.status}"><h2>${escapeHtml29(scenario.label)}</h2>${scenario.description ? `<p>${escapeHtml29(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>`;
|
|
17270
17560
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
17271
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17561
|
+
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{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>${escapeHtml29(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>`;
|
|
17272
17562
|
};
|
|
17273
17563
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
17274
17564
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
17275
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17565
|
+
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${escapeHtml29(link.href)}">${escapeHtml29(link.label)}</a>`).join("")}</nav>` : "";
|
|
17276
17566
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
17277
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
17278
|
-
return `<section class="${fixture.status}"><h2>${
|
|
17567
|
+
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${escapeHtml29(scenario.label)}</td><td>${escapeHtml29(scenario.status)}</td><td>${scenario.matchedSessions}</td><td>${escapeHtml29([...scenario.issues, ...scenario.sessions.flatMap((session) => session.issues)].join(", ") || "none")}</td></tr>`).join("");
|
|
17568
|
+
return `<section class="${fixture.status}"><h2>${escapeHtml29(fixture.label)}</h2>${fixture.description ? `<p>${escapeHtml29(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>`;
|
|
17279
17569
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
17280
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17570
|
+
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{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>${escapeHtml29(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>`;
|
|
17281
17571
|
};
|
|
17282
17572
|
var createVoiceEvalRoutes = (options) => {
|
|
17283
17573
|
const path = options.path ?? "/evals";
|
|
17284
|
-
const routes = new
|
|
17574
|
+
const routes = new Elysia29({
|
|
17285
17575
|
name: options.name ?? "absolutejs-voice-evals"
|
|
17286
17576
|
});
|
|
17287
17577
|
const getReport = () => runVoiceSessionEvals({
|
|
@@ -17418,11 +17708,11 @@ var createVoiceEvalRoutes = (options) => {
|
|
|
17418
17708
|
return routes;
|
|
17419
17709
|
};
|
|
17420
17710
|
// src/simulationSuite.ts
|
|
17421
|
-
import { Elysia as
|
|
17711
|
+
import { Elysia as Elysia32 } from "elysia";
|
|
17422
17712
|
|
|
17423
17713
|
// src/outcomeContract.ts
|
|
17424
|
-
import { Elysia as
|
|
17425
|
-
var
|
|
17714
|
+
import { Elysia as Elysia30 } from "elysia";
|
|
17715
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17426
17716
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
17427
17717
|
if (value === false) {
|
|
17428
17718
|
return;
|
|
@@ -17633,13 +17923,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
17633
17923
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
17634
17924
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
17635
17925
|
const contracts = report.contracts.map((contract) => {
|
|
17636
|
-
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${
|
|
17926
|
+
const sessionLinks = contract.operationsRecordHrefs.length ? `<p>${contract.operationsRecordHrefs.map((href, index) => `<a href="${escapeHtml30(href)}">${escapeHtml30(contract.sessionIds[index] ?? href)}</a>`).join(" \xB7 ")}</p>` : "";
|
|
17637
17927
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
17638
17928
|
<div class="contract-header">
|
|
17639
17929
|
<div>
|
|
17640
|
-
<p class="eyebrow">${
|
|
17641
|
-
<h2>${
|
|
17642
|
-
${contract.description ? `<p>${
|
|
17930
|
+
<p class="eyebrow">${escapeHtml30(contract.contractId)}</p>
|
|
17931
|
+
<h2>${escapeHtml30(contract.label ?? contract.contractId)}</h2>
|
|
17932
|
+
${contract.description ? `<p>${escapeHtml30(contract.description)}</p>` : ""}
|
|
17643
17933
|
${sessionLinks}
|
|
17644
17934
|
</div>
|
|
17645
17935
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -17651,10 +17941,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
17651
17941
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
17652
17942
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
17653
17943
|
</div>
|
|
17654
|
-
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${
|
|
17944
|
+
${contract.issues.length ? `<ul>${contract.issues.map((issue) => `<li>${escapeHtml30(issue.message)}</li>`).join("")}</ul>` : ""}
|
|
17655
17945
|
</section>`;
|
|
17656
17946
|
}).join("");
|
|
17657
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
17947
|
+
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,.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>${escapeHtml30(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>`;
|
|
17658
17948
|
};
|
|
17659
17949
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
17660
17950
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -17670,7 +17960,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
|
17670
17960
|
var createVoiceOutcomeContractRoutes = (options) => {
|
|
17671
17961
|
const path = options.path ?? "/api/outcome-contracts";
|
|
17672
17962
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17673
|
-
const routes = new
|
|
17963
|
+
const routes = new Elysia30({
|
|
17674
17964
|
name: options.name ?? "absolutejs-voice-outcome-contracts"
|
|
17675
17965
|
}).get(path, createVoiceOutcomeContractJSONHandler(options));
|
|
17676
17966
|
if (htmlPath) {
|
|
@@ -17680,7 +17970,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
|
|
|
17680
17970
|
};
|
|
17681
17971
|
|
|
17682
17972
|
// src/toolContract.ts
|
|
17683
|
-
import { Elysia as
|
|
17973
|
+
import { Elysia as Elysia31 } from "elysia";
|
|
17684
17974
|
|
|
17685
17975
|
// src/toolRuntime.ts
|
|
17686
17976
|
var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -17889,7 +18179,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
17889
18179
|
});
|
|
17890
18180
|
var defaultApi = {};
|
|
17891
18181
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
17892
|
-
var
|
|
18182
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17893
18183
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
17894
18184
|
if (value === false) {
|
|
17895
18185
|
return;
|
|
@@ -18138,7 +18428,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
18138
18428
|
};
|
|
18139
18429
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
18140
18430
|
const title = options.title ?? "Voice Tool Contracts";
|
|
18141
|
-
const snippet =
|
|
18431
|
+
const snippet = escapeHtml31(`app.use(
|
|
18142
18432
|
createVoiceToolContractRoutes({
|
|
18143
18433
|
htmlPath: '/tool-contracts',
|
|
18144
18434
|
path: '/api/tool-contracts',
|
|
@@ -18164,20 +18454,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
18164
18454
|
);`);
|
|
18165
18455
|
const contracts = report.contracts.map((contract) => {
|
|
18166
18456
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
18167
|
-
<td>${testCase.operationsRecordHref ? `<a href="${
|
|
18457
|
+
<td>${testCase.operationsRecordHref ? `<a href="${escapeHtml31(testCase.operationsRecordHref)}">${escapeHtml31(testCase.label ?? testCase.caseId)}</a>` : escapeHtml31(testCase.label ?? testCase.caseId)}</td>
|
|
18168
18458
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
18169
|
-
<td>${
|
|
18170
|
-
<td>${
|
|
18459
|
+
<td>${escapeHtml31(testCase.status)}</td>
|
|
18460
|
+
<td>${escapeHtml31(testCase.sessionId)}</td>
|
|
18171
18461
|
<td>${String(testCase.attempts)}</td>
|
|
18172
18462
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
18173
18463
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
18174
|
-
<td>${
|
|
18464
|
+
<td>${escapeHtml31(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
18175
18465
|
</tr>`).join("");
|
|
18176
18466
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
18177
18467
|
<div class="contract-header">
|
|
18178
18468
|
<div>
|
|
18179
|
-
<p class="eyebrow">${
|
|
18180
|
-
<h2>${
|
|
18469
|
+
<p class="eyebrow">${escapeHtml31(contract.toolName)}</p>
|
|
18470
|
+
<h2>${escapeHtml31(contract.label ?? contract.contractId)}</h2>
|
|
18181
18471
|
</div>
|
|
18182
18472
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
18183
18473
|
</div>
|
|
@@ -18187,7 +18477,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
18187
18477
|
</table>
|
|
18188
18478
|
</section>`;
|
|
18189
18479
|
}).join("");
|
|
18190
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18480
|
+
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:#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>${escapeHtml31(title)}</h1><div class="summary"><span class="pill ${report.status === "pass" ? "pass" : "fail"}">${escapeHtml31(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>`;
|
|
18191
18481
|
};
|
|
18192
18482
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
18193
18483
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -18204,7 +18494,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
|
18204
18494
|
var createVoiceToolContractRoutes = (options) => {
|
|
18205
18495
|
const path = options.path ?? "/api/tool-contracts";
|
|
18206
18496
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18207
|
-
const routes = new
|
|
18497
|
+
const routes = new Elysia31({
|
|
18208
18498
|
name: options.name ?? "absolutejs-voice-tool-contracts"
|
|
18209
18499
|
}).get(path, createVoiceToolContractJSONHandler(options));
|
|
18210
18500
|
if (htmlPath) {
|
|
@@ -18214,7 +18504,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
18214
18504
|
};
|
|
18215
18505
|
|
|
18216
18506
|
// src/simulationSuite.ts
|
|
18217
|
-
var
|
|
18507
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18218
18508
|
var summarizeSection = (report) => ({
|
|
18219
18509
|
failed: report.failed,
|
|
18220
18510
|
passed: report.passed,
|
|
@@ -18410,15 +18700,15 @@ var renderSection = (label, summary) => {
|
|
|
18410
18700
|
if (!summary) {
|
|
18411
18701
|
return "";
|
|
18412
18702
|
}
|
|
18413
|
-
return `<article class="${
|
|
18703
|
+
return `<article class="${escapeHtml32(summary.status)}"><span>${escapeHtml32(label)}</span><strong>${escapeHtml32(summary.status)}</strong><p>${summary.passed}/${summary.total} passed, ${summary.failed} failed.</p></article>`;
|
|
18414
18704
|
};
|
|
18415
18705
|
var renderAction = (action) => {
|
|
18416
|
-
const content = `<strong>${
|
|
18417
|
-
return action.href ? `<a class="action" href="${
|
|
18706
|
+
const content = `<strong>${escapeHtml32(action.label)}</strong><p>${escapeHtml32(action.description)}</p><span>${escapeHtml32(action.section)} / ${escapeHtml32(action.severity)}</span>`;
|
|
18707
|
+
return action.href ? `<a class="action" href="${escapeHtml32(action.href)}">${content}</a>` : `<article class="action">${content}</article>`;
|
|
18418
18708
|
};
|
|
18419
18709
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
18420
18710
|
const title = options.title ?? "Voice Simulation Suite";
|
|
18421
|
-
const snippet =
|
|
18711
|
+
const snippet = escapeHtml32(`app.use(
|
|
18422
18712
|
createVoiceSimulationSuiteRoutes({
|
|
18423
18713
|
htmlPath: '/voice/simulations',
|
|
18424
18714
|
path: '/api/voice/simulations',
|
|
@@ -18451,12 +18741,12 @@ app.use(
|
|
|
18451
18741
|
store: traceStore
|
|
18452
18742
|
})
|
|
18453
18743
|
);`);
|
|
18454
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
18744
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml32(title)}</title><style>body{background:#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>${escapeHtml32(title)}</h1><p>One report for session quality, scenario evals, fixture simulations, tool contracts, and outcome contracts.</p><p class="badge ${escapeHtml32(report.status)}">Status: ${escapeHtml32(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>${escapeHtml32(JSON.stringify({ summary: report.summary, actions: report.actions }, null, 2))}</pre></main></body></html>`;
|
|
18455
18745
|
};
|
|
18456
18746
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
18457
18747
|
const path = options.path ?? "/api/voice/simulations";
|
|
18458
18748
|
const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
|
|
18459
|
-
const app = new
|
|
18749
|
+
const app = new Elysia32({
|
|
18460
18750
|
name: options.name ?? "absolutejs-voice-simulation-suite"
|
|
18461
18751
|
}).get(path, () => runVoiceSimulationSuite(options));
|
|
18462
18752
|
if (htmlPath) {
|
|
@@ -18768,9 +19058,9 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
18768
19058
|
};
|
|
18769
19059
|
};
|
|
18770
19060
|
// src/sessionReplay.ts
|
|
18771
|
-
import { Elysia as
|
|
19061
|
+
import { Elysia as Elysia33 } from "elysia";
|
|
18772
19062
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
18773
|
-
var
|
|
19063
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18774
19064
|
var increment4 = (record, key) => {
|
|
18775
19065
|
record[key] = (record[key] ?? 0) + 1;
|
|
18776
19066
|
};
|
|
@@ -18964,10 +19254,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
18964
19254
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
18965
19255
|
'<div class="voice-sessions-list">',
|
|
18966
19256
|
...sessions.map((session) => [
|
|
18967
|
-
`<article class="voice-session-card ${
|
|
19257
|
+
`<article class="voice-session-card ${escapeHtml33(session.status)}">`,
|
|
18968
19258
|
'<div class="voice-session-card-header">',
|
|
18969
|
-
`<strong>${
|
|
18970
|
-
`<span>${
|
|
19259
|
+
`<strong>${escapeHtml33(session.sessionId)}</strong>`,
|
|
19260
|
+
`<span>${escapeHtml33(session.status)}</span>`,
|
|
18971
19261
|
"</div>",
|
|
18972
19262
|
"<dl>",
|
|
18973
19263
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -18975,9 +19265,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
18975
19265
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
18976
19266
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
18977
19267
|
"</dl>",
|
|
18978
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
18979
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
18980
|
-
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${
|
|
19268
|
+
session.latestOutcome ? `<p>Outcome: ${escapeHtml33(session.latestOutcome)}</p>` : "",
|
|
19269
|
+
session.providers.length ? `<p>Providers: ${session.providers.map(escapeHtml33).join(", ")}</p>` : "",
|
|
19270
|
+
session.replayHref ? `<p>${session.operationsRecordHref ? `<a href="${escapeHtml33(session.operationsRecordHref)}">Open operations record</a> \xB7 ` : ""}<a href="${escapeHtml33(session.replayHref)}">Open replay</a></p>` : "",
|
|
18981
19271
|
"</article>"
|
|
18982
19272
|
].join("")),
|
|
18983
19273
|
"</div>"
|
|
@@ -19008,7 +19298,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
|
|
|
19008
19298
|
var createVoiceSessionListRoutes = (options = {}) => {
|
|
19009
19299
|
const path = options.path ?? "/api/voice-sessions";
|
|
19010
19300
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
19011
|
-
const routes = new
|
|
19301
|
+
const routes = new Elysia33({
|
|
19012
19302
|
name: options.name ?? "absolutejs-voice-session-list"
|
|
19013
19303
|
}).get(path, createVoiceSessionsJSONHandler(options));
|
|
19014
19304
|
if (htmlPath) {
|
|
@@ -19036,7 +19326,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
|
|
|
19036
19326
|
var createVoiceSessionReplayRoutes = (options) => {
|
|
19037
19327
|
const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
|
|
19038
19328
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
19039
|
-
const routes = new
|
|
19329
|
+
const routes = new Elysia33({
|
|
19040
19330
|
name: options.name ?? "absolutejs-voice-session-replay"
|
|
19041
19331
|
}).get(path, createVoiceSessionReplayJSONHandler(options));
|
|
19042
19332
|
if (htmlPath) {
|
|
@@ -19350,11 +19640,11 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
19350
19640
|
return report;
|
|
19351
19641
|
};
|
|
19352
19642
|
// src/turnLatency.ts
|
|
19353
|
-
import { Elysia as
|
|
19643
|
+
import { Elysia as Elysia34 } from "elysia";
|
|
19354
19644
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
19355
19645
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
19356
|
-
var
|
|
19357
|
-
var
|
|
19646
|
+
var escapeHtml34 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19647
|
+
var firstNumber2 = (values) => values.filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
19358
19648
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
19359
19649
|
var createTraceStageIndex = (events) => {
|
|
19360
19650
|
const index = new Map;
|
|
@@ -19378,8 +19668,8 @@ var createTraceStageIndex = (events) => {
|
|
|
19378
19668
|
};
|
|
19379
19669
|
var summarizeTurn = (sessionId, turn, options) => {
|
|
19380
19670
|
const traceStages = options.stageIndex?.get(`${sessionId}:${turn.id}`);
|
|
19381
|
-
const firstTranscriptAt = traceStages?.get("speech_detected") ??
|
|
19382
|
-
const finalTranscriptAt = traceStages?.get("final_transcript") ??
|
|
19671
|
+
const firstTranscriptAt = traceStages?.get("speech_detected") ?? firstNumber2(turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs));
|
|
19672
|
+
const finalTranscriptAt = traceStages?.get("final_transcript") ?? firstNumber2(turn.transcripts.filter((transcript) => transcript.isFinal).map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs));
|
|
19383
19673
|
const committedAt = traceStages?.get("turn_committed") ?? turn.committedAt;
|
|
19384
19674
|
const assistantTextStartedAt = traceStages?.get("assistant_text_started") ?? (turn.assistantText ? committedAt : undefined);
|
|
19385
19675
|
const ttsSendStartedAt = traceStages?.get("tts_send_started");
|
|
@@ -19485,11 +19775,11 @@ await traceStore.append({
|
|
|
19485
19775
|
turnId,
|
|
19486
19776
|
type: 'turn_latency.stage'
|
|
19487
19777
|
});`;
|
|
19488
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
19489
|
-
<header><div><p class="eyebrow">${
|
|
19490
|
-
<dl>${turn.stages.map((stage) => `<div><dt>${
|
|
19778
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml34(turn.status)}">
|
|
19779
|
+
<header><div><p class="eyebrow">${escapeHtml34(turn.sessionId)} \xB7 ${escapeHtml34(turn.turnId)}</p><h2>${escapeHtml34(turn.text || "Empty turn")}</h2></div><strong>${escapeHtml34(turn.status)}</strong></header>
|
|
19780
|
+
<dl>${turn.stages.map((stage) => `<div><dt>${escapeHtml34(stage.label)}</dt><dd>${escapeHtml34(formatMs2(stage.valueMs))}</dd></div>`).join("")}</dl>
|
|
19491
19781
|
</article>`).join("");
|
|
19492
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
19782
|
+
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:#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>${escapeHtml34(title)}</h1><div class="summary"><span class="pill ${escapeHtml34(report.status)}">${escapeHtml34(report.status)}</span><span class="pill">${String(report.total)} turns</span><span class="pill">avg ${escapeHtml34(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>${escapeHtml34(snippet)}</code></pre></section>${turns || '<section class="turn"><p>No committed turns found.</p></section>'}</main></body></html>`;
|
|
19493
19783
|
};
|
|
19494
19784
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
19495
19785
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -19506,7 +19796,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
19506
19796
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
19507
19797
|
const path = options.path ?? "/api/turn-latency";
|
|
19508
19798
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
19509
|
-
const routes = new
|
|
19799
|
+
const routes = new Elysia34({
|
|
19510
19800
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
19511
19801
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
19512
19802
|
if (htmlPath) {
|
|
@@ -19515,8 +19805,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
19515
19805
|
return routes;
|
|
19516
19806
|
};
|
|
19517
19807
|
// src/liveLatency.ts
|
|
19518
|
-
import { Elysia as
|
|
19519
|
-
var
|
|
19808
|
+
import { Elysia as Elysia35 } from "elysia";
|
|
19809
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19520
19810
|
var percentile3 = (values, percentileValue) => {
|
|
19521
19811
|
if (values.length === 0) {
|
|
19522
19812
|
return;
|
|
@@ -19583,13 +19873,13 @@ await traceStore.append({
|
|
|
19583
19873
|
sessionId,
|
|
19584
19874
|
type: 'client.live_latency'
|
|
19585
19875
|
});`;
|
|
19586
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
19587
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
19876
|
+
const rows = report.recent.map((sample) => `<tr><td>${escapeHtml35(sample.sessionId)}</td><td>${escapeHtml35(formatMs3(sample.latencyMs))}</td><td>${escapeHtml35(sample.status ?? "unknown")}</td><td>${escapeHtml35(new Date(sample.at).toLocaleString())}</td></tr>`).join("");
|
|
19877
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml35(title)}</title><style>body{background:#0c0f14;color:#f6f2e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1060px;padding:32px}.hero{background:linear-gradient(135deg,rgba(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>${escapeHtml35(title)}</h1><p>Recent real browser speech-to-assistant response measurements from persisted <code>client.live_latency</code> traces.</p><p class="status ${escapeHtml35(report.status)}">Status: ${escapeHtml35(report.status)}</p><section class="metrics"><article><span>p50</span><strong>${escapeHtml35(formatMs3(report.p50LatencyMs))}</strong></article><article><span>p95</span><strong>${escapeHtml35(formatMs3(report.p95LatencyMs))}</strong></article><article><span>Average</span><strong>${escapeHtml35(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>${escapeHtml35(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>`;
|
|
19588
19878
|
};
|
|
19589
19879
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
19590
19880
|
const path = options.path ?? "/api/live-latency";
|
|
19591
19881
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
19592
|
-
const routes = new
|
|
19882
|
+
const routes = new Elysia35({
|
|
19593
19883
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
19594
19884
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
19595
19885
|
if (htmlPath) {
|
|
@@ -19908,9 +20198,9 @@ None.
|
|
|
19908
20198
|
`}`;
|
|
19909
20199
|
};
|
|
19910
20200
|
// src/turnQuality.ts
|
|
19911
|
-
import { Elysia as
|
|
20201
|
+
import { Elysia as Elysia36 } from "elysia";
|
|
19912
20202
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
19913
|
-
var
|
|
20203
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19914
20204
|
var getTurnLatencyMs = (turn) => {
|
|
19915
20205
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
19916
20206
|
if (firstTranscriptAt === undefined) {
|
|
@@ -19981,24 +20271,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
19981
20271
|
};
|
|
19982
20272
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
19983
20273
|
const title = options.title ?? "Voice Turn Quality";
|
|
19984
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
20274
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml36(turn.status)}">
|
|
19985
20275
|
<div class="turn-header">
|
|
19986
20276
|
<div>
|
|
19987
|
-
<p class="eyebrow">${
|
|
19988
|
-
<h2>${
|
|
20277
|
+
<p class="eyebrow">${escapeHtml36(turn.sessionId)} \xB7 ${escapeHtml36(turn.turnId)}</p>
|
|
20278
|
+
<h2>${escapeHtml36(turn.text || "Empty turn")}</h2>
|
|
19989
20279
|
</div>
|
|
19990
|
-
<strong>${
|
|
20280
|
+
<strong>${escapeHtml36(turn.status)}</strong>
|
|
19991
20281
|
</div>
|
|
19992
20282
|
<dl>
|
|
19993
|
-
<div><dt>Source</dt><dd>${
|
|
20283
|
+
<div><dt>Source</dt><dd>${escapeHtml36(turn.source ?? "unknown")}</dd></div>
|
|
19994
20284
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
19995
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
19996
|
-
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${
|
|
20285
|
+
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${escapeHtml36(turn.fallbackSelectionReason ?? "selected")})` : "no"}</dd></div>
|
|
20286
|
+
<div><dt>Correction</dt><dd>${turn.correctionChanged ? `changed${turn.correctionProvider ? ` by ${escapeHtml36(turn.correctionProvider)}` : ""}` : "none"}</dd></div>
|
|
19997
20287
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
19998
20288
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
19999
20289
|
</dl>
|
|
20000
20290
|
</article>`).join("");
|
|
20001
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
20291
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml36(title)}</title><style>body{background:#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>${escapeHtml36(title)}</h1><div class="summary"><span class="pill ${escapeHtml36(report.status)}">${escapeHtml36(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>`;
|
|
20002
20292
|
};
|
|
20003
20293
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
20004
20294
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -20015,7 +20305,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
20015
20305
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
20016
20306
|
const path = options.path ?? "/api/turn-quality";
|
|
20017
20307
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
20018
|
-
const routes = new
|
|
20308
|
+
const routes = new Elysia36({
|
|
20019
20309
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
20020
20310
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
20021
20311
|
if (htmlPath) {
|
|
@@ -20024,7 +20314,7 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
20024
20314
|
return routes;
|
|
20025
20315
|
};
|
|
20026
20316
|
// src/telephonyOutcome.ts
|
|
20027
|
-
import { Elysia as
|
|
20317
|
+
import { Elysia as Elysia37 } from "elysia";
|
|
20028
20318
|
var DEFAULT_COMPLETED_STATUSES = [
|
|
20029
20319
|
"answered",
|
|
20030
20320
|
"completed",
|
|
@@ -20195,7 +20485,7 @@ var assertVoiceTelephonyWebhookNormalizationEvidence = (input = {}) => {
|
|
|
20195
20485
|
return assertion;
|
|
20196
20486
|
};
|
|
20197
20487
|
var normalizeToken = (value) => typeof value === "string" ? value.trim().toLowerCase().replace(/\s+/g, "-").replace(/_+/g, "-") : undefined;
|
|
20198
|
-
var
|
|
20488
|
+
var firstString3 = (source, keys) => {
|
|
20199
20489
|
for (const key of keys) {
|
|
20200
20490
|
const value = source[key];
|
|
20201
20491
|
if (typeof value === "string" && value.trim()) {
|
|
@@ -20206,7 +20496,7 @@ var firstString2 = (source, keys) => {
|
|
|
20206
20496
|
}
|
|
20207
20497
|
}
|
|
20208
20498
|
};
|
|
20209
|
-
var
|
|
20499
|
+
var firstNumber3 = (source, keys) => {
|
|
20210
20500
|
for (const key of keys) {
|
|
20211
20501
|
const value = source[key];
|
|
20212
20502
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -20567,8 +20857,8 @@ var verifyVoiceTelephonyWebhook = async (input) => {
|
|
|
20567
20857
|
var durationMsFromSeconds = (value) => typeof value === "number" ? value * 1000 : undefined;
|
|
20568
20858
|
var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
20569
20859
|
const payload = flattenPayload(input.body);
|
|
20570
|
-
const provider =
|
|
20571
|
-
const status =
|
|
20860
|
+
const provider = firstString3(payload, ["provider", "Provider"]) ?? input.provider;
|
|
20861
|
+
const status = firstString3(payload, [
|
|
20572
20862
|
"CallStatus",
|
|
20573
20863
|
"call_status",
|
|
20574
20864
|
"callStatus",
|
|
@@ -20578,7 +20868,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
20578
20868
|
"event_type",
|
|
20579
20869
|
"type"
|
|
20580
20870
|
]);
|
|
20581
|
-
const durationMs =
|
|
20871
|
+
const durationMs = firstNumber3(payload, ["durationMs", "duration_ms"]) ?? durationMsFromSeconds(firstNumber3(payload, [
|
|
20582
20872
|
"CallDuration",
|
|
20583
20873
|
"call_duration",
|
|
20584
20874
|
"callDuration",
|
|
@@ -20586,16 +20876,16 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
20586
20876
|
"dial_call_duration",
|
|
20587
20877
|
"duration"
|
|
20588
20878
|
]));
|
|
20589
|
-
const sipCode =
|
|
20879
|
+
const sipCode = firstNumber3(payload, [
|
|
20590
20880
|
"SipResponseCode",
|
|
20591
20881
|
"sip_response_code",
|
|
20592
20882
|
"sipCode",
|
|
20593
20883
|
"sip_code",
|
|
20594
20884
|
"hangupCauseCode"
|
|
20595
20885
|
]);
|
|
20596
|
-
const from =
|
|
20597
|
-
const to =
|
|
20598
|
-
const target =
|
|
20886
|
+
const from = firstString3(payload, ["From", "from", "caller_id", "callerId"]);
|
|
20887
|
+
const to = firstString3(payload, ["To", "to", "called_number", "calledNumber"]);
|
|
20888
|
+
const target = firstString3(payload, [
|
|
20599
20889
|
"transferTarget",
|
|
20600
20890
|
"TransferTarget",
|
|
20601
20891
|
"target",
|
|
@@ -20603,7 +20893,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
20603
20893
|
"department"
|
|
20604
20894
|
]);
|
|
20605
20895
|
return {
|
|
20606
|
-
answeredBy:
|
|
20896
|
+
answeredBy: firstString3(payload, [
|
|
20607
20897
|
"AnsweredBy",
|
|
20608
20898
|
"answered_by",
|
|
20609
20899
|
"answeredBy",
|
|
@@ -20617,7 +20907,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
20617
20907
|
...payload
|
|
20618
20908
|
},
|
|
20619
20909
|
provider,
|
|
20620
|
-
reason:
|
|
20910
|
+
reason: firstString3(payload, [
|
|
20621
20911
|
"Reason",
|
|
20622
20912
|
"reason",
|
|
20623
20913
|
"HangupCause",
|
|
@@ -20633,7 +20923,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
20633
20923
|
var defaultSessionId = (input) => {
|
|
20634
20924
|
const payload = flattenPayload(input.body);
|
|
20635
20925
|
const metadataSessionId = input.event.metadata?.sessionId;
|
|
20636
|
-
return
|
|
20926
|
+
return firstString3(input.query, ["sessionId", "session_id"]) ?? firstString3(payload, [
|
|
20637
20927
|
"sessionId",
|
|
20638
20928
|
"session_id",
|
|
20639
20929
|
"SessionId",
|
|
@@ -20648,7 +20938,7 @@ var defaultSessionId = (input) => {
|
|
|
20648
20938
|
};
|
|
20649
20939
|
var defaultIdempotencyKey = (input) => {
|
|
20650
20940
|
const payload = flattenPayload(input.body);
|
|
20651
|
-
const eventId =
|
|
20941
|
+
const eventId = firstString3(payload, [
|
|
20652
20942
|
"id",
|
|
20653
20943
|
"event_id",
|
|
20654
20944
|
"eventId",
|
|
@@ -20785,7 +21075,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
|
|
|
20785
21075
|
var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
20786
21076
|
const path = options.path ?? "/api/voice/telephony/webhook";
|
|
20787
21077
|
const handler = createVoiceTelephonyWebhookHandler(options);
|
|
20788
|
-
return new
|
|
21078
|
+
return new Elysia37({
|
|
20789
21079
|
name: options.name ?? "absolutejs-voice-telephony-webhooks"
|
|
20790
21080
|
}).post(path, async ({ query, request }) => {
|
|
20791
21081
|
try {
|
|
@@ -20806,12 +21096,12 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
|
20806
21096
|
});
|
|
20807
21097
|
};
|
|
20808
21098
|
// src/phoneAgent.ts
|
|
20809
|
-
import { Elysia as
|
|
21099
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
20810
21100
|
|
|
20811
21101
|
// src/telephony/plivo.ts
|
|
20812
21102
|
import { Buffer as Buffer5 } from "buffer";
|
|
20813
21103
|
import { Database } from "bun:sqlite";
|
|
20814
|
-
import { Elysia as
|
|
21104
|
+
import { Elysia as Elysia39 } from "elysia";
|
|
20815
21105
|
|
|
20816
21106
|
// src/telephony/contract.ts
|
|
20817
21107
|
var DEFAULT_REQUIREMENTS = [
|
|
@@ -20895,7 +21185,7 @@ var evaluateVoiceTelephonyContract = (input) => {
|
|
|
20895
21185
|
|
|
20896
21186
|
// src/telephony/twilio.ts
|
|
20897
21187
|
import { Buffer as Buffer4 } from "buffer";
|
|
20898
|
-
import { Elysia as
|
|
21188
|
+
import { Elysia as Elysia38 } from "elysia";
|
|
20899
21189
|
var TWILIO_MULAW_SAMPLE_RATE = 8000;
|
|
20900
21190
|
var VOICE_PCM_SAMPLE_RATE = 16000;
|
|
20901
21191
|
var escapeXml2 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
@@ -20925,7 +21215,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
20925
21215
|
return parameters;
|
|
20926
21216
|
};
|
|
20927
21217
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
20928
|
-
var
|
|
21218
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20929
21219
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
20930
21220
|
if (!webhook?.verificationUrl) {
|
|
20931
21221
|
return;
|
|
@@ -20968,23 +21258,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
20968
21258
|
};
|
|
20969
21259
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20970
21260
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
20971
|
-
<h1>${
|
|
21261
|
+
<h1>${escapeHtml37(title)}</h1>
|
|
20972
21262
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
20973
21263
|
<section>
|
|
20974
21264
|
<h2>URLs</h2>
|
|
20975
21265
|
<ul>
|
|
20976
|
-
<li><strong>TwiML:</strong> <code>${
|
|
20977
|
-
<li><strong>Media stream:</strong> <code>${
|
|
20978
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
21266
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml37(status.urls.twiml)}</code></li>
|
|
21267
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml37(status.urls.stream)}</code></li>
|
|
21268
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml37(status.urls.webhook)}</code></li>
|
|
20979
21269
|
</ul>
|
|
20980
21270
|
</section>
|
|
20981
21271
|
<section>
|
|
20982
21272
|
<h2>Signing</h2>
|
|
20983
21273
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
20984
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
21274
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml37(status.signing.verificationUrl)}</code></p>` : ""}
|
|
20985
21275
|
</section>
|
|
20986
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
20987
|
-
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
21276
|
+
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml37(name)}</code></li>`).join("")}</ul></section>` : ""}
|
|
21277
|
+
${status.warnings.length ? `<section><h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml37(warning)}</li>`).join("")}</ul></section>` : ""}
|
|
20988
21278
|
</main>`;
|
|
20989
21279
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
20990
21280
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -20995,20 +21285,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
20995
21285
|
});
|
|
20996
21286
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20997
21287
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
20998
|
-
<h1>${
|
|
21288
|
+
<h1>${escapeHtml37(title)}</h1>
|
|
20999
21289
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21000
21290
|
<section>
|
|
21001
21291
|
<h2>Checks</h2>
|
|
21002
21292
|
<ul>
|
|
21003
|
-
${report.checks.map((check) => `<li><strong>${
|
|
21293
|
+
${report.checks.map((check) => `<li><strong>${escapeHtml37(check.name)}</strong>: ${escapeHtml37(check.status)}${check.message ? ` - ${escapeHtml37(check.message)}` : ""}</li>`).join("")}
|
|
21004
21294
|
</ul>
|
|
21005
21295
|
</section>
|
|
21006
21296
|
<section>
|
|
21007
21297
|
<h2>Observed URLs</h2>
|
|
21008
21298
|
<ul>
|
|
21009
|
-
<li><strong>TwiML:</strong> <code>${
|
|
21010
|
-
<li><strong>Stream:</strong> <code>${
|
|
21011
|
-
<li><strong>Webhook:</strong> <code>${
|
|
21299
|
+
<li><strong>TwiML:</strong> <code>${escapeHtml37(report.setup.urls.twiml)}</code></li>
|
|
21300
|
+
<li><strong>Stream:</strong> <code>${escapeHtml37(report.twiml?.streamUrl ?? report.setup.urls.stream)}</code></li>
|
|
21301
|
+
<li><strong>Webhook:</strong> <code>${escapeHtml37(report.setup.urls.webhook)}</code></li>
|
|
21012
21302
|
</ul>
|
|
21013
21303
|
</section>
|
|
21014
21304
|
</main>`;
|
|
@@ -21468,7 +21758,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
21468
21758
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
|
|
21469
21759
|
const bridges = new WeakMap;
|
|
21470
21760
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
21471
|
-
const app = new
|
|
21761
|
+
const app = new Elysia38({
|
|
21472
21762
|
name: options.name ?? "absolutejs-voice-twilio"
|
|
21473
21763
|
}).get(twimlPath, async ({ query, request }) => {
|
|
21474
21764
|
const streamUrl = await resolveTwilioStreamUrl(options, {
|
|
@@ -21605,7 +21895,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
21605
21895
|
|
|
21606
21896
|
// src/telephony/plivo.ts
|
|
21607
21897
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21608
|
-
var
|
|
21898
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21609
21899
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
21610
21900
|
var resolveRequestOrigin2 = (request) => {
|
|
21611
21901
|
const url = new URL(request.url);
|
|
@@ -22035,21 +22325,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
22035
22325
|
};
|
|
22036
22326
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22037
22327
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
22038
|
-
<h1>${
|
|
22328
|
+
<h1>${escapeHtml38(title)}</h1>
|
|
22039
22329
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
22040
22330
|
<ul>
|
|
22041
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
22042
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
22043
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
22331
|
+
<li><strong>Answer XML:</strong> <code>${escapeHtml38(status.urls.answer)}</code></li>
|
|
22332
|
+
<li><strong>Audio stream:</strong> <code>${escapeHtml38(status.urls.stream)}</code></li>
|
|
22333
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml38(status.urls.webhook)}</code></li>
|
|
22044
22334
|
</ul>
|
|
22045
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
22046
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
22335
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml38(name)}</code></li>`).join("")}</ul>` : ""}
|
|
22336
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml38(warning)}</li>`).join("")}</ul>` : ""}
|
|
22047
22337
|
</main>`;
|
|
22048
22338
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22049
22339
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
22050
|
-
<h1>${
|
|
22340
|
+
<h1>${escapeHtml38(title)}</h1>
|
|
22051
22341
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
22052
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
22342
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml38(check.name)}</strong>: ${escapeHtml38(check.status)}${check.message ? ` - ${escapeHtml38(check.message)}` : ""}</li>`).join("")}</ul>
|
|
22053
22343
|
</main>`;
|
|
22054
22344
|
var runPlivoSmokeTest = async (input) => {
|
|
22055
22345
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -22139,7 +22429,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
22139
22429
|
nonceStore: options.webhook.nonceStore,
|
|
22140
22430
|
verificationUrl: options.webhook.verificationUrl
|
|
22141
22431
|
}) : undefined);
|
|
22142
|
-
const app = new
|
|
22432
|
+
const app = new Elysia39({
|
|
22143
22433
|
name: options.name ?? "absolutejs-voice-plivo"
|
|
22144
22434
|
}).get(answerPath, async ({ query, request }) => {
|
|
22145
22435
|
const streamUrl = await resolvePlivoStreamUrl(options, {
|
|
@@ -22251,9 +22541,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
22251
22541
|
// src/telephony/telnyx.ts
|
|
22252
22542
|
import { Buffer as Buffer6 } from "buffer";
|
|
22253
22543
|
import { Database as Database2 } from "bun:sqlite";
|
|
22254
|
-
import { Elysia as
|
|
22544
|
+
import { Elysia as Elysia40 } from "elysia";
|
|
22255
22545
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22256
|
-
var
|
|
22546
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22257
22547
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
22258
22548
|
var resolveRequestOrigin3 = (request) => {
|
|
22259
22549
|
const url = new URL(request.url);
|
|
@@ -22646,21 +22936,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
22646
22936
|
};
|
|
22647
22937
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22648
22938
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
22649
|
-
<h1>${
|
|
22939
|
+
<h1>${escapeHtml39(title)}</h1>
|
|
22650
22940
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
22651
22941
|
<ul>
|
|
22652
|
-
<li><strong>TeXML:</strong> <code>${
|
|
22653
|
-
<li><strong>Media stream:</strong> <code>${
|
|
22654
|
-
<li><strong>Status webhook:</strong> <code>${
|
|
22942
|
+
<li><strong>TeXML:</strong> <code>${escapeHtml39(status.urls.texml)}</code></li>
|
|
22943
|
+
<li><strong>Media stream:</strong> <code>${escapeHtml39(status.urls.stream)}</code></li>
|
|
22944
|
+
<li><strong>Status webhook:</strong> <code>${escapeHtml39(status.urls.webhook)}</code></li>
|
|
22655
22945
|
</ul>
|
|
22656
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
22657
|
-
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${
|
|
22946
|
+
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${escapeHtml39(name)}</code></li>`).join("")}</ul>` : ""}
|
|
22947
|
+
${status.warnings.length ? `<h2>Warnings</h2><ul>${status.warnings.map((warning) => `<li>${escapeHtml39(warning)}</li>`).join("")}</ul>` : ""}
|
|
22658
22948
|
</main>`;
|
|
22659
22949
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22660
22950
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
22661
|
-
<h1>${
|
|
22951
|
+
<h1>${escapeHtml39(title)}</h1>
|
|
22662
22952
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
22663
|
-
<ul>${report.checks.map((check) => `<li><strong>${
|
|
22953
|
+
<ul>${report.checks.map((check) => `<li><strong>${escapeHtml39(check.name)}</strong>: ${escapeHtml39(check.status)}${check.message ? ` - ${escapeHtml39(check.message)}` : ""}</li>`).join("")}</ul>
|
|
22664
22954
|
</main>`;
|
|
22665
22955
|
var runTelnyxSmokeTest = async (input) => {
|
|
22666
22956
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -22753,7 +23043,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
22753
23043
|
publicKey: options.webhook.publicKey,
|
|
22754
23044
|
toleranceSeconds: options.webhook.toleranceSeconds
|
|
22755
23045
|
}) : undefined);
|
|
22756
|
-
const app = new
|
|
23046
|
+
const app = new Elysia40({
|
|
22757
23047
|
name: options.name ?? "absolutejs-voice-telnyx"
|
|
22758
23048
|
}).get(texmlPath, async ({ query, request }) => {
|
|
22759
23049
|
const streamUrl = await resolveTelnyxStreamUrl(options, {
|
|
@@ -22863,8 +23153,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
22863
23153
|
};
|
|
22864
23154
|
|
|
22865
23155
|
// src/telephony/matrix.ts
|
|
22866
|
-
import { Elysia as
|
|
22867
|
-
var
|
|
23156
|
+
import { Elysia as Elysia41 } from "elysia";
|
|
23157
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22868
23158
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
22869
23159
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
22870
23160
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -22925,13 +23215,13 @@ var badgeStyles = {
|
|
|
22925
23215
|
};
|
|
22926
23216
|
var renderVoiceTelephonyCarrierMatrixHTML = (matrix, options = {}) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 1040px; margin: 40px auto; padding: 0 20px; color: #172033;">
|
|
22927
23217
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
22928
|
-
<h1 style="font-size: 34px; margin: 0 0 8px;">${
|
|
23218
|
+
<h1 style="font-size: 34px; margin: 0 0 8px;">${escapeHtml40(options.title ?? "AbsoluteJS Voice Carrier Matrix")}</h1>
|
|
22929
23219
|
<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>
|
|
22930
23220
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
22931
23221
|
${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);">
|
|
22932
23222
|
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
|
|
22933
|
-
<h2 style="margin:0; font-size:20px;">${
|
|
22934
|
-
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${
|
|
23223
|
+
<h2 style="margin:0; font-size:20px;">${escapeHtml40(entry.name)}</h2>
|
|
23224
|
+
<span style="border:1px solid; border-radius:999px; padding:4px 10px; font-size:12px; font-weight:700; ${badgeStyles[entry.status]}">${escapeHtml40(entry.status.toUpperCase())}</span>
|
|
22935
23225
|
</div>
|
|
22936
23226
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
22937
23227
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -22939,15 +23229,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
22939
23229
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
22940
23230
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
22941
23231
|
</dl>
|
|
22942
|
-
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${
|
|
22943
|
-
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${
|
|
22944
|
-
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${
|
|
23232
|
+
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${escapeHtml40(entry.setup.urls.stream || "missing")}</code></p>
|
|
23233
|
+
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${escapeHtml40(entry.setup.urls.webhook || "missing")}</code></p>
|
|
23234
|
+
${entry.issues.length ? `<ul style="margin:12px 0 0; padding-left:18px;">${entry.issues.map((issue) => `<li>${escapeHtml40(issue.severity)}: ${escapeHtml40(issue.message)}</li>`).join("")}</ul>` : '<p style="margin:12px 0 0; color:#166534;">No contract issues.</p>'}
|
|
22945
23235
|
</article>`).join("")}
|
|
22946
23236
|
</section>
|
|
22947
23237
|
</main>`;
|
|
22948
23238
|
var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
22949
23239
|
const path = options.path ?? "/api/voice/telephony/carriers";
|
|
22950
|
-
return new
|
|
23240
|
+
return new Elysia41({
|
|
22951
23241
|
name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
|
|
22952
23242
|
}).get(path, async ({ query, request }) => {
|
|
22953
23243
|
const providers = await options.load({ query, request });
|
|
@@ -22969,7 +23259,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
|
22969
23259
|
};
|
|
22970
23260
|
|
|
22971
23261
|
// src/phoneAgentProductionSmoke.ts
|
|
22972
|
-
import { Elysia as
|
|
23262
|
+
import { Elysia as Elysia42 } from "elysia";
|
|
22973
23263
|
var defaultRequirements = [
|
|
22974
23264
|
"media-started",
|
|
22975
23265
|
"transcript",
|
|
@@ -22977,7 +23267,7 @@ var defaultRequirements = [
|
|
|
22977
23267
|
"lifecycle-outcome",
|
|
22978
23268
|
"no-session-error"
|
|
22979
23269
|
];
|
|
22980
|
-
var
|
|
23270
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
22981
23271
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
22982
23272
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
22983
23273
|
const value = event.payload[key];
|
|
@@ -23086,10 +23376,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
23086
23376
|
});
|
|
23087
23377
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
23088
23378
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
23089
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
23090
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
23091
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
23092
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
23379
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml41(issue.requirement)}</strong>: ${escapeHtml41(issue.message)}</li>`).join("");
|
|
23380
|
+
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${escapeHtml41(outcome)}</span>`).join("");
|
|
23381
|
+
const requirements = report.required.map((requirement) => `<span class="pill">${escapeHtml41(requirement)}</span>`).join("");
|
|
23382
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml41(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>${escapeHtml41(title)}</h1><p class="status ${report.pass ? "pass" : "fail"}">${report.pass ? "PASS" : "FAIL"}</p><p>Contract <code>${escapeHtml41(report.contractId)}</code>${report.provider ? ` for <code>${escapeHtml41(report.provider)}</code>` : ""}${report.sessionId ? ` on session <code>${escapeHtml41(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>`;
|
|
23093
23383
|
};
|
|
23094
23384
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
23095
23385
|
query,
|
|
@@ -23112,7 +23402,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
23112
23402
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
23113
23403
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
23114
23404
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
23115
|
-
const routes = new
|
|
23405
|
+
const routes = new Elysia42({
|
|
23116
23406
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
23117
23407
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
23118
23408
|
if (htmlPath) {
|
|
@@ -23155,7 +23445,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
23155
23445
|
"completed",
|
|
23156
23446
|
"failed"
|
|
23157
23447
|
];
|
|
23158
|
-
var
|
|
23448
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
23159
23449
|
var loadRouteJson = async (input) => {
|
|
23160
23450
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
23161
23451
|
headers: {
|
|
@@ -23393,10 +23683,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
23393
23683
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
23394
23684
|
const urls = entry?.setup.urls;
|
|
23395
23685
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
23396
|
-
return `<tr><td>${
|
|
23686
|
+
return `<tr><td>${escapeHtml42(carrier.name ?? carrier.provider)}</td><td>${escapeHtml42(carrier.provider)}</td><td><code>${escapeHtml42(carrier.setupPath || "disabled")}</code></td><td><code>${escapeHtml42(carrier.smokePath || "disabled")}</code></td><td>${entry ? `<span class="${escapeHtml42(entry.status)}">${escapeHtml42(entry.status.toUpperCase())}</span>` : "unknown"}</td><td>${primaryUrl ? `<code>${escapeHtml42(primaryUrl)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.webhook ? `<code>${escapeHtml42(urls.webhook)}</code>` : '<span class="muted">missing</span>'}</td><td>${urls?.stream ? `<code>${escapeHtml42(urls.stream)}</code>` : '<span class="muted">missing</span>'}</td></tr>`;
|
|
23397
23687
|
}).join("");
|
|
23398
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
23399
|
-
const snippet =
|
|
23688
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml42(stage)}</code></li>`).join("");
|
|
23689
|
+
const snippet = escapeHtml42(`const phoneAgent = createVoicePhoneAgent({
|
|
23400
23690
|
carriers: [
|
|
23401
23691
|
{
|
|
23402
23692
|
provider: 'twilio',
|
|
@@ -23430,11 +23720,11 @@ app.use(
|
|
|
23430
23720
|
);`);
|
|
23431
23721
|
const checklist = report.carriers.map((carrier) => {
|
|
23432
23722
|
const instruction = report.setupInstructions.find((candidate) => candidate.provider === carrier.provider && candidate.carrierName === (carrier.name ?? carrier.provider));
|
|
23433
|
-
const issueList = instruction?.issues.map((issue) => `<li>${
|
|
23434
|
-
const steps = instruction?.steps.map((step) => `<li>${
|
|
23435
|
-
return `<article><h3>${
|
|
23723
|
+
const issueList = instruction?.issues.map((issue) => `<li>${escapeHtml42(issue)}</li>`).join("") ?? "";
|
|
23724
|
+
const steps = instruction?.steps.map((step) => `<li>${escapeHtml42(step)}</li>`).join("") ?? "";
|
|
23725
|
+
return `<article><h3>${escapeHtml42(carrier.name ?? carrier.provider)}</h3><ol>${steps}</ol>${issueList ? `<ul class="issues">${issueList}</ul>` : '<p class="pass">No carrier contract issues.</p>'}</article>`;
|
|
23436
23726
|
}).join("");
|
|
23437
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
23727
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml42(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>${escapeHtml42(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="${escapeHtml42(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>`;
|
|
23438
23728
|
};
|
|
23439
23729
|
var createVoicePhoneAgent = (options) => {
|
|
23440
23730
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -23443,7 +23733,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
23443
23733
|
setupPath: resolveSetupPath(carrier),
|
|
23444
23734
|
smokePath: resolveSmokePath(carrier)
|
|
23445
23735
|
}));
|
|
23446
|
-
const app = new
|
|
23736
|
+
const app = new Elysia43({
|
|
23447
23737
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
23448
23738
|
});
|
|
23449
23739
|
for (const carrier of options.carriers) {
|
|
@@ -25073,8 +25363,8 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
25073
25363
|
};
|
|
25074
25364
|
};
|
|
25075
25365
|
// src/providerCapabilities.ts
|
|
25076
|
-
import { Elysia as
|
|
25077
|
-
var
|
|
25366
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
25367
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25078
25368
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
25079
25369
|
configured: true,
|
|
25080
25370
|
features: options.features?.[provider],
|
|
@@ -25137,27 +25427,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
25137
25427
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
25138
25428
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
25139
25429
|
const cards = report.capabilities.map((capability) => {
|
|
25140
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
25141
|
-
return `<article class="card ${
|
|
25430
|
+
const features = (capability.features ?? []).map((feature) => `<span class="pill">${escapeHtml43(feature)}</span>`).join("");
|
|
25431
|
+
return `<article class="card ${escapeHtml43(capability.status)}">
|
|
25142
25432
|
<div class="card-header">
|
|
25143
25433
|
<div>
|
|
25144
|
-
<p class="eyebrow">${
|
|
25145
|
-
<h2>${
|
|
25434
|
+
<p class="eyebrow">${escapeHtml43(capability.kind)}</p>
|
|
25435
|
+
<h2>${escapeHtml43(capability.label ?? capability.provider)}</h2>
|
|
25146
25436
|
</div>
|
|
25147
|
-
<strong>${
|
|
25437
|
+
<strong>${escapeHtml43(capability.status)}</strong>
|
|
25148
25438
|
</div>
|
|
25149
|
-
${capability.description ? `<p>${
|
|
25439
|
+
${capability.description ? `<p>${escapeHtml43(capability.description)}</p>` : ""}
|
|
25150
25440
|
<dl>
|
|
25151
25441
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
25152
25442
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
25153
|
-
<div><dt>Model</dt><dd>${
|
|
25443
|
+
<div><dt>Model</dt><dd>${escapeHtml43(capability.model ?? "default")}</dd></div>
|
|
25154
25444
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
25155
25445
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
25156
25446
|
</dl>
|
|
25157
25447
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
25158
25448
|
</article>`;
|
|
25159
25449
|
}).join("");
|
|
25160
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25450
|
+
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:#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>${escapeHtml43(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>`;
|
|
25161
25451
|
};
|
|
25162
25452
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
25163
25453
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -25174,7 +25464,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
25174
25464
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
25175
25465
|
const path = options.path ?? "/api/provider-capabilities";
|
|
25176
25466
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
25177
|
-
const routes = new
|
|
25467
|
+
const routes = new Elysia44({
|
|
25178
25468
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
25179
25469
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
25180
25470
|
if (htmlPath) {
|
|
@@ -25183,7 +25473,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
25183
25473
|
return routes;
|
|
25184
25474
|
};
|
|
25185
25475
|
// src/providerOrchestration.ts
|
|
25186
|
-
import { Elysia as
|
|
25476
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
25187
25477
|
var defaultRequirement = {
|
|
25188
25478
|
minProviders: 1,
|
|
25189
25479
|
requireBudgetPolicy: false,
|
|
@@ -25196,7 +25486,7 @@ var statusRank4 = {
|
|
|
25196
25486
|
warn: 1,
|
|
25197
25487
|
fail: 2
|
|
25198
25488
|
};
|
|
25199
|
-
var
|
|
25489
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25200
25490
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
25201
25491
|
var uniqueSorted6 = (values) => [
|
|
25202
25492
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -25339,27 +25629,27 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
25339
25629
|
};
|
|
25340
25630
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
25341
25631
|
const title = options.title ?? "Voice Provider Orchestration";
|
|
25342
|
-
const cards = report.surfaces.map((surface) => `<article class="card ${
|
|
25343
|
-
<div class="card-header"><div><p class="eyebrow">${
|
|
25632
|
+
const cards = report.surfaces.map((surface) => `<article class="card ${escapeHtml44(surface.status)}">
|
|
25633
|
+
<div class="card-header"><div><p class="eyebrow">${escapeHtml44(surface.surface)}</p><h2>${escapeHtml44(surface.strategy ?? "default policy")}</h2></div><strong>${escapeHtml44(surface.status)}</strong></div>
|
|
25344
25634
|
<dl>
|
|
25345
|
-
<div><dt>Providers</dt><dd>${
|
|
25346
|
-
<div><dt>Fallback</dt><dd>${
|
|
25635
|
+
<div><dt>Providers</dt><dd>${escapeHtml44(surface.providers.join(", ") || "none")}</dd></div>
|
|
25636
|
+
<div><dt>Fallback</dt><dd>${escapeHtml44(surface.fallbackProviders.join(" -> ") || "none")}</dd></div>
|
|
25347
25637
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
25348
25638
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
25349
25639
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
25350
25640
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
25351
25641
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
25352
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
25642
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml44(surface.fallbackMode || "default")}</dd></div>
|
|
25353
25643
|
</dl>
|
|
25354
|
-
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${
|
|
25644
|
+
${surface.issues.length ? `<ul>${surface.issues.map((issue) => `<li><strong>${escapeHtml44(issue.status)}</strong> ${escapeHtml44(issue.message)}</li>`).join("")}</ul>` : "<p>No orchestration issues.</p>"}
|
|
25355
25645
|
</article>`).join("");
|
|
25356
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
25646
|
+
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:#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>${escapeHtml44(title)}</h1><div class="summary"><span class="pill">${escapeHtml44(report.profileId)}</span><span class="pill">${escapeHtml44(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>`;
|
|
25357
25647
|
};
|
|
25358
25648
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
25359
25649
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
25360
25650
|
const htmlPath = options.htmlPath === undefined ? "/voice/provider-orchestration" : options.htmlPath;
|
|
25361
25651
|
const markdownPath = options.markdownPath === undefined ? "/voice/provider-orchestration.md" : options.markdownPath;
|
|
25362
|
-
const routes = new
|
|
25652
|
+
const routes = new Elysia45({
|
|
25363
25653
|
name: options.name ?? "absolutejs-voice-provider-orchestration"
|
|
25364
25654
|
}).get(path, () => buildVoiceProviderOrchestrationReport(options));
|
|
25365
25655
|
if (htmlPath) {
|
|
@@ -25530,7 +25820,7 @@ var assertVoiceProviderRoutingContractEvidence = (reports, input = {}) => {
|
|
|
25530
25820
|
return report;
|
|
25531
25821
|
};
|
|
25532
25822
|
// src/providerSlo.ts
|
|
25533
|
-
import { Elysia as
|
|
25823
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
25534
25824
|
var defaultThresholds = {
|
|
25535
25825
|
llm: {
|
|
25536
25826
|
maxAverageElapsedMs: 2500,
|
|
@@ -25563,7 +25853,7 @@ var statusRank5 = {
|
|
|
25563
25853
|
warn: 1,
|
|
25564
25854
|
fail: 2
|
|
25565
25855
|
};
|
|
25566
|
-
var
|
|
25856
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25567
25857
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
25568
25858
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
25569
25859
|
var uniqueSorted7 = (values) => [
|
|
@@ -25859,11 +26149,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25859
26149
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
25860
26150
|
const kindCards = providerKinds.map((kind) => {
|
|
25861
26151
|
const kindReport = report.kinds[kind];
|
|
25862
|
-
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${
|
|
26152
|
+
const metrics = Object.values(kindReport.metrics).map((metric) => `<div><dt>${escapeHtml45(metric.label)}</dt><dd>${escapeHtml45(formatMetricValue2(metric))}</dd><small>budget ${escapeHtml45(formatMetricThreshold(metric))}</small></div>`).join("");
|
|
25863
26153
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
25864
|
-
return `<article class="${
|
|
26154
|
+
return `<article class="${escapeHtml45(kindReport.status)}"><h2>${kind.toUpperCase()} <span>${escapeHtml45(kindReport.status)}</span></h2><p>${kindReport.events} routing event(s), ${kindReport.eventsWithLatency} latency sample(s), providers: ${escapeHtml45(providers)}.</p><dl>${metrics}</dl></article>`;
|
|
25865
26155
|
}).join("");
|
|
25866
|
-
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${
|
|
26156
|
+
const issues = report.issues.length > 0 ? `<ul>${report.issues.map((issue) => `<li class="${escapeHtml45(issue.status)}"><strong>${escapeHtml45(issue.kind ? `${issue.kind.toUpperCase()} ${issue.label}` : issue.label)}</strong><span>${escapeHtml45(issue.detail ?? "")}</span></li>`).join("")}</ul>` : "<p>No provider SLO issues.</p>";
|
|
25867
26157
|
const snippet = `createVoiceProviderSloRoutes({
|
|
25868
26158
|
store: runtimeStorage.traces,
|
|
25869
26159
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -25873,7 +26163,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25873
26163
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
25874
26164
|
}
|
|
25875
26165
|
})`;
|
|
25876
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
26166
|
+
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{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>${escapeHtml45(title)}</h1><p class="status ${escapeHtml45(report.status)}">${escapeHtml45(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>${escapeHtml45(snippet)}</code></pre></section><section><h2>Issues</h2>${issues}</section></main></body></html>`;
|
|
25877
26167
|
};
|
|
25878
26168
|
var createVoiceProviderSloRoutes = (options) => {
|
|
25879
26169
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -25884,7 +26174,7 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25884
26174
|
...options.headers ?? {}
|
|
25885
26175
|
};
|
|
25886
26176
|
const buildReport = () => buildVoiceProviderSloReport(options);
|
|
25887
|
-
const app = new
|
|
26177
|
+
const app = new Elysia46({ name: options.name ?? "absolute-voice-provider-slos" });
|
|
25888
26178
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
25889
26179
|
if (markdownPath !== false) {
|
|
25890
26180
|
app.get(markdownPath, async () => {
|
|
@@ -25914,10 +26204,10 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25914
26204
|
return app;
|
|
25915
26205
|
};
|
|
25916
26206
|
// src/productionReadiness.ts
|
|
25917
|
-
import { Elysia as
|
|
26207
|
+
import { Elysia as Elysia52 } from "elysia";
|
|
25918
26208
|
|
|
25919
26209
|
// src/telephony/security.ts
|
|
25920
|
-
import { Elysia as
|
|
26210
|
+
import { Elysia as Elysia47 } from "elysia";
|
|
25921
26211
|
|
|
25922
26212
|
// src/postgresStore.ts
|
|
25923
26213
|
var normalizeIdentifierSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
|
|
@@ -26655,7 +26945,7 @@ var assertVoiceTelephonyWebhookSecurityEvidence = (report, input = {}) => {
|
|
|
26655
26945
|
};
|
|
26656
26946
|
var createVoiceTelephonyWebhookSecurityRoutes = (options) => {
|
|
26657
26947
|
const path = options.path ?? "/api/voice/telephony/webhook-security";
|
|
26658
|
-
return new
|
|
26948
|
+
return new Elysia47({
|
|
26659
26949
|
name: options.name ?? "absolutejs-voice-telephony-webhook-security"
|
|
26660
26950
|
}).get(path, () => buildVoiceTelephonyWebhookSecurityReport(options.options));
|
|
26661
26951
|
};
|
|
@@ -26712,8 +27002,8 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
26712
27002
|
};
|
|
26713
27003
|
|
|
26714
27004
|
// src/opsRecovery.ts
|
|
26715
|
-
import { Elysia as
|
|
26716
|
-
var
|
|
27005
|
+
import { Elysia as Elysia48 } from "elysia";
|
|
27006
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26717
27007
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
26718
27008
|
var hrefForSession = (value, sessionId) => {
|
|
26719
27009
|
if (typeof value === "function") {
|
|
@@ -26927,19 +27217,19 @@ ${failedSessions || "None."}
|
|
|
26927
27217
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
26928
27218
|
`;
|
|
26929
27219
|
};
|
|
26930
|
-
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${
|
|
27220
|
+
var renderDeliverySummary = (label, summary) => summary ? `<article><span>${escapeHtml46(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>${escapeHtml46(label)}</span><strong>not configured</strong></article>`;
|
|
26931
27221
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
26932
27222
|
const title = options.title ?? "Voice Ops Recovery";
|
|
26933
|
-
const issues = report.issues.map((issue) => `<tr><td>${
|
|
26934
|
-
const providers = report.providers.providers.map((provider) => `<tr><td>${
|
|
26935
|
-
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${
|
|
26936
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27223
|
+
const issues = report.issues.map((issue) => `<tr><td>${escapeHtml46(issue.severity)}</td><td><code>${escapeHtml46(issue.code)}</code></td><td>${issue.href ? `<a href="${escapeHtml46(issue.href)}">${escapeHtml46(issue.label)}</a>` : escapeHtml46(issue.label)}</td><td>${escapeHtml46(String(issue.value ?? ""))}</td><td>${escapeHtml46(issue.detail ?? "")}</td></tr>`).join("");
|
|
27224
|
+
const providers = report.providers.providers.map((provider) => `<tr><td>${escapeHtml46(provider.provider)}</td><td>${escapeHtml46(provider.status)}</td><td>${String(provider.runCount)}</td><td>${String(provider.errorCount)}</td><td>${String(provider.fallbackCount)}</td><td>${escapeHtml46(provider.lastError ?? "")}</td></tr>`).join("");
|
|
27225
|
+
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${escapeHtml46(session.operationsRecordHref)}">${escapeHtml46(session.sessionId)}</a>` : escapeHtml46(session.sessionId)}${session.provider ? ` via ${escapeHtml46(session.provider)}` : ""}${session.error ? `: ${escapeHtml46(session.error)}` : ""}</li>`).join("");
|
|
27226
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml46(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>${escapeHtml46(title)}</h1><p><span class="status">${escapeHtml46(report.status)}</span> Checked ${escapeHtml46(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>${escapeHtml46(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>`;
|
|
26937
27227
|
};
|
|
26938
27228
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
26939
27229
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
26940
27230
|
const htmlPath = options.htmlPath === undefined ? "/ops-recovery" : options.htmlPath;
|
|
26941
27231
|
const markdownPath = options.markdownPath === undefined ? `${path}.md` : options.markdownPath;
|
|
26942
|
-
const routes = new
|
|
27232
|
+
const routes = new Elysia48({
|
|
26943
27233
|
name: options.name ?? "absolutejs-voice-ops-recovery"
|
|
26944
27234
|
}).get(path, async () => buildVoiceOpsRecoveryReport(options));
|
|
26945
27235
|
if (htmlPath) {
|
|
@@ -26969,21 +27259,21 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
|
26969
27259
|
};
|
|
26970
27260
|
|
|
26971
27261
|
// src/observabilityExport.ts
|
|
26972
|
-
import { Elysia as
|
|
27262
|
+
import { Elysia as Elysia51 } from "elysia";
|
|
26973
27263
|
import { Database as Database4 } from "bun:sqlite";
|
|
26974
27264
|
import { createHash } from "crypto";
|
|
26975
27265
|
import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
|
|
26976
27266
|
import { join as join3 } from "path";
|
|
26977
27267
|
|
|
26978
27268
|
// src/operationsRecord.ts
|
|
26979
|
-
import { Elysia as
|
|
27269
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
26980
27270
|
|
|
26981
27271
|
// src/traceTimeline.ts
|
|
26982
|
-
import { Elysia as
|
|
26983
|
-
var
|
|
27272
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
27273
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26984
27274
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
26985
27275
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
26986
|
-
var
|
|
27276
|
+
var firstString4 = (payload, keys) => {
|
|
26987
27277
|
for (const key of keys) {
|
|
26988
27278
|
const value = getString16(payload[key]);
|
|
26989
27279
|
if (value) {
|
|
@@ -26992,7 +27282,7 @@ var firstString3 = (payload, keys) => {
|
|
|
26992
27282
|
}
|
|
26993
27283
|
return;
|
|
26994
27284
|
};
|
|
26995
|
-
var
|
|
27285
|
+
var firstNumber4 = (payload, keys) => {
|
|
26996
27286
|
for (const key of keys) {
|
|
26997
27287
|
const value = getNumber9(payload[key]);
|
|
26998
27288
|
if (value !== undefined) {
|
|
@@ -27001,20 +27291,20 @@ var firstNumber3 = (payload, keys) => {
|
|
|
27001
27291
|
}
|
|
27002
27292
|
return;
|
|
27003
27293
|
};
|
|
27004
|
-
var eventProvider = (event) =>
|
|
27294
|
+
var eventProvider = (event) => firstString4(event.payload, [
|
|
27005
27295
|
"provider",
|
|
27006
27296
|
"selectedProvider",
|
|
27007
27297
|
"fallbackProvider",
|
|
27008
27298
|
"variantId"
|
|
27009
27299
|
]);
|
|
27010
|
-
var eventStatus = (event) =>
|
|
27300
|
+
var eventStatus = (event) => firstString4(event.payload, [
|
|
27011
27301
|
"providerStatus",
|
|
27012
27302
|
"status",
|
|
27013
27303
|
"disposition",
|
|
27014
27304
|
"type",
|
|
27015
27305
|
"reason"
|
|
27016
27306
|
]);
|
|
27017
|
-
var eventElapsedMs2 = (event) =>
|
|
27307
|
+
var eventElapsedMs2 = (event) => firstNumber4(event.payload, ["elapsedMs", "latencyMs", "durationMs"]);
|
|
27018
27308
|
var resolveSessionHref5 = (value, sessionId) => {
|
|
27019
27309
|
if (value === false) {
|
|
27020
27310
|
return;
|
|
@@ -27163,17 +27453,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
27163
27453
|
};
|
|
27164
27454
|
};
|
|
27165
27455
|
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
27166
|
-
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>${
|
|
27456
|
+
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>${escapeHtml47(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>`;
|
|
27167
27457
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
27168
|
-
const events = session.events.map((event) => `<tr class="${
|
|
27169
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
27170
|
-
const supportLinks = session.operationsRecordHref ? `<p><a href="${
|
|
27171
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27458
|
+
const events = session.events.map((event) => `<tr class="${escapeHtml47(event.status ?? "")}"><td>+${String(event.offsetMs)}ms</td><td>${escapeHtml47(event.type)}</td><td>${escapeHtml47(event.label)}</td><td>${escapeHtml47(event.provider ?? "")}</td><td>${escapeHtml47(event.status ?? "")}</td><td>${formatMs4(event.elapsedMs)}</td></tr>`).join("");
|
|
27459
|
+
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${escapeHtml47(issue.severity)}">${escapeHtml47(issue.code)}: ${escapeHtml47(issue.message)}</li>`).join("") : "<li>none</li>";
|
|
27460
|
+
const supportLinks = session.operationsRecordHref ? `<p><a href="${escapeHtml47(session.operationsRecordHref)}">Open operations record</a></p>` : "";
|
|
27461
|
+
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 Trace Timeline")}</title><style>${timelineCSS}</style></head><body><main><a href="/traces">Back to traces</a><header><p class="eyebrow">Call timeline</p><h1>${escapeHtml47(session.sessionId)}</h1><p class="status ${escapeHtml47(session.status)}">${escapeHtml47(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>`;
|
|
27172
27462
|
};
|
|
27173
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
27463
|
+
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${escapeHtml47(session.status)}"><td>${session.operationsRecordHref ? `<a href="${escapeHtml47(session.operationsRecordHref)}">${escapeHtml47(session.sessionId)}</a>` : `<a href="/traces/${encodeURIComponent(session.sessionId)}">${escapeHtml47(session.sessionId)}</a>`}</td><td>${escapeHtml47(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) => escapeHtml47(provider.provider)).join(", ")}</td></tr>`).join("");
|
|
27174
27464
|
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}}";
|
|
27175
27465
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
27176
|
-
const snippet =
|
|
27466
|
+
const snippet = escapeHtml47(`const traceStore = createVoiceTraceSinkStore({
|
|
27177
27467
|
store: runtimeStorage.traces,
|
|
27178
27468
|
sinks: [
|
|
27179
27469
|
createVoiceTraceHTTPSink({
|
|
@@ -27199,13 +27489,13 @@ app.use(
|
|
|
27199
27489
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
27200
27490
|
})
|
|
27201
27491
|
);`);
|
|
27202
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
27492
|
+
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 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>${escapeHtml47(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>`;
|
|
27203
27493
|
};
|
|
27204
27494
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
27205
27495
|
const path = options.path ?? "/api/voice-traces";
|
|
27206
27496
|
const htmlPath = options.htmlPath ?? "/traces";
|
|
27207
27497
|
const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
|
|
27208
|
-
const routes = new
|
|
27498
|
+
const routes = new Elysia49({
|
|
27209
27499
|
name: options.name ?? "absolutejs-voice-trace-timelines"
|
|
27210
27500
|
});
|
|
27211
27501
|
const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
|
|
@@ -27634,7 +27924,7 @@ var assertVoiceOperationsRecordProviderRecovery = (record, input = {}) => {
|
|
|
27634
27924
|
}
|
|
27635
27925
|
return report;
|
|
27636
27926
|
};
|
|
27637
|
-
var
|
|
27927
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27638
27928
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
27639
27929
|
var outcomeLabels = (outcome) => [
|
|
27640
27930
|
outcome.complete ? "complete" : undefined,
|
|
@@ -27714,20 +28004,20 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
27714
28004
|
`);
|
|
27715
28005
|
};
|
|
27716
28006
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
27717
|
-
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${
|
|
27718
|
-
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${
|
|
27719
|
-
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${
|
|
28007
|
+
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${escapeHtml48(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>';
|
|
28008
|
+
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${escapeHtml48(turn.id)}</strong>${turn.committedText ? `<p><span class="label">Caller</span>${escapeHtml48(turn.committedText)}</p>` : ""}${turn.assistantReplies.map((reply) => `<p><span class="label">Assistant</span>${escapeHtml48(reply)}</p>`).join("")}${turn.errors.map((error) => `<p class="error"><span class="label">Error</span>${escapeHtml48(error)}</p>`).join("")}</li>`).join("") : "<li>No transcript turns recorded.</li>";
|
|
28009
|
+
const providerDecisions = record.providerDecisions.length ? record.providerDecisions.map((decision) => `<li><strong>${escapeHtml48(decision.provider ?? decision.selectedProvider ?? decision.fallbackProvider ?? "provider")}</strong> <span>${escapeHtml48(decision.status ?? decision.type)}</span> ${formatMs5(decision.elapsedMs)}${decision.surface ? `<p><span class="label">Surface</span>${escapeHtml48(decision.surface)}</p>` : ""}${decision.kind ? `<p><span class="label">Kind</span>${escapeHtml48(decision.kind)}</p>` : ""}${decision.selectedProvider ? `<p>Selected: ${escapeHtml48(decision.selectedProvider)}</p>` : ""}${decision.fallbackProvider ? `<p>Fallback: ${escapeHtml48(decision.fallbackProvider)}</p>` : ""}${decision.error ? `<p class="error">${escapeHtml48(decision.error)}</p>` : ""}${decision.reason ? `<p>${escapeHtml48(decision.reason)}</p>` : ""}</li>`).join("") : "<li>No provider decisions recorded.</li>";
|
|
27720
28010
|
const providerDecisionSummary = record.providerDecisionSummary;
|
|
27721
|
-
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${
|
|
27722
|
-
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${
|
|
27723
|
-
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${
|
|
27724
|
-
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${
|
|
27725
|
-
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${
|
|
28011
|
+
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${escapeHtml48(handoff.fromAgentId ?? "unknown")}</strong> to <strong>${escapeHtml48(handoff.targetAgentId ?? "unknown")}</strong> <span>${escapeHtml48(handoff.status ?? "")}</span><p>${escapeHtml48(handoff.summary ?? handoff.reason ?? "")}</p></li>`).join("") : "<li>No agent handoffs recorded.</li>";
|
|
28012
|
+
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${escapeHtml48(tool.toolName ?? "tool")}</strong> <span>${escapeHtml48(tool.status ?? "")}</span> ${formatMs5(tool.elapsedMs)} ${tool.error ? `<p>${escapeHtml48(tool.error)}</p>` : ""}</li>`).join("") : "<li>No tool calls recorded.</li>";
|
|
28013
|
+
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${escapeHtml48(review.title)}</strong> <span>${escapeHtml48(review.summary.outcome ?? "")}</span><p>${escapeHtml48(review.postCall?.summary ?? review.transcript.actual)}</p></li>`).join("") : "<li>No call reviews recorded.</li>";
|
|
28014
|
+
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${escapeHtml48(task.title)}</strong> <span>${escapeHtml48(task.status)}</span><p>${escapeHtml48(task.recommendedAction)}</p></li>`).join("") : "<li>No ops tasks recorded.</li>";
|
|
28015
|
+
const integrationEvents = record.integrationEvents?.events.length ? record.integrationEvents.events.map((event) => `<li><strong>${escapeHtml48(event.type)}</strong> <span>${escapeHtml48(event.deliveryStatus ?? "local")}</span><p>${escapeHtml48(event.deliveryError ?? event.deliveredTo ?? "")}</p></li>`).join("") : "<li>No integration events recorded.</li>";
|
|
27726
28016
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
27727
28017
|
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
27728
|
-
return `<li><strong>assistant.guardrail ${
|
|
28018
|
+
return `<li><strong>assistant.guardrail ${escapeHtml48(decision.stage ?? "unknown")}</strong> <span>${escapeHtml48(decision.status ?? "")}</span><p>Allowed: ${escapeHtml48(String(decision.allowed ?? "unknown"))} \xB7 Proof: ${escapeHtml48(decision.proof ?? "runtime")}${decision.turnId ? ` \xB7 Turn: ${escapeHtml48(decision.turnId)}` : ""}</p><p>${escapeHtml48(findings)}</p></li>`;
|
|
27729
28019
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
27730
|
-
const snippet =
|
|
28020
|
+
const snippet = escapeHtml48(`app.use(
|
|
27731
28021
|
createVoiceOperationsRecordRoutes({
|
|
27732
28022
|
audit: auditStore,
|
|
27733
28023
|
integrationEvents: opsEvents,
|
|
@@ -27741,16 +28031,16 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
27741
28031
|
tasks: opsTasks
|
|
27742
28032
|
})
|
|
27743
28033
|
);`);
|
|
27744
|
-
const incidentMarkdown =
|
|
27745
|
-
const incidentLink = options.incidentHref ? `<a href="${
|
|
27746
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
28034
|
+
const incidentMarkdown = escapeHtml48(renderVoiceOperationsRecordIncidentMarkdown(record));
|
|
28035
|
+
const incidentLink = options.incidentHref ? `<a href="${escapeHtml48(options.incidentHref)}">Download incident.md</a>` : "";
|
|
28036
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml48(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>${escapeHtml48(options.title ?? "Voice Operations Record")}</h1><p class="status ${escapeHtml48(record.status)}">${escapeHtml48(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>${escapeHtml48(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>`;
|
|
27747
28037
|
};
|
|
27748
28038
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
27749
28039
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
27750
28040
|
const htmlPath = options.htmlPath === undefined ? "/voice-operations/:sessionId" : options.htmlPath;
|
|
27751
28041
|
const incidentPath = options.incidentPath === undefined ? `${path}/incident.md` : options.incidentPath;
|
|
27752
28042
|
const incidentHtmlPath = options.incidentHtmlPath === undefined && htmlPath ? `${htmlPath}/incident.md` : options.incidentHtmlPath;
|
|
27753
|
-
const routes = new
|
|
28043
|
+
const routes = new Elysia50({
|
|
27754
28044
|
name: options.name ?? "absolutejs-voice-operations-record"
|
|
27755
28045
|
});
|
|
27756
28046
|
const buildRecord = (sessionId) => buildVoiceOperationsRecord({
|
|
@@ -28111,7 +28401,7 @@ var checksumFile = async (path) => {
|
|
|
28111
28401
|
const buffer = await readFile2(path);
|
|
28112
28402
|
return createHash("sha256").update(buffer).digest("hex");
|
|
28113
28403
|
};
|
|
28114
|
-
var
|
|
28404
|
+
var byteLength2 = (value) => new TextEncoder().encode(value).byteLength;
|
|
28115
28405
|
var deliveryReceiptId = (runId) => `observability-export:${encodeURIComponent(runId)}`;
|
|
28116
28406
|
var safeArtifactFileName = (artifact) => {
|
|
28117
28407
|
const extension = artifact.contentType === "image/png" ? ".png" : artifact.contentType?.includes("markdown") ? ".md" : artifact.contentType?.includes("json") ? ".json" : "";
|
|
@@ -28401,7 +28691,7 @@ var createVoiceObservabilityExportReplayRoutes = (options) => {
|
|
|
28401
28691
|
...options.headers ?? {}
|
|
28402
28692
|
};
|
|
28403
28693
|
const buildReport = () => resolveVoiceObservabilityExportReplayReport(options.source);
|
|
28404
|
-
const app = new
|
|
28694
|
+
const app = new Elysia51({
|
|
28405
28695
|
name: options.name ?? "absolute-voice-observability-export-replay"
|
|
28406
28696
|
});
|
|
28407
28697
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -29024,7 +29314,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29024
29314
|
destinationId,
|
|
29025
29315
|
destinationKind: destination.kind,
|
|
29026
29316
|
label,
|
|
29027
|
-
manifestBytes:
|
|
29317
|
+
manifestBytes: byteLength2(manifest),
|
|
29028
29318
|
schema: options.report.schema,
|
|
29029
29319
|
status: "delivered",
|
|
29030
29320
|
target
|
|
@@ -29069,7 +29359,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29069
29359
|
destinationId,
|
|
29070
29360
|
destinationKind: destination.kind,
|
|
29071
29361
|
label,
|
|
29072
|
-
manifestBytes:
|
|
29362
|
+
manifestBytes: byteLength2(manifest),
|
|
29073
29363
|
schema: options.report.schema,
|
|
29074
29364
|
status: "delivered",
|
|
29075
29365
|
target: destination.bucket ? `s3://${destination.bucket}/${rootKey}` : rootKey
|
|
@@ -29091,7 +29381,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29091
29381
|
destinationId,
|
|
29092
29382
|
destinationKind: destination.kind,
|
|
29093
29383
|
label,
|
|
29094
|
-
manifestBytes:
|
|
29384
|
+
manifestBytes: byteLength2(manifest),
|
|
29095
29385
|
schema: options.report.schema,
|
|
29096
29386
|
status: "delivered",
|
|
29097
29387
|
target
|
|
@@ -29113,7 +29403,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29113
29403
|
destinationId,
|
|
29114
29404
|
destinationKind: destination.kind,
|
|
29115
29405
|
label,
|
|
29116
|
-
manifestBytes:
|
|
29406
|
+
manifestBytes: byteLength2(manifest),
|
|
29117
29407
|
schema: options.report.schema,
|
|
29118
29408
|
status: "delivered",
|
|
29119
29409
|
target
|
|
@@ -29149,7 +29439,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29149
29439
|
destinationId,
|
|
29150
29440
|
destinationKind: destination.kind,
|
|
29151
29441
|
label,
|
|
29152
|
-
manifestBytes:
|
|
29442
|
+
manifestBytes: byteLength2(manifest),
|
|
29153
29443
|
schema: options.report.schema,
|
|
29154
29444
|
status: "delivered",
|
|
29155
29445
|
target: destination.url
|
|
@@ -29162,7 +29452,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29162
29452
|
destinationKind: destination.kind,
|
|
29163
29453
|
error: error instanceof Error ? error.message : String(error),
|
|
29164
29454
|
label,
|
|
29165
|
-
manifestBytes:
|
|
29455
|
+
manifestBytes: byteLength2(manifest),
|
|
29166
29456
|
schema: options.report.schema,
|
|
29167
29457
|
status: "failed",
|
|
29168
29458
|
target: observabilityExportDeliveryFailureTarget(destination)
|
|
@@ -29210,7 +29500,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
29210
29500
|
artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
|
|
29211
29501
|
}
|
|
29212
29502
|
});
|
|
29213
|
-
const app = new
|
|
29503
|
+
const app = new Elysia51({
|
|
29214
29504
|
name: options.name ?? "absolute-voice-observability-export"
|
|
29215
29505
|
});
|
|
29216
29506
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -29287,7 +29577,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
29287
29577
|
};
|
|
29288
29578
|
|
|
29289
29579
|
// src/productionReadiness.ts
|
|
29290
|
-
var
|
|
29580
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29291
29581
|
var rollupStatus4 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
29292
29582
|
var readinessGateCodes = {
|
|
29293
29583
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
@@ -30856,25 +31146,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30856
31146
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
30857
31147
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
30858
31148
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
30859
|
-
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${
|
|
30860
|
-
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${
|
|
31149
|
+
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${escapeHtml49(report.links.sloReadinessThresholds)}">Open Calibration -> Active Readiness Gate</a> to inspect the thresholds currently driving calibrated provider, latency, interruption, reconnect, and monitoring gates.</p>` : "";
|
|
31150
|
+
const profile = report.profile ? `<section class="profile"><p class="eyebrow">Readiness profile</p><h2>${escapeHtml49(report.profile.name)}</h2><p>${escapeHtml49(report.profile.description)}</p><p>${escapeHtml49(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="${escapeHtml49(surface.href)}">${escapeHtml49(surface.label)}</a>` : escapeHtml49(surface.label)}</strong></article>`).join("")}</div></section>` : "";
|
|
30861
31151
|
const checks = report.checks.map((check, index) => {
|
|
30862
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
30863
|
-
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${
|
|
30864
|
-
return `<article class="check ${
|
|
31152
|
+
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${escapeHtml49(action.href)}">${escapeHtml49(action.label)}</button>` : `<a href="${escapeHtml49(action.href)}">${escapeHtml49(action.label)}</a>`).join("");
|
|
31153
|
+
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${escapeHtml49(check.status)}: observed ${escapeHtml49(String(check.gateExplanation.observed ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml49(check.gateExplanation.unit)}` : ""}; threshold ${escapeHtml49(String(check.gateExplanation.threshold ?? "n/a"))}${check.gateExplanation.unit ? ` ${escapeHtml49(check.gateExplanation.unit)}` : ""}. ${escapeHtml49(check.gateExplanation.remediation)} ${check.gateExplanation.sourceHref ? `<a href="${escapeHtml49(check.gateExplanation.sourceHref)}">Open threshold source</a>` : ""}</p>` : "";
|
|
31154
|
+
return `<article class="check ${escapeHtml49(check.status)}">
|
|
30865
31155
|
<div>
|
|
30866
|
-
<span>${
|
|
30867
|
-
<h2>${
|
|
30868
|
-
${check.detail ? `<p>${
|
|
31156
|
+
<span>${escapeHtml49(check.status.toUpperCase())}</span>
|
|
31157
|
+
<h2>${escapeHtml49(check.label)}</h2>
|
|
31158
|
+
${check.detail ? `<p>${escapeHtml49(check.detail)}</p>` : ""}
|
|
30869
31159
|
${explanation}
|
|
30870
|
-
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${
|
|
31160
|
+
${check.proofSource ? `<p class="proof-source">Proof source: ${check.proofSource.href ? `<a href="${escapeHtml49(check.proofSource.href)}">${escapeHtml49(check.proofSource.sourceLabel)}</a>` : escapeHtml49(check.proofSource.sourceLabel)}${check.proofSource.detail ? ` \xB7 ${escapeHtml49(check.proofSource.detail)}` : ""}</p>` : ""}
|
|
30871
31161
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
30872
31162
|
</div>
|
|
30873
|
-
<strong>${
|
|
30874
|
-
${check.href ? `<a href="${
|
|
31163
|
+
<strong>${escapeHtml49(String(check.value ?? check.status))}</strong>
|
|
31164
|
+
${check.href ? `<a href="${escapeHtml49(check.href)}">Open surface</a>` : ""}
|
|
30875
31165
|
</article>`;
|
|
30876
31166
|
}).join("");
|
|
30877
|
-
const snippet =
|
|
31167
|
+
const snippet = escapeHtml49(`createVoiceProductionReadinessRoutes({
|
|
30878
31168
|
htmlPath: '/production-readiness',
|
|
30879
31169
|
path: '/api/production-readiness',
|
|
30880
31170
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -30890,13 +31180,13 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
30890
31180
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
30891
31181
|
store: traceStore
|
|
30892
31182
|
});`);
|
|
30893
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31183
|
+
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:#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>${escapeHtml49(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 ${escapeHtml49(report.status)}">Overall: ${escapeHtml49(report.status.toUpperCase())}</p><p>Checked ${escapeHtml49(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>`;
|
|
30894
31184
|
};
|
|
30895
31185
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
30896
31186
|
const path = options.path ?? "/api/production-readiness";
|
|
30897
31187
|
const gatePath = options.gatePath === undefined ? "/api/production-readiness/gate" : options.gatePath;
|
|
30898
31188
|
const htmlPath = options.htmlPath ?? "/production-readiness";
|
|
30899
|
-
const routes = new
|
|
31189
|
+
const routes = new Elysia52({
|
|
30900
31190
|
name: options.name ?? "absolutejs-voice-production-readiness"
|
|
30901
31191
|
});
|
|
30902
31192
|
const resolveOptions = async (input) => {
|
|
@@ -30944,8 +31234,8 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
30944
31234
|
return routes;
|
|
30945
31235
|
};
|
|
30946
31236
|
// src/voiceMonitoring.ts
|
|
30947
|
-
import { Elysia as
|
|
30948
|
-
var
|
|
31237
|
+
import { Elysia as Elysia53 } from "elysia";
|
|
31238
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30949
31239
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
30950
31240
|
var rollupStatus5 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
30951
31241
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
@@ -31198,14 +31488,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
31198
31488
|
};
|
|
31199
31489
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
31200
31490
|
const title = options.title ?? "Voice Monitors";
|
|
31201
|
-
const runs = report.runs.map((run) => `<tr><td>${
|
|
31202
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
31203
|
-
const snippet =
|
|
31491
|
+
const runs = report.runs.map((run) => `<tr><td>${escapeHtml50(run.label)}</td><td class="${escapeHtml50(run.status)}">${escapeHtml50(run.status)}</td><td>${escapeHtml50(run.severity)}</td><td>${escapeHtml50(String(run.value ?? ""))}</td><td>${escapeHtml50(String(run.threshold ?? ""))}</td><td>${escapeHtml50(run.detail ?? "")}</td></tr>`).join("");
|
|
31492
|
+
const issues = report.issues.map((issue) => `<li><strong>${escapeHtml50(issue.label)}</strong> <span class="${escapeHtml50(issue.status)}">${escapeHtml50(issue.status)}</span> ${escapeHtml50(issue.detail ?? "")}</li>`).join("");
|
|
31493
|
+
const snippet = escapeHtml50(`app.use(createVoiceMonitorRoutes({
|
|
31204
31494
|
evidence,
|
|
31205
31495
|
issueStore,
|
|
31206
31496
|
monitors: [defineVoiceMonitor(...)]
|
|
31207
31497
|
}));`);
|
|
31208
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
31498
|
+
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:#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>${escapeHtml50(title)}</h1><p class="pill ${escapeHtml50(report.status)}">Status: ${escapeHtml50(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>`;
|
|
31209
31499
|
};
|
|
31210
31500
|
var actorFromRequest = async (request) => {
|
|
31211
31501
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -31229,7 +31519,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
31229
31519
|
monitors: options.monitors,
|
|
31230
31520
|
now: options.now
|
|
31231
31521
|
});
|
|
31232
|
-
const routes = new
|
|
31522
|
+
const routes = new Elysia53({
|
|
31233
31523
|
name: options.name ?? "absolutejs-voice-monitoring"
|
|
31234
31524
|
}).get(path, report).get(`${path}.md`, async () => {
|
|
31235
31525
|
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
@@ -31276,7 +31566,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
31276
31566
|
};
|
|
31277
31567
|
var createVoiceMonitorRunnerRoutes = (options) => {
|
|
31278
31568
|
const path = options.path ?? "/api/voice/monitor-runner";
|
|
31279
|
-
return new
|
|
31569
|
+
return new Elysia53({
|
|
31280
31570
|
name: options.name ?? "absolutejs-voice-monitor-runner"
|
|
31281
31571
|
}).get(path, () => ({
|
|
31282
31572
|
isRunning: options.runner.isRunning()
|
|
@@ -31652,8 +31942,8 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
31652
31942
|
};
|
|
31653
31943
|
};
|
|
31654
31944
|
// src/providerStackRecommendations.ts
|
|
31655
|
-
import { Elysia as
|
|
31656
|
-
var
|
|
31945
|
+
import { Elysia as Elysia54 } from "elysia";
|
|
31946
|
+
var escapeHtml51 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31657
31947
|
var profileProviderPriorities = {
|
|
31658
31948
|
"meeting-recorder": {
|
|
31659
31949
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -31972,17 +32262,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
31972
32262
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
31973
32263
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
31974
32264
|
const rows = report.rows.map((row) => {
|
|
31975
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
31976
|
-
return `<article class="row ${
|
|
32265
|
+
const checks = row.checks.map((check) => `<li class="${escapeHtml51(check.status)}"><strong>${escapeHtml51(check.label)}</strong><span>${escapeHtml51(check.detail ?? check.status)}</span>${check.remediation ? `<em>${check.remediation.href ? `<a href="${escapeHtml51(check.remediation.href)}">${escapeHtml51(check.remediation.label)}</a>` : escapeHtml51(check.remediation.label)}: ${escapeHtml51(check.remediation.detail)}</em>` : ""}</li>`).join("");
|
|
32266
|
+
return `<article class="row ${escapeHtml51(row.status)}">
|
|
31977
32267
|
<div>
|
|
31978
|
-
<p class="eyebrow">${
|
|
31979
|
-
<h2>${
|
|
31980
|
-
<p class="status ${
|
|
32268
|
+
<p class="eyebrow">${escapeHtml51(row.kind)}${row.selected ? " \xB7 selected" : ""}</p>
|
|
32269
|
+
<h2>${escapeHtml51(row.provider)}</h2>
|
|
32270
|
+
<p class="status ${escapeHtml51(row.status)}">${escapeHtml51(row.status.toUpperCase())}</p>
|
|
31981
32271
|
</div>
|
|
31982
32272
|
<ul>${checks}</ul>
|
|
31983
32273
|
</article>`;
|
|
31984
32274
|
}).join("");
|
|
31985
|
-
const snippet =
|
|
32275
|
+
const snippet = escapeHtml51(`const providerContracts = () =>
|
|
31986
32276
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
31987
32277
|
env: process.env,
|
|
31988
32278
|
providers: {
|
|
@@ -32003,7 +32293,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
32003
32293
|
providerContractMatrix: () =>
|
|
32004
32294
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
32005
32295
|
});`);
|
|
32006
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32296
|
+
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{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>${escapeHtml51(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>`;
|
|
32007
32297
|
};
|
|
32008
32298
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
32009
32299
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -32018,7 +32308,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
32018
32308
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
32019
32309
|
const path = options.path ?? "/api/provider-contracts";
|
|
32020
32310
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
32021
|
-
const routes = new
|
|
32311
|
+
const routes = new Elysia54({
|
|
32022
32312
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
32023
32313
|
});
|
|
32024
32314
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -32136,7 +32426,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
32136
32426
|
return assertion;
|
|
32137
32427
|
};
|
|
32138
32428
|
// src/opsConsoleRoutes.ts
|
|
32139
|
-
import { Elysia as
|
|
32429
|
+
import { Elysia as Elysia55 } from "elysia";
|
|
32140
32430
|
var DEFAULT_LINKS = [
|
|
32141
32431
|
{
|
|
32142
32432
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -32171,7 +32461,7 @@ var DEFAULT_LINKS = [
|
|
|
32171
32461
|
label: "Handoffs"
|
|
32172
32462
|
}
|
|
32173
32463
|
];
|
|
32174
|
-
var
|
|
32464
|
+
var escapeHtml52 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32175
32465
|
var countProviderStatuses = (providers) => {
|
|
32176
32466
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
32177
32467
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -32240,20 +32530,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
32240
32530
|
trace
|
|
32241
32531
|
};
|
|
32242
32532
|
};
|
|
32243
|
-
var renderMetricCard = (input) => `<article class="metric"><span>${
|
|
32533
|
+
var renderMetricCard = (input) => `<article class="metric"><span>${escapeHtml52(input.label)}</span><strong>${escapeHtml52(String(input.value))}</strong>${input.status ? `<p class="${escapeHtml52(input.status)}">${escapeHtml52(input.status)}</p>` : ""}${input.href ? `<a href="${escapeHtml52(input.href)}">Open</a>` : ""}</article>`;
|
|
32244
32534
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
32245
32535
|
const links = report.links.map((link) => `<article class="surface">
|
|
32246
|
-
<div><h2>${
|
|
32247
|
-
<p><a href="${
|
|
32536
|
+
<div><h2>${escapeHtml52(link.label)}</h2>${link.description ? `<p>${escapeHtml52(link.description)}</p>` : ""}</div>
|
|
32537
|
+
<p><a href="${escapeHtml52(link.href)}">Open ${escapeHtml52(link.label)}</a>${link.statusHref ? ` \xB7 <a href="${escapeHtml52(link.statusHref)}">Status</a>` : ""}</p>
|
|
32248
32538
|
</article>`).join("");
|
|
32249
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
32250
|
-
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${
|
|
32539
|
+
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${escapeHtml52(session.sessionId)}</td><td>${escapeHtml52(session.status)}</td><td>${session.turnCount}</td><td>${session.errorCount}</td><td>${session.replayHref ? `<a href="${escapeHtml52(session.replayHref)}">Replay</a>` : ""}</td></tr>`).join("") : '<tr><td colspan="5">No sessions yet.</td></tr>';
|
|
32540
|
+
const routing = report.recentRoutingEvents.length ? report.recentRoutingEvents.map((event) => `<tr><td>${escapeHtml52(event.kind)}</td><td>${escapeHtml52(event.provider ?? "unknown")}</td><td>${escapeHtml52(event.status ?? "unknown")}</td><td>${event.elapsedMs ?? 0}ms</td><td>${escapeHtml52(event.sessionId)}</td></tr>`).join("") : '<tr><td colspan="5">No provider routing events yet.</td></tr>';
|
|
32251
32541
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
32252
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32542
|
+
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{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>${escapeHtml52(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 ${escapeHtml52(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>`;
|
|
32253
32543
|
};
|
|
32254
32544
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
32255
32545
|
const path = options.path ?? "/ops-console";
|
|
32256
|
-
const routes = new
|
|
32546
|
+
const routes = new Elysia55({
|
|
32257
32547
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
32258
32548
|
});
|
|
32259
32549
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -32270,7 +32560,7 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
32270
32560
|
return routes;
|
|
32271
32561
|
};
|
|
32272
32562
|
// src/incidentBundle.ts
|
|
32273
|
-
import { Elysia as
|
|
32563
|
+
import { Elysia as Elysia56 } from "elysia";
|
|
32274
32564
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
32275
32565
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
32276
32566
|
return false;
|
|
@@ -32471,7 +32761,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
32471
32761
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
32472
32762
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
32473
32763
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
32474
|
-
const routes = new
|
|
32764
|
+
const routes = new Elysia56({
|
|
32475
32765
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
32476
32766
|
});
|
|
32477
32767
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -32672,19 +32962,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
32672
32962
|
};
|
|
32673
32963
|
};
|
|
32674
32964
|
// src/opsStatusRoutes.ts
|
|
32675
|
-
import { Elysia as
|
|
32676
|
-
var
|
|
32965
|
+
import { Elysia as Elysia57 } from "elysia";
|
|
32966
|
+
var escapeHtml53 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32677
32967
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
32678
32968
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
32679
32969
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
32680
32970
|
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;
|
|
32681
|
-
return `<article class="surface ${
|
|
32971
|
+
return `<article class="surface ${escapeHtml53(surface.status)}"><span>${escapeHtml53(surface.status.toUpperCase())}</span><h2>${escapeHtml53(key)}</h2><strong>${escapeHtml53(value)}</strong></article>`;
|
|
32682
32972
|
}).join("");
|
|
32683
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
32973
|
+
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:#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>${escapeHtml53(title)}</h1><p>Compact pass/fail status for framework widgets, demos, and small customer-facing health badges.</p><p class="status ${escapeHtml53(report.status)}">Overall: ${escapeHtml53(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>`;
|
|
32684
32974
|
};
|
|
32685
32975
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
32686
32976
|
const path = options.path ?? "/api/voice/ops-status";
|
|
32687
|
-
const routes = new
|
|
32977
|
+
const routes = new Elysia57({
|
|
32688
32978
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
32689
32979
|
});
|
|
32690
32980
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -33117,8 +33407,8 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
33117
33407
|
};
|
|
33118
33408
|
};
|
|
33119
33409
|
// src/traceDeliveryRoutes.ts
|
|
33120
|
-
import { Elysia as
|
|
33121
|
-
var
|
|
33410
|
+
import { Elysia as Elysia58 } from "elysia";
|
|
33411
|
+
var escapeHtml54 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
33122
33412
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
33123
33413
|
var getNumber12 = (value) => {
|
|
33124
33414
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -33199,14 +33489,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
33199
33489
|
if (entries.length === 0) {
|
|
33200
33490
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
33201
33491
|
}
|
|
33202
|
-
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${
|
|
33492
|
+
return `<ul>${entries.map(([sinkId, result]) => `<li><strong>${escapeHtml54(sinkId)}</strong>: ${escapeHtml54(result.status)}${result.deliveredTo ? ` to ${escapeHtml54(result.deliveredTo)}` : ""}${result.error ? ` (${escapeHtml54(result.error)})` : ""}</li>`).join("")}</ul>`;
|
|
33203
33493
|
};
|
|
33204
|
-
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${
|
|
33494
|
+
var renderEventList2 = (delivery) => delivery.events.length === 0 ? "<p>No trace events in this delivery.</p>" : `<ul>${delivery.events.map((event) => `<li>${escapeHtml54(event.type)} <small>${escapeHtml54(event.id)}</small>${event.sessionId ? ` session=${escapeHtml54(event.sessionId)}` : ""}</li>`).join("")}</ul>`;
|
|
33205
33495
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
33206
33496
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
33207
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
33208
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
33209
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${
|
|
33497
|
+
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${escapeHtml54(options.workerPath ?? "/api/voice-trace-deliveries/drain")}"><button type="submit">Drain trace deliveries</button></form>`;
|
|
33498
|
+
const rows = report.deliveries.map((delivery) => `<article class="delivery ${escapeHtml54(delivery.deliveryStatus)}"><div class="head"><div><span>${escapeHtml54(delivery.deliveryStatus)}</span><h2>${escapeHtml54(delivery.id)}</h2><p>${escapeHtml54(new Date(delivery.createdAt).toLocaleString())}${delivery.deliveredAt ? ` \xB7 delivered ${escapeHtml54(new Date(delivery.deliveredAt).toLocaleString())}` : ""}</p></div><strong>${String(delivery.deliveryAttempts ?? 0)} attempt(s)</strong></div>${delivery.deliveryError ? `<p class="error">${escapeHtml54(delivery.deliveryError)}</p>` : ""}<h3>Sinks</h3>${renderSinkResults2(delivery)}<h3>Events</h3>${renderEventList2(delivery)}</article>`).join("");
|
|
33499
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml54(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>${escapeHtml54(title)}</h1><p>Checked ${escapeHtml54(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>`;
|
|
33210
33500
|
};
|
|
33211
33501
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
33212
33502
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -33226,7 +33516,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
33226
33516
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
33227
33517
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
33228
33518
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
33229
|
-
const routes = new
|
|
33519
|
+
const routes = new Elysia58({
|
|
33230
33520
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
33231
33521
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
33232
33522
|
if (htmlPath !== false) {
|
|
@@ -33323,7 +33613,7 @@ var createVoiceMemoryStore = () => {
|
|
|
33323
33613
|
return { get, getOrCreate, list, remove, set };
|
|
33324
33614
|
};
|
|
33325
33615
|
// src/opsWebhook.ts
|
|
33326
|
-
import { Elysia as
|
|
33616
|
+
import { Elysia as Elysia59 } from "elysia";
|
|
33327
33617
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
33328
33618
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
33329
33619
|
const encoder = new TextEncoder;
|
|
@@ -33453,7 +33743,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
33453
33743
|
};
|
|
33454
33744
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
33455
33745
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
33456
|
-
return new
|
|
33746
|
+
return new Elysia59().post(path, async ({ body, request, set }) => {
|
|
33457
33747
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
33458
33748
|
if (options.signingSecret) {
|
|
33459
33749
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -33908,7 +34198,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
33908
34198
|
};
|
|
33909
34199
|
};
|
|
33910
34200
|
// src/postCallAnalysis.ts
|
|
33911
|
-
import { Elysia as
|
|
34201
|
+
import { Elysia as Elysia60 } from "elysia";
|
|
33912
34202
|
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
33913
34203
|
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
33914
34204
|
var getPathValue3 = (source, path) => {
|
|
@@ -34087,7 +34377,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
|
|
|
34087
34377
|
};
|
|
34088
34378
|
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
34089
34379
|
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
34090
|
-
const routes = new
|
|
34380
|
+
const routes = new Elysia60({
|
|
34091
34381
|
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
34092
34382
|
});
|
|
34093
34383
|
routes.get(path, async ({ query }) => {
|
|
@@ -34112,7 +34402,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
|
34112
34402
|
return routes;
|
|
34113
34403
|
};
|
|
34114
34404
|
// src/guardrails.ts
|
|
34115
|
-
import { Elysia as
|
|
34405
|
+
import { Elysia as Elysia61 } from "elysia";
|
|
34116
34406
|
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
34117
34407
|
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
34118
34408
|
var matchesRule = async (rule, input) => {
|
|
@@ -34414,7 +34704,7 @@ var resolveGuardrailReport = async (options, input) => {
|
|
|
34414
34704
|
};
|
|
34415
34705
|
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
34416
34706
|
const path = options.path ?? "/api/voice/guardrails";
|
|
34417
|
-
const routes = new
|
|
34707
|
+
const routes = new Elysia61({
|
|
34418
34708
|
name: options.name ?? "absolutejs-voice-guardrails"
|
|
34419
34709
|
});
|
|
34420
34710
|
routes.all(path, async ({ request }) => {
|
|
@@ -34929,6 +35219,7 @@ export {
|
|
|
34929
35219
|
renderVoiceTraceHTML,
|
|
34930
35220
|
renderVoiceTraceDeliveryHTML,
|
|
34931
35221
|
renderVoiceToolContractHTML,
|
|
35222
|
+
renderVoiceTelephonyMediaHTML,
|
|
34932
35223
|
renderVoiceTelephonyCarrierMatrixHTML,
|
|
34933
35224
|
renderVoiceSloReadinessThresholdMarkdown,
|
|
34934
35225
|
renderVoiceSloReadinessThresholdHTML,
|
|
@@ -35126,6 +35417,7 @@ export {
|
|
|
35126
35417
|
createVoiceTelephonyWebhookRoutes,
|
|
35127
35418
|
createVoiceTelephonyWebhookHandler,
|
|
35128
35419
|
createVoiceTelephonyOutcomePolicy,
|
|
35420
|
+
createVoiceTelephonyMediaRoutes,
|
|
35129
35421
|
createVoiceTelephonyCarrierMatrixRoutes,
|
|
35130
35422
|
createVoiceTelephonyCarrierMatrix,
|
|
35131
35423
|
createVoiceTaskUpdatedEvent,
|
|
@@ -35378,6 +35670,7 @@ export {
|
|
|
35378
35670
|
buildVoiceTraceReplay,
|
|
35379
35671
|
buildVoiceTraceDeliveryReport,
|
|
35380
35672
|
buildVoiceTelephonyWebhookSecurityReport,
|
|
35673
|
+
buildVoiceTelephonyMediaReport,
|
|
35381
35674
|
buildVoiceSloReadinessThresholdReport,
|
|
35382
35675
|
buildVoiceSloCalibrationReport,
|
|
35383
35676
|
buildVoiceRealtimeProviderContractMatrix,
|