@absolutejs/voice 0.0.22-beta.321 → 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/README.md +7 -0
- package/dist/angular/index.js +233 -7
- package/dist/browserMediaRoutes.d.ts +2 -1
- package/dist/client/htmxBootstrap.js +69 -7
- package/dist/client/index.js +233 -7
- package/dist/index.d.ts +2 -0
- package/dist/index.js +816 -444
- package/dist/react/index.js +233 -7
- package/dist/svelte/index.js +233 -7
- package/dist/telephonyMediaRoutes.d.ts +63 -0
- package/dist/testing/index.js +246 -20
- package/dist/types.d.ts +3 -1
- package/dist/vue/index.js +233 -7
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -11637,7 +11637,65 @@ var stringStat = (stat, key) => {
|
|
|
11637
11637
|
const value = stat[key];
|
|
11638
11638
|
return typeof value === "string" ? value : undefined;
|
|
11639
11639
|
};
|
|
11640
|
+
var statKey = (stat) => String(stat.id ?? stringStat(stat, "ssrc") ?? numericStat(stat, "ssrc") ?? stringStat(stat, "trackIdentifier") ?? stringStat(stat, "mid") ?? "unknown");
|
|
11640
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";
|
|
11641
11699
|
var normalizeWebRTCStat = (stat) => {
|
|
11642
11700
|
const sample = {};
|
|
11643
11701
|
for (const [key, value] of Object.entries(stat)) {
|
|
@@ -11647,6 +11705,113 @@ var normalizeWebRTCStat = (stat) => {
|
|
|
11647
11705
|
}
|
|
11648
11706
|
return sample;
|
|
11649
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
|
+
};
|
|
11650
11815
|
var buildMediaResamplingPlan = (input) => {
|
|
11651
11816
|
const required = !formatMatches2(input.inputFormat, input.outputFormat);
|
|
11652
11817
|
return {
|
|
@@ -11883,12 +12048,64 @@ var collectMediaWebRTCStats = async (input) => {
|
|
|
11883
12048
|
const report = await input.peerConnection.getStats(input.selector ?? null);
|
|
11884
12049
|
return [...report.values()].map(normalizeWebRTCStat);
|
|
11885
12050
|
};
|
|
11886
|
-
var
|
|
11887
|
-
const stats =
|
|
11888
|
-
|
|
11889
|
-
|
|
11890
|
-
|
|
12051
|
+
var buildMediaWebRTCStreamContinuityReport = (input = {}) => {
|
|
12052
|
+
const stats = input.stats ?? [];
|
|
12053
|
+
const previousStats = input.previousStats ?? [];
|
|
12054
|
+
const issues = [];
|
|
12055
|
+
const previousByKey = new Map(previousStats.map((stat) => [statKey(stat), stat]));
|
|
12056
|
+
const audioRtp = stats.filter((stat) => (stat.type === "inbound-rtp" || stat.type === "outbound-rtp") && stringStat(stat, "kind") !== "video" && stringStat(stat, "mediaType") !== "video");
|
|
12057
|
+
const streams = audioRtp.map((stat) => {
|
|
12058
|
+
const direction = stat.type === "outbound-rtp" ? "outbound" : "inbound";
|
|
12059
|
+
const packetsKey = direction === "outbound" ? "packetsSent" : "packetsReceived";
|
|
12060
|
+
const bytesKey = direction === "outbound" ? "bytesSent" : "bytesReceived";
|
|
12061
|
+
const previous = previousByKey.get(statKey(stat));
|
|
12062
|
+
const currentPackets = numericStat(stat, packetsKey);
|
|
12063
|
+
const previousPackets = previous ? numericStat(previous, packetsKey) : undefined;
|
|
12064
|
+
const currentBytes = numericStat(stat, bytesKey);
|
|
12065
|
+
const previousBytes = previous ? numericStat(previous, bytesKey) : undefined;
|
|
12066
|
+
const timeDeltaMs = stat.timestamp !== undefined && previous?.timestamp !== undefined ? stat.timestamp - previous.timestamp : undefined;
|
|
12067
|
+
return {
|
|
12068
|
+
bytesDelta: currentBytes !== undefined && previousBytes !== undefined ? currentBytes - previousBytes : undefined,
|
|
12069
|
+
currentPackets,
|
|
12070
|
+
direction,
|
|
12071
|
+
id: statKey(stat),
|
|
12072
|
+
packetDelta: currentPackets !== undefined && previousPackets !== undefined ? currentPackets - previousPackets : undefined,
|
|
12073
|
+
previousPackets,
|
|
12074
|
+
timeDeltaMs
|
|
12075
|
+
};
|
|
11891
12076
|
});
|
|
12077
|
+
const inbound = streams.filter((stream) => stream.direction === "inbound");
|
|
12078
|
+
const outbound = streams.filter((stream) => stream.direction === "outbound");
|
|
12079
|
+
const maxObservedGapMs = max(streams.map((stream) => stream.timeDeltaMs).filter((value) => value !== undefined));
|
|
12080
|
+
const stalledInboundStreams = inbound.filter((stream) => input.maxInboundPacketStallMs !== undefined && stream.timeDeltaMs !== undefined && stream.timeDeltaMs >= input.maxInboundPacketStallMs && stream.packetDelta !== undefined && stream.packetDelta <= 0).length;
|
|
12081
|
+
const stalledOutboundStreams = outbound.filter((stream) => input.maxOutboundPacketStallMs !== undefined && stream.timeDeltaMs !== undefined && stream.timeDeltaMs >= input.maxOutboundPacketStallMs && stream.packetDelta !== undefined && stream.packetDelta <= 0).length;
|
|
12082
|
+
if (input.requireInboundAudio && inbound.length === 0) {
|
|
12083
|
+
pushIssue(issues, "error", "media.webrtc_inbound_audio_missing", "No inbound WebRTC audio RTP stream was observed.");
|
|
12084
|
+
}
|
|
12085
|
+
if (input.requireOutboundAudio && outbound.length === 0) {
|
|
12086
|
+
pushIssue(issues, "error", "media.webrtc_outbound_audio_missing", "No outbound WebRTC audio RTP stream was observed.");
|
|
12087
|
+
}
|
|
12088
|
+
if (input.maxGapMs !== undefined && maxObservedGapMs !== undefined && maxObservedGapMs > input.maxGapMs) {
|
|
12089
|
+
pushIssue(issues, "warning", "media.webrtc_stream_gap", `Observed WebRTC stream sample gap ${String(maxObservedGapMs)}ms above ${String(input.maxGapMs)}ms.`);
|
|
12090
|
+
}
|
|
12091
|
+
if (stalledInboundStreams > 0) {
|
|
12092
|
+
pushIssue(issues, "error", "media.webrtc_inbound_stalled", `${String(stalledInboundStreams)} inbound WebRTC audio stream(s) stopped receiving packets.`);
|
|
12093
|
+
}
|
|
12094
|
+
if (stalledOutboundStreams > 0) {
|
|
12095
|
+
pushIssue(issues, "error", "media.webrtc_outbound_stalled", `${String(stalledOutboundStreams)} outbound WebRTC audio stream(s) stopped sending packets.`);
|
|
12096
|
+
}
|
|
12097
|
+
return {
|
|
12098
|
+
checkedAt: Date.now(),
|
|
12099
|
+
inboundAudioStreams: inbound.length,
|
|
12100
|
+
issues,
|
|
12101
|
+
maxObservedGapMs,
|
|
12102
|
+
outboundAudioStreams: outbound.length,
|
|
12103
|
+
stalledInboundStreams,
|
|
12104
|
+
stalledOutboundStreams,
|
|
12105
|
+
status: issues.some((issue) => issue.severity === "error") ? "fail" : issues.length > 0 ? "warn" : "pass",
|
|
12106
|
+
streams,
|
|
12107
|
+
totalStats: stats.length
|
|
12108
|
+
};
|
|
11892
12109
|
};
|
|
11893
12110
|
var buildMediaPipelineCalibrationReport = (input = {}) => {
|
|
11894
12111
|
const frames = input.frames ?? [];
|
|
@@ -12196,23 +12413,169 @@ var createVoiceMediaPipelineRoutes = (options = {}) => {
|
|
|
12196
12413
|
}
|
|
12197
12414
|
return app;
|
|
12198
12415
|
};
|
|
12199
|
-
// src/
|
|
12416
|
+
// src/telephonyMediaRoutes.ts
|
|
12200
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
|
+
};
|
|
12201
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("'", "'");
|
|
12202
12545
|
var isMediaWebRTCStatsReport = (value) => {
|
|
12203
12546
|
const report = value;
|
|
12204
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);
|
|
12205
12548
|
};
|
|
12549
|
+
var isMediaWebRTCStreamContinuityReport = (value) => {
|
|
12550
|
+
const report = value;
|
|
12551
|
+
return !!report && typeof report === "object" && (report.status === "pass" || report.status === "warn" || report.status === "fail") && typeof report.inboundAudioStreams === "number" && typeof report.outboundAudioStreams === "number" && typeof report.stalledInboundStreams === "number" && typeof report.stalledOutboundStreams === "number" && Array.isArray(report.issues) && Array.isArray(report.streams);
|
|
12552
|
+
};
|
|
12206
12553
|
var isBrowserMediaPostBody = (value) => {
|
|
12207
12554
|
const body = value;
|
|
12208
12555
|
return !!body && isMediaWebRTCStatsReport(body.report);
|
|
12209
12556
|
};
|
|
12557
|
+
var mergeIssues = (report, continuity) => {
|
|
12558
|
+
if (!continuity) {
|
|
12559
|
+
return report;
|
|
12560
|
+
}
|
|
12561
|
+
const issues = [
|
|
12562
|
+
...report.issues,
|
|
12563
|
+
...continuity.issues
|
|
12564
|
+
];
|
|
12565
|
+
const status = report.status === "fail" || continuity.status === "fail" ? "fail" : report.status === "warn" || continuity.status === "warn" ? "warn" : "pass";
|
|
12566
|
+
return {
|
|
12567
|
+
...report,
|
|
12568
|
+
issues,
|
|
12569
|
+
status
|
|
12570
|
+
};
|
|
12571
|
+
};
|
|
12210
12572
|
var toBrowserMediaSample = (event) => {
|
|
12211
12573
|
if (event.type !== "client.browser_media" || !isMediaWebRTCStatsReport(event.payload.report)) {
|
|
12212
12574
|
return;
|
|
12213
12575
|
}
|
|
12214
12576
|
return {
|
|
12215
12577
|
at: event.at,
|
|
12578
|
+
continuity: isMediaWebRTCStreamContinuityReport(event.payload.continuity) ? event.payload.continuity : undefined,
|
|
12216
12579
|
report: event.payload.report,
|
|
12217
12580
|
scenarioId: event.scenarioId,
|
|
12218
12581
|
sessionId: event.sessionId,
|
|
@@ -12228,29 +12591,34 @@ var summarizeVoiceBrowserMedia = async (options) => {
|
|
|
12228
12591
|
const latest = recent[0];
|
|
12229
12592
|
const maxAgeMs = options.maxAgeMs ?? 30000;
|
|
12230
12593
|
const stale = latest ? Date.now() - latest.at > maxAgeMs : false;
|
|
12594
|
+
const latestReport = latest ? mergeIssues(latest.report, latest.continuity) : undefined;
|
|
12231
12595
|
return {
|
|
12232
12596
|
checkedAt: Date.now(),
|
|
12233
12597
|
latest,
|
|
12234
12598
|
recent,
|
|
12235
12599
|
stale,
|
|
12236
|
-
status: latest ?
|
|
12600
|
+
status: latest ? latestReport?.status === "pass" && !stale ? "pass" : stale ? "warn" : latestReport?.status ?? latest.report.status : "empty",
|
|
12237
12601
|
total: recent.length
|
|
12238
12602
|
};
|
|
12239
12603
|
};
|
|
12240
12604
|
var getLatestVoiceBrowserMediaReport = async (options) => {
|
|
12241
12605
|
const summary = await summarizeVoiceBrowserMedia(options);
|
|
12242
|
-
return summary.latest
|
|
12606
|
+
return summary.latest ? mergeIssues(summary.latest.report, summary.latest.continuity) : undefined;
|
|
12243
12607
|
};
|
|
12244
12608
|
var renderVoiceBrowserMediaHTML = (report, options = {}) => {
|
|
12245
12609
|
const title = options.title ?? "Voice Browser Media";
|
|
12246
12610
|
const latest = report.latest?.report;
|
|
12247
|
-
const
|
|
12248
|
-
|
|
12611
|
+
const latestContinuity = report.latest?.continuity;
|
|
12612
|
+
const rows = report.recent.slice(0, 20).map((sample) => {
|
|
12613
|
+
const stalledStreams = (sample.continuity?.stalledInboundStreams ?? 0) + (sample.continuity?.stalledOutboundStreams ?? 0);
|
|
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>`;
|
|
12615
|
+
}).join("");
|
|
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>`;
|
|
12249
12617
|
};
|
|
12250
12618
|
var createVoiceBrowserMediaRoutes = (options) => {
|
|
12251
12619
|
const path = options.path ?? "/api/voice/browser-media";
|
|
12252
12620
|
const htmlPath = options.htmlPath === undefined ? "/voice/browser-media" : options.htmlPath;
|
|
12253
|
-
const routes = new
|
|
12621
|
+
const routes = new Elysia14({
|
|
12254
12622
|
name: options.name ?? "absolutejs-voice-browser-media"
|
|
12255
12623
|
});
|
|
12256
12624
|
routes.get(path, () => summarizeVoiceBrowserMedia(options));
|
|
@@ -12261,6 +12629,7 @@ var createVoiceBrowserMediaRoutes = (options) => {
|
|
|
12261
12629
|
await options.store.append({
|
|
12262
12630
|
at: typeof body.at === "number" ? body.at : Date.now(),
|
|
12263
12631
|
payload: {
|
|
12632
|
+
continuity: isMediaWebRTCStreamContinuityReport(body.continuity) ? body.continuity : undefined,
|
|
12264
12633
|
report: body.report
|
|
12265
12634
|
},
|
|
12266
12635
|
scenarioId: typeof body.scenarioId === "string" ? body.scenarioId : undefined,
|
|
@@ -12283,8 +12652,8 @@ var createVoiceBrowserMediaRoutes = (options) => {
|
|
|
12283
12652
|
return routes;
|
|
12284
12653
|
};
|
|
12285
12654
|
// src/demoReadyRoutes.ts
|
|
12286
|
-
import { Elysia as
|
|
12287
|
-
var
|
|
12655
|
+
import { Elysia as Elysia15 } from "elysia";
|
|
12656
|
+
var escapeHtml18 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
12288
12657
|
var rollupStatus2 = (sections) => sections.some((section) => section.status === "fail") ? "fail" : sections.some((section) => section.status === "warn") ? "warn" : "pass";
|
|
12289
12658
|
var resolveLoader = async (loader, input) => typeof loader === "function" ? await loader(input) : loader;
|
|
12290
12659
|
var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
@@ -12368,17 +12737,17 @@ var buildVoiceDemoReadyReport = async (options, input = {}) => {
|
|
|
12368
12737
|
};
|
|
12369
12738
|
};
|
|
12370
12739
|
var renderVoiceDemoReadyHTML = (report) => {
|
|
12371
|
-
const sections = report.sections.map((section) => `<article class="section ${
|
|
12372
|
-
<div><span>${
|
|
12373
|
-
<strong>${
|
|
12374
|
-
${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>` : ""}
|
|
12375
12744
|
</article>`).join("");
|
|
12376
|
-
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>`;
|
|
12377
12746
|
};
|
|
12378
12747
|
var createVoiceDemoReadyRoutes = (options) => {
|
|
12379
12748
|
const path = options.path ?? "/api/demo-ready";
|
|
12380
12749
|
const htmlPath = options.htmlPath ?? "/demo-ready";
|
|
12381
|
-
const routes = new
|
|
12750
|
+
const routes = new Elysia15({
|
|
12382
12751
|
name: options.name ?? "absolutejs-voice-demo-ready"
|
|
12383
12752
|
});
|
|
12384
12753
|
routes.get(path, async ({ query, request }) => buildVoiceDemoReadyReport(options, { query, request }));
|
|
@@ -12397,7 +12766,7 @@ var createVoiceDemoReadyRoutes = (options) => {
|
|
|
12397
12766
|
return routes;
|
|
12398
12767
|
};
|
|
12399
12768
|
// src/deliverySinkRoutes.ts
|
|
12400
|
-
import { Elysia as
|
|
12769
|
+
import { Elysia as Elysia16 } from "elysia";
|
|
12401
12770
|
|
|
12402
12771
|
// src/queue.ts
|
|
12403
12772
|
var releaseLeaseScript = `
|
|
@@ -13340,7 +13709,7 @@ var createVoiceOpsTaskProcessorWorkerLoop = (options) => {
|
|
|
13340
13709
|
};
|
|
13341
13710
|
|
|
13342
13711
|
// src/deliverySinkRoutes.ts
|
|
13343
|
-
var
|
|
13712
|
+
var escapeHtml19 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13344
13713
|
var deliveryStatus = (summary) => {
|
|
13345
13714
|
if (!summary) {
|
|
13346
13715
|
return "warn";
|
|
@@ -13439,13 +13808,13 @@ var renderSurfaceCard = (surface) => {
|
|
|
13439
13808
|
return "";
|
|
13440
13809
|
}
|
|
13441
13810
|
const value = `${surface.summary.delivered}/${surface.summary.total}`;
|
|
13442
|
-
const body = `<span>${
|
|
13443
|
-
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>`;
|
|
13444
13813
|
};
|
|
13445
13814
|
var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
13446
13815
|
const title = options.title ?? "AbsoluteJS Voice Delivery Sinks";
|
|
13447
|
-
const sinks = report.sinks.length ? report.sinks.map((sink) => `<article><span>${
|
|
13448
|
-
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({
|
|
13449
13818
|
auditDeliveries: { store: runtimeStorage.auditDeliveries },
|
|
13450
13819
|
traceDeliveries: { store: runtimeStorage.traceDeliveries },
|
|
13451
13820
|
sinks: createVoiceDeliverySinkPair({
|
|
@@ -13457,7 +13826,7 @@ var renderVoiceDeliverySinkHTML = (report, options = {}) => {
|
|
|
13457
13826
|
var createVoiceDeliverySinkRoutes = (options) => {
|
|
13458
13827
|
const path = options.path ?? "/api/voice-delivery-sinks";
|
|
13459
13828
|
const htmlPath = options.htmlPath === undefined ? "/delivery-sinks" : options.htmlPath;
|
|
13460
|
-
const routes = new
|
|
13829
|
+
const routes = new Elysia16({
|
|
13461
13830
|
name: options.name ?? "absolutejs-voice-delivery-sinks"
|
|
13462
13831
|
}).get(path, () => buildVoiceDeliverySinkReport(options));
|
|
13463
13832
|
if (htmlPath !== false) {
|
|
@@ -13475,7 +13844,7 @@ var createVoiceDeliverySinkRoutes = (options) => {
|
|
|
13475
13844
|
return routes;
|
|
13476
13845
|
};
|
|
13477
13846
|
// src/opsActionAuditRoutes.ts
|
|
13478
|
-
import { Elysia as
|
|
13847
|
+
import { Elysia as Elysia17 } from "elysia";
|
|
13479
13848
|
var readRecordBody = (body) => {
|
|
13480
13849
|
if (!body || typeof body !== "object") {
|
|
13481
13850
|
throw new Error("Voice ops action audit requires a JSON body.");
|
|
@@ -13550,7 +13919,7 @@ var createVoiceOpsActionAuditRoutes = (options) => {
|
|
|
13550
13919
|
const path = options.path ?? "/api/voice/ops-actions/audit";
|
|
13551
13920
|
const historyPath = options.historyPath === undefined ? "/api/voice/ops-actions/history" : options.historyPath;
|
|
13552
13921
|
const historyHtmlPath = options.historyHtmlPath === undefined ? "/voice/ops-actions" : options.historyHtmlPath;
|
|
13553
|
-
const routes = new
|
|
13922
|
+
const routes = new Elysia17({
|
|
13554
13923
|
name: options.name ?? "absolutejs-voice-ops-action-audit"
|
|
13555
13924
|
}).post(path, async ({ body, request, set }) => {
|
|
13556
13925
|
try {
|
|
@@ -13600,13 +13969,13 @@ var buildVoiceOpsActionHistoryReport = async (options) => {
|
|
|
13600
13969
|
total: entries.length
|
|
13601
13970
|
};
|
|
13602
13971
|
};
|
|
13603
|
-
var
|
|
13972
|
+
var escapeHtml20 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13604
13973
|
var renderVoiceOpsActionHistoryHTML = (report) => {
|
|
13605
|
-
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("");
|
|
13606
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>`;
|
|
13607
13976
|
};
|
|
13608
13977
|
// src/platformCoverage.ts
|
|
13609
|
-
import { Elysia as
|
|
13978
|
+
import { Elysia as Elysia18 } from "elysia";
|
|
13610
13979
|
var buildVoicePlatformCoverageSummary = (input) => {
|
|
13611
13980
|
const coverage = input.coverage ?? [];
|
|
13612
13981
|
const ok = input.ok ?? (coverage.length > 0 && coverage.every((surface) => surface.status === "pass"));
|
|
@@ -13667,7 +14036,7 @@ var assertVoicePlatformCoverage = (summary, input = {}) => {
|
|
|
13667
14036
|
var normalizeCoverageSummary = (value) => ("status" in value) && ("total" in value) && ("coverage" in value) ? value : buildVoicePlatformCoverageSummary(value);
|
|
13668
14037
|
var createVoicePlatformCoverageRoutes = (options) => {
|
|
13669
14038
|
const path = options.path ?? "/api/voice/platform-coverage";
|
|
13670
|
-
const routes = new
|
|
14039
|
+
const routes = new Elysia18({
|
|
13671
14040
|
name: options.name ?? "absolutejs-voice-platform-coverage"
|
|
13672
14041
|
});
|
|
13673
14042
|
routes.get(path, async () => {
|
|
@@ -13679,8 +14048,8 @@ var createVoicePlatformCoverageRoutes = (options) => {
|
|
|
13679
14048
|
return routes;
|
|
13680
14049
|
};
|
|
13681
14050
|
// src/competitiveCoverage.ts
|
|
13682
|
-
import { Elysia as
|
|
13683
|
-
var
|
|
14051
|
+
import { Elysia as Elysia19 } from "elysia";
|
|
14052
|
+
var escapeHtml21 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
13684
14053
|
var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
|
|
13685
14054
|
var resolveSurfaceStatus = (surface) => {
|
|
13686
14055
|
if (surface.status)
|
|
@@ -13848,24 +14217,24 @@ var renderVoiceCompetitiveCoverageMarkdown = (report, title = "Voice Competitive
|
|
|
13848
14217
|
`);
|
|
13849
14218
|
var renderVoiceCompetitiveCoverageHTML = (report, title = "Voice Competitive Coverage") => {
|
|
13850
14219
|
const surfaceCards = report.surfaces.map((surface) => {
|
|
13851
|
-
const evidence = (surface.evidence ?? []).map((item) => `<li><strong>${
|
|
13852
|
-
return `<article class="surface ${
|
|
13853
|
-
<header><div><p class="eyebrow">${
|
|
13854
|
-
<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>
|
|
13855
14224
|
<dl>
|
|
13856
|
-
<div><dt>Competitors</dt><dd>${
|
|
13857
|
-
<div><dt>Operations record</dt><dd>${
|
|
13858
|
-
<div><dt>Readiness gate</dt><dd>${
|
|
13859
|
-
<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>
|
|
13860
14229
|
</dl>
|
|
13861
|
-
${surface.remainingGap ? `<p class="gap"><strong>Gap:</strong> ${
|
|
13862
|
-
${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>` : ""}
|
|
13863
14232
|
${evidence ? `<h3>Evidence</h3><ul>${evidence}</ul>` : '<p class="muted">No evidence links configured.</p>'}
|
|
13864
14233
|
</article>`;
|
|
13865
14234
|
}).join(`
|
|
13866
14235
|
`);
|
|
13867
|
-
const issueList = report.issues.map((issue) => `<li class="${
|
|
13868
|
-
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>`;
|
|
13869
14238
|
};
|
|
13870
14239
|
var normalizeCompetitiveCoverageReport = (value) => ("status" in value) && ("summary" in value) && ("issues" in value) ? value : buildVoiceCompetitiveCoverageReport(value);
|
|
13871
14240
|
var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
@@ -13878,7 +14247,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
13878
14247
|
const value = typeof options.source === "function" ? await options.source() : options.source;
|
|
13879
14248
|
return normalizeCompetitiveCoverageReport(value);
|
|
13880
14249
|
};
|
|
13881
|
-
const app = new
|
|
14250
|
+
const app = new Elysia19({
|
|
13882
14251
|
name: options.name ?? "absolutejs-voice-competitive-coverage"
|
|
13883
14252
|
}).get(path, async () => new Response(JSON.stringify(await report(), null, 2), {
|
|
13884
14253
|
headers: {
|
|
@@ -13909,7 +14278,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
13909
14278
|
return app;
|
|
13910
14279
|
};
|
|
13911
14280
|
// src/proofTrends.ts
|
|
13912
|
-
import { Elysia as
|
|
14281
|
+
import { Elysia as Elysia20 } from "elysia";
|
|
13913
14282
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
13914
14283
|
var normalizeMaxAgeMs = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS;
|
|
13915
14284
|
var toTimeMs = (value) => {
|
|
@@ -14060,7 +14429,7 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
|
|
|
14060
14429
|
};
|
|
14061
14430
|
var createVoiceProofTrendRoutes = (options) => {
|
|
14062
14431
|
const path = options.path ?? "/api/voice/proof-trends";
|
|
14063
|
-
const routes = new
|
|
14432
|
+
const routes = new Elysia20({
|
|
14064
14433
|
name: options.name ?? "absolutejs-voice-proof-trends"
|
|
14065
14434
|
});
|
|
14066
14435
|
routes.get(path, async () => {
|
|
@@ -14093,11 +14462,11 @@ var formatVoiceProofTrendAge = (ageMs) => {
|
|
|
14093
14462
|
return `${days}d ${hours % 24}h`;
|
|
14094
14463
|
};
|
|
14095
14464
|
// src/providerDecisionTraces.ts
|
|
14096
|
-
import { Elysia as
|
|
14465
|
+
import { Elysia as Elysia22 } from "elysia";
|
|
14097
14466
|
|
|
14098
14467
|
// src/resilienceRoutes.ts
|
|
14099
|
-
import { Elysia as
|
|
14100
|
-
var
|
|
14468
|
+
import { Elysia as Elysia21 } from "elysia";
|
|
14469
|
+
var escapeHtml22 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14101
14470
|
var getString7 = (value) => typeof value === "string" ? value : undefined;
|
|
14102
14471
|
var getNumber5 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
14103
14472
|
var getBoolean2 = (value) => value === true;
|
|
@@ -14245,13 +14614,13 @@ var summarizeRoutingEvents = (events) => {
|
|
|
14245
14614
|
};
|
|
14246
14615
|
var renderProviderCards = (title, providers) => {
|
|
14247
14616
|
if (providers.length === 0) {
|
|
14248
|
-
return `<p class="muted">No ${
|
|
14617
|
+
return `<p class="muted">No ${escapeHtml22(title)} provider health yet.</p>`;
|
|
14249
14618
|
}
|
|
14250
14619
|
return `<div class="provider-grid">${providers.map((provider) => `
|
|
14251
|
-
<article class="card provider ${
|
|
14620
|
+
<article class="card provider ${escapeHtml22(provider.status)}">
|
|
14252
14621
|
<div class="card-header">
|
|
14253
|
-
<strong>${
|
|
14254
|
-
<span>${
|
|
14622
|
+
<strong>${escapeHtml22(provider.provider)}</strong>
|
|
14623
|
+
<span>${escapeHtml22(provider.status)}${provider.recommended ? " \xB7 recommended" : ""}</span>
|
|
14255
14624
|
</div>
|
|
14256
14625
|
<dl>
|
|
14257
14626
|
<div><dt>Runs</dt><dd>${provider.runCount}</dd></div>
|
|
@@ -14260,7 +14629,7 @@ var renderProviderCards = (title, providers) => {
|
|
|
14260
14629
|
<div><dt>Timeouts</dt><dd>${provider.timeoutCount}</dd></div>
|
|
14261
14630
|
<div><dt>Fallbacks</dt><dd>${provider.fallbackCount}</dd></div>
|
|
14262
14631
|
</dl>
|
|
14263
|
-
${provider.lastError ? `<p class="muted">${
|
|
14632
|
+
${provider.lastError ? `<p class="muted">${escapeHtml22(provider.lastError)}</p>` : ""}
|
|
14264
14633
|
</article>
|
|
14265
14634
|
`).join("")}</div>`;
|
|
14266
14635
|
};
|
|
@@ -14269,24 +14638,24 @@ var renderTimeline2 = (events) => {
|
|
|
14269
14638
|
return '<p class="muted">No provider routing events yet. Run the app or simulate provider failover.</p>';
|
|
14270
14639
|
}
|
|
14271
14640
|
return `<div class="timeline">${events.slice(0, 40).map((event) => `
|
|
14272
|
-
<article class="card event ${
|
|
14641
|
+
<article class="card event ${escapeHtml22(event.status ?? "unknown")}">
|
|
14273
14642
|
<div class="card-header">
|
|
14274
|
-
<strong>${
|
|
14643
|
+
<strong>${escapeHtml22(event.kind.toUpperCase())} ${escapeHtml22(event.operation ?? "generate")}</strong>
|
|
14275
14644
|
<span>${new Date(event.at).toLocaleString()}</span>
|
|
14276
14645
|
</div>
|
|
14277
14646
|
<p>
|
|
14278
|
-
<span class="pill">${
|
|
14279
|
-
<span class="pill">provider: ${
|
|
14280
|
-
${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>` : ""}
|
|
14281
14650
|
${event.timedOut ? '<span class="pill danger">timed out</span>' : ""}
|
|
14282
14651
|
</p>
|
|
14283
14652
|
<dl>
|
|
14284
14653
|
<div><dt>Attempt</dt><dd>${event.attempt ?? 0}</dd></div>
|
|
14285
14654
|
<div><dt>Elapsed</dt><dd>${event.elapsedMs ?? 0}ms</dd></div>
|
|
14286
14655
|
<div><dt>Budget</dt><dd>${event.latencyBudgetMs ?? 0}ms</dd></div>
|
|
14287
|
-
<div><dt>Session</dt><dd>${
|
|
14656
|
+
<div><dt>Session</dt><dd>${escapeHtml22(event.sessionId)}</dd></div>
|
|
14288
14657
|
</dl>
|
|
14289
|
-
${event.error ? `<p class="muted">${
|
|
14658
|
+
${event.error ? `<p class="muted">${escapeHtml22(event.error)}</p>` : ""}
|
|
14290
14659
|
</article>
|
|
14291
14660
|
`).join("")}</div>`;
|
|
14292
14661
|
};
|
|
@@ -14296,9 +14665,9 @@ var renderSessionKind = (kind, summary) => {
|
|
|
14296
14665
|
const status = latest?.status ?? "idle";
|
|
14297
14666
|
const fallback = latest?.fallbackProvider && latest.fallbackProvider !== provider ? ` -> ${latest.fallbackProvider}` : "";
|
|
14298
14667
|
return `<div>
|
|
14299
|
-
<dt>${
|
|
14300
|
-
<dd>${
|
|
14301
|
-
<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>
|
|
14302
14671
|
</div>`;
|
|
14303
14672
|
};
|
|
14304
14673
|
var renderSessionSummaries = (sessions) => {
|
|
@@ -14306,10 +14675,10 @@ var renderSessionSummaries = (sessions) => {
|
|
|
14306
14675
|
return '<p class="muted">No call-level routing summaries yet. Run a voice session or provider simulation.</p>';
|
|
14307
14676
|
}
|
|
14308
14677
|
return `<div class="session-grid">${sessions.slice(0, 12).map((session) => `
|
|
14309
|
-
<article class="card session ${
|
|
14678
|
+
<article class="card session ${escapeHtml22(session.status)}">
|
|
14310
14679
|
<div class="card-header">
|
|
14311
|
-
<strong>${
|
|
14312
|
-
<span>${
|
|
14680
|
+
<strong>${escapeHtml22(session.sessionId)}</strong>
|
|
14681
|
+
<span>${escapeHtml22(session.status)}</span>
|
|
14313
14682
|
</div>
|
|
14314
14683
|
<p>
|
|
14315
14684
|
<span class="pill">${session.eventCount} routing events</span>
|
|
@@ -14336,21 +14705,21 @@ var renderSimulationControls = (kind, simulation) => {
|
|
|
14336
14705
|
const pathPrefix = simulation.pathPrefix ?? `/api/${kind}-simulate`;
|
|
14337
14706
|
const failureProviders = simulation.failureProviders ?? configuredProviders.map(({ provider }) => provider);
|
|
14338
14707
|
const canFail = (provider) => configuredProviders.some((entry) => entry.provider === provider) && (!simulation.fallbackRequiredProvider || configuredProviders.some((entry) => entry.provider === simulation.fallbackRequiredProvider));
|
|
14339
|
-
return `<div class="simulate-panel" data-sim-kind="${kind}" data-sim-prefix="${
|
|
14340
|
-
<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>
|
|
14341
14710
|
<div class="simulate-actions">
|
|
14342
|
-
${failureProviders.map((provider) => `<button type="button" data-provider-fail="${
|
|
14343
|
-
${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("")}
|
|
14344
14713
|
</div>
|
|
14345
|
-
${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>` : ""}
|
|
14346
14715
|
<pre class="simulate-output" hidden></pre>
|
|
14347
14716
|
</div>`;
|
|
14348
14717
|
};
|
|
14349
14718
|
var renderVoiceResilienceHTML = (input) => {
|
|
14350
14719
|
const summary = summarizeRoutingEvents(input.routingEvents);
|
|
14351
|
-
const kindCounts = [...summary.byKind.entries()].map(([kind, count]) => `<span class="pill">${
|
|
14352
|
-
const links = input.links?.length ? input.links.map((link) => `<a href="${
|
|
14353
|
-
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({
|
|
14354
14723
|
kind: 'stt',
|
|
14355
14724
|
providers: ['deepgram', 'assemblyai'],
|
|
14356
14725
|
fallback: ['deepgram', 'assemblyai'],
|
|
@@ -14388,7 +14757,7 @@ app.use(
|
|
|
14388
14757
|
<head>
|
|
14389
14758
|
<meta charset="utf-8" />
|
|
14390
14759
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
14391
|
-
<title>${
|
|
14760
|
+
<title>${escapeHtml22(input.title ?? "AbsoluteJS Voice Resilience")}</title>
|
|
14392
14761
|
<style>
|
|
14393
14762
|
:root { color-scheme: dark; }
|
|
14394
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; }
|
|
@@ -14540,7 +14909,7 @@ var registerSimulationRoutes = (routes, simulation, defaultPathPrefix) => {
|
|
|
14540
14909
|
};
|
|
14541
14910
|
var createVoiceResilienceRoutes = (options) => {
|
|
14542
14911
|
const path = options.path ?? "/resilience";
|
|
14543
|
-
const routes = new
|
|
14912
|
+
const routes = new Elysia21({
|
|
14544
14913
|
name: options.name ?? "absolutejs-voice-resilience"
|
|
14545
14914
|
}).get(path, async () => {
|
|
14546
14915
|
const events = await options.store.list();
|
|
@@ -14581,7 +14950,7 @@ var createVoiceResilienceRoutes = (options) => {
|
|
|
14581
14950
|
};
|
|
14582
14951
|
|
|
14583
14952
|
// src/providerDecisionTraces.ts
|
|
14584
|
-
var
|
|
14953
|
+
var escapeHtml23 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
14585
14954
|
var getString8 = (value) => typeof value === "string" ? value : undefined;
|
|
14586
14955
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
14587
14956
|
var isDecisionTrace = (event) => Boolean(event && typeof event === "object" && "provider" in event && "reason" in event && "sessionId" in event && "status" in event && "surface" in event);
|
|
@@ -14822,7 +15191,7 @@ var renderVoiceProviderDecisionTraceHTML = (report, title = "Provider Decision T
|
|
|
14822
15191
|
<head>
|
|
14823
15192
|
<meta charset="utf-8" />
|
|
14824
15193
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
14825
|
-
<title>${
|
|
15194
|
+
<title>${escapeHtml23(title)}</title>
|
|
14826
15195
|
<style>
|
|
14827
15196
|
body{font-family:ui-sans-serif,system-ui,sans-serif;margin:0;background:#f8fafc;color:#0f172a}
|
|
14828
15197
|
main{max-width:1100px;margin:0 auto;padding:32px}
|
|
@@ -14836,8 +15205,8 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
14836
15205
|
</head>
|
|
14837
15206
|
<body>
|
|
14838
15207
|
<main>
|
|
14839
|
-
<p class="status ${report.status}">${
|
|
14840
|
-
<h1>${
|
|
15208
|
+
<p class="status ${report.status}">${escapeHtml23(report.status)}</p>
|
|
15209
|
+
<h1>${escapeHtml23(title)}</h1>
|
|
14841
15210
|
<p class="muted">Runtime proof for why providers were selected, skipped, failed, or recovered by fallback.</p>
|
|
14842
15211
|
<section class="grid">
|
|
14843
15212
|
<article class="card"><strong>${String(report.summary.decisions)}</strong><p>decisions</p></article>
|
|
@@ -14848,10 +15217,10 @@ code{background:#e2e8f0;border-radius:8px;padding:2px 6px}
|
|
|
14848
15217
|
</section>
|
|
14849
15218
|
<section class="surfaces">
|
|
14850
15219
|
${report.surfaces.map((surface) => `<article class="surface">
|
|
14851
|
-
<header><strong>${
|
|
15220
|
+
<header><strong>${escapeHtml23(surface.surface)}</strong> <span class="status ${surface.status}">${escapeHtml23(surface.status)}</span></header>
|
|
14852
15221
|
<p>${String(surface.decisions)} decision(s), ${String(surface.fallbacks)} fallback(s), ${String(surface.degraded)} degraded decision(s), ${String(surface.errors)} error(s).</p>
|
|
14853
|
-
<p class="muted">Providers: ${
|
|
14854
|
-
<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>
|
|
14855
15224
|
</article>`).join(`
|
|
14856
15225
|
`)}
|
|
14857
15226
|
</section>
|
|
@@ -14865,7 +15234,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
14865
15234
|
const headers = options.headers ?? {};
|
|
14866
15235
|
const title = options.title ?? "Provider Decision Traces";
|
|
14867
15236
|
const report = () => buildVoiceProviderDecisionTraceReport(options);
|
|
14868
|
-
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), {
|
|
14869
15238
|
headers: {
|
|
14870
15239
|
"content-type": "application/json; charset=utf-8",
|
|
14871
15240
|
...headers
|
|
@@ -14893,7 +15262,7 @@ var createVoiceProviderDecisionTraceRoutes = (options) => {
|
|
|
14893
15262
|
return app;
|
|
14894
15263
|
};
|
|
14895
15264
|
// src/sloCalibration.ts
|
|
14896
|
-
import { Elysia as
|
|
15265
|
+
import { Elysia as Elysia23 } from "elysia";
|
|
14897
15266
|
var DEFAULT_HEADROOM_MULTIPLIER = 1.5;
|
|
14898
15267
|
var DEFAULT_WARN_RATIO = 0.8;
|
|
14899
15268
|
var DEFAULT_MIN_PASSING_RUNS = 3;
|
|
@@ -15073,7 +15442,7 @@ var buildVoiceSloReadinessThresholdReport = (input, options = {}) => {
|
|
|
15073
15442
|
};
|
|
15074
15443
|
};
|
|
15075
15444
|
var escapeMarkdown2 = (value) => value.replaceAll("|", "\\|");
|
|
15076
|
-
var
|
|
15445
|
+
var escapeHtml24 = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15077
15446
|
var formatMs = (value) => value === undefined ? "n/a" : `${value.toLocaleString()} ms`;
|
|
15078
15447
|
var readinessThresholdRows = (report) => [
|
|
15079
15448
|
{
|
|
@@ -15164,15 +15533,15 @@ ${report.issues.map((issue) => `- ${issue}`).join(`
|
|
|
15164
15533
|
};
|
|
15165
15534
|
var renderVoiceSloReadinessThresholdHTML = (report, options = {}) => {
|
|
15166
15535
|
const title = options.title ?? "Calibration -> Active Readiness Gate";
|
|
15167
|
-
const rows = readinessThresholdRows(report).map((row) => `<tr><td>${
|
|
15168
|
-
const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${
|
|
15169
|
-
const sources = report.sources.length === 0 ? "<li>n/a</li>" : report.sources.map((source) => `<li><code>${
|
|
15170
|
-
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>`;
|
|
15171
15540
|
};
|
|
15172
15541
|
var createVoiceSloCalibrationRoutes = (options) => {
|
|
15173
15542
|
const path = options.path ?? "/api/voice/slo-calibration";
|
|
15174
15543
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-calibration.md" : options.markdownPath;
|
|
15175
|
-
const routes = new
|
|
15544
|
+
const routes = new Elysia23({
|
|
15176
15545
|
name: options.name ?? "absolutejs-voice-slo-calibration"
|
|
15177
15546
|
});
|
|
15178
15547
|
const loadReport = async () => buildVoiceSloCalibrationReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -15196,7 +15565,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
15196
15565
|
const path = options.path ?? "/api/voice/slo-readiness-thresholds";
|
|
15197
15566
|
const htmlPath = options.htmlPath === undefined ? "/voice/slo-readiness-thresholds" : options.htmlPath;
|
|
15198
15567
|
const markdownPath = options.markdownPath === undefined ? "/voice/slo-readiness-thresholds.md" : options.markdownPath;
|
|
15199
|
-
const routes = new
|
|
15568
|
+
const routes = new Elysia23({
|
|
15200
15569
|
name: options.name ?? "absolutejs-voice-slo-readiness-thresholds"
|
|
15201
15570
|
});
|
|
15202
15571
|
const loadReport = async () => buildVoiceSloReadinessThresholdReport(typeof options.source === "function" ? await options.source() : options.source, options);
|
|
@@ -15230,7 +15599,7 @@ var createVoiceSloReadinessThresholdRoutes = (options) => {
|
|
|
15230
15599
|
return routes;
|
|
15231
15600
|
};
|
|
15232
15601
|
// src/liveOps.ts
|
|
15233
|
-
import { Elysia as
|
|
15602
|
+
import { Elysia as Elysia24 } from "elysia";
|
|
15234
15603
|
var VOICE_LIVE_OPS_ACTIONS = [
|
|
15235
15604
|
"assign",
|
|
15236
15605
|
"create-task",
|
|
@@ -15540,7 +15909,7 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
15540
15909
|
const controller = createVoiceLiveOpsController(options);
|
|
15541
15910
|
const path = options.path ?? "/api/voice/live-ops/action";
|
|
15542
15911
|
const controlPath = options.controlPath ?? "/api/voice/live-ops/control/:sessionId";
|
|
15543
|
-
return new
|
|
15912
|
+
return new Elysia24({
|
|
15544
15913
|
name: options.name ?? "absolutejs-voice-live-ops"
|
|
15545
15914
|
}).post(path, async ({ request, set }) => {
|
|
15546
15915
|
try {
|
|
@@ -15562,15 +15931,15 @@ var createVoiceLiveOpsRoutes = (options = {}) => {
|
|
|
15562
15931
|
});
|
|
15563
15932
|
};
|
|
15564
15933
|
// src/deliveryRuntime.ts
|
|
15565
|
-
import { Elysia as
|
|
15934
|
+
import { Elysia as Elysia25 } from "elysia";
|
|
15566
15935
|
import { mkdir } from "fs/promises";
|
|
15567
15936
|
import { dirname, join } from "path";
|
|
15568
|
-
var
|
|
15937
|
+
var escapeHtml25 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
15569
15938
|
var renderSummaryCard = (label, summary) => {
|
|
15570
15939
|
if (!summary) {
|
|
15571
|
-
return `<article><span>${
|
|
15940
|
+
return `<article><span>${escapeHtml25(label)}</span><strong>Disabled</strong><p class="muted">No worker configured.</p></article>`;
|
|
15572
15941
|
}
|
|
15573
|
-
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>`;
|
|
15574
15943
|
};
|
|
15575
15944
|
var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
15576
15945
|
audit: leases,
|
|
@@ -15781,9 +16150,9 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
15781
16150
|
});
|
|
15782
16151
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
15783
16152
|
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
15784
|
-
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${
|
|
15785
|
-
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${
|
|
15786
|
-
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(
|
|
15787
16156
|
createVoiceDeliveryRuntimePresetConfig({
|
|
15788
16157
|
audit: {
|
|
15789
16158
|
deliveries: runtimeStorage.auditDeliveries,
|
|
@@ -15809,14 +16178,14 @@ app.use(
|
|
|
15809
16178
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
15810
16179
|
})
|
|
15811
16180
|
);`);
|
|
15812
|
-
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>`;
|
|
15813
16182
|
};
|
|
15814
16183
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
15815
16184
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
15816
16185
|
const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
|
|
15817
16186
|
const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
|
|
15818
16187
|
const requeueDeadLettersPath = options.requeueDeadLettersPath === undefined ? "/api/voice-delivery-runtime/requeue-dead-letters" : options.requeueDeadLettersPath;
|
|
15819
|
-
const routes = new
|
|
16188
|
+
const routes = new Elysia25({
|
|
15820
16189
|
name: options.name ?? "absolutejs-voice-delivery-runtime"
|
|
15821
16190
|
}).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
|
|
15822
16191
|
if (tickPath !== false) {
|
|
@@ -15852,7 +16221,7 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
15852
16221
|
return routes;
|
|
15853
16222
|
};
|
|
15854
16223
|
// src/dataControl.ts
|
|
15855
|
-
import { Elysia as
|
|
16224
|
+
import { Elysia as Elysia26 } from "elysia";
|
|
15856
16225
|
var voiceComplianceRedactionDefaults = {
|
|
15857
16226
|
keys: [
|
|
15858
16227
|
"apiKey",
|
|
@@ -16091,7 +16460,7 @@ var parseRetentionScopes = (value) => {
|
|
|
16091
16460
|
const allowed = new Set(allRetentionScopes);
|
|
16092
16461
|
return value.split(",").map((entry) => entry.trim()).filter((entry) => allowed.has(entry));
|
|
16093
16462
|
};
|
|
16094
|
-
var
|
|
16463
|
+
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16095
16464
|
var buildStorageSurfaces = (options) => [
|
|
16096
16465
|
{
|
|
16097
16466
|
configured: Boolean(options.session ?? options.sessions),
|
|
@@ -16328,12 +16697,12 @@ var buildVoiceDataControlReport = async (options) => {
|
|
|
16328
16697
|
zeroRetentionAvailable: true
|
|
16329
16698
|
};
|
|
16330
16699
|
};
|
|
16331
|
-
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("");
|
|
16332
16701
|
var renderVoiceDataControlHTML = (report, options = {}) => {
|
|
16333
16702
|
const title = options.title ?? "Voice Data Control";
|
|
16334
|
-
const storageRows = report.storage.map((surface) => `<tr><td>${
|
|
16335
|
-
const keyRows = report.providerKeys.map((key) => `<tr><td>${
|
|
16336
|
-
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>`;
|
|
16337
16706
|
};
|
|
16338
16707
|
var renderVoiceDataControlMarkdown = (report, options = {}) => [
|
|
16339
16708
|
`# ${options.title ?? "Voice Data Control"}`,
|
|
@@ -16391,7 +16760,7 @@ var parseRetentionPolicyBody = (body, options, dryRun) => {
|
|
|
16391
16760
|
var createVoiceDataControlRoutes = (options) => {
|
|
16392
16761
|
const path = options.path ?? "/data-control";
|
|
16393
16762
|
const title = options.title ?? "AbsoluteJS Voice Data Control";
|
|
16394
|
-
const routes = new
|
|
16763
|
+
const routes = new Elysia26({
|
|
16395
16764
|
name: options.name ?? "absolutejs-voice-data-control"
|
|
16396
16765
|
});
|
|
16397
16766
|
routes.get(path, async ({ query }) => {
|
|
@@ -16467,16 +16836,16 @@ var createVoiceDataControlRoutes = (options) => {
|
|
|
16467
16836
|
return routes;
|
|
16468
16837
|
};
|
|
16469
16838
|
// src/evalRoutes.ts
|
|
16470
|
-
import { Elysia as
|
|
16839
|
+
import { Elysia as Elysia29 } from "elysia";
|
|
16471
16840
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
16472
16841
|
import { dirname as dirname2 } from "path";
|
|
16473
16842
|
|
|
16474
16843
|
// src/qualityRoutes.ts
|
|
16475
|
-
import { Elysia as
|
|
16844
|
+
import { Elysia as Elysia28 } from "elysia";
|
|
16476
16845
|
|
|
16477
16846
|
// src/handoffHealth.ts
|
|
16478
|
-
import { Elysia as
|
|
16479
|
-
var
|
|
16847
|
+
import { Elysia as Elysia27 } from "elysia";
|
|
16848
|
+
var escapeHtml27 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16480
16849
|
var getString9 = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
16481
16850
|
var isStatus = (value) => value === "delivered" || value === "failed" || value === "skipped";
|
|
16482
16851
|
var increment3 = (record, key) => {
|
|
@@ -16594,10 +16963,10 @@ var renderActionSummary = (summary) => {
|
|
|
16594
16963
|
return [
|
|
16595
16964
|
'<section class="voice-handoff-health-columns">',
|
|
16596
16965
|
"<article><h3>Actions</h3>",
|
|
16597
|
-
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>`,
|
|
16598
16967
|
"</article>",
|
|
16599
16968
|
"<article><h3>Adapters</h3>",
|
|
16600
|
-
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>`,
|
|
16601
16970
|
"</article>",
|
|
16602
16971
|
"</section>"
|
|
16603
16972
|
].join("");
|
|
@@ -16611,22 +16980,22 @@ var renderVoiceHandoffHealthHTML = (summary) => [
|
|
|
16611
16980
|
summary.events.length === 0 ? '<p class="voice-handoff-health-empty">No handoffs found.</p>' : [
|
|
16612
16981
|
'<div class="voice-handoff-health-events">',
|
|
16613
16982
|
...summary.events.map((event) => [
|
|
16614
|
-
`<article class="${
|
|
16983
|
+
`<article class="${escapeHtml27(event.status)}">`,
|
|
16615
16984
|
'<div class="voice-handoff-health-event-header">',
|
|
16616
|
-
`<strong>${
|
|
16617
|
-
`<span>${
|
|
16985
|
+
`<strong>${escapeHtml27(event.action ?? "handoff")}</strong>`,
|
|
16986
|
+
`<span>${escapeHtml27(event.status)}</span>`,
|
|
16618
16987
|
"</div>",
|
|
16619
|
-
`<p><small>${
|
|
16620
|
-
event.target ? `<p>Target: ${
|
|
16621
|
-
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>` : "",
|
|
16622
16991
|
event.deliveries.length ? `<ul>${event.deliveries.map((delivery) => [
|
|
16623
16992
|
"<li>",
|
|
16624
|
-
`${
|
|
16625
|
-
delivery.deliveredTo ? ` to ${
|
|
16626
|
-
delivery.error ? ` (${
|
|
16993
|
+
`${escapeHtml27(delivery.adapterId)}: ${escapeHtml27(delivery.status)}`,
|
|
16994
|
+
delivery.deliveredTo ? ` to ${escapeHtml27(delivery.deliveredTo)}` : "",
|
|
16995
|
+
delivery.error ? ` (${escapeHtml27(delivery.error)})` : "",
|
|
16627
16996
|
"</li>"
|
|
16628
16997
|
].join("")).join("")}</ul>` : "",
|
|
16629
|
-
event.replayHref ? `<p><a href="${
|
|
16998
|
+
event.replayHref ? `<p><a href="${escapeHtml27(event.replayHref)}">Open replay</a></p>` : "",
|
|
16630
16999
|
"</article>"
|
|
16631
17000
|
].join("")),
|
|
16632
17001
|
"</div>"
|
|
@@ -16658,7 +17027,7 @@ var createVoiceHandoffHealthHTMLHandler = (options = {}) => async ({ query }) =>
|
|
|
16658
17027
|
var createVoiceHandoffHealthRoutes = (options = {}) => {
|
|
16659
17028
|
const path = options.path ?? "/api/voice-handoffs";
|
|
16660
17029
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
16661
|
-
const routes = new
|
|
17030
|
+
const routes = new Elysia27({
|
|
16662
17031
|
name: options.name ?? "absolutejs-voice-handoff-health"
|
|
16663
17032
|
}).get(path, createVoiceHandoffHealthJSONHandler(options));
|
|
16664
17033
|
if (htmlPath) {
|
|
@@ -16779,17 +17148,17 @@ var evaluateVoiceQuality = async (input) => {
|
|
|
16779
17148
|
thresholds
|
|
16780
17149
|
};
|
|
16781
17150
|
};
|
|
16782
|
-
var
|
|
17151
|
+
var escapeHtml28 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16783
17152
|
var formatMetricValue = (metric) => metric.unit === "rate" ? `${(metric.actual * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.actual)}ms` : String(metric.actual);
|
|
16784
17153
|
var formatThreshold = (metric) => metric.unit === "rate" ? `${(metric.threshold * 100).toFixed(2)}%` : metric.unit === "ms" ? `${Math.round(metric.threshold)}ms` : String(metric.threshold);
|
|
16785
17154
|
var renderVoiceQualityHTML = (report, options = {}) => {
|
|
16786
|
-
const rows = Object.entries(report.metrics).map(([key, metric]) => `<tr class="${metric.pass ? "pass" : "fail"}"><td>${
|
|
16787
|
-
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>` : "";
|
|
16788
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>`;
|
|
16789
17158
|
};
|
|
16790
17159
|
var createVoiceQualityRoutes = (options) => {
|
|
16791
17160
|
const path = options.path ?? "/quality";
|
|
16792
|
-
const routes = new
|
|
17161
|
+
const routes = new Elysia28({
|
|
16793
17162
|
name: options.name ?? "absolutejs-voice-quality"
|
|
16794
17163
|
});
|
|
16795
17164
|
const getReport = () => evaluateVoiceQuality({
|
|
@@ -16818,7 +17187,7 @@ var createVoiceQualityRoutes = (options) => {
|
|
|
16818
17187
|
};
|
|
16819
17188
|
|
|
16820
17189
|
// src/evalRoutes.ts
|
|
16821
|
-
var
|
|
17190
|
+
var escapeHtml29 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
16822
17191
|
var rate2 = (count, total) => count / Math.max(1, total);
|
|
16823
17192
|
var normalizeSearchText = (value) => value.trim().toLowerCase();
|
|
16824
17193
|
var getString11 = (value) => typeof value === "string" ? value : undefined;
|
|
@@ -17140,7 +17509,7 @@ var createVoiceFileScenarioFixtureStore = (filePath) => ({
|
|
|
17140
17509
|
var formatTime = (value) => value === undefined ? "unknown" : new Date(value).toLocaleString();
|
|
17141
17510
|
var formatPercent = (value) => `${(value * 100).toFixed(2)}%`;
|
|
17142
17511
|
var renderVoiceEvalPrimitiveCopy = () => {
|
|
17143
|
-
const snippet =
|
|
17512
|
+
const snippet = escapeHtml29(`app.use(
|
|
17144
17513
|
createVoiceEvalRoutes({
|
|
17145
17514
|
path: '/evals',
|
|
17146
17515
|
store: traceStore,
|
|
@@ -17161,48 +17530,48 @@ var renderVoiceEvalPrimitiveCopy = () => {
|
|
|
17161
17530
|
};
|
|
17162
17531
|
var renderVoiceEvalHTML = (report, options = {}) => {
|
|
17163
17532
|
const title = options.title ?? "AbsoluteJS Voice Evals";
|
|
17164
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17165
|
-
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>';
|
|
17166
17535
|
const sessions = report.sessions.length ? report.sessions.map((session) => {
|
|
17167
17536
|
const failedMetrics = Object.entries(session.quality.metrics).filter(([, metric]) => !metric.pass).map(([, metric]) => metric.label).join(", ");
|
|
17168
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
17169
|
-
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>`;
|
|
17170
17539
|
}).join("") : '<tr><td colspan="7">No sessions found.</td></tr>';
|
|
17171
|
-
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>`;
|
|
17172
17541
|
};
|
|
17173
17542
|
var renderVoiceEvalBaselineHTML = (comparison, options = {}) => {
|
|
17174
17543
|
const title = options.title ?? "AbsoluteJS Voice Eval Baseline";
|
|
17175
|
-
const links = options.links?.length ? `<nav>${options.links.map((link) => `<a href="${
|
|
17176
|
-
const reasons = comparison.reasons.length ? comparison.reasons.map((reason) => `<li>${
|
|
17177
|
-
const newFailures = comparison.newFailedSessionIds.length ? comparison.newFailedSessionIds.map((id) => `<li>${
|
|
17178
|
-
const recovered = comparison.recoveredSessionIds.length ? comparison.recoveredSessionIds.map((id) => `<li>${
|
|
17179
|
-
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>`;
|
|
17180
17549
|
};
|
|
17181
17550
|
var renderVoiceScenarioEvalHTML = (report, options = {}) => {
|
|
17182
17551
|
const title = options.title ?? "AbsoluteJS Voice Scenario Evals";
|
|
17183
|
-
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>` : "";
|
|
17184
17553
|
const scenarios = report.scenarios.length ? report.scenarios.map((scenario) => {
|
|
17185
|
-
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>` : "";
|
|
17186
17555
|
const sessions = scenario.sessions.length ? scenario.sessions.map((session) => {
|
|
17187
|
-
const sessionLabel = session.operationsRecordHref ? `<a href="${
|
|
17188
|
-
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>`;
|
|
17189
17558
|
}).join("") : '<tr><td colspan="4">No matching sessions.</td></tr>';
|
|
17190
|
-
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>`;
|
|
17191
17560
|
}).join("") : "<section><p>No scenarios configured.</p></section>";
|
|
17192
|
-
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>`;
|
|
17193
17562
|
};
|
|
17194
17563
|
var renderVoiceScenarioFixtureEvalHTML = (report, options = {}) => {
|
|
17195
17564
|
const title = options.title ?? "AbsoluteJS Voice Fixture Evals";
|
|
17196
|
-
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>` : "";
|
|
17197
17566
|
const fixtures = report.fixtures.length ? report.fixtures.map((fixture) => {
|
|
17198
|
-
const scenarios = fixture.report.scenarios.map((scenario) => `<tr class="${scenario.status}"><td>${
|
|
17199
|
-
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>`;
|
|
17200
17569
|
}).join("") : "<section><p>No scenario fixtures configured.</p></section>";
|
|
17201
|
-
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>`;
|
|
17202
17571
|
};
|
|
17203
17572
|
var createVoiceEvalRoutes = (options) => {
|
|
17204
17573
|
const path = options.path ?? "/evals";
|
|
17205
|
-
const routes = new
|
|
17574
|
+
const routes = new Elysia29({
|
|
17206
17575
|
name: options.name ?? "absolutejs-voice-evals"
|
|
17207
17576
|
});
|
|
17208
17577
|
const getReport = () => runVoiceSessionEvals({
|
|
@@ -17339,11 +17708,11 @@ var createVoiceEvalRoutes = (options) => {
|
|
|
17339
17708
|
return routes;
|
|
17340
17709
|
};
|
|
17341
17710
|
// src/simulationSuite.ts
|
|
17342
|
-
import { Elysia as
|
|
17711
|
+
import { Elysia as Elysia32 } from "elysia";
|
|
17343
17712
|
|
|
17344
17713
|
// src/outcomeContract.ts
|
|
17345
|
-
import { Elysia as
|
|
17346
|
-
var
|
|
17714
|
+
import { Elysia as Elysia30 } from "elysia";
|
|
17715
|
+
var escapeHtml30 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17347
17716
|
var resolveSessionHref2 = (value, sessionId) => {
|
|
17348
17717
|
if (value === false) {
|
|
17349
17718
|
return;
|
|
@@ -17554,13 +17923,13 @@ var assertVoiceOutcomeContractEvidence = (report, input = {}) => {
|
|
|
17554
17923
|
var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
17555
17924
|
const title = options.title ?? "Voice Outcome Contracts";
|
|
17556
17925
|
const contracts = report.contracts.map((contract) => {
|
|
17557
|
-
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>` : "";
|
|
17558
17927
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
17559
17928
|
<div class="contract-header">
|
|
17560
17929
|
<div>
|
|
17561
|
-
<p class="eyebrow">${
|
|
17562
|
-
<h2>${
|
|
17563
|
-
${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>` : ""}
|
|
17564
17933
|
${sessionLinks}
|
|
17565
17934
|
</div>
|
|
17566
17935
|
<strong>${contract.pass ? "pass" : "fail"}</strong>
|
|
@@ -17572,10 +17941,10 @@ var renderVoiceOutcomeContractHTML = (report, options = {}) => {
|
|
|
17572
17941
|
<span>handoffs ${String(contract.matched.handoffs)}</span>
|
|
17573
17942
|
<span>events ${String(contract.matched.integrationEvents)}</span>
|
|
17574
17943
|
</div>
|
|
17575
|
-
${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>` : ""}
|
|
17576
17945
|
</section>`;
|
|
17577
17946
|
}).join("");
|
|
17578
|
-
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>`;
|
|
17579
17948
|
};
|
|
17580
17949
|
var createVoiceOutcomeContractJSONHandler = (options) => async () => runVoiceOutcomeContractSuite(options);
|
|
17581
17950
|
var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
@@ -17591,7 +17960,7 @@ var createVoiceOutcomeContractHTMLHandler = (options) => async () => {
|
|
|
17591
17960
|
var createVoiceOutcomeContractRoutes = (options) => {
|
|
17592
17961
|
const path = options.path ?? "/api/outcome-contracts";
|
|
17593
17962
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
17594
|
-
const routes = new
|
|
17963
|
+
const routes = new Elysia30({
|
|
17595
17964
|
name: options.name ?? "absolutejs-voice-outcome-contracts"
|
|
17596
17965
|
}).get(path, createVoiceOutcomeContractJSONHandler(options));
|
|
17597
17966
|
if (htmlPath) {
|
|
@@ -17601,7 +17970,7 @@ var createVoiceOutcomeContractRoutes = (options) => {
|
|
|
17601
17970
|
};
|
|
17602
17971
|
|
|
17603
17972
|
// src/toolContract.ts
|
|
17604
|
-
import { Elysia as
|
|
17973
|
+
import { Elysia as Elysia31 } from "elysia";
|
|
17605
17974
|
|
|
17606
17975
|
// src/toolRuntime.ts
|
|
17607
17976
|
var toErrorMessage4 = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -17810,7 +18179,7 @@ var createDefaultTurn = (caseId) => ({
|
|
|
17810
18179
|
});
|
|
17811
18180
|
var defaultApi = {};
|
|
17812
18181
|
var sameJSON = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
17813
|
-
var
|
|
18182
|
+
var escapeHtml31 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17814
18183
|
var resolveSessionHref3 = (value, sessionId) => {
|
|
17815
18184
|
if (value === false) {
|
|
17816
18185
|
return;
|
|
@@ -18059,7 +18428,7 @@ var assertVoiceToolContractEvidence = (report, input = {}) => {
|
|
|
18059
18428
|
};
|
|
18060
18429
|
var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
18061
18430
|
const title = options.title ?? "Voice Tool Contracts";
|
|
18062
|
-
const snippet =
|
|
18431
|
+
const snippet = escapeHtml31(`app.use(
|
|
18063
18432
|
createVoiceToolContractRoutes({
|
|
18064
18433
|
htmlPath: '/tool-contracts',
|
|
18065
18434
|
path: '/api/tool-contracts',
|
|
@@ -18085,20 +18454,20 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
18085
18454
|
);`);
|
|
18086
18455
|
const contracts = report.contracts.map((contract) => {
|
|
18087
18456
|
const cases = contract.cases.map((testCase) => `<tr>
|
|
18088
|
-
<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>
|
|
18089
18458
|
<td class="${testCase.pass ? "pass" : "fail"}">${testCase.pass ? "pass" : "fail"}</td>
|
|
18090
|
-
<td>${
|
|
18091
|
-
<td>${
|
|
18459
|
+
<td>${escapeHtml31(testCase.status)}</td>
|
|
18460
|
+
<td>${escapeHtml31(testCase.sessionId)}</td>
|
|
18092
18461
|
<td>${String(testCase.attempts)}</td>
|
|
18093
18462
|
<td>${String(testCase.elapsedMs)}ms</td>
|
|
18094
18463
|
<td>${testCase.timedOut ? "yes" : "no"}</td>
|
|
18095
|
-
<td>${
|
|
18464
|
+
<td>${escapeHtml31(testCase.issues.map((issue) => issue.message).join(" ") || testCase.error || "")}</td>
|
|
18096
18465
|
</tr>`).join("");
|
|
18097
18466
|
return `<section class="contract ${contract.pass ? "pass" : "fail"}">
|
|
18098
18467
|
<div class="contract-header">
|
|
18099
18468
|
<div>
|
|
18100
|
-
<p class="eyebrow">${
|
|
18101
|
-
<h2>${
|
|
18469
|
+
<p class="eyebrow">${escapeHtml31(contract.toolName)}</p>
|
|
18470
|
+
<h2>${escapeHtml31(contract.label ?? contract.contractId)}</h2>
|
|
18102
18471
|
</div>
|
|
18103
18472
|
<strong class="${contract.pass ? "pass" : "fail"}">${contract.pass ? "Passing" : "Failing"}</strong>
|
|
18104
18473
|
</div>
|
|
@@ -18108,7 +18477,7 @@ var renderVoiceToolContractHTML = (report, options = {}) => {
|
|
|
18108
18477
|
</table>
|
|
18109
18478
|
</section>`;
|
|
18110
18479
|
}).join("");
|
|
18111
|
-
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>`;
|
|
18112
18481
|
};
|
|
18113
18482
|
var createVoiceToolContractJSONHandler = (options) => () => runVoiceToolContractSuite(options);
|
|
18114
18483
|
var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
@@ -18125,7 +18494,7 @@ var createVoiceToolContractHTMLHandler = (options) => async () => {
|
|
|
18125
18494
|
var createVoiceToolContractRoutes = (options) => {
|
|
18126
18495
|
const path = options.path ?? "/api/tool-contracts";
|
|
18127
18496
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18128
|
-
const routes = new
|
|
18497
|
+
const routes = new Elysia31({
|
|
18129
18498
|
name: options.name ?? "absolutejs-voice-tool-contracts"
|
|
18130
18499
|
}).get(path, createVoiceToolContractJSONHandler(options));
|
|
18131
18500
|
if (htmlPath) {
|
|
@@ -18135,7 +18504,7 @@ var createVoiceToolContractRoutes = (options) => {
|
|
|
18135
18504
|
};
|
|
18136
18505
|
|
|
18137
18506
|
// src/simulationSuite.ts
|
|
18138
|
-
var
|
|
18507
|
+
var escapeHtml32 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18139
18508
|
var summarizeSection = (report) => ({
|
|
18140
18509
|
failed: report.failed,
|
|
18141
18510
|
passed: report.passed,
|
|
@@ -18331,15 +18700,15 @@ var renderSection = (label, summary) => {
|
|
|
18331
18700
|
if (!summary) {
|
|
18332
18701
|
return "";
|
|
18333
18702
|
}
|
|
18334
|
-
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>`;
|
|
18335
18704
|
};
|
|
18336
18705
|
var renderAction = (action) => {
|
|
18337
|
-
const content = `<strong>${
|
|
18338
|
-
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>`;
|
|
18339
18708
|
};
|
|
18340
18709
|
var renderVoiceSimulationSuiteHTML = (report, options = {}) => {
|
|
18341
18710
|
const title = options.title ?? "Voice Simulation Suite";
|
|
18342
|
-
const snippet =
|
|
18711
|
+
const snippet = escapeHtml32(`app.use(
|
|
18343
18712
|
createVoiceSimulationSuiteRoutes({
|
|
18344
18713
|
htmlPath: '/voice/simulations',
|
|
18345
18714
|
path: '/api/voice/simulations',
|
|
@@ -18372,12 +18741,12 @@ app.use(
|
|
|
18372
18741
|
store: traceStore
|
|
18373
18742
|
})
|
|
18374
18743
|
);`);
|
|
18375
|
-
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>`;
|
|
18376
18745
|
};
|
|
18377
18746
|
var createVoiceSimulationSuiteRoutes = (options) => {
|
|
18378
18747
|
const path = options.path ?? "/api/voice/simulations";
|
|
18379
18748
|
const htmlPath = options.htmlPath === undefined ? "/voice/simulations" : options.htmlPath;
|
|
18380
|
-
const app = new
|
|
18749
|
+
const app = new Elysia32({
|
|
18381
18750
|
name: options.name ?? "absolutejs-voice-simulation-suite"
|
|
18382
18751
|
}).get(path, () => runVoiceSimulationSuite(options));
|
|
18383
18752
|
if (htmlPath) {
|
|
@@ -18689,9 +19058,9 @@ var createVoiceWorkflowContractHandler = (input) => {
|
|
|
18689
19058
|
};
|
|
18690
19059
|
};
|
|
18691
19060
|
// src/sessionReplay.ts
|
|
18692
|
-
import { Elysia as
|
|
19061
|
+
import { Elysia as Elysia33 } from "elysia";
|
|
18693
19062
|
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
18694
|
-
var
|
|
19063
|
+
var escapeHtml33 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
18695
19064
|
var increment4 = (record, key) => {
|
|
18696
19065
|
record[key] = (record[key] ?? 0) + 1;
|
|
18697
19066
|
};
|
|
@@ -18885,10 +19254,10 @@ var summarizeVoiceSessions = async (options = {}) => {
|
|
|
18885
19254
|
var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="voice-sessions-empty">No voice sessions found.</p>' : [
|
|
18886
19255
|
'<div class="voice-sessions-list">',
|
|
18887
19256
|
...sessions.map((session) => [
|
|
18888
|
-
`<article class="voice-session-card ${
|
|
19257
|
+
`<article class="voice-session-card ${escapeHtml33(session.status)}">`,
|
|
18889
19258
|
'<div class="voice-session-card-header">',
|
|
18890
|
-
`<strong>${
|
|
18891
|
-
`<span>${
|
|
19259
|
+
`<strong>${escapeHtml33(session.sessionId)}</strong>`,
|
|
19260
|
+
`<span>${escapeHtml33(session.status)}</span>`,
|
|
18892
19261
|
"</div>",
|
|
18893
19262
|
"<dl>",
|
|
18894
19263
|
`<div><dt>Events</dt><dd>${String(session.eventCount)}</dd></div>`,
|
|
@@ -18896,9 +19265,9 @@ var renderVoiceSessionsHTML = (sessions) => sessions.length === 0 ? '<p class="v
|
|
|
18896
19265
|
`<div><dt>Transcripts</dt><dd>${String(session.transcriptCount)}</dd></div>`,
|
|
18897
19266
|
`<div><dt>Errors</dt><dd>${String(session.errorCount)}</dd></div>`,
|
|
18898
19267
|
"</dl>",
|
|
18899
|
-
session.latestOutcome ? `<p>Outcome: ${
|
|
18900
|
-
session.providers.length ? `<p>Providers: ${session.providers.map(
|
|
18901
|
-
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>` : "",
|
|
18902
19271
|
"</article>"
|
|
18903
19272
|
].join("")),
|
|
18904
19273
|
"</div>"
|
|
@@ -18929,7 +19298,7 @@ var createVoiceSessionsHTMLHandler = (options = {}) => async ({ query }) => {
|
|
|
18929
19298
|
var createVoiceSessionListRoutes = (options = {}) => {
|
|
18930
19299
|
const path = options.path ?? "/api/voice-sessions";
|
|
18931
19300
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18932
|
-
const routes = new
|
|
19301
|
+
const routes = new Elysia33({
|
|
18933
19302
|
name: options.name ?? "absolutejs-voice-session-list"
|
|
18934
19303
|
}).get(path, createVoiceSessionsJSONHandler(options));
|
|
18935
19304
|
if (htmlPath) {
|
|
@@ -18957,7 +19326,7 @@ var createVoiceSessionReplayHTMLHandler = (options) => async ({ params }) => {
|
|
|
18957
19326
|
var createVoiceSessionReplayRoutes = (options) => {
|
|
18958
19327
|
const path = options.path ?? "/api/voice-sessions/:sessionId/replay";
|
|
18959
19328
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
18960
|
-
const routes = new
|
|
19329
|
+
const routes = new Elysia33({
|
|
18961
19330
|
name: options.name ?? "absolutejs-voice-session-replay"
|
|
18962
19331
|
}).get(path, createVoiceSessionReplayJSONHandler(options));
|
|
18963
19332
|
if (htmlPath) {
|
|
@@ -19271,11 +19640,11 @@ var assertVoiceAgentSquadContractEvidence = (reports, input = {}) => {
|
|
|
19271
19640
|
return report;
|
|
19272
19641
|
};
|
|
19273
19642
|
// src/turnLatency.ts
|
|
19274
|
-
import { Elysia as
|
|
19643
|
+
import { Elysia as Elysia34 } from "elysia";
|
|
19275
19644
|
var DEFAULT_WARN_AFTER_MS = 1800;
|
|
19276
19645
|
var DEFAULT_FAIL_AFTER_MS = 3200;
|
|
19277
|
-
var
|
|
19278
|
-
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];
|
|
19279
19648
|
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
19280
19649
|
var createTraceStageIndex = (events) => {
|
|
19281
19650
|
const index = new Map;
|
|
@@ -19299,8 +19668,8 @@ var createTraceStageIndex = (events) => {
|
|
|
19299
19668
|
};
|
|
19300
19669
|
var summarizeTurn = (sessionId, turn, options) => {
|
|
19301
19670
|
const traceStages = options.stageIndex?.get(`${sessionId}:${turn.id}`);
|
|
19302
|
-
const firstTranscriptAt = traceStages?.get("speech_detected") ??
|
|
19303
|
-
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));
|
|
19304
19673
|
const committedAt = traceStages?.get("turn_committed") ?? turn.committedAt;
|
|
19305
19674
|
const assistantTextStartedAt = traceStages?.get("assistant_text_started") ?? (turn.assistantText ? committedAt : undefined);
|
|
19306
19675
|
const ttsSendStartedAt = traceStages?.get("tts_send_started");
|
|
@@ -19406,11 +19775,11 @@ await traceStore.append({
|
|
|
19406
19775
|
turnId,
|
|
19407
19776
|
type: 'turn_latency.stage'
|
|
19408
19777
|
});`;
|
|
19409
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
19410
|
-
<header><div><p class="eyebrow">${
|
|
19411
|
-
<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>
|
|
19412
19781
|
</article>`).join("");
|
|
19413
|
-
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>`;
|
|
19414
19783
|
};
|
|
19415
19784
|
var createVoiceTurnLatencyJSONHandler = (options) => async () => summarizeVoiceTurnLatency(options);
|
|
19416
19785
|
var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
@@ -19427,7 +19796,7 @@ var createVoiceTurnLatencyHTMLHandler = (options) => async () => {
|
|
|
19427
19796
|
var createVoiceTurnLatencyRoutes = (options) => {
|
|
19428
19797
|
const path = options.path ?? "/api/turn-latency";
|
|
19429
19798
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
19430
|
-
const routes = new
|
|
19799
|
+
const routes = new Elysia34({
|
|
19431
19800
|
name: options.name ?? "absolutejs-voice-turn-latency"
|
|
19432
19801
|
}).get(path, createVoiceTurnLatencyJSONHandler(options));
|
|
19433
19802
|
if (htmlPath) {
|
|
@@ -19436,8 +19805,8 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
19436
19805
|
return routes;
|
|
19437
19806
|
};
|
|
19438
19807
|
// src/liveLatency.ts
|
|
19439
|
-
import { Elysia as
|
|
19440
|
-
var
|
|
19808
|
+
import { Elysia as Elysia35 } from "elysia";
|
|
19809
|
+
var escapeHtml35 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19441
19810
|
var percentile3 = (values, percentileValue) => {
|
|
19442
19811
|
if (values.length === 0) {
|
|
19443
19812
|
return;
|
|
@@ -19504,13 +19873,13 @@ await traceStore.append({
|
|
|
19504
19873
|
sessionId,
|
|
19505
19874
|
type: 'client.live_latency'
|
|
19506
19875
|
});`;
|
|
19507
|
-
const rows = report.recent.map((sample) => `<tr><td>${
|
|
19508
|
-
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>`;
|
|
19509
19878
|
};
|
|
19510
19879
|
var createVoiceLiveLatencyRoutes = (options) => {
|
|
19511
19880
|
const path = options.path ?? "/api/live-latency";
|
|
19512
19881
|
const htmlPath = options.htmlPath === undefined ? "/live-latency" : options.htmlPath;
|
|
19513
|
-
const routes = new
|
|
19882
|
+
const routes = new Elysia35({
|
|
19514
19883
|
name: options.name ?? "absolutejs-voice-live-latency"
|
|
19515
19884
|
}).get(path, () => summarizeVoiceLiveLatency(options));
|
|
19516
19885
|
if (htmlPath) {
|
|
@@ -19829,9 +20198,9 @@ None.
|
|
|
19829
20198
|
`}`;
|
|
19830
20199
|
};
|
|
19831
20200
|
// src/turnQuality.ts
|
|
19832
|
-
import { Elysia as
|
|
20201
|
+
import { Elysia as Elysia36 } from "elysia";
|
|
19833
20202
|
var DEFAULT_CONFIDENCE_WARN_THRESHOLD = 0.72;
|
|
19834
|
-
var
|
|
20203
|
+
var escapeHtml36 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
19835
20204
|
var getTurnLatencyMs = (turn) => {
|
|
19836
20205
|
const firstTranscriptAt = turn.transcripts.map((transcript) => transcript.endedAtMs ?? transcript.startedAtMs).filter((value) => typeof value === "number").sort((left, right) => left - right)[0];
|
|
19837
20206
|
if (firstTranscriptAt === undefined) {
|
|
@@ -19902,24 +20271,24 @@ var summarizeVoiceTurnQuality = async (options) => {
|
|
|
19902
20271
|
};
|
|
19903
20272
|
var renderVoiceTurnQualityHTML = (report, options = {}) => {
|
|
19904
20273
|
const title = options.title ?? "Voice Turn Quality";
|
|
19905
|
-
const turns = report.turns.map((turn) => `<article class="turn ${
|
|
20274
|
+
const turns = report.turns.map((turn) => `<article class="turn ${escapeHtml36(turn.status)}">
|
|
19906
20275
|
<div class="turn-header">
|
|
19907
20276
|
<div>
|
|
19908
|
-
<p class="eyebrow">${
|
|
19909
|
-
<h2>${
|
|
20277
|
+
<p class="eyebrow">${escapeHtml36(turn.sessionId)} \xB7 ${escapeHtml36(turn.turnId)}</p>
|
|
20278
|
+
<h2>${escapeHtml36(turn.text || "Empty turn")}</h2>
|
|
19910
20279
|
</div>
|
|
19911
|
-
<strong>${
|
|
20280
|
+
<strong>${escapeHtml36(turn.status)}</strong>
|
|
19912
20281
|
</div>
|
|
19913
20282
|
<dl>
|
|
19914
|
-
<div><dt>Source</dt><dd>${
|
|
20283
|
+
<div><dt>Source</dt><dd>${escapeHtml36(turn.source ?? "unknown")}</dd></div>
|
|
19915
20284
|
<div><dt>Confidence</dt><dd>${turn.averageConfidence === undefined ? "n/a" : `${Math.round(turn.averageConfidence * 100)}%`}</dd></div>
|
|
19916
|
-
<div><dt>Fallback</dt><dd>${turn.fallbackUsed ? `yes (${
|
|
19917
|
-
<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>
|
|
19918
20287
|
<div><dt>Transcripts</dt><dd>${String(turn.selectedTranscriptCount)} selected \xB7 ${String(turn.finalTranscriptCount)} final \xB7 ${String(turn.partialTranscriptCount)} partial</dd></div>
|
|
19919
20288
|
<div><dt>Cost</dt><dd>${turn.costUnits === undefined ? "n/a" : String(turn.costUnits)}</dd></div>
|
|
19920
20289
|
</dl>
|
|
19921
20290
|
</article>`).join("");
|
|
19922
|
-
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>`;
|
|
19923
20292
|
};
|
|
19924
20293
|
var createVoiceTurnQualityJSONHandler = (options) => async () => summarizeVoiceTurnQuality(options);
|
|
19925
20294
|
var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
@@ -19936,7 +20305,7 @@ var createVoiceTurnQualityHTMLHandler = (options) => async () => {
|
|
|
19936
20305
|
var createVoiceTurnQualityRoutes = (options) => {
|
|
19937
20306
|
const path = options.path ?? "/api/turn-quality";
|
|
19938
20307
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
19939
|
-
const routes = new
|
|
20308
|
+
const routes = new Elysia36({
|
|
19940
20309
|
name: options.name ?? "absolutejs-voice-turn-quality"
|
|
19941
20310
|
}).get(path, createVoiceTurnQualityJSONHandler(options));
|
|
19942
20311
|
if (htmlPath) {
|
|
@@ -19945,7 +20314,7 @@ var createVoiceTurnQualityRoutes = (options) => {
|
|
|
19945
20314
|
return routes;
|
|
19946
20315
|
};
|
|
19947
20316
|
// src/telephonyOutcome.ts
|
|
19948
|
-
import { Elysia as
|
|
20317
|
+
import { Elysia as Elysia37 } from "elysia";
|
|
19949
20318
|
var DEFAULT_COMPLETED_STATUSES = [
|
|
19950
20319
|
"answered",
|
|
19951
20320
|
"completed",
|
|
@@ -20116,7 +20485,7 @@ var assertVoiceTelephonyWebhookNormalizationEvidence = (input = {}) => {
|
|
|
20116
20485
|
return assertion;
|
|
20117
20486
|
};
|
|
20118
20487
|
var normalizeToken = (value) => typeof value === "string" ? value.trim().toLowerCase().replace(/\s+/g, "-").replace(/_+/g, "-") : undefined;
|
|
20119
|
-
var
|
|
20488
|
+
var firstString3 = (source, keys) => {
|
|
20120
20489
|
for (const key of keys) {
|
|
20121
20490
|
const value = source[key];
|
|
20122
20491
|
if (typeof value === "string" && value.trim()) {
|
|
@@ -20127,7 +20496,7 @@ var firstString2 = (source, keys) => {
|
|
|
20127
20496
|
}
|
|
20128
20497
|
}
|
|
20129
20498
|
};
|
|
20130
|
-
var
|
|
20499
|
+
var firstNumber3 = (source, keys) => {
|
|
20131
20500
|
for (const key of keys) {
|
|
20132
20501
|
const value = source[key];
|
|
20133
20502
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -20488,8 +20857,8 @@ var verifyVoiceTelephonyWebhook = async (input) => {
|
|
|
20488
20857
|
var durationMsFromSeconds = (value) => typeof value === "number" ? value * 1000 : undefined;
|
|
20489
20858
|
var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
20490
20859
|
const payload = flattenPayload(input.body);
|
|
20491
|
-
const provider =
|
|
20492
|
-
const status =
|
|
20860
|
+
const provider = firstString3(payload, ["provider", "Provider"]) ?? input.provider;
|
|
20861
|
+
const status = firstString3(payload, [
|
|
20493
20862
|
"CallStatus",
|
|
20494
20863
|
"call_status",
|
|
20495
20864
|
"callStatus",
|
|
@@ -20499,7 +20868,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
20499
20868
|
"event_type",
|
|
20500
20869
|
"type"
|
|
20501
20870
|
]);
|
|
20502
|
-
const durationMs =
|
|
20871
|
+
const durationMs = firstNumber3(payload, ["durationMs", "duration_ms"]) ?? durationMsFromSeconds(firstNumber3(payload, [
|
|
20503
20872
|
"CallDuration",
|
|
20504
20873
|
"call_duration",
|
|
20505
20874
|
"callDuration",
|
|
@@ -20507,16 +20876,16 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
20507
20876
|
"dial_call_duration",
|
|
20508
20877
|
"duration"
|
|
20509
20878
|
]));
|
|
20510
|
-
const sipCode =
|
|
20879
|
+
const sipCode = firstNumber3(payload, [
|
|
20511
20880
|
"SipResponseCode",
|
|
20512
20881
|
"sip_response_code",
|
|
20513
20882
|
"sipCode",
|
|
20514
20883
|
"sip_code",
|
|
20515
20884
|
"hangupCauseCode"
|
|
20516
20885
|
]);
|
|
20517
|
-
const from =
|
|
20518
|
-
const to =
|
|
20519
|
-
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, [
|
|
20520
20889
|
"transferTarget",
|
|
20521
20890
|
"TransferTarget",
|
|
20522
20891
|
"target",
|
|
@@ -20524,7 +20893,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
20524
20893
|
"department"
|
|
20525
20894
|
]);
|
|
20526
20895
|
return {
|
|
20527
|
-
answeredBy:
|
|
20896
|
+
answeredBy: firstString3(payload, [
|
|
20528
20897
|
"AnsweredBy",
|
|
20529
20898
|
"answered_by",
|
|
20530
20899
|
"answeredBy",
|
|
@@ -20538,7 +20907,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
20538
20907
|
...payload
|
|
20539
20908
|
},
|
|
20540
20909
|
provider,
|
|
20541
|
-
reason:
|
|
20910
|
+
reason: firstString3(payload, [
|
|
20542
20911
|
"Reason",
|
|
20543
20912
|
"reason",
|
|
20544
20913
|
"HangupCause",
|
|
@@ -20554,7 +20923,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
|
|
|
20554
20923
|
var defaultSessionId = (input) => {
|
|
20555
20924
|
const payload = flattenPayload(input.body);
|
|
20556
20925
|
const metadataSessionId = input.event.metadata?.sessionId;
|
|
20557
|
-
return
|
|
20926
|
+
return firstString3(input.query, ["sessionId", "session_id"]) ?? firstString3(payload, [
|
|
20558
20927
|
"sessionId",
|
|
20559
20928
|
"session_id",
|
|
20560
20929
|
"SessionId",
|
|
@@ -20569,7 +20938,7 @@ var defaultSessionId = (input) => {
|
|
|
20569
20938
|
};
|
|
20570
20939
|
var defaultIdempotencyKey = (input) => {
|
|
20571
20940
|
const payload = flattenPayload(input.body);
|
|
20572
|
-
const eventId =
|
|
20941
|
+
const eventId = firstString3(payload, [
|
|
20573
20942
|
"id",
|
|
20574
20943
|
"event_id",
|
|
20575
20944
|
"eventId",
|
|
@@ -20706,7 +21075,7 @@ var createVoiceTelephonyWebhookHandler = (options = {}) => async (input) => {
|
|
|
20706
21075
|
var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
20707
21076
|
const path = options.path ?? "/api/voice/telephony/webhook";
|
|
20708
21077
|
const handler = createVoiceTelephonyWebhookHandler(options);
|
|
20709
|
-
return new
|
|
21078
|
+
return new Elysia37({
|
|
20710
21079
|
name: options.name ?? "absolutejs-voice-telephony-webhooks"
|
|
20711
21080
|
}).post(path, async ({ query, request }) => {
|
|
20712
21081
|
try {
|
|
@@ -20727,12 +21096,12 @@ var createVoiceTelephonyWebhookRoutes = (options = {}) => {
|
|
|
20727
21096
|
});
|
|
20728
21097
|
};
|
|
20729
21098
|
// src/phoneAgent.ts
|
|
20730
|
-
import { Elysia as
|
|
21099
|
+
import { Elysia as Elysia43 } from "elysia";
|
|
20731
21100
|
|
|
20732
21101
|
// src/telephony/plivo.ts
|
|
20733
21102
|
import { Buffer as Buffer5 } from "buffer";
|
|
20734
21103
|
import { Database } from "bun:sqlite";
|
|
20735
|
-
import { Elysia as
|
|
21104
|
+
import { Elysia as Elysia39 } from "elysia";
|
|
20736
21105
|
|
|
20737
21106
|
// src/telephony/contract.ts
|
|
20738
21107
|
var DEFAULT_REQUIREMENTS = [
|
|
@@ -20816,7 +21185,7 @@ var evaluateVoiceTelephonyContract = (input) => {
|
|
|
20816
21185
|
|
|
20817
21186
|
// src/telephony/twilio.ts
|
|
20818
21187
|
import { Buffer as Buffer4 } from "buffer";
|
|
20819
|
-
import { Elysia as
|
|
21188
|
+
import { Elysia as Elysia38 } from "elysia";
|
|
20820
21189
|
var TWILIO_MULAW_SAMPLE_RATE = 8000;
|
|
20821
21190
|
var VOICE_PCM_SAMPLE_RATE = 16000;
|
|
20822
21191
|
var escapeXml2 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
@@ -20846,7 +21215,7 @@ var resolveTwilioStreamParameters = async (parameters, input) => {
|
|
|
20846
21215
|
return parameters;
|
|
20847
21216
|
};
|
|
20848
21217
|
var joinUrlPath2 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
20849
|
-
var
|
|
21218
|
+
var escapeHtml37 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
20850
21219
|
var getWebhookVerificationUrl = (webhook, input) => {
|
|
20851
21220
|
if (!webhook?.verificationUrl) {
|
|
20852
21221
|
return;
|
|
@@ -20889,23 +21258,23 @@ var buildTwilioVoiceSetupStatus = async (options, input) => {
|
|
|
20889
21258
|
};
|
|
20890
21259
|
var renderTwilioVoiceSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20891
21260
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio setup</p>
|
|
20892
|
-
<h1>${
|
|
21261
|
+
<h1>${escapeHtml37(title)}</h1>
|
|
20893
21262
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
20894
21263
|
<section>
|
|
20895
21264
|
<h2>URLs</h2>
|
|
20896
21265
|
<ul>
|
|
20897
|
-
<li><strong>TwiML:</strong> <code>${
|
|
20898
|
-
<li><strong>Media stream:</strong> <code>${
|
|
20899
|
-
<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>
|
|
20900
21269
|
</ul>
|
|
20901
21270
|
</section>
|
|
20902
21271
|
<section>
|
|
20903
21272
|
<h2>Signing</h2>
|
|
20904
21273
|
<p>Mode: <code>${status.signing.mode}</code></p>
|
|
20905
|
-
${status.signing.verificationUrl ? `<p>Verification URL: <code>${
|
|
21274
|
+
${status.signing.verificationUrl ? `<p>Verification URL: <code>${escapeHtml37(status.signing.verificationUrl)}</code></p>` : ""}
|
|
20906
21275
|
</section>
|
|
20907
|
-
${status.missing.length ? `<section><h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
20908
|
-
${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>` : ""}
|
|
20909
21278
|
</main>`;
|
|
20910
21279
|
var extractTwilioStreamUrl = (twiml) => twiml.match(/<Stream\b[^>]*\surl="([^"]+)"/i)?.[1]?.replaceAll("&", "&");
|
|
20911
21280
|
var createSmokeCheck = (name, status, message, details) => ({
|
|
@@ -20916,20 +21285,20 @@ var createSmokeCheck = (name, status, message, details) => ({
|
|
|
20916
21285
|
});
|
|
20917
21286
|
var renderTwilioVoiceSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
20918
21287
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Twilio smoke test</p>
|
|
20919
|
-
<h1>${
|
|
21288
|
+
<h1>${escapeHtml37(title)}</h1>
|
|
20920
21289
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
20921
21290
|
<section>
|
|
20922
21291
|
<h2>Checks</h2>
|
|
20923
21292
|
<ul>
|
|
20924
|
-
${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("")}
|
|
20925
21294
|
</ul>
|
|
20926
21295
|
</section>
|
|
20927
21296
|
<section>
|
|
20928
21297
|
<h2>Observed URLs</h2>
|
|
20929
21298
|
<ul>
|
|
20930
|
-
<li><strong>TwiML:</strong> <code>${
|
|
20931
|
-
<li><strong>Stream:</strong> <code>${
|
|
20932
|
-
<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>
|
|
20933
21302
|
</ul>
|
|
20934
21303
|
</section>
|
|
20935
21304
|
</main>`;
|
|
@@ -21389,7 +21758,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
21389
21758
|
const smokePath = options.smoke?.path === false ? false : options.smoke?.path ?? "/api/voice/twilio/smoke";
|
|
21390
21759
|
const bridges = new WeakMap;
|
|
21391
21760
|
const webhookPolicy = options.webhook?.policy ?? options.outcomePolicy ?? createVoiceTelephonyOutcomePolicy();
|
|
21392
|
-
const app = new
|
|
21761
|
+
const app = new Elysia38({
|
|
21393
21762
|
name: options.name ?? "absolutejs-voice-twilio"
|
|
21394
21763
|
}).get(twimlPath, async ({ query, request }) => {
|
|
21395
21764
|
const streamUrl = await resolveTwilioStreamUrl(options, {
|
|
@@ -21526,7 +21895,7 @@ var createTwilioVoiceRoutes = (options) => {
|
|
|
21526
21895
|
|
|
21527
21896
|
// src/telephony/plivo.ts
|
|
21528
21897
|
var escapeXml3 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21529
|
-
var
|
|
21898
|
+
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
21530
21899
|
var joinUrlPath3 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
21531
21900
|
var resolveRequestOrigin2 = (request) => {
|
|
21532
21901
|
const url = new URL(request.url);
|
|
@@ -21956,21 +22325,21 @@ var buildPlivoVoiceSetupStatus = async (options, input) => {
|
|
|
21956
22325
|
};
|
|
21957
22326
|
var renderPlivoSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21958
22327
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo setup</p>
|
|
21959
|
-
<h1>${
|
|
22328
|
+
<h1>${escapeHtml38(title)}</h1>
|
|
21960
22329
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
21961
22330
|
<ul>
|
|
21962
|
-
<li><strong>Answer XML:</strong> <code>${
|
|
21963
|
-
<li><strong>Audio stream:</strong> <code>${
|
|
21964
|
-
<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>
|
|
21965
22334
|
</ul>
|
|
21966
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
21967
|
-
${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>` : ""}
|
|
21968
22337
|
</main>`;
|
|
21969
22338
|
var renderPlivoSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
21970
22339
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Plivo smoke test</p>
|
|
21971
|
-
<h1>${
|
|
22340
|
+
<h1>${escapeHtml38(title)}</h1>
|
|
21972
22341
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
21973
|
-
<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>
|
|
21974
22343
|
</main>`;
|
|
21975
22344
|
var runPlivoSmokeTest = async (input) => {
|
|
21976
22345
|
const setup = await buildPlivoVoiceSetupStatus(input.options, input);
|
|
@@ -22060,7 +22429,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
22060
22429
|
nonceStore: options.webhook.nonceStore,
|
|
22061
22430
|
verificationUrl: options.webhook.verificationUrl
|
|
22062
22431
|
}) : undefined);
|
|
22063
|
-
const app = new
|
|
22432
|
+
const app = new Elysia39({
|
|
22064
22433
|
name: options.name ?? "absolutejs-voice-plivo"
|
|
22065
22434
|
}).get(answerPath, async ({ query, request }) => {
|
|
22066
22435
|
const streamUrl = await resolvePlivoStreamUrl(options, {
|
|
@@ -22172,9 +22541,9 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
22172
22541
|
// src/telephony/telnyx.ts
|
|
22173
22542
|
import { Buffer as Buffer6 } from "buffer";
|
|
22174
22543
|
import { Database as Database2 } from "bun:sqlite";
|
|
22175
|
-
import { Elysia as
|
|
22544
|
+
import { Elysia as Elysia40 } from "elysia";
|
|
22176
22545
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22177
|
-
var
|
|
22546
|
+
var escapeHtml39 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22178
22547
|
var joinUrlPath4 = (origin, path) => `${origin.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
|
|
22179
22548
|
var resolveRequestOrigin3 = (request) => {
|
|
22180
22549
|
const url = new URL(request.url);
|
|
@@ -22567,21 +22936,21 @@ var buildTelnyxVoiceSetupStatus = async (options, input) => {
|
|
|
22567
22936
|
};
|
|
22568
22937
|
var renderTelnyxSetupHTML = (status, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22569
22938
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx setup</p>
|
|
22570
|
-
<h1>${
|
|
22939
|
+
<h1>${escapeHtml39(title)}</h1>
|
|
22571
22940
|
<p><strong>Status:</strong> ${status.ready ? "Ready" : "Needs attention"}</p>
|
|
22572
22941
|
<ul>
|
|
22573
|
-
<li><strong>TeXML:</strong> <code>${
|
|
22574
|
-
<li><strong>Media stream:</strong> <code>${
|
|
22575
|
-
<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>
|
|
22576
22945
|
</ul>
|
|
22577
|
-
${status.missing.length ? `<h2>Missing env</h2><ul>${status.missing.map((name) => `<li><code>${
|
|
22578
|
-
${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>` : ""}
|
|
22579
22948
|
</main>`;
|
|
22580
22949
|
var renderTelnyxSmokeHTML = (report, title) => `<main style="font-family: ui-sans-serif, system-ui; max-width: 860px; margin: 40px auto; padding: 0 20px;">
|
|
22581
22950
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Telnyx smoke test</p>
|
|
22582
|
-
<h1>${
|
|
22951
|
+
<h1>${escapeHtml39(title)}</h1>
|
|
22583
22952
|
<p><strong>Status:</strong> ${report.pass ? "Pass" : "Fail"}</p>
|
|
22584
|
-
<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>
|
|
22585
22954
|
</main>`;
|
|
22586
22955
|
var runTelnyxSmokeTest = async (input) => {
|
|
22587
22956
|
const setup = await buildTelnyxVoiceSetupStatus(input.options, input);
|
|
@@ -22674,7 +23043,7 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
22674
23043
|
publicKey: options.webhook.publicKey,
|
|
22675
23044
|
toleranceSeconds: options.webhook.toleranceSeconds
|
|
22676
23045
|
}) : undefined);
|
|
22677
|
-
const app = new
|
|
23046
|
+
const app = new Elysia40({
|
|
22678
23047
|
name: options.name ?? "absolutejs-voice-telnyx"
|
|
22679
23048
|
}).get(texmlPath, async ({ query, request }) => {
|
|
22680
23049
|
const streamUrl = await resolveTelnyxStreamUrl(options, {
|
|
@@ -22784,8 +23153,8 @@ var createTelnyxVoiceRoutes = (options = {}) => {
|
|
|
22784
23153
|
};
|
|
22785
23154
|
|
|
22786
23155
|
// src/telephony/matrix.ts
|
|
22787
|
-
import { Elysia as
|
|
22788
|
-
var
|
|
23156
|
+
import { Elysia as Elysia41 } from "elysia";
|
|
23157
|
+
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
22789
23158
|
var labelForProvider = (provider) => provider.split("-").map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
22790
23159
|
var resolveEntryStatus = (contract, setup, smoke) => {
|
|
22791
23160
|
if (!contract.pass || !setup.ready || smoke?.pass === false) {
|
|
@@ -22846,13 +23215,13 @@ var badgeStyles = {
|
|
|
22846
23215
|
};
|
|
22847
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;">
|
|
22848
23217
|
<p style="letter-spacing: .12em; text-transform: uppercase; color: #52606d;">Carrier matrix</p>
|
|
22849
|
-
<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>
|
|
22850
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>
|
|
22851
23220
|
<section style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px;">
|
|
22852
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);">
|
|
22853
23222
|
<div style="display:flex; justify-content:space-between; gap:12px; align-items:center;">
|
|
22854
|
-
<h2 style="margin:0; font-size:20px;">${
|
|
22855
|
-
<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>
|
|
22856
23225
|
</div>
|
|
22857
23226
|
<dl style="display:grid; grid-template-columns: 1fr 1fr; gap:8px 12px; margin:16px 0;">
|
|
22858
23227
|
<dt style="color:#64748b;">Setup</dt><dd style="margin:0; font-weight:700;">${entry.ready ? "Ready" : "Needs attention"}</dd>
|
|
@@ -22860,15 +23229,15 @@ ${matrix.entries.map((entry) => `<article style="border:1px solid #d9e2ec; borde
|
|
|
22860
23229
|
<dt style="color:#64748b;">Smoke</dt><dd style="margin:0; font-weight:700;">${entry.smoke ? entry.smoke.pass ? "Pass" : "Fail" : "Missing"}</dd>
|
|
22861
23230
|
<dt style="color:#64748b;">Contract</dt><dd style="margin:0; font-weight:700;">${entry.contract.pass ? "Pass" : "Fail"}</dd>
|
|
22862
23231
|
</dl>
|
|
22863
|
-
<p style="margin:0 0 8px; color:#475569;"><strong>Stream:</strong> <code>${
|
|
22864
|
-
<p style="margin:0 0 12px; color:#475569;"><strong>Webhook:</strong> <code>${
|
|
22865
|
-
${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>'}
|
|
22866
23235
|
</article>`).join("")}
|
|
22867
23236
|
</section>
|
|
22868
23237
|
</main>`;
|
|
22869
23238
|
var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
22870
23239
|
const path = options.path ?? "/api/voice/telephony/carriers";
|
|
22871
|
-
return new
|
|
23240
|
+
return new Elysia41({
|
|
22872
23241
|
name: options.name ?? "absolutejs-voice-telephony-carrier-matrix"
|
|
22873
23242
|
}).get(path, async ({ query, request }) => {
|
|
22874
23243
|
const providers = await options.load({ query, request });
|
|
@@ -22890,7 +23259,7 @@ var createVoiceTelephonyCarrierMatrixRoutes = (options) => {
|
|
|
22890
23259
|
};
|
|
22891
23260
|
|
|
22892
23261
|
// src/phoneAgentProductionSmoke.ts
|
|
22893
|
-
import { Elysia as
|
|
23262
|
+
import { Elysia as Elysia42 } from "elysia";
|
|
22894
23263
|
var defaultRequirements = [
|
|
22895
23264
|
"media-started",
|
|
22896
23265
|
"transcript",
|
|
@@ -22898,7 +23267,7 @@ var defaultRequirements = [
|
|
|
22898
23267
|
"lifecycle-outcome",
|
|
22899
23268
|
"no-session-error"
|
|
22900
23269
|
];
|
|
22901
|
-
var
|
|
23270
|
+
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
22902
23271
|
var payloadType = (event) => typeof event.payload.type === "string" ? event.payload.type : undefined;
|
|
22903
23272
|
var hasTextPayload = (event) => ["text", "assistantText", "transcript"].some((key) => {
|
|
22904
23273
|
const value = event.payload[key];
|
|
@@ -23007,10 +23376,10 @@ var resolveHandlerOptions = async (options, input) => ({
|
|
|
23007
23376
|
});
|
|
23008
23377
|
var renderVoicePhoneAgentProductionSmokeHTML = (report, options = {}) => {
|
|
23009
23378
|
const title = options.title ?? "AbsoluteJS Voice Phone Smoke Contract";
|
|
23010
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
23011
|
-
const outcomes = report.observed.lifecycleOutcomes.map((outcome) => `<span class="pill">${
|
|
23012
|
-
const requirements = report.required.map((requirement) => `<span class="pill">${
|
|
23013
|
-
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>`;
|
|
23014
23383
|
};
|
|
23015
23384
|
var createVoicePhoneAgentProductionSmokeJSONHandler = (options) => async ({
|
|
23016
23385
|
query,
|
|
@@ -23033,7 +23402,7 @@ var createVoicePhoneAgentProductionSmokeHTMLHandler = (options) => async ({
|
|
|
23033
23402
|
var createVoicePhoneAgentProductionSmokeRoutes = (options) => {
|
|
23034
23403
|
const path = options.path ?? "/api/voice/phone/smoke-contract";
|
|
23035
23404
|
const htmlPath = options.htmlPath === undefined ? "/voice/phone/smoke-contract" : options.htmlPath;
|
|
23036
|
-
const routes = new
|
|
23405
|
+
const routes = new Elysia42({
|
|
23037
23406
|
name: options.name ?? "absolutejs-voice-phone-smoke-contract"
|
|
23038
23407
|
}).get(path, createVoicePhoneAgentProductionSmokeJSONHandler(options));
|
|
23039
23408
|
if (htmlPath) {
|
|
@@ -23076,7 +23445,7 @@ var PHONE_AGENT_LIFECYCLE_STAGES = [
|
|
|
23076
23445
|
"completed",
|
|
23077
23446
|
"failed"
|
|
23078
23447
|
];
|
|
23079
|
-
var
|
|
23448
|
+
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
23080
23449
|
var loadRouteJson = async (input) => {
|
|
23081
23450
|
const response = await input.app.handle(new Request(new URL(input.path, input.origin).toString(), {
|
|
23082
23451
|
headers: {
|
|
@@ -23314,10 +23683,10 @@ var renderVoicePhoneAgentSetupHTML = (report) => {
|
|
|
23314
23683
|
const entry = findCarrierMatrixEntry(report.matrix, carrier);
|
|
23315
23684
|
const urls = entry?.setup.urls;
|
|
23316
23685
|
const primaryUrl = carrier.provider === "plivo" ? urls?.twiml : urls?.twiml;
|
|
23317
|
-
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>`;
|
|
23318
23687
|
}).join("");
|
|
23319
|
-
const stageList = report.lifecycleStages.map((stage) => `<li><code>${
|
|
23320
|
-
const snippet =
|
|
23688
|
+
const stageList = report.lifecycleStages.map((stage) => `<li><code>${escapeHtml42(stage)}</code></li>`).join("");
|
|
23689
|
+
const snippet = escapeHtml42(`const phoneAgent = createVoicePhoneAgent({
|
|
23321
23690
|
carriers: [
|
|
23322
23691
|
{
|
|
23323
23692
|
provider: 'twilio',
|
|
@@ -23351,11 +23720,11 @@ app.use(
|
|
|
23351
23720
|
);`);
|
|
23352
23721
|
const checklist = report.carriers.map((carrier) => {
|
|
23353
23722
|
const instruction = report.setupInstructions.find((candidate) => candidate.provider === carrier.provider && candidate.carrierName === (carrier.name ?? carrier.provider));
|
|
23354
|
-
const issueList = instruction?.issues.map((issue) => `<li>${
|
|
23355
|
-
const steps = instruction?.steps.map((step) => `<li>${
|
|
23356
|
-
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>`;
|
|
23357
23726
|
}).join("");
|
|
23358
|
-
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>`;
|
|
23359
23728
|
};
|
|
23360
23729
|
var createVoicePhoneAgent = (options) => {
|
|
23361
23730
|
const carrierSummaries = options.carriers.map((carrier) => ({
|
|
@@ -23364,7 +23733,7 @@ var createVoicePhoneAgent = (options) => {
|
|
|
23364
23733
|
setupPath: resolveSetupPath(carrier),
|
|
23365
23734
|
smokePath: resolveSmokePath(carrier)
|
|
23366
23735
|
}));
|
|
23367
|
-
const app = new
|
|
23736
|
+
const app = new Elysia43({
|
|
23368
23737
|
name: options.name ?? "absolutejs-voice-phone-agent"
|
|
23369
23738
|
});
|
|
23370
23739
|
for (const carrier of options.carriers) {
|
|
@@ -24994,8 +25363,8 @@ var createOpenAIVoiceTTS = (options) => {
|
|
|
24994
25363
|
};
|
|
24995
25364
|
};
|
|
24996
25365
|
// src/providerCapabilities.ts
|
|
24997
|
-
import { Elysia as
|
|
24998
|
-
var
|
|
25366
|
+
import { Elysia as Elysia44 } from "elysia";
|
|
25367
|
+
var escapeHtml43 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
24999
25368
|
var fromProviderList = (kind, providers, options) => (providers ?? []).map((provider) => ({
|
|
25000
25369
|
configured: true,
|
|
25001
25370
|
features: options.features?.[provider],
|
|
@@ -25058,27 +25427,27 @@ var summarizeVoiceProviderCapabilities = async (options) => {
|
|
|
25058
25427
|
var renderVoiceProviderCapabilityHTML = (report, options = {}) => {
|
|
25059
25428
|
const title = options.title ?? "Voice Provider Capabilities";
|
|
25060
25429
|
const cards = report.capabilities.map((capability) => {
|
|
25061
|
-
const features = (capability.features ?? []).map((feature) => `<span class="pill">${
|
|
25062
|
-
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)}">
|
|
25063
25432
|
<div class="card-header">
|
|
25064
25433
|
<div>
|
|
25065
|
-
<p class="eyebrow">${
|
|
25066
|
-
<h2>${
|
|
25434
|
+
<p class="eyebrow">${escapeHtml43(capability.kind)}</p>
|
|
25435
|
+
<h2>${escapeHtml43(capability.label ?? capability.provider)}</h2>
|
|
25067
25436
|
</div>
|
|
25068
|
-
<strong>${
|
|
25437
|
+
<strong>${escapeHtml43(capability.status)}</strong>
|
|
25069
25438
|
</div>
|
|
25070
|
-
${capability.description ? `<p>${
|
|
25439
|
+
${capability.description ? `<p>${escapeHtml43(capability.description)}</p>` : ""}
|
|
25071
25440
|
<dl>
|
|
25072
25441
|
<div><dt>Configured</dt><dd>${capability.configured ? "yes" : "no"}</dd></div>
|
|
25073
25442
|
<div><dt>Selected</dt><dd>${capability.selected ? "yes" : "no"}</dd></div>
|
|
25074
|
-
<div><dt>Model</dt><dd>${
|
|
25443
|
+
<div><dt>Model</dt><dd>${escapeHtml43(capability.model ?? "default")}</dd></div>
|
|
25075
25444
|
<div><dt>Runs</dt><dd>${String(capability.health?.runCount ?? 0)}</dd></div>
|
|
25076
25445
|
<div><dt>Errors</dt><dd>${String(capability.health?.errorCount ?? 0)}</dd></div>
|
|
25077
25446
|
</dl>
|
|
25078
25447
|
${features ? `<div class="features">${features}</div>` : ""}
|
|
25079
25448
|
</article>`;
|
|
25080
25449
|
}).join("");
|
|
25081
|
-
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>`;
|
|
25082
25451
|
};
|
|
25083
25452
|
var createVoiceProviderCapabilityJSONHandler = (options) => async () => summarizeVoiceProviderCapabilities(options);
|
|
25084
25453
|
var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
@@ -25095,7 +25464,7 @@ var createVoiceProviderCapabilityHTMLHandler = (options) => async () => {
|
|
|
25095
25464
|
var createVoiceProviderCapabilityRoutes = (options) => {
|
|
25096
25465
|
const path = options.path ?? "/api/provider-capabilities";
|
|
25097
25466
|
const htmlPath = options.htmlPath === undefined ? `${path}/htmx` : options.htmlPath;
|
|
25098
|
-
const routes = new
|
|
25467
|
+
const routes = new Elysia44({
|
|
25099
25468
|
name: options.name ?? "absolutejs-voice-provider-capabilities"
|
|
25100
25469
|
}).get(path, createVoiceProviderCapabilityJSONHandler(options));
|
|
25101
25470
|
if (htmlPath) {
|
|
@@ -25104,7 +25473,7 @@ var createVoiceProviderCapabilityRoutes = (options) => {
|
|
|
25104
25473
|
return routes;
|
|
25105
25474
|
};
|
|
25106
25475
|
// src/providerOrchestration.ts
|
|
25107
|
-
import { Elysia as
|
|
25476
|
+
import { Elysia as Elysia45 } from "elysia";
|
|
25108
25477
|
var defaultRequirement = {
|
|
25109
25478
|
minProviders: 1,
|
|
25110
25479
|
requireBudgetPolicy: false,
|
|
@@ -25117,7 +25486,7 @@ var statusRank4 = {
|
|
|
25117
25486
|
warn: 1,
|
|
25118
25487
|
fail: 2
|
|
25119
25488
|
};
|
|
25120
|
-
var
|
|
25489
|
+
var escapeHtml44 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25121
25490
|
var isProviderList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
25122
25491
|
var uniqueSorted6 = (values) => [
|
|
25123
25492
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
@@ -25260,27 +25629,27 @@ var renderVoiceProviderOrchestrationMarkdown = (report) => {
|
|
|
25260
25629
|
};
|
|
25261
25630
|
var renderVoiceProviderOrchestrationHTML = (report, options = {}) => {
|
|
25262
25631
|
const title = options.title ?? "Voice Provider Orchestration";
|
|
25263
|
-
const cards = report.surfaces.map((surface) => `<article class="card ${
|
|
25264
|
-
<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>
|
|
25265
25634
|
<dl>
|
|
25266
|
-
<div><dt>Providers</dt><dd>${
|
|
25267
|
-
<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>
|
|
25268
25637
|
<div><dt>Circuit breaker</dt><dd>${surface.circuitBreaker ? "yes" : "no"}</dd></div>
|
|
25269
25638
|
<div><dt>Timeout</dt><dd>${surface.timeoutBudget ? `${String(surface.timeoutMs)}ms` : "none"}</dd></div>
|
|
25270
25639
|
<div><dt>Max cost</dt><dd>${surface.budgetPolicy.maxCost ?? "none"}</dd></div>
|
|
25271
25640
|
<div><dt>Max latency</dt><dd>${surface.budgetPolicy.maxLatencyMs ? `${String(surface.budgetPolicy.maxLatencyMs)}ms` : "none"}</dd></div>
|
|
25272
25641
|
<div><dt>Min quality</dt><dd>${surface.budgetPolicy.minQuality ?? "none"}</dd></div>
|
|
25273
|
-
<div><dt>Fallback mode</dt><dd>${
|
|
25642
|
+
<div><dt>Fallback mode</dt><dd>${escapeHtml44(surface.fallbackMode || "default")}</dd></div>
|
|
25274
25643
|
</dl>
|
|
25275
|
-
${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>"}
|
|
25276
25645
|
</article>`).join("");
|
|
25277
|
-
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>`;
|
|
25278
25647
|
};
|
|
25279
25648
|
var createVoiceProviderOrchestrationRoutes = (options) => {
|
|
25280
25649
|
const path = options.path ?? "/api/voice/provider-orchestration";
|
|
25281
25650
|
const htmlPath = options.htmlPath === undefined ? "/voice/provider-orchestration" : options.htmlPath;
|
|
25282
25651
|
const markdownPath = options.markdownPath === undefined ? "/voice/provider-orchestration.md" : options.markdownPath;
|
|
25283
|
-
const routes = new
|
|
25652
|
+
const routes = new Elysia45({
|
|
25284
25653
|
name: options.name ?? "absolutejs-voice-provider-orchestration"
|
|
25285
25654
|
}).get(path, () => buildVoiceProviderOrchestrationReport(options));
|
|
25286
25655
|
if (htmlPath) {
|
|
@@ -25451,7 +25820,7 @@ var assertVoiceProviderRoutingContractEvidence = (reports, input = {}) => {
|
|
|
25451
25820
|
return report;
|
|
25452
25821
|
};
|
|
25453
25822
|
// src/providerSlo.ts
|
|
25454
|
-
import { Elysia as
|
|
25823
|
+
import { Elysia as Elysia46 } from "elysia";
|
|
25455
25824
|
var defaultThresholds = {
|
|
25456
25825
|
llm: {
|
|
25457
25826
|
maxAverageElapsedMs: 2500,
|
|
@@ -25484,7 +25853,7 @@ var statusRank5 = {
|
|
|
25484
25853
|
warn: 1,
|
|
25485
25854
|
fail: 2
|
|
25486
25855
|
};
|
|
25487
|
-
var
|
|
25856
|
+
var escapeHtml45 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25488
25857
|
var roundMetric3 = (value) => Math.round(value * 1e4) / 1e4;
|
|
25489
25858
|
var rate3 = (count, total) => count / Math.max(1, total);
|
|
25490
25859
|
var uniqueSorted7 = (values) => [
|
|
@@ -25780,11 +26149,11 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25780
26149
|
const title = options.title ?? "AbsoluteJS Voice Provider SLOs";
|
|
25781
26150
|
const kindCards = providerKinds.map((kind) => {
|
|
25782
26151
|
const kindReport = report.kinds[kind];
|
|
25783
|
-
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("");
|
|
25784
26153
|
const providers = kindReport.providers.length ? kindReport.providers.join(", ") : "none recorded";
|
|
25785
|
-
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>`;
|
|
25786
26155
|
}).join("");
|
|
25787
|
-
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>";
|
|
25788
26157
|
const snippet = `createVoiceProviderSloRoutes({
|
|
25789
26158
|
store: runtimeStorage.traces,
|
|
25790
26159
|
requiredKinds: ['llm', 'stt', 'tts'],
|
|
@@ -25794,7 +26163,7 @@ var renderVoiceProviderSloHTML = (report, options = {}) => {
|
|
|
25794
26163
|
tts: { maxAverageElapsedMs: 1200, maxP95ElapsedMs: 2200 }
|
|
25795
26164
|
}
|
|
25796
26165
|
})`;
|
|
25797
|
-
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>`;
|
|
25798
26167
|
};
|
|
25799
26168
|
var createVoiceProviderSloRoutes = (options) => {
|
|
25800
26169
|
const path = options.path ?? "/api/voice/provider-slos";
|
|
@@ -25805,7 +26174,7 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25805
26174
|
...options.headers ?? {}
|
|
25806
26175
|
};
|
|
25807
26176
|
const buildReport = () => buildVoiceProviderSloReport(options);
|
|
25808
|
-
const app = new
|
|
26177
|
+
const app = new Elysia46({ name: options.name ?? "absolute-voice-provider-slos" });
|
|
25809
26178
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
25810
26179
|
if (markdownPath !== false) {
|
|
25811
26180
|
app.get(markdownPath, async () => {
|
|
@@ -25835,10 +26204,10 @@ var createVoiceProviderSloRoutes = (options) => {
|
|
|
25835
26204
|
return app;
|
|
25836
26205
|
};
|
|
25837
26206
|
// src/productionReadiness.ts
|
|
25838
|
-
import { Elysia as
|
|
26207
|
+
import { Elysia as Elysia52 } from "elysia";
|
|
25839
26208
|
|
|
25840
26209
|
// src/telephony/security.ts
|
|
25841
|
-
import { Elysia as
|
|
26210
|
+
import { Elysia as Elysia47 } from "elysia";
|
|
25842
26211
|
|
|
25843
26212
|
// src/postgresStore.ts
|
|
25844
26213
|
var normalizeIdentifierSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
|
|
@@ -26576,7 +26945,7 @@ var assertVoiceTelephonyWebhookSecurityEvidence = (report, input = {}) => {
|
|
|
26576
26945
|
};
|
|
26577
26946
|
var createVoiceTelephonyWebhookSecurityRoutes = (options) => {
|
|
26578
26947
|
const path = options.path ?? "/api/voice/telephony/webhook-security";
|
|
26579
|
-
return new
|
|
26948
|
+
return new Elysia47({
|
|
26580
26949
|
name: options.name ?? "absolutejs-voice-telephony-webhook-security"
|
|
26581
26950
|
}).get(path, () => buildVoiceTelephonyWebhookSecurityReport(options.options));
|
|
26582
26951
|
};
|
|
@@ -26633,8 +27002,8 @@ var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
|
|
|
26633
27002
|
};
|
|
26634
27003
|
|
|
26635
27004
|
// src/opsRecovery.ts
|
|
26636
|
-
import { Elysia as
|
|
26637
|
-
var
|
|
27005
|
+
import { Elysia as Elysia48 } from "elysia";
|
|
27006
|
+
var escapeHtml46 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26638
27007
|
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
26639
27008
|
var hrefForSession = (value, sessionId) => {
|
|
26640
27009
|
if (typeof value === "function") {
|
|
@@ -26848,19 +27217,19 @@ ${failedSessions || "None."}
|
|
|
26848
27217
|
${report.latency ? renderVoiceLatencySLOMarkdown(report.latency, { title: "Latency SLO" }) : "Latency SLO disabled."}
|
|
26849
27218
|
`;
|
|
26850
27219
|
};
|
|
26851
|
-
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>`;
|
|
26852
27221
|
var renderVoiceOpsRecoveryHTML = (report, options = {}) => {
|
|
26853
27222
|
const title = options.title ?? "Voice Ops Recovery";
|
|
26854
|
-
const issues = report.issues.map((issue) => `<tr><td>${
|
|
26855
|
-
const providers = report.providers.providers.map((provider) => `<tr><td>${
|
|
26856
|
-
const failedSessions = report.failedSessions.map((session) => `<li>${session.operationsRecordHref ? `<a href="${
|
|
26857
|
-
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>`;
|
|
26858
27227
|
};
|
|
26859
27228
|
var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
26860
27229
|
const path = options.path ?? "/api/voice/ops-recovery";
|
|
26861
27230
|
const htmlPath = options.htmlPath === undefined ? "/ops-recovery" : options.htmlPath;
|
|
26862
27231
|
const markdownPath = options.markdownPath === undefined ? `${path}.md` : options.markdownPath;
|
|
26863
|
-
const routes = new
|
|
27232
|
+
const routes = new Elysia48({
|
|
26864
27233
|
name: options.name ?? "absolutejs-voice-ops-recovery"
|
|
26865
27234
|
}).get(path, async () => buildVoiceOpsRecoveryReport(options));
|
|
26866
27235
|
if (htmlPath) {
|
|
@@ -26890,21 +27259,21 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
|
26890
27259
|
};
|
|
26891
27260
|
|
|
26892
27261
|
// src/observabilityExport.ts
|
|
26893
|
-
import { Elysia as
|
|
27262
|
+
import { Elysia as Elysia51 } from "elysia";
|
|
26894
27263
|
import { Database as Database4 } from "bun:sqlite";
|
|
26895
27264
|
import { createHash } from "crypto";
|
|
26896
27265
|
import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
|
|
26897
27266
|
import { join as join3 } from "path";
|
|
26898
27267
|
|
|
26899
27268
|
// src/operationsRecord.ts
|
|
26900
|
-
import { Elysia as
|
|
27269
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
26901
27270
|
|
|
26902
27271
|
// src/traceTimeline.ts
|
|
26903
|
-
import { Elysia as
|
|
26904
|
-
var
|
|
27272
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
27273
|
+
var escapeHtml47 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
26905
27274
|
var getString16 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
26906
27275
|
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
26907
|
-
var
|
|
27276
|
+
var firstString4 = (payload, keys) => {
|
|
26908
27277
|
for (const key of keys) {
|
|
26909
27278
|
const value = getString16(payload[key]);
|
|
26910
27279
|
if (value) {
|
|
@@ -26913,7 +27282,7 @@ var firstString3 = (payload, keys) => {
|
|
|
26913
27282
|
}
|
|
26914
27283
|
return;
|
|
26915
27284
|
};
|
|
26916
|
-
var
|
|
27285
|
+
var firstNumber4 = (payload, keys) => {
|
|
26917
27286
|
for (const key of keys) {
|
|
26918
27287
|
const value = getNumber9(payload[key]);
|
|
26919
27288
|
if (value !== undefined) {
|
|
@@ -26922,20 +27291,20 @@ var firstNumber3 = (payload, keys) => {
|
|
|
26922
27291
|
}
|
|
26923
27292
|
return;
|
|
26924
27293
|
};
|
|
26925
|
-
var eventProvider = (event) =>
|
|
27294
|
+
var eventProvider = (event) => firstString4(event.payload, [
|
|
26926
27295
|
"provider",
|
|
26927
27296
|
"selectedProvider",
|
|
26928
27297
|
"fallbackProvider",
|
|
26929
27298
|
"variantId"
|
|
26930
27299
|
]);
|
|
26931
|
-
var eventStatus = (event) =>
|
|
27300
|
+
var eventStatus = (event) => firstString4(event.payload, [
|
|
26932
27301
|
"providerStatus",
|
|
26933
27302
|
"status",
|
|
26934
27303
|
"disposition",
|
|
26935
27304
|
"type",
|
|
26936
27305
|
"reason"
|
|
26937
27306
|
]);
|
|
26938
|
-
var eventElapsedMs2 = (event) =>
|
|
27307
|
+
var eventElapsedMs2 = (event) => firstNumber4(event.payload, ["elapsedMs", "latencyMs", "durationMs"]);
|
|
26939
27308
|
var resolveSessionHref5 = (value, sessionId) => {
|
|
26940
27309
|
if (value === false) {
|
|
26941
27310
|
return;
|
|
@@ -27084,17 +27453,17 @@ var summarizeVoiceTraceTimeline = (events, options = {}) => {
|
|
|
27084
27453
|
};
|
|
27085
27454
|
};
|
|
27086
27455
|
var formatMs4 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
27087
|
-
var renderProviderCards2 = (session) => session.providers.length === 0 ? '<p class="muted">No provider events recorded for this session.</p>' : `<div class="providers">${session.providers.map((provider) => `<article><strong>${
|
|
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>`;
|
|
27088
27457
|
var renderVoiceTraceTimelineSessionHTML = (session, options = {}) => {
|
|
27089
|
-
const events = session.events.map((event) => `<tr class="${
|
|
27090
|
-
const issues = session.evaluation.issues.length ? session.evaluation.issues.map((issue) => `<li class="${
|
|
27091
|
-
const supportLinks = session.operationsRecordHref ? `<p><a href="${
|
|
27092
|
-
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>`;
|
|
27093
27462
|
};
|
|
27094
|
-
var renderSessionRows = (report) => report.sessions.length === 0 ? '<tr><td colspan="7">No trace events recorded yet.</td></tr>' : report.sessions.map((session) => `<tr class="${
|
|
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("");
|
|
27095
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}}";
|
|
27096
27465
|
var renderVoiceTraceTimelineHTML = (report, options = {}) => {
|
|
27097
|
-
const snippet =
|
|
27466
|
+
const snippet = escapeHtml47(`const traceStore = createVoiceTraceSinkStore({
|
|
27098
27467
|
store: runtimeStorage.traces,
|
|
27099
27468
|
sinks: [
|
|
27100
27469
|
createVoiceTraceHTTPSink({
|
|
@@ -27120,13 +27489,13 @@ app.use(
|
|
|
27120
27489
|
traceDeliveries: runtimeStorage.traceDeliveries
|
|
27121
27490
|
})
|
|
27122
27491
|
);`);
|
|
27123
|
-
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>`;
|
|
27124
27493
|
};
|
|
27125
27494
|
var createVoiceTraceTimelineRoutes = (options) => {
|
|
27126
27495
|
const path = options.path ?? "/api/voice-traces";
|
|
27127
27496
|
const htmlPath = options.htmlPath ?? "/traces";
|
|
27128
27497
|
const title = options.title ?? "AbsoluteJS Voice Trace Timelines";
|
|
27129
|
-
const routes = new
|
|
27498
|
+
const routes = new Elysia49({
|
|
27130
27499
|
name: options.name ?? "absolutejs-voice-trace-timelines"
|
|
27131
27500
|
});
|
|
27132
27501
|
const buildReport = async () => summarizeVoiceTraceTimeline(await options.store.list(), {
|
|
@@ -27555,7 +27924,7 @@ var assertVoiceOperationsRecordProviderRecovery = (record, input = {}) => {
|
|
|
27555
27924
|
}
|
|
27556
27925
|
return report;
|
|
27557
27926
|
};
|
|
27558
|
-
var
|
|
27927
|
+
var escapeHtml48 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
27559
27928
|
var formatMs5 = (value) => value === undefined ? "n/a" : `${String(value)}ms`;
|
|
27560
27929
|
var outcomeLabels = (outcome) => [
|
|
27561
27930
|
outcome.complete ? "complete" : undefined,
|
|
@@ -27635,20 +28004,20 @@ var renderVoiceOperationsRecordGuardrailMarkdown = (record) => {
|
|
|
27635
28004
|
`);
|
|
27636
28005
|
};
|
|
27637
28006
|
var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
27638
|
-
const providers = record.providers.length ? record.providers.map((provider) => `<article><strong>${
|
|
27639
|
-
const transcript = record.transcript.length ? record.transcript.map((turn) => `<li><strong>${
|
|
27640
|
-
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>";
|
|
27641
28010
|
const providerDecisionSummary = record.providerDecisionSummary;
|
|
27642
|
-
const handoffs = record.handoffs.length ? record.handoffs.map((handoff) => `<li><strong>${
|
|
27643
|
-
const tools = record.tools.length ? record.tools.map((tool) => `<li><strong>${
|
|
27644
|
-
const reviews = record.reviews?.reviews.length ? record.reviews.reviews.map((review) => `<li><strong>${
|
|
27645
|
-
const tasks = record.tasks?.tasks.length ? record.tasks.tasks.map((task) => `<li><strong>${
|
|
27646
|
-
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>";
|
|
27647
28016
|
const guardrails = record.guardrails.total ? record.guardrails.decisions.map((decision) => {
|
|
27648
28017
|
const findings = decision.findings.map((finding) => finding.label ?? finding.ruleId ?? finding.action).filter((value) => typeof value === "string").join(", ") || "none";
|
|
27649
|
-
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>`;
|
|
27650
28019
|
}).join("") : "<li>No assistant.guardrail events recorded.</li>";
|
|
27651
|
-
const snippet =
|
|
28020
|
+
const snippet = escapeHtml48(`app.use(
|
|
27652
28021
|
createVoiceOperationsRecordRoutes({
|
|
27653
28022
|
audit: auditStore,
|
|
27654
28023
|
integrationEvents: opsEvents,
|
|
@@ -27662,16 +28031,16 @@ var renderVoiceOperationsRecordHTML = (record, options = {}) => {
|
|
|
27662
28031
|
tasks: opsTasks
|
|
27663
28032
|
})
|
|
27664
28033
|
);`);
|
|
27665
|
-
const incidentMarkdown =
|
|
27666
|
-
const incidentLink = options.incidentHref ? `<a href="${
|
|
27667
|
-
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>`;
|
|
27668
28037
|
};
|
|
27669
28038
|
var createVoiceOperationsRecordRoutes = (options) => {
|
|
27670
28039
|
const path = options.path ?? "/api/voice-operations/:sessionId";
|
|
27671
28040
|
const htmlPath = options.htmlPath === undefined ? "/voice-operations/:sessionId" : options.htmlPath;
|
|
27672
28041
|
const incidentPath = options.incidentPath === undefined ? `${path}/incident.md` : options.incidentPath;
|
|
27673
28042
|
const incidentHtmlPath = options.incidentHtmlPath === undefined && htmlPath ? `${htmlPath}/incident.md` : options.incidentHtmlPath;
|
|
27674
|
-
const routes = new
|
|
28043
|
+
const routes = new Elysia50({
|
|
27675
28044
|
name: options.name ?? "absolutejs-voice-operations-record"
|
|
27676
28045
|
});
|
|
27677
28046
|
const buildRecord = (sessionId) => buildVoiceOperationsRecord({
|
|
@@ -28032,7 +28401,7 @@ var checksumFile = async (path) => {
|
|
|
28032
28401
|
const buffer = await readFile2(path);
|
|
28033
28402
|
return createHash("sha256").update(buffer).digest("hex");
|
|
28034
28403
|
};
|
|
28035
|
-
var
|
|
28404
|
+
var byteLength2 = (value) => new TextEncoder().encode(value).byteLength;
|
|
28036
28405
|
var deliveryReceiptId = (runId) => `observability-export:${encodeURIComponent(runId)}`;
|
|
28037
28406
|
var safeArtifactFileName = (artifact) => {
|
|
28038
28407
|
const extension = artifact.contentType === "image/png" ? ".png" : artifact.contentType?.includes("markdown") ? ".md" : artifact.contentType?.includes("json") ? ".json" : "";
|
|
@@ -28322,7 +28691,7 @@ var createVoiceObservabilityExportReplayRoutes = (options) => {
|
|
|
28322
28691
|
...options.headers ?? {}
|
|
28323
28692
|
};
|
|
28324
28693
|
const buildReport = () => resolveVoiceObservabilityExportReplayReport(options.source);
|
|
28325
|
-
const app = new
|
|
28694
|
+
const app = new Elysia51({
|
|
28326
28695
|
name: options.name ?? "absolute-voice-observability-export-replay"
|
|
28327
28696
|
});
|
|
28328
28697
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -28945,7 +29314,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
28945
29314
|
destinationId,
|
|
28946
29315
|
destinationKind: destination.kind,
|
|
28947
29316
|
label,
|
|
28948
|
-
manifestBytes:
|
|
29317
|
+
manifestBytes: byteLength2(manifest),
|
|
28949
29318
|
schema: options.report.schema,
|
|
28950
29319
|
status: "delivered",
|
|
28951
29320
|
target
|
|
@@ -28990,7 +29359,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
28990
29359
|
destinationId,
|
|
28991
29360
|
destinationKind: destination.kind,
|
|
28992
29361
|
label,
|
|
28993
|
-
manifestBytes:
|
|
29362
|
+
manifestBytes: byteLength2(manifest),
|
|
28994
29363
|
schema: options.report.schema,
|
|
28995
29364
|
status: "delivered",
|
|
28996
29365
|
target: destination.bucket ? `s3://${destination.bucket}/${rootKey}` : rootKey
|
|
@@ -29012,7 +29381,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29012
29381
|
destinationId,
|
|
29013
29382
|
destinationKind: destination.kind,
|
|
29014
29383
|
label,
|
|
29015
|
-
manifestBytes:
|
|
29384
|
+
manifestBytes: byteLength2(manifest),
|
|
29016
29385
|
schema: options.report.schema,
|
|
29017
29386
|
status: "delivered",
|
|
29018
29387
|
target
|
|
@@ -29034,7 +29403,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29034
29403
|
destinationId,
|
|
29035
29404
|
destinationKind: destination.kind,
|
|
29036
29405
|
label,
|
|
29037
|
-
manifestBytes:
|
|
29406
|
+
manifestBytes: byteLength2(manifest),
|
|
29038
29407
|
schema: options.report.schema,
|
|
29039
29408
|
status: "delivered",
|
|
29040
29409
|
target
|
|
@@ -29070,7 +29439,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29070
29439
|
destinationId,
|
|
29071
29440
|
destinationKind: destination.kind,
|
|
29072
29441
|
label,
|
|
29073
|
-
manifestBytes:
|
|
29442
|
+
manifestBytes: byteLength2(manifest),
|
|
29074
29443
|
schema: options.report.schema,
|
|
29075
29444
|
status: "delivered",
|
|
29076
29445
|
target: destination.url
|
|
@@ -29083,7 +29452,7 @@ var deliverVoiceObservabilityExport = async (options) => {
|
|
|
29083
29452
|
destinationKind: destination.kind,
|
|
29084
29453
|
error: error instanceof Error ? error.message : String(error),
|
|
29085
29454
|
label,
|
|
29086
|
-
manifestBytes:
|
|
29455
|
+
manifestBytes: byteLength2(manifest),
|
|
29087
29456
|
schema: options.report.schema,
|
|
29088
29457
|
status: "failed",
|
|
29089
29458
|
target: observabilityExportDeliveryFailureTarget(destination)
|
|
@@ -29131,7 +29500,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
29131
29500
|
artifactDownload: options.links?.artifactDownload ?? (artifactDownloadPath ? (artifact) => `${artifactDownloadPath}/${encodeURIComponent(artifact.id)}` : undefined)
|
|
29132
29501
|
}
|
|
29133
29502
|
});
|
|
29134
|
-
const app = new
|
|
29503
|
+
const app = new Elysia51({
|
|
29135
29504
|
name: options.name ?? "absolute-voice-observability-export"
|
|
29136
29505
|
});
|
|
29137
29506
|
app.get(path, async () => Response.json(await buildReport(), { headers }));
|
|
@@ -29208,7 +29577,7 @@ var createVoiceObservabilityExportRoutes = (options = {}) => {
|
|
|
29208
29577
|
};
|
|
29209
29578
|
|
|
29210
29579
|
// src/productionReadiness.ts
|
|
29211
|
-
var
|
|
29580
|
+
var escapeHtml49 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
29212
29581
|
var rollupStatus4 = (checks) => checks.some((check) => check.status === "fail") ? "fail" : checks.some((check) => check.status === "warn") ? "warn" : "pass";
|
|
29213
29582
|
var readinessGateCodes = {
|
|
29214
29583
|
"Agent squad contracts": "voice.readiness.agent_squad_contracts",
|
|
@@ -30777,25 +31146,25 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
30777
31146
|
var buildVoiceProductionReadinessGate = async (options, input = {}) => summarizeVoiceProductionReadinessGate(await buildVoiceProductionReadinessReport(options, input), options.gate || undefined);
|
|
30778
31147
|
var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
30779
31148
|
const title = options.title ?? "AbsoluteJS Voice Production Readiness";
|
|
30780
|
-
const thresholdLink = report.links.sloReadinessThresholds ? `<p><a href="${
|
|
30781
|
-
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>` : "";
|
|
30782
31151
|
const checks = report.checks.map((check, index) => {
|
|
30783
|
-
const actions = (check.actions ?? []).map((action) => action.method === "POST" ? `<button type="button" data-readiness-action="${index}" data-action-url="${
|
|
30784
|
-
const explanation = check.gateExplanation ? `<p class="gate-explanation">Why this gate is ${
|
|
30785
|
-
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)}">
|
|
30786
31155
|
<div>
|
|
30787
|
-
<span>${
|
|
30788
|
-
<h2>${
|
|
30789
|
-
${check.detail ? `<p>${
|
|
31156
|
+
<span>${escapeHtml49(check.status.toUpperCase())}</span>
|
|
31157
|
+
<h2>${escapeHtml49(check.label)}</h2>
|
|
31158
|
+
${check.detail ? `<p>${escapeHtml49(check.detail)}</p>` : ""}
|
|
30790
31159
|
${explanation}
|
|
30791
|
-
${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>` : ""}
|
|
30792
31161
|
${actions ? `<p class="actions">${actions}</p>` : ""}
|
|
30793
31162
|
</div>
|
|
30794
|
-
<strong>${
|
|
30795
|
-
${check.href ? `<a href="${
|
|
31163
|
+
<strong>${escapeHtml49(String(check.value ?? check.status))}</strong>
|
|
31164
|
+
${check.href ? `<a href="${escapeHtml49(check.href)}">Open surface</a>` : ""}
|
|
30796
31165
|
</article>`;
|
|
30797
31166
|
}).join("");
|
|
30798
|
-
const snippet =
|
|
31167
|
+
const snippet = escapeHtml49(`createVoiceProductionReadinessRoutes({
|
|
30799
31168
|
htmlPath: '/production-readiness',
|
|
30800
31169
|
path: '/api/production-readiness',
|
|
30801
31170
|
gatePath: '/api/production-readiness/gate',
|
|
@@ -30811,13 +31180,13 @@ var renderVoiceProductionReadinessHTML = (report, options = {}) => {
|
|
|
30811
31180
|
providerRoutingContracts: loadProviderRoutingContracts,
|
|
30812
31181
|
store: traceStore
|
|
30813
31182
|
});`);
|
|
30814
|
-
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>`;
|
|
30815
31184
|
};
|
|
30816
31185
|
var createVoiceProductionReadinessRoutes = (options) => {
|
|
30817
31186
|
const path = options.path ?? "/api/production-readiness";
|
|
30818
31187
|
const gatePath = options.gatePath === undefined ? "/api/production-readiness/gate" : options.gatePath;
|
|
30819
31188
|
const htmlPath = options.htmlPath ?? "/production-readiness";
|
|
30820
|
-
const routes = new
|
|
31189
|
+
const routes = new Elysia52({
|
|
30821
31190
|
name: options.name ?? "absolutejs-voice-production-readiness"
|
|
30822
31191
|
});
|
|
30823
31192
|
const resolveOptions = async (input) => {
|
|
@@ -30865,8 +31234,8 @@ var createVoiceProductionReadinessRoutes = (options) => {
|
|
|
30865
31234
|
return routes;
|
|
30866
31235
|
};
|
|
30867
31236
|
// src/voiceMonitoring.ts
|
|
30868
|
-
import { Elysia as
|
|
30869
|
-
var
|
|
31237
|
+
import { Elysia as Elysia53 } from "elysia";
|
|
31238
|
+
var escapeHtml50 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
30870
31239
|
var issueIdForRun = (run) => `voice-monitor:${run.id}:${run.impactedSessions?.[0] ?? "global"}`;
|
|
30871
31240
|
var rollupStatus5 = (runs) => runs.some((run) => run.status === "fail") ? "fail" : runs.some((run) => run.status === "warn") ? "warn" : "pass";
|
|
30872
31241
|
var createVoiceMemoryMonitorIssueStore = (initial = []) => {
|
|
@@ -31119,14 +31488,14 @@ ${rows || "| none | pass | info | | | No monitors configured. |"}
|
|
|
31119
31488
|
};
|
|
31120
31489
|
var renderVoiceMonitorHTML = (report, options = {}) => {
|
|
31121
31490
|
const title = options.title ?? "Voice Monitors";
|
|
31122
|
-
const runs = report.runs.map((run) => `<tr><td>${
|
|
31123
|
-
const issues = report.issues.map((issue) => `<li><strong>${
|
|
31124
|
-
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({
|
|
31125
31494
|
evidence,
|
|
31126
31495
|
issueStore,
|
|
31127
31496
|
monitors: [defineVoiceMonitor(...)]
|
|
31128
31497
|
}));`);
|
|
31129
|
-
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>`;
|
|
31130
31499
|
};
|
|
31131
31500
|
var actorFromRequest = async (request) => {
|
|
31132
31501
|
if (!request.headers.get("content-type")?.includes("application/json")) {
|
|
@@ -31150,7 +31519,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
31150
31519
|
monitors: options.monitors,
|
|
31151
31520
|
now: options.now
|
|
31152
31521
|
});
|
|
31153
|
-
const routes = new
|
|
31522
|
+
const routes = new Elysia53({
|
|
31154
31523
|
name: options.name ?? "absolutejs-voice-monitoring"
|
|
31155
31524
|
}).get(path, report).get(`${path}.md`, async () => {
|
|
31156
31525
|
return new Response(renderVoiceMonitorMarkdown(await report()), {
|
|
@@ -31197,7 +31566,7 @@ var createVoiceMonitorRoutes = (options) => {
|
|
|
31197
31566
|
};
|
|
31198
31567
|
var createVoiceMonitorRunnerRoutes = (options) => {
|
|
31199
31568
|
const path = options.path ?? "/api/voice/monitor-runner";
|
|
31200
|
-
return new
|
|
31569
|
+
return new Elysia53({
|
|
31201
31570
|
name: options.name ?? "absolutejs-voice-monitor-runner"
|
|
31202
31571
|
}).get(path, () => ({
|
|
31203
31572
|
isRunning: options.runner.isRunning()
|
|
@@ -31573,8 +31942,8 @@ var recommendVoiceReadinessProfile = (options) => {
|
|
|
31573
31942
|
};
|
|
31574
31943
|
};
|
|
31575
31944
|
// src/providerStackRecommendations.ts
|
|
31576
|
-
import { Elysia as
|
|
31577
|
-
var
|
|
31945
|
+
import { Elysia as Elysia54 } from "elysia";
|
|
31946
|
+
var escapeHtml51 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
31578
31947
|
var profileProviderPriorities = {
|
|
31579
31948
|
"meeting-recorder": {
|
|
31580
31949
|
llm: ["openai", "anthropic", "gemini"],
|
|
@@ -31893,17 +32262,17 @@ var resolveProviderContractMatrixInput = async (matrix) => typeof matrix === "fu
|
|
|
31893
32262
|
var renderVoiceProviderContractMatrixHTML = (report, options = {}) => {
|
|
31894
32263
|
const title = options.title ?? "Voice Provider Contract Matrix";
|
|
31895
32264
|
const rows = report.rows.map((row) => {
|
|
31896
|
-
const checks = row.checks.map((check) => `<li class="${
|
|
31897
|
-
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)}">
|
|
31898
32267
|
<div>
|
|
31899
|
-
<p class="eyebrow">${
|
|
31900
|
-
<h2>${
|
|
31901
|
-
<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>
|
|
31902
32271
|
</div>
|
|
31903
32272
|
<ul>${checks}</ul>
|
|
31904
32273
|
</article>`;
|
|
31905
32274
|
}).join("");
|
|
31906
|
-
const snippet =
|
|
32275
|
+
const snippet = escapeHtml51(`const providerContracts = () =>
|
|
31907
32276
|
createVoiceProviderContractMatrixPreset('phone-agent', {
|
|
31908
32277
|
env: process.env,
|
|
31909
32278
|
providers: {
|
|
@@ -31924,7 +32293,7 @@ createVoiceProductionReadinessRoutes({
|
|
|
31924
32293
|
providerContractMatrix: () =>
|
|
31925
32294
|
buildVoiceProviderContractMatrix(providerContracts())
|
|
31926
32295
|
});`);
|
|
31927
|
-
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>`;
|
|
31928
32297
|
};
|
|
31929
32298
|
var createVoiceProviderContractMatrixJSONHandler = (matrix) => async () => buildVoiceProviderContractMatrix(await resolveProviderContractMatrixInput(matrix));
|
|
31930
32299
|
var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
@@ -31939,7 +32308,7 @@ var createVoiceProviderContractMatrixHTMLHandler = (options) => async () => {
|
|
|
31939
32308
|
var createVoiceProviderContractMatrixRoutes = (options) => {
|
|
31940
32309
|
const path = options.path ?? "/api/provider-contracts";
|
|
31941
32310
|
const htmlPath = options.htmlPath ?? "/provider-contracts";
|
|
31942
|
-
const routes = new
|
|
32311
|
+
const routes = new Elysia54({
|
|
31943
32312
|
name: options.name ?? "absolutejs-voice-provider-contract-matrix"
|
|
31944
32313
|
});
|
|
31945
32314
|
const jsonHandler = createVoiceProviderContractMatrixJSONHandler(options.matrix);
|
|
@@ -32057,7 +32426,7 @@ var assertVoiceProviderStackEvidence = (report, input = {}) => {
|
|
|
32057
32426
|
return assertion;
|
|
32058
32427
|
};
|
|
32059
32428
|
// src/opsConsoleRoutes.ts
|
|
32060
|
-
import { Elysia as
|
|
32429
|
+
import { Elysia as Elysia55 } from "elysia";
|
|
32061
32430
|
var DEFAULT_LINKS = [
|
|
32062
32431
|
{
|
|
32063
32432
|
description: "Quality gates for CI, deploy checks, and production readiness.",
|
|
@@ -32092,7 +32461,7 @@ var DEFAULT_LINKS = [
|
|
|
32092
32461
|
label: "Handoffs"
|
|
32093
32462
|
}
|
|
32094
32463
|
];
|
|
32095
|
-
var
|
|
32464
|
+
var escapeHtml52 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32096
32465
|
var countProviderStatuses = (providers) => {
|
|
32097
32466
|
const degradedStatuses = new Set(["degraded", "rate-limited", "suppressed"]);
|
|
32098
32467
|
const healthy = providers.filter((provider) => provider.status === "healthy").length;
|
|
@@ -32161,20 +32530,20 @@ var buildVoiceOpsConsoleReport = async (options) => {
|
|
|
32161
32530
|
trace
|
|
32162
32531
|
};
|
|
32163
32532
|
};
|
|
32164
|
-
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>`;
|
|
32165
32534
|
var renderVoiceOpsConsoleHTML = (report, options = {}) => {
|
|
32166
32535
|
const links = report.links.map((link) => `<article class="surface">
|
|
32167
|
-
<div><h2>${
|
|
32168
|
-
<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>
|
|
32169
32538
|
</article>`).join("");
|
|
32170
|
-
const sessions = report.recentSessions.length ? report.recentSessions.map((session) => `<tr><td>${
|
|
32171
|
-
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>';
|
|
32172
32541
|
const title = options.title ?? "AbsoluteJS Voice Ops Console";
|
|
32173
|
-
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>`;
|
|
32174
32543
|
};
|
|
32175
32544
|
var createVoiceOpsConsoleRoutes = (options) => {
|
|
32176
32545
|
const path = options.path ?? "/ops-console";
|
|
32177
|
-
const routes = new
|
|
32546
|
+
const routes = new Elysia55({
|
|
32178
32547
|
name: options.name ?? "absolutejs-voice-ops-console"
|
|
32179
32548
|
});
|
|
32180
32549
|
const getReport = () => buildVoiceOpsConsoleReport(options);
|
|
@@ -32191,7 +32560,7 @@ var createVoiceOpsConsoleRoutes = (options) => {
|
|
|
32191
32560
|
return routes;
|
|
32192
32561
|
};
|
|
32193
32562
|
// src/incidentBundle.ts
|
|
32194
|
-
import { Elysia as
|
|
32563
|
+
import { Elysia as Elysia56 } from "elysia";
|
|
32195
32564
|
var filterIncidentBundleArtifacts = (artifacts, filter = {}) => artifacts.filter((artifact) => {
|
|
32196
32565
|
if (filter.sessionId && artifact.sessionId !== filter.sessionId) {
|
|
32197
32566
|
return false;
|
|
@@ -32392,7 +32761,7 @@ var buildVoiceIncidentBundle = async (options) => {
|
|
|
32392
32761
|
var createVoiceIncidentBundleRoutes = (options) => {
|
|
32393
32762
|
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
32394
32763
|
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
32395
|
-
const routes = new
|
|
32764
|
+
const routes = new Elysia56({
|
|
32396
32765
|
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
32397
32766
|
});
|
|
32398
32767
|
const getSessionId = (params) => params.sessionId ?? "";
|
|
@@ -32593,19 +32962,19 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
32593
32962
|
};
|
|
32594
32963
|
};
|
|
32595
32964
|
// src/opsStatusRoutes.ts
|
|
32596
|
-
import { Elysia as
|
|
32597
|
-
var
|
|
32965
|
+
import { Elysia as Elysia57 } from "elysia";
|
|
32966
|
+
var escapeHtml53 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32598
32967
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
32599
32968
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
32600
32969
|
const surfaces = Object.entries(report.surfaces).map(([key, surface]) => {
|
|
32601
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;
|
|
32602
|
-
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>`;
|
|
32603
32972
|
}).join("");
|
|
32604
|
-
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>`;
|
|
32605
32974
|
};
|
|
32606
32975
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
32607
32976
|
const path = options.path ?? "/api/voice/ops-status";
|
|
32608
|
-
const routes = new
|
|
32977
|
+
const routes = new Elysia57({
|
|
32609
32978
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
32610
32979
|
});
|
|
32611
32980
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -33038,8 +33407,8 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
33038
33407
|
};
|
|
33039
33408
|
};
|
|
33040
33409
|
// src/traceDeliveryRoutes.ts
|
|
33041
|
-
import { Elysia as
|
|
33042
|
-
var
|
|
33410
|
+
import { Elysia as Elysia58 } from "elysia";
|
|
33411
|
+
var escapeHtml54 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
33043
33412
|
var getString20 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
33044
33413
|
var getNumber12 = (value) => {
|
|
33045
33414
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -33120,14 +33489,14 @@ var renderSinkResults2 = (delivery) => {
|
|
|
33120
33489
|
if (entries.length === 0) {
|
|
33121
33490
|
return "<p>No sink delivery attempts recorded yet.</p>";
|
|
33122
33491
|
}
|
|
33123
|
-
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>`;
|
|
33124
33493
|
};
|
|
33125
|
-
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>`;
|
|
33126
33495
|
var renderVoiceTraceDeliveryHTML = (report, options = {}) => {
|
|
33127
33496
|
const title = options.title ?? "AbsoluteJS Voice Trace Deliveries";
|
|
33128
|
-
const drainAction = options.workerPath === false ? "" : `<form method="post" action="${
|
|
33129
|
-
const rows = report.deliveries.map((delivery) => `<article class="delivery ${
|
|
33130
|
-
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>`;
|
|
33131
33500
|
};
|
|
33132
33501
|
var createVoiceTraceDeliveryJSONHandler = (options) => async ({ query }) => buildVoiceTraceDeliveryReport(options, resolveVoiceTraceDeliveryFilter(query, options.filter));
|
|
33133
33502
|
var createVoiceTraceDeliveryHTMLHandler = (options) => async ({ query }) => {
|
|
@@ -33147,7 +33516,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
33147
33516
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
33148
33517
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
33149
33518
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
33150
|
-
const routes = new
|
|
33519
|
+
const routes = new Elysia58({
|
|
33151
33520
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
33152
33521
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
33153
33522
|
if (htmlPath !== false) {
|
|
@@ -33244,7 +33613,7 @@ var createVoiceMemoryStore = () => {
|
|
|
33244
33613
|
return { get, getOrCreate, list, remove, set };
|
|
33245
33614
|
};
|
|
33246
33615
|
// src/opsWebhook.ts
|
|
33247
|
-
import { Elysia as
|
|
33616
|
+
import { Elysia as Elysia59 } from "elysia";
|
|
33248
33617
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
33249
33618
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
33250
33619
|
const encoder = new TextEncoder;
|
|
@@ -33374,7 +33743,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
33374
33743
|
};
|
|
33375
33744
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
33376
33745
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
33377
|
-
return new
|
|
33746
|
+
return new Elysia59().post(path, async ({ body, request, set }) => {
|
|
33378
33747
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
33379
33748
|
if (options.signingSecret) {
|
|
33380
33749
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -33829,7 +34198,7 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
33829
34198
|
};
|
|
33830
34199
|
};
|
|
33831
34200
|
// src/postCallAnalysis.ts
|
|
33832
|
-
import { Elysia as
|
|
34201
|
+
import { Elysia as Elysia60 } from "elysia";
|
|
33833
34202
|
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
33834
34203
|
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
33835
34204
|
var getPathValue3 = (source, path) => {
|
|
@@ -34008,7 +34377,7 @@ var resolvePostCallAnalysisReport = async (options, input) => {
|
|
|
34008
34377
|
};
|
|
34009
34378
|
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
34010
34379
|
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
34011
|
-
const routes = new
|
|
34380
|
+
const routes = new Elysia60({
|
|
34012
34381
|
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
34013
34382
|
});
|
|
34014
34383
|
routes.get(path, async ({ query }) => {
|
|
@@ -34033,7 +34402,7 @@ var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
|
34033
34402
|
return routes;
|
|
34034
34403
|
};
|
|
34035
34404
|
// src/guardrails.ts
|
|
34036
|
-
import { Elysia as
|
|
34405
|
+
import { Elysia as Elysia61 } from "elysia";
|
|
34037
34406
|
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
34038
34407
|
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
34039
34408
|
var matchesRule = async (rule, input) => {
|
|
@@ -34335,7 +34704,7 @@ var resolveGuardrailReport = async (options, input) => {
|
|
|
34335
34704
|
};
|
|
34336
34705
|
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
34337
34706
|
const path = options.path ?? "/api/voice/guardrails";
|
|
34338
|
-
const routes = new
|
|
34707
|
+
const routes = new Elysia61({
|
|
34339
34708
|
name: options.name ?? "absolutejs-voice-guardrails"
|
|
34340
34709
|
});
|
|
34341
34710
|
routes.all(path, async ({ request }) => {
|
|
@@ -34850,6 +35219,7 @@ export {
|
|
|
34850
35219
|
renderVoiceTraceHTML,
|
|
34851
35220
|
renderVoiceTraceDeliveryHTML,
|
|
34852
35221
|
renderVoiceToolContractHTML,
|
|
35222
|
+
renderVoiceTelephonyMediaHTML,
|
|
34853
35223
|
renderVoiceTelephonyCarrierMatrixHTML,
|
|
34854
35224
|
renderVoiceSloReadinessThresholdMarkdown,
|
|
34855
35225
|
renderVoiceSloReadinessThresholdHTML,
|
|
@@ -35047,6 +35417,7 @@ export {
|
|
|
35047
35417
|
createVoiceTelephonyWebhookRoutes,
|
|
35048
35418
|
createVoiceTelephonyWebhookHandler,
|
|
35049
35419
|
createVoiceTelephonyOutcomePolicy,
|
|
35420
|
+
createVoiceTelephonyMediaRoutes,
|
|
35050
35421
|
createVoiceTelephonyCarrierMatrixRoutes,
|
|
35051
35422
|
createVoiceTelephonyCarrierMatrix,
|
|
35052
35423
|
createVoiceTaskUpdatedEvent,
|
|
@@ -35299,6 +35670,7 @@ export {
|
|
|
35299
35670
|
buildVoiceTraceReplay,
|
|
35300
35671
|
buildVoiceTraceDeliveryReport,
|
|
35301
35672
|
buildVoiceTelephonyWebhookSecurityReport,
|
|
35673
|
+
buildVoiceTelephonyMediaReport,
|
|
35302
35674
|
buildVoiceSloReadinessThresholdReport,
|
|
35303
35675
|
buildVoiceSloCalibrationReport,
|
|
35304
35676
|
buildVoiceRealtimeProviderContractMatrix,
|