@absolutejs/voice 0.0.22-beta.463 → 0.0.22-beta.465

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.
@@ -2159,669 +2159,12 @@ var serverMessageToAction = (message) => {
2159
2159
  }
2160
2160
  };
2161
2161
 
2162
- // node_modules/@absolutejs/media/dist/index.js
2163
- var formatLabel = (format) => `${format.container}/${format.encoding}/${String(format.sampleRateHz)}hz/${String(format.channels)}ch`;
2164
- var formatMatches = (actual, expected) => actual.container === expected.container && actual.encoding === expected.encoding && actual.sampleRateHz === expected.sampleRateHz && actual.channels === expected.channels;
2165
- var pushIssue = (issues, severity, code, message) => {
2166
- issues.push({ code, message, severity });
2167
- };
2168
- var numericMetadata = (frame, key) => {
2169
- const value = frame.metadata?.[key];
2170
- return typeof value === "number" && Number.isFinite(value) ? value : undefined;
2171
- };
2172
- var average3 = (values) => values.length === 0 ? undefined : values.reduce((total, value) => total + value, 0) / values.length;
2173
- var max = (values) => values.length === 0 ? undefined : Math.max(...values);
2174
- var min = (values) => values.length === 0 ? undefined : Math.min(...values);
2175
- var numericStat = (stat, key) => {
2176
- const value = stat[key];
2177
- return typeof value === "number" && Number.isFinite(value) ? value : undefined;
2178
- };
2179
- var booleanStat = (stat, key) => {
2180
- const value = stat[key];
2181
- return typeof value === "boolean" ? value : undefined;
2182
- };
2183
- var stringStat = (stat, key) => {
2184
- const value = stat[key];
2185
- return typeof value === "string" ? value : undefined;
2186
- };
2187
- var statKey = (stat) => String(stat.id ?? stringStat(stat, "ssrc") ?? numericStat(stat, "ssrc") ?? stringStat(stat, "trackIdentifier") ?? stringStat(stat, "mid") ?? "unknown");
2188
- var secondsToMs = (value) => value === undefined ? undefined : value * 1000;
2189
- var DEFAULT_TELEPHONY_FORMAT = {
2190
- channels: 1,
2191
- container: "raw",
2192
- encoding: "mulaw",
2193
- sampleRateHz: 8000
2194
- };
2195
- var bytesToBase64 = (audio) => {
2196
- const bytes = audio instanceof ArrayBuffer ? new Uint8Array(audio) : new Uint8Array(audio.buffer, audio.byteOffset, audio.byteLength);
2197
- return Buffer.from(bytes).toString("base64");
2198
- };
2199
- var base64ToBytes = (value) => new Uint8Array(Buffer.from(value, "base64"));
2200
- var unknownRecord = (value) => value && typeof value === "object" ? value : {};
2201
- var firstString = (records, keys) => {
2202
- for (const record of records) {
2203
- for (const key of keys) {
2204
- const value = record[key];
2205
- if (typeof value === "string" && value.length > 0) {
2206
- return value;
2207
- }
2208
- if (typeof value === "number" && Number.isFinite(value)) {
2209
- return String(value);
2210
- }
2211
- }
2212
- }
2213
- return;
2214
- };
2215
- var firstNumber = (records, keys) => {
2216
- for (const record of records) {
2217
- for (const key of keys) {
2218
- const value = record[key];
2219
- if (typeof value === "number" && Number.isFinite(value)) {
2220
- return value;
2221
- }
2222
- if (typeof value === "string") {
2223
- const parsed = Number(value);
2224
- if (Number.isFinite(parsed)) {
2225
- return parsed;
2226
- }
2227
- }
2228
- }
2229
- }
2230
- return;
2231
- };
2232
- var telephonyDirection = (track) => {
2233
- const normalized = track?.toLowerCase();
2234
- if (!normalized) {
2235
- return "unknown";
2236
- }
2237
- if (normalized.includes("inbound") || normalized.includes("caller") || normalized.includes("in")) {
2238
- return "inbound";
2239
- }
2240
- if (normalized.includes("outbound") || normalized.includes("assistant") || normalized.includes("out")) {
2241
- return "outbound";
2242
- }
2243
- return "unknown";
2244
- };
2245
- var telephonyFrameKind = (direction) => direction === "outbound" ? "assistant-audio" : "input-audio";
2246
- var telephonyEventKind = (envelope) => {
2247
- const raw = firstString([envelope], ["event", "type", "eventType"]) ?? firstString([unknownRecord(envelope.message)], ["event", "type"]);
2248
- const normalized = raw?.toLowerCase().replace(/[_\s-]+/g, "-");
2249
- if (!normalized) {
2250
- return "unknown";
2251
- }
2252
- if (normalized.includes("connected")) {
2253
- return "connected";
2254
- }
2255
- if (normalized.includes("start")) {
2256
- return "start";
2257
- }
2258
- if (normalized.includes("media")) {
2259
- return "media";
2260
- }
2261
- if (normalized.includes("stop") || normalized.includes("closed")) {
2262
- return "stop";
2263
- }
2264
- if (normalized.includes("error") || normalized.includes("failed")) {
2265
- return "error";
2266
- }
2267
- return "unknown";
2268
- };
2269
- var normalizeWebRTCStat = (stat) => {
2270
- const sample = {};
2271
- for (const [key, value] of Object.entries(stat)) {
2272
- if (value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string") {
2273
- sample[key] = value;
2274
- }
2275
- }
2276
- return sample;
2277
- };
2278
- var parseTelephonyMediaFrame = (input) => {
2279
- const envelope = input.envelope;
2280
- const media = unknownRecord(envelope.media);
2281
- const payload = firstString([media, envelope], ["payload", "audio", "data"]) ?? firstString([unknownRecord(envelope.message)], ["payload"]);
2282
- if (!payload) {
2283
- return;
2284
- }
2285
- const carrier = input.carrier ?? firstString([envelope], ["provider"]) ?? "telephony";
2286
- const streamId = firstString([media, envelope], ["streamSid", "stream_id", "streamId", "streamId", "callSid", "call_id"]);
2287
- const sequenceNumber = firstString([media, envelope], ["sequenceNumber", "sequence_number", "chunk"]);
2288
- const track = firstString([media, envelope], ["track", "direction"]);
2289
- const direction = telephonyDirection(track);
2290
- const timestamp = firstNumber([media, envelope], ["timestamp", "time", "startedAt"]);
2291
- return {
2292
- at: timestamp,
2293
- audio: base64ToBytes(payload),
2294
- format: input.format ?? DEFAULT_TELEPHONY_FORMAT,
2295
- id: [
2296
- carrier,
2297
- streamId ?? input.sessionId ?? "stream",
2298
- sequenceNumber ?? timestamp ?? Date.now()
2299
- ].join(":"),
2300
- kind: telephonyFrameKind(direction),
2301
- metadata: {
2302
- carrier,
2303
- direction,
2304
- event: firstString([envelope], ["event", "type"]),
2305
- sequenceNumber,
2306
- streamId,
2307
- track
2308
- },
2309
- sessionId: input.sessionId ?? streamId,
2310
- source: "telephony"
2311
- };
2312
- };
2313
- var serializeTelephonyMediaFrame = (input) => {
2314
- const carrier = input.carrier ?? input.frame.metadata?.carrier ?? "telephony";
2315
- const streamId = input.streamId ?? (typeof input.frame.metadata?.streamId === "string" ? input.frame.metadata.streamId : input.frame.sessionId);
2316
- const sequenceNumber = input.sequenceNumber ?? (typeof input.frame.metadata?.sequenceNumber === "string" || typeof input.frame.metadata?.sequenceNumber === "number" ? input.frame.metadata.sequenceNumber : undefined);
2317
- const direction = input.frame.kind === "assistant-audio" ? "outbound" : "inbound";
2318
- const payload = input.frame.audio ? bytesToBase64(input.frame.audio) : "";
2319
- if (carrier === "twilio") {
2320
- return {
2321
- event: "media",
2322
- sequenceNumber,
2323
- streamSid: streamId,
2324
- media: {
2325
- payload,
2326
- timestamp: input.frame.at,
2327
- track: direction
2328
- }
2329
- };
2330
- }
2331
- if (carrier === "telnyx") {
2332
- return {
2333
- event: "media",
2334
- stream_id: streamId,
2335
- sequence_number: sequenceNumber,
2336
- media: {
2337
- payload,
2338
- timestamp: input.frame.at,
2339
- track: direction
2340
- }
2341
- };
2342
- }
2343
- if (carrier === "plivo") {
2344
- return {
2345
- event: "media",
2346
- streamId,
2347
- sequenceNumber,
2348
- media: {
2349
- payload,
2350
- timestamp: input.frame.at,
2351
- track: direction
2352
- }
2353
- };
2354
- }
2355
- return {
2356
- event: "media",
2357
- provider: carrier,
2358
- sequenceNumber,
2359
- streamId,
2360
- media: {
2361
- payload,
2362
- timestamp: input.frame.at,
2363
- track: direction
2364
- }
2365
- };
2366
- };
2367
- var createTelephonyMediaSerializer = (input) => {
2368
- const format = input.format ?? DEFAULT_TELEPHONY_FORMAT;
2369
- return {
2370
- carrier: input.carrier,
2371
- format,
2372
- parse: (envelope) => parseTelephonyMediaFrame({
2373
- carrier: input.carrier,
2374
- envelope,
2375
- format,
2376
- sessionId: input.sessionId ?? input.streamId
2377
- }),
2378
- serialize: (frame) => serializeTelephonyMediaFrame({
2379
- carrier: input.carrier,
2380
- frame,
2381
- streamId: input.streamId
2382
- })
2383
- };
2384
- };
2385
- var parseTelephonyStreamEvent = (input) => {
2386
- const envelope = input.envelope;
2387
- const media = unknownRecord(envelope.media);
2388
- const start = unknownRecord(envelope.start);
2389
- const stop = unknownRecord(envelope.stop);
2390
- const errorRecord = unknownRecord(envelope.error);
2391
- const kind = telephonyEventKind(envelope);
2392
- const carrier = input.carrier ?? firstString([envelope], ["provider", "carrier"]) ?? "telephony";
2393
- const frame = kind === "media" ? parseTelephonyMediaFrame({
2394
- carrier,
2395
- envelope,
2396
- format: input.format,
2397
- sessionId: input.sessionId
2398
- }) : undefined;
2399
- const streamId = firstString([media, start, stop, envelope], ["streamSid", "stream_id", "streamId", "callSid", "call_id"]) ?? input.sessionId;
2400
- const sequenceNumber = firstString([media, envelope], ["sequenceNumber", "sequence_number", "chunk"]);
2401
- const track = firstString([media, envelope], ["track", "direction"]);
2402
- return {
2403
- audioBytes: frame?.audio ? frame.audio instanceof ArrayBuffer ? frame.audio.byteLength : frame.audio.byteLength : 0,
2404
- at: frame?.at ?? firstNumber([media, start, stop, envelope], ["timestamp", "time", "startedAt"]),
2405
- carrier,
2406
- direction: telephonyDirection(track),
2407
- error: firstString([errorRecord, envelope], ["message", "error", "reason"]),
2408
- kind,
2409
- sequenceNumber,
2410
- streamId
2411
- };
2412
- };
2413
- var buildMediaTelephonyStreamLifecycleReport = (input = {}) => {
2414
- const envelopes = input.envelopes ?? [];
2415
- const events = envelopes.map((envelope) => parseTelephonyStreamEvent({
2416
- carrier: input.carrier,
2417
- envelope
2418
- }));
2419
- const issues = [];
2420
- const startedIndex = events.findIndex((event) => event.kind === "start");
2421
- const firstMediaIndex = events.findIndex((event) => event.kind === "media");
2422
- const stoppedIndex = events.findIndex((event) => event.kind === "stop");
2423
- const started = startedIndex >= 0;
2424
- const stopped = stoppedIndex >= 0;
2425
- const mediaEvents = events.filter((event) => event.kind === "media");
2426
- const audioBytes = events.reduce((total, event) => total + event.audioBytes, 0);
2427
- const minAudioBytes = input.minAudioBytes ?? 1;
2428
- const streamIds = Array.from(new Set(events.map((event) => event.streamId).filter(Boolean)));
2429
- if ((input.requireStart ?? true) && !started) {
2430
- pushIssue(issues, "error", "media.telephony_missing_start", "Telephony media stream did not include a start event.");
2431
- }
2432
- if ((input.requireMedia ?? true) && mediaEvents.length === 0) {
2433
- pushIssue(issues, "error", "media.telephony_missing_media", "Telephony media stream did not include media payload events.");
2434
- }
2435
- if ((input.requireStop ?? true) && !stopped) {
2436
- pushIssue(issues, input.maxMissingStop === false ? "warning" : "error", "media.telephony_missing_stop", "Telephony media stream did not include a stop event.");
2437
- }
2438
- if (started && firstMediaIndex >= 0 && firstMediaIndex < startedIndex) {
2439
- pushIssue(issues, "error", "media.telephony_media_before_start", "Telephony media payload arrived before the stream start event.");
2440
- }
2441
- if (stopped && firstMediaIndex >= 0 && stoppedIndex < firstMediaIndex) {
2442
- pushIssue(issues, "error", "media.telephony_stop_before_media", "Telephony media stream stopped before any media payload arrived.");
2443
- }
2444
- if (mediaEvents.length > 0 && audioBytes < minAudioBytes) {
2445
- pushIssue(issues, "error", "media.telephony_no_audio_bytes", `Telephony media stream parsed ${String(audioBytes)} audio byte(s), below required ${String(minAudioBytes)}.`);
2446
- }
2447
- for (const event of events) {
2448
- if (event.kind === "error") {
2449
- pushIssue(issues, "error", "media.telephony_stream_error", event.error ?? "Telephony media stream emitted an error event.");
2450
- }
2451
- }
2452
- return {
2453
- audioBytes,
2454
- carrier: input.carrier,
2455
- checkedAt: Date.now(),
2456
- events,
2457
- issues,
2458
- mediaEvents: mediaEvents.length,
2459
- started,
2460
- status: issues.some((issue) => issue.severity === "error") ? "fail" : issues.length > 0 ? "warn" : "pass",
2461
- stopped,
2462
- streamIds
2463
- };
2464
- };
2465
- var buildMediaResamplingPlan = (input) => {
2466
- const required = !formatMatches(input.inputFormat, input.outputFormat);
2467
- return {
2468
- inputFormat: input.inputFormat,
2469
- outputFormat: input.outputFormat,
2470
- ratio: input.outputFormat.sampleRateHz / input.inputFormat.sampleRateHz,
2471
- required,
2472
- status: input.inputFormat.container === input.outputFormat.container && input.inputFormat.encoding === input.outputFormat.encoding && input.inputFormat.channels === input.outputFormat.channels ? "pass" : "warn"
2473
- };
2474
- };
2475
- var speechProbability = (frame) => {
2476
- if (frame.metadata?.isSpeech === true) {
2477
- return 1;
2478
- }
2479
- if (frame.metadata?.isSpeech === false) {
2480
- return 0;
2481
- }
2482
- for (const key of ["speechProbability", "voiceProbability", "rms", "energy"]) {
2483
- const value = numericMetadata(frame, key);
2484
- if (value !== undefined) {
2485
- return value;
2486
- }
2487
- }
2488
- return 0;
2489
- };
2490
- var buildMediaVadReport = (input = {}) => {
2491
- const frames = (input.frames ?? []).filter((frame) => frame.kind === "input-audio");
2492
- const speechStartThreshold = input.speechStartThreshold ?? 0.6;
2493
- const speechEndThreshold = input.speechEndThreshold ?? 0.35;
2494
- const minSpeechFrames = input.minSpeechFrames ?? 1;
2495
- const maxSilenceFrames = input.maxSilenceFrames ?? 1;
2496
- const segments = [];
2497
- let activeFrames = [];
2498
- let silenceFrames = 0;
2499
- const closeSegment = () => {
2500
- if (activeFrames.length < minSpeechFrames) {
2501
- activeFrames = [];
2502
- silenceFrames = 0;
2503
- return;
2504
- }
2505
- const first = activeFrames[0];
2506
- const last = activeFrames.at(-1);
2507
- if (!first) {
2508
- return;
2509
- }
2510
- segments.push({
2511
- durationMs: first.at !== undefined && last?.at !== undefined ? last.at - first.at + (last.durationMs ?? 0) : undefined,
2512
- endAt: last?.at !== undefined ? last.at + (last.durationMs ?? 0) : undefined,
2513
- frameCount: activeFrames.length,
2514
- segmentId: `vad:${String(segments.length + 1)}`,
2515
- sessionId: first.sessionId,
2516
- startAt: first.at,
2517
- turnId: first.turnId
2518
- });
2519
- activeFrames = [];
2520
- silenceFrames = 0;
2521
- };
2522
- for (const frame of frames) {
2523
- const probability = speechProbability(frame);
2524
- if (activeFrames.length === 0) {
2525
- if (probability >= speechStartThreshold) {
2526
- activeFrames.push(frame);
2527
- }
2528
- continue;
2529
- }
2530
- activeFrames.push(frame);
2531
- if (probability <= speechEndThreshold) {
2532
- silenceFrames += 1;
2533
- } else {
2534
- silenceFrames = 0;
2535
- }
2536
- if (silenceFrames > maxSilenceFrames) {
2537
- closeSegment();
2538
- }
2539
- }
2540
- closeSegment();
2541
- return {
2542
- checkedAt: Date.now(),
2543
- inputAudioFrames: frames.length,
2544
- segments,
2545
- status: frames.length === 0 ? "warn" : "pass"
2546
- };
2547
- };
2548
- var buildMediaInterruptionReport = (input = {}) => {
2549
- const issues = [];
2550
- const interruptionFrames = (input.frames ?? []).filter((frame) => frame.kind === "interruption");
2551
- const latenciesMs = interruptionFrames.map((frame) => frame.latencyMs).filter((latency) => typeof latency === "number");
2552
- const maxInterruptionLatencyMs = input.maxInterruptionLatencyMs;
2553
- if (interruptionFrames.length === 0) {
2554
- pushIssue(issues, "warning", "media.interruption_missing", "No interruption frame was observed.");
2555
- }
2556
- if (maxInterruptionLatencyMs !== undefined && latenciesMs.some((latency) => latency > maxInterruptionLatencyMs)) {
2557
- pushIssue(issues, "error", "media.interruption_latency", `Interruption latency exceeded ${String(maxInterruptionLatencyMs)}ms.`);
2558
- }
2559
- return {
2560
- checkedAt: Date.now(),
2561
- interruptionFrames: interruptionFrames.length,
2562
- issues,
2563
- latenciesMs,
2564
- status: issues.some((issue) => issue.severity === "error") ? "fail" : issues.length > 0 ? "warn" : "pass"
2565
- };
2566
- };
2567
- var buildMediaQualityReport = (input = {}) => {
2568
- const frames = [...input.frames ?? []].sort((a, b) => (a.at ?? 0) - (b.at ?? 0));
2569
- const audioFrames = frames.filter((frame) => frame.kind === "input-audio" || frame.kind === "assistant-audio");
2570
- const inputAudioFrames = frames.filter((frame) => frame.kind === "input-audio");
2571
- const assistantAudioFrames = frames.filter((frame) => frame.kind === "assistant-audio");
2572
- const issues = [];
2573
- const gapsMs = [];
2574
- for (const [index, frame] of audioFrames.entries()) {
2575
- const previous = audioFrames[index - 1];
2576
- if (previous?.at === undefined || frame.at === undefined || previous.durationMs === undefined) {
2577
- continue;
2578
- }
2579
- const gap = frame.at - (previous.at + previous.durationMs);
2580
- if (gap > 0) {
2581
- gapsMs.push(gap);
2582
- }
2583
- }
2584
- const jitterMs = audioFrames.map((frame) => numericMetadata(frame, "jitterMs")).filter((value) => value !== undefined).at(-1) ?? max(gapsMs);
2585
- const first = audioFrames.find((frame) => frame.at !== undefined);
2586
- const last = audioFrames.toReversed().find((frame) => frame.at !== undefined);
2587
- const durationMs = first?.at !== undefined && last?.at !== undefined ? last.at - first.at + (last.durationMs ?? 0) : undefined;
2588
- const expectedDurationMs = audioFrames.length > 0 ? audioFrames.reduce((total, frame) => total + (frame.durationMs ?? 0), 0) : undefined;
2589
- const timestampDriftMs = durationMs !== undefined && expectedDurationMs !== undefined ? Math.max(0, durationMs - expectedDurationMs) : undefined;
2590
- const speechScores = inputAudioFrames.map(speechProbability);
2591
- const speechFrames = speechScores.filter((score) => score >= 0.6).length;
2592
- const silenceFrames = speechScores.filter((score) => score <= 0.35).length;
2593
- const unknownSpeechFrames = Math.max(0, inputAudioFrames.length - speechFrames - silenceFrames);
2594
- const speechRatio = inputAudioFrames.length === 0 ? 0 : speechFrames / inputAudioFrames.length;
2595
- const silenceRatio = inputAudioFrames.length === 0 ? 0 : silenceFrames / inputAudioFrames.length;
2596
- const levels = audioFrames.map((frame) => numericMetadata(frame, "level") ?? numericMetadata(frame, "rms") ?? numericMetadata(frame, "energy")).filter((value) => value !== undefined);
2597
- const backpressureEvents = input.transport?.backpressureEvents ?? 0;
2598
- const maxGapMs = input.maxGapMs;
2599
- if (maxGapMs !== undefined && gapsMs.some((gap) => gap > maxGapMs)) {
2600
- pushIssue(issues, "warning", "media.quality_gap", `Observed media gap above ${String(maxGapMs)}ms.`);
2601
- }
2602
- if (input.maxJitterMs !== undefined && jitterMs !== undefined && jitterMs > input.maxJitterMs) {
2603
- pushIssue(issues, "warning", "media.quality_jitter", `Observed jitter ${String(jitterMs)}ms above ${String(input.maxJitterMs)}ms.`);
2604
- }
2605
- if (input.maxTimestampDriftMs !== undefined && timestampDriftMs !== undefined && timestampDriftMs > input.maxTimestampDriftMs) {
2606
- pushIssue(issues, "warning", "media.quality_timestamp_drift", `Observed timestamp drift ${String(timestampDriftMs)}ms above ${String(input.maxTimestampDriftMs)}ms.`);
2607
- }
2608
- if (input.minSpeechRatio !== undefined && inputAudioFrames.length > 0 && speechRatio < input.minSpeechRatio) {
2609
- pushIssue(issues, "warning", "media.quality_speech_ratio", `Observed speech ratio ${String(speechRatio)} below ${String(input.minSpeechRatio)}.`);
2610
- }
2611
- if (input.maxBackpressureEvents !== undefined && backpressureEvents > input.maxBackpressureEvents) {
2612
- pushIssue(issues, "warning", "media.quality_backpressure", `Observed ${String(backpressureEvents)} backpressure event(s), above ${String(input.maxBackpressureEvents)}.`);
2613
- }
2614
- return {
2615
- assistantAudioFrames: assistantAudioFrames.length,
2616
- backpressureEvents,
2617
- checkedAt: Date.now(),
2618
- durationMs,
2619
- gapCount: gapsMs.length,
2620
- gapsMs,
2621
- inputAudioFrames: inputAudioFrames.length,
2622
- issues,
2623
- jitterMs,
2624
- levelAverage: average3(levels),
2625
- levelMax: max(levels),
2626
- levelMin: min(levels),
2627
- silenceFrames,
2628
- silenceRatio,
2629
- speechFrames,
2630
- speechRatio,
2631
- status: issues.some((issue) => issue.severity === "error") ? "fail" : issues.length > 0 ? "warn" : "pass",
2632
- timestampDriftMs,
2633
- totalFrames: frames.length,
2634
- unknownSpeechFrames
2635
- };
2636
- };
2637
- var buildMediaWebRTCStatsReport = (input = {}) => {
2638
- const stats = input.stats ?? [];
2639
- const issues = [];
2640
- const inbound = stats.filter((stat) => stat.type === "inbound-rtp" && stringStat(stat, "kind") !== "video");
2641
- const outbound = stats.filter((stat) => stat.type === "outbound-rtp" && stringStat(stat, "kind") !== "video");
2642
- const candidatePairs = stats.filter((stat) => stat.type === "candidate-pair");
2643
- const audioTracks = stats.filter((stat) => (stat.type === "track" || stat.type === "media-source") && stringStat(stat, "kind") === "audio");
2644
- const activeCandidatePairs = candidatePairs.filter((stat) => booleanStat(stat, "selected") === true || booleanStat(stat, "nominated") === true || stringStat(stat, "state") === "succeeded").length;
2645
- const liveAudioTracks = audioTracks.filter((stat) => stringStat(stat, "readyState") !== "ended" && stringStat(stat, "trackState") !== "ended" && booleanStat(stat, "ended") !== true).length;
2646
- const endedAudioTracks = audioTracks.filter((stat) => stringStat(stat, "readyState") === "ended" || stringStat(stat, "trackState") === "ended" || booleanStat(stat, "ended") === true).length;
2647
- const inboundPackets = inbound.reduce((total, stat) => total + (numericStat(stat, "packetsReceived") ?? 0), 0);
2648
- const outboundPackets = outbound.reduce((total, stat) => total + (numericStat(stat, "packetsSent") ?? 0), 0);
2649
- const packetsLost = [...inbound, ...outbound].reduce((total, stat) => total + Math.max(0, numericStat(stat, "packetsLost") ?? 0), 0);
2650
- const packetLossDenominator = inboundPackets + packetsLost;
2651
- const packetLossRatio = packetLossDenominator === 0 ? 0 : packetsLost / packetLossDenominator;
2652
- const bytesReceived = inbound.reduce((total, stat) => total + (numericStat(stat, "bytesReceived") ?? 0), 0);
2653
- const bytesSent = outbound.reduce((total, stat) => total + (numericStat(stat, "bytesSent") ?? 0), 0);
2654
- const roundTripTimeMs = max(candidatePairs.map((stat) => secondsToMs(numericStat(stat, "currentRoundTripTime") ?? numericStat(stat, "roundTripTime"))).filter((value) => value !== undefined));
2655
- const jitterMs = max([...inbound, ...outbound].map((stat) => secondsToMs(numericStat(stat, "jitter"))).filter((value) => value !== undefined));
2656
- const jitterBufferDelayMs = max(inbound.map((stat) => {
2657
- const delay = numericStat(stat, "jitterBufferDelay");
2658
- const emitted = numericStat(stat, "jitterBufferEmittedCount");
2659
- return delay !== undefined && emitted !== undefined && emitted > 0 ? delay / emitted * 1000 : undefined;
2660
- }).filter((value) => value !== undefined));
2661
- const audioLevels = audioTracks.map((stat) => numericStat(stat, "audioLevel")).filter((value) => value !== undefined);
2662
- if (input.requireConnectedCandidatePair && candidatePairs.length > 0 && activeCandidatePairs === 0) {
2663
- pushIssue(issues, "error", "media.webrtc_candidate_pair_missing", "No active WebRTC candidate pair was observed.");
2664
- }
2665
- if (input.requireLiveAudioTrack && liveAudioTracks === 0) {
2666
- pushIssue(issues, "error", "media.webrtc_audio_track_missing", "No live WebRTC audio track was observed.");
2667
- }
2668
- if (input.maxPacketLossRatio !== undefined && packetLossRatio > input.maxPacketLossRatio) {
2669
- pushIssue(issues, "warning", "media.webrtc_packet_loss", `Observed WebRTC packet loss ratio ${String(packetLossRatio)} above ${String(input.maxPacketLossRatio)}.`);
2670
- }
2671
- if (input.maxRoundTripTimeMs !== undefined && roundTripTimeMs !== undefined && roundTripTimeMs > input.maxRoundTripTimeMs) {
2672
- pushIssue(issues, "warning", "media.webrtc_round_trip_time", `Observed WebRTC RTT ${String(roundTripTimeMs)}ms above ${String(input.maxRoundTripTimeMs)}ms.`);
2673
- }
2674
- if (input.maxJitterMs !== undefined && jitterMs !== undefined && jitterMs > input.maxJitterMs) {
2675
- pushIssue(issues, "warning", "media.webrtc_jitter", `Observed WebRTC jitter ${String(jitterMs)}ms above ${String(input.maxJitterMs)}ms.`);
2676
- }
2677
- return {
2678
- activeCandidatePairs,
2679
- audioLevelAverage: average3(audioLevels),
2680
- bytesReceived,
2681
- bytesSent,
2682
- checkedAt: Date.now(),
2683
- endedAudioTracks,
2684
- inboundPackets,
2685
- issues,
2686
- jitterBufferDelayMs,
2687
- jitterMs,
2688
- liveAudioTracks,
2689
- outboundPackets,
2690
- packetLossRatio,
2691
- packetsLost,
2692
- roundTripTimeMs,
2693
- status: issues.some((issue) => issue.severity === "error") ? "fail" : issues.length > 0 ? "warn" : "pass",
2694
- totalStats: stats.length
2695
- };
2696
- };
2697
- var collectMediaWebRTCStats = async (input) => {
2698
- const report = await input.peerConnection.getStats(input.selector ?? null);
2699
- return [...report.values()].map(normalizeWebRTCStat);
2700
- };
2701
- var buildMediaWebRTCStreamContinuityReport = (input = {}) => {
2702
- const stats = input.stats ?? [];
2703
- const previousStats = input.previousStats ?? [];
2704
- const issues = [];
2705
- const previousByKey = new Map(previousStats.map((stat) => [statKey(stat), stat]));
2706
- const audioRtp = stats.filter((stat) => (stat.type === "inbound-rtp" || stat.type === "outbound-rtp") && stringStat(stat, "kind") !== "video" && stringStat(stat, "mediaType") !== "video");
2707
- const streams = audioRtp.map((stat) => {
2708
- const direction = stat.type === "outbound-rtp" ? "outbound" : "inbound";
2709
- const packetsKey = direction === "outbound" ? "packetsSent" : "packetsReceived";
2710
- const bytesKey = direction === "outbound" ? "bytesSent" : "bytesReceived";
2711
- const previous = previousByKey.get(statKey(stat));
2712
- const currentPackets = numericStat(stat, packetsKey);
2713
- const previousPackets = previous ? numericStat(previous, packetsKey) : undefined;
2714
- const currentBytes = numericStat(stat, bytesKey);
2715
- const previousBytes = previous ? numericStat(previous, bytesKey) : undefined;
2716
- const timeDeltaMs = stat.timestamp !== undefined && previous?.timestamp !== undefined ? stat.timestamp - previous.timestamp : undefined;
2717
- return {
2718
- bytesDelta: currentBytes !== undefined && previousBytes !== undefined ? currentBytes - previousBytes : undefined,
2719
- currentPackets,
2720
- direction,
2721
- id: statKey(stat),
2722
- packetDelta: currentPackets !== undefined && previousPackets !== undefined ? currentPackets - previousPackets : undefined,
2723
- previousPackets,
2724
- timeDeltaMs
2725
- };
2726
- });
2727
- const inbound = streams.filter((stream) => stream.direction === "inbound");
2728
- const outbound = streams.filter((stream) => stream.direction === "outbound");
2729
- const maxObservedGapMs = max(streams.map((stream) => stream.timeDeltaMs).filter((value) => value !== undefined));
2730
- const stalledInboundStreams = inbound.filter((stream) => input.maxInboundPacketStallMs !== undefined && stream.timeDeltaMs !== undefined && stream.timeDeltaMs >= input.maxInboundPacketStallMs && stream.packetDelta !== undefined && stream.packetDelta <= 0).length;
2731
- const stalledOutboundStreams = outbound.filter((stream) => input.maxOutboundPacketStallMs !== undefined && stream.timeDeltaMs !== undefined && stream.timeDeltaMs >= input.maxOutboundPacketStallMs && stream.packetDelta !== undefined && stream.packetDelta <= 0).length;
2732
- if (input.requireInboundAudio && inbound.length === 0) {
2733
- pushIssue(issues, "error", "media.webrtc_inbound_audio_missing", "No inbound WebRTC audio RTP stream was observed.");
2734
- }
2735
- if (input.requireOutboundAudio && outbound.length === 0) {
2736
- pushIssue(issues, "error", "media.webrtc_outbound_audio_missing", "No outbound WebRTC audio RTP stream was observed.");
2737
- }
2738
- if (input.maxGapMs !== undefined && maxObservedGapMs !== undefined && maxObservedGapMs > input.maxGapMs) {
2739
- pushIssue(issues, "warning", "media.webrtc_stream_gap", `Observed WebRTC stream sample gap ${String(maxObservedGapMs)}ms above ${String(input.maxGapMs)}ms.`);
2740
- }
2741
- if (stalledInboundStreams > 0) {
2742
- pushIssue(issues, "error", "media.webrtc_inbound_stalled", `${String(stalledInboundStreams)} inbound WebRTC audio stream(s) stopped receiving packets.`);
2743
- }
2744
- if (stalledOutboundStreams > 0) {
2745
- pushIssue(issues, "error", "media.webrtc_outbound_stalled", `${String(stalledOutboundStreams)} outbound WebRTC audio stream(s) stopped sending packets.`);
2746
- }
2747
- return {
2748
- checkedAt: Date.now(),
2749
- inboundAudioStreams: inbound.length,
2750
- issues,
2751
- maxObservedGapMs,
2752
- outboundAudioStreams: outbound.length,
2753
- stalledInboundStreams,
2754
- stalledOutboundStreams,
2755
- status: issues.some((issue) => issue.severity === "error") ? "fail" : issues.length > 0 ? "warn" : "pass",
2756
- streams,
2757
- totalStats: stats.length
2758
- };
2759
- };
2760
- var buildMediaPipelineCalibrationReport = (input = {}) => {
2761
- const frames = input.frames ?? [];
2762
- const issues = [];
2763
- const inputFrames = frames.filter((frame) => frame.kind === "input-audio");
2764
- const assistantFrames = frames.filter((frame) => frame.kind === "assistant-audio");
2765
- const turnCommitFrames = frames.filter((frame) => frame.kind === "turn-commit");
2766
- const interruptionFrameRecords = frames.filter((frame) => frame.kind === "interruption");
2767
- const traceLinkedFrames = frames.filter((frame) => frame.traceEventId).length;
2768
- const backpressureFrames = frames.filter((frame) => Boolean(frame.metadata?.backpressure)).length;
2769
- const audioLatencies = assistantFrames.map((frame) => frame.latencyMs).filter((latency) => typeof latency === "number");
2770
- const firstAudioLatencyMs = audioLatencies.length > 0 ? Math.min(...audioLatencies) : undefined;
2771
- const jitterValues = frames.map((frame) => numericMetadata(frame, "jitterMs")).filter((value) => value !== undefined);
2772
- const jitterMs = jitterValues.length > 0 ? Math.max(...jitterValues) : undefined;
2773
- const inputFormat = input.inputFormat ?? inputFrames.find((frame) => frame.format)?.format;
2774
- const outputFormat = input.outputFormat ?? assistantFrames.find((frame) => frame.format)?.format;
2775
- const resamplingRequired = Boolean(input.expectedInputFormat && inputFormat && inputFormat.sampleRateHz !== input.expectedInputFormat.sampleRateHz) || Boolean(input.expectedOutputFormat && outputFormat && outputFormat.sampleRateHz !== input.expectedOutputFormat.sampleRateHz);
2776
- const resamplingTargetHz = resamplingRequired && input.expectedInputFormat ? input.expectedInputFormat.sampleRateHz : resamplingRequired ? input.expectedOutputFormat?.sampleRateHz : undefined;
2777
- if (inputFrames.length === 0) {
2778
- pushIssue(issues, "warning", "media.input_audio_missing", "No input audio frames were observed.");
2779
- }
2780
- if (assistantFrames.length === 0) {
2781
- pushIssue(issues, "warning", "media.assistant_audio_missing", "No assistant audio frames were observed.");
2782
- }
2783
- if (input.expectedInputFormat && inputFormat && !formatMatches(inputFormat, input.expectedInputFormat)) {
2784
- pushIssue(issues, inputFormat.sampleRateHz === input.expectedInputFormat.sampleRateHz ? "warning" : "error", "media.input_format_mismatch", `Input format ${formatLabel(inputFormat)} does not match expected ${formatLabel(input.expectedInputFormat)}.`);
2785
- }
2786
- if (input.expectedOutputFormat && outputFormat && !formatMatches(outputFormat, input.expectedOutputFormat)) {
2787
- pushIssue(issues, outputFormat.sampleRateHz === input.expectedOutputFormat.sampleRateHz ? "warning" : "error", "media.output_format_mismatch", `Output format ${formatLabel(outputFormat)} does not match expected ${formatLabel(input.expectedOutputFormat)}.`);
2788
- }
2789
- if (firstAudioLatencyMs !== undefined && input.maxFirstAudioLatencyMs !== undefined && firstAudioLatencyMs > input.maxFirstAudioLatencyMs) {
2790
- pushIssue(issues, "error", "media.first_audio_latency", `First audio latency ${String(firstAudioLatencyMs)}ms exceeds budget ${String(input.maxFirstAudioLatencyMs)}ms.`);
2791
- }
2792
- if (jitterMs !== undefined && input.maxJitterMs !== undefined && jitterMs > input.maxJitterMs) {
2793
- pushIssue(issues, "warning", "media.jitter", `Media jitter ${String(jitterMs)}ms exceeds budget ${String(input.maxJitterMs)}ms.`);
2794
- }
2795
- if (input.maxBackpressureFrames !== undefined && backpressureFrames > input.maxBackpressureFrames) {
2796
- pushIssue(issues, "warning", "media.backpressure", `Backpressure frame count ${String(backpressureFrames)} exceeds budget ${String(input.maxBackpressureFrames)}.`);
2797
- }
2798
- if (input.requireInterruptionFrame && interruptionFrameRecords.length === 0) {
2799
- pushIssue(issues, "warning", "media.interruption_missing", "No interruption frame was observed.");
2800
- }
2801
- if (input.requireTraceEvidence && traceLinkedFrames === 0) {
2802
- pushIssue(issues, "warning", "media.trace_evidence_missing", "No media frames were linked to trace evidence.");
2803
- }
2804
- return {
2805
- assistantAudioFrames: assistantFrames.length,
2806
- backpressureFrames,
2807
- checkedAt: Date.now(),
2808
- firstAudioLatencyMs,
2809
- inputAudioFrames: inputFrames.length,
2810
- inputFormat,
2811
- interruptionFrames: interruptionFrameRecords.length,
2812
- issues,
2813
- jitterMs,
2814
- outputFormat,
2815
- resamplingRequired,
2816
- resamplingTargetHz,
2817
- status: issues.some((issue) => issue.severity === "error") ? "fail" : issues.length > 0 ? "warn" : "pass",
2818
- surface: input.surface ?? "media-pipeline",
2819
- traceLinkedFrames,
2820
- turnCommitFrames: turnCommitFrames.length
2821
- };
2822
- };
2823
-
2824
2162
  // src/client/browserMedia.ts
2163
+ import {
2164
+ buildMediaWebRTCStatsReport,
2165
+ buildMediaWebRTCStreamContinuityReport,
2166
+ collectMediaWebRTCStats
2167
+ } from "@absolutejs/media";
2825
2168
  var DEFAULT_BROWSER_MEDIA_PATH = "/api/voice/browser-media";
2826
2169
  var DEFAULT_BROWSER_MEDIA_INTERVAL_MS = 5000;
2827
2170
  var resolvePeerConnection = async (options) => options.peerConnection ?? await options.getPeerConnection?.() ?? null;
@@ -8589,16 +7932,16 @@ var renderVoiceCallReviewHTML = (artifact) => {
8589
7932
  </html>`;
8590
7933
  };
8591
7934
  // src/testing/sessionBenchmark.ts
8592
- var average4 = (values) => values.length > 0 ? values.reduce((sum, value) => sum + value, 0) / values.length : 0;
7935
+ var average3 = (values) => values.length > 0 ? values.reduce((sum, value) => sum + value, 0) / values.length : 0;
8593
7936
  var normalizeTurnText = (value) => value.toLowerCase().replace(/[^\p{L}\p{N}\s']/gu, " ").replace(/\s+/g, " ").trim();
8594
7937
  var countPassedTurns = (turnResults) => turnResults.reduce((count, result) => count + (result.passes ? 1 : 0), 0);
8595
7938
  var calculateTurnPassRate = (turnResults) => turnResults.length > 0 ? countPassedTurns(turnResults) / turnResults.length : 0;
8596
7939
  var summarizeScenarioCosts = (turnResults) => {
8597
7940
  const costEstimates = turnResults.map((turn) => turn.quality?.cost).filter((value) => value !== undefined);
8598
7941
  return {
8599
- averageRelativeCostUnits: roundMetric5(average4(costEstimates.map((estimate) => estimate.estimatedRelativeCostUnits))),
8600
- fallbackReplayAudioMs: roundMetric5(average4(costEstimates.map((estimate) => estimate.fallbackReplayAudioMs)), 2),
8601
- primaryAudioMs: roundMetric5(average4(costEstimates.map((estimate) => estimate.primaryAudioMs)), 2)
7942
+ averageRelativeCostUnits: roundMetric5(average3(costEstimates.map((estimate) => estimate.estimatedRelativeCostUnits))),
7943
+ fallbackReplayAudioMs: roundMetric5(average3(costEstimates.map((estimate) => estimate.fallbackReplayAudioMs)), 2),
7944
+ primaryAudioMs: roundMetric5(average3(costEstimates.map((estimate) => estimate.primaryAudioMs)), 2)
8602
7945
  };
8603
7946
  };
8604
7947
  var roundMetric5 = (value, digits = 4) => {
@@ -8917,13 +8260,13 @@ var summarizeVoiceSessionBenchmark = (adapterId, scenarios) => {
8917
8260
  const turnAccuracies = scenarios.flatMap((scenario) => scenario.turnResults.map((turn) => turn.accuracy?.wordErrorRate).filter((value) => typeof value === "number"));
8918
8261
  return {
8919
8262
  adapterId,
8920
- averageElapsedMs: roundMetric5(average4(scenarios.map((scenario) => scenario.elapsedMs)), 2),
8921
- averageFallbackReplayAudioMs: roundMetric5(average4(scenarios.map((scenario) => scenario.fallbackReplayAudioMs)), 2),
8922
- averagePrimaryAudioMs: roundMetric5(average4(scenarios.map((scenario) => scenario.primaryAudioMs)), 2),
8923
- averageReconnectCount: roundMetric5(average4(scenarios.map((scenario) => scenario.reconnectCount))),
8924
- averageRelativeCostUnits: roundMetric5(average4(scenarios.map((scenario) => scenario.averageRelativeCostUnits))),
8925
- averageTurnPassRate: roundMetric5(average4(scenarios.map((scenario) => scenario.turnPassRate))),
8926
- averageWordErrorRate: roundMetric5(average4(turnAccuracies)),
8263
+ averageElapsedMs: roundMetric5(average3(scenarios.map((scenario) => scenario.elapsedMs)), 2),
8264
+ averageFallbackReplayAudioMs: roundMetric5(average3(scenarios.map((scenario) => scenario.fallbackReplayAudioMs)), 2),
8265
+ averagePrimaryAudioMs: roundMetric5(average3(scenarios.map((scenario) => scenario.primaryAudioMs)), 2),
8266
+ averageReconnectCount: roundMetric5(average3(scenarios.map((scenario) => scenario.reconnectCount))),
8267
+ averageRelativeCostUnits: roundMetric5(average3(scenarios.map((scenario) => scenario.averageRelativeCostUnits))),
8268
+ averageTurnPassRate: roundMetric5(average3(scenarios.map((scenario) => scenario.turnPassRate))),
8269
+ averageWordErrorRate: roundMetric5(average3(turnAccuracies)),
8927
8270
  duplicateTurnRate: roundMetric5(scenarios.length > 0 ? scenarios.filter((scenario) => scenario.duplicateTurnCount > 0).length / scenarios.length : 0),
8928
8271
  passCount,
8929
8272
  passRate: roundMetric5(scenarios.length > 0 ? passCount / scenarios.length : 0),
@@ -8949,13 +8292,13 @@ var summarizeVoiceSessionBenchmarkSeries = (input) => {
8949
8292
  const passCount = results.filter((scenario) => scenario.passes).length;
8950
8293
  const sample = results[0];
8951
8294
  return {
8952
- averageElapsedMs: roundMetric5(average4(results.map((scenario) => scenario.elapsedMs)), 2),
8953
- averageFallbackReplayAudioMs: roundMetric5(average4(results.map((scenario) => scenario.fallbackReplayAudioMs)), 2),
8954
- averagePrimaryAudioMs: roundMetric5(average4(results.map((scenario) => scenario.primaryAudioMs)), 2),
8955
- averageReconnectCount: roundMetric5(average4(results.map((scenario) => scenario.reconnectCount))),
8956
- averageRelativeCostUnits: roundMetric5(average4(results.map((scenario) => scenario.averageRelativeCostUnits))),
8957
- averageTurnPassRate: roundMetric5(average4(results.map((scenario) => scenario.turnPassRate))),
8958
- averageWordErrorRate: roundMetric5(average4(wordErrorRates)),
8295
+ averageElapsedMs: roundMetric5(average3(results.map((scenario) => scenario.elapsedMs)), 2),
8296
+ averageFallbackReplayAudioMs: roundMetric5(average3(results.map((scenario) => scenario.fallbackReplayAudioMs)), 2),
8297
+ averagePrimaryAudioMs: roundMetric5(average3(results.map((scenario) => scenario.primaryAudioMs)), 2),
8298
+ averageReconnectCount: roundMetric5(average3(results.map((scenario) => scenario.reconnectCount))),
8299
+ averageRelativeCostUnits: roundMetric5(average3(results.map((scenario) => scenario.averageRelativeCostUnits))),
8300
+ averageTurnPassRate: roundMetric5(average3(results.map((scenario) => scenario.turnPassRate))),
8301
+ averageWordErrorRate: roundMetric5(average3(wordErrorRates)),
8959
8302
  bestWordErrorRate: roundMetric5(wordErrorRates.length > 0 ? Math.min(...wordErrorRates) : 0),
8960
8303
  fixtureId,
8961
8304
  passCount,
@@ -8978,18 +8321,18 @@ var summarizeVoiceSessionBenchmarkSeries = (input) => {
8978
8321
  scenarios: scenarioAggregates,
8979
8322
  summary: {
8980
8323
  adapterId: input.adapterId,
8981
- averageElapsedMs: roundMetric5(average4(scenarioAggregates.map((scenario) => scenario.averageElapsedMs)), 2),
8982
- averageFallbackReplayAudioMs: roundMetric5(average4(scenarioAggregates.map((scenario) => scenario.averageFallbackReplayAudioMs)), 2),
8983
- averagePassRate: roundMetric5(average4(scenarioAggregates.map((scenario) => scenario.passRate))),
8984
- averagePrimaryAudioMs: roundMetric5(average4(scenarioAggregates.map((scenario) => scenario.averagePrimaryAudioMs)), 2),
8985
- averageReconnectCount: roundMetric5(average4(scenarioAggregates.map((scenario) => scenario.averageReconnectCount))),
8986
- averageRelativeCostUnits: roundMetric5(average4(scenarioAggregates.map((scenario) => scenario.averageRelativeCostUnits))),
8987
- averageTurnPassRate: roundMetric5(average4(scenarioAggregates.map((scenario) => scenario.averageTurnPassRate))),
8988
- averageWordErrorRate: roundMetric5(average4(scenarioAggregates.map((scenario) => scenario.averageWordErrorRate))),
8324
+ averageElapsedMs: roundMetric5(average3(scenarioAggregates.map((scenario) => scenario.averageElapsedMs)), 2),
8325
+ averageFallbackReplayAudioMs: roundMetric5(average3(scenarioAggregates.map((scenario) => scenario.averageFallbackReplayAudioMs)), 2),
8326
+ averagePassRate: roundMetric5(average3(scenarioAggregates.map((scenario) => scenario.passRate))),
8327
+ averagePrimaryAudioMs: roundMetric5(average3(scenarioAggregates.map((scenario) => scenario.averagePrimaryAudioMs)), 2),
8328
+ averageReconnectCount: roundMetric5(average3(scenarioAggregates.map((scenario) => scenario.averageReconnectCount))),
8329
+ averageRelativeCostUnits: roundMetric5(average3(scenarioAggregates.map((scenario) => scenario.averageRelativeCostUnits))),
8330
+ averageTurnPassRate: roundMetric5(average3(scenarioAggregates.map((scenario) => scenario.averageTurnPassRate))),
8331
+ averageWordErrorRate: roundMetric5(average3(scenarioAggregates.map((scenario) => scenario.averageWordErrorRate))),
8989
8332
  flakyScenarioCount: scenarioAggregates.filter((scenario) => scenario.passRate > 0 && scenario.passRate < 1).length,
8990
8333
  generatedRunCount: input.reports.length,
8991
- reconnectCoverageRate: roundMetric5(average4(reconnectCoverageRates)),
8992
- reconnectSuccessRate: roundMetric5(average4(reconnectRates)),
8334
+ reconnectCoverageRate: roundMetric5(average3(reconnectCoverageRates)),
8335
+ reconnectSuccessRate: roundMetric5(average3(reconnectRates)),
8993
8336
  scenarioCount: scenarioAggregates.length,
8994
8337
  stableScenarioCount: scenarioAggregates.filter((scenario) => scenario.passRate === 1).length,
8995
8338
  totalPassCount,
@@ -10663,7 +10006,7 @@ import { Elysia as Elysia3 } from "elysia";
10663
10006
  var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10664
10007
  var getString3 = (value) => typeof value === "string" && value.trim() ? value : undefined;
10665
10008
  var getNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
10666
- var firstString2 = (payload, keys) => {
10009
+ var firstString = (payload, keys) => {
10667
10010
  for (const key of keys) {
10668
10011
  const value = getString3(payload[key]);
10669
10012
  if (value) {
@@ -10672,7 +10015,7 @@ var firstString2 = (payload, keys) => {
10672
10015
  }
10673
10016
  return;
10674
10017
  };
10675
- var firstNumber2 = (payload, keys) => {
10018
+ var firstNumber = (payload, keys) => {
10676
10019
  for (const key of keys) {
10677
10020
  const value = getNumber2(payload[key]);
10678
10021
  if (value !== undefined) {
@@ -10681,20 +10024,20 @@ var firstNumber2 = (payload, keys) => {
10681
10024
  }
10682
10025
  return;
10683
10026
  };
10684
- var eventProvider = (event) => firstString2(event.payload, [
10027
+ var eventProvider = (event) => firstString(event.payload, [
10685
10028
  "provider",
10686
10029
  "selectedProvider",
10687
10030
  "fallbackProvider",
10688
10031
  "variantId"
10689
10032
  ]);
10690
- var eventStatus = (event) => firstString2(event.payload, [
10033
+ var eventStatus = (event) => firstString(event.payload, [
10691
10034
  "providerStatus",
10692
10035
  "status",
10693
10036
  "disposition",
10694
10037
  "type",
10695
10038
  "reason"
10696
10039
  ]);
10697
- var eventElapsedMs = (event) => firstNumber2(event.payload, ["elapsedMs", "latencyMs", "durationMs"]);
10040
+ var eventElapsedMs = (event) => firstNumber(event.payload, ["elapsedMs", "latencyMs", "durationMs"]);
10698
10041
  var resolveSessionHref2 = (value, sessionId) => {
10699
10042
  if (value === false) {
10700
10043
  return;
@@ -11903,7 +11246,7 @@ var assertVoiceTelephonyWebhookNormalizationEvidence = (input = {}) => {
11903
11246
  return assertion;
11904
11247
  };
11905
11248
  var normalizeToken = (value) => typeof value === "string" ? value.trim().toLowerCase().replace(/\s+/g, "-").replace(/_+/g, "-") : undefined;
11906
- var firstString3 = (source, keys) => {
11249
+ var firstString2 = (source, keys) => {
11907
11250
  for (const key of keys) {
11908
11251
  const value = source[key];
11909
11252
  if (typeof value === "string" && value.trim()) {
@@ -11914,7 +11257,7 @@ var firstString3 = (source, keys) => {
11914
11257
  }
11915
11258
  }
11916
11259
  };
11917
- var firstNumber3 = (source, keys) => {
11260
+ var firstNumber2 = (source, keys) => {
11918
11261
  for (const key of keys) {
11919
11262
  const value = source[key];
11920
11263
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -12279,8 +11622,8 @@ var verifyVoiceTelephonyWebhook = async (input) => {
12279
11622
  var durationMsFromSeconds = (value) => typeof value === "number" ? value * 1000 : undefined;
12280
11623
  var parseVoiceTelephonyWebhookEvent = (input) => {
12281
11624
  const payload = flattenPayload(input.body);
12282
- const provider = firstString3(payload, ["provider", "Provider"]) ?? input.provider;
12283
- const status = firstString3(payload, [
11625
+ const provider = firstString2(payload, ["provider", "Provider"]) ?? input.provider;
11626
+ const status = firstString2(payload, [
12284
11627
  "CallStatus",
12285
11628
  "call_status",
12286
11629
  "callStatus",
@@ -12290,7 +11633,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
12290
11633
  "event_type",
12291
11634
  "type"
12292
11635
  ]);
12293
- const durationMs = firstNumber3(payload, ["durationMs", "duration_ms"]) ?? durationMsFromSeconds(firstNumber3(payload, [
11636
+ const durationMs = firstNumber2(payload, ["durationMs", "duration_ms"]) ?? durationMsFromSeconds(firstNumber2(payload, [
12294
11637
  "CallDuration",
12295
11638
  "call_duration",
12296
11639
  "callDuration",
@@ -12298,21 +11641,21 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
12298
11641
  "dial_call_duration",
12299
11642
  "duration"
12300
11643
  ]));
12301
- const sipCode = firstNumber3(payload, [
11644
+ const sipCode = firstNumber2(payload, [
12302
11645
  "SipResponseCode",
12303
11646
  "sip_response_code",
12304
11647
  "sipCode",
12305
11648
  "sip_code",
12306
11649
  "hangupCauseCode"
12307
11650
  ]);
12308
- const from = firstString3(payload, ["From", "from", "caller_id", "callerId"]);
12309
- const to = firstString3(payload, [
11651
+ const from = firstString2(payload, ["From", "from", "caller_id", "callerId"]);
11652
+ const to = firstString2(payload, [
12310
11653
  "To",
12311
11654
  "to",
12312
11655
  "called_number",
12313
11656
  "calledNumber"
12314
11657
  ]);
12315
- const target = firstString3(payload, [
11658
+ const target = firstString2(payload, [
12316
11659
  "transferTarget",
12317
11660
  "TransferTarget",
12318
11661
  "target",
@@ -12320,7 +11663,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
12320
11663
  "department"
12321
11664
  ]);
12322
11665
  return {
12323
- answeredBy: firstString3(payload, [
11666
+ answeredBy: firstString2(payload, [
12324
11667
  "AnsweredBy",
12325
11668
  "answered_by",
12326
11669
  "answeredBy",
@@ -12334,7 +11677,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
12334
11677
  ...payload
12335
11678
  },
12336
11679
  provider,
12337
- reason: firstString3(payload, [
11680
+ reason: firstString2(payload, [
12338
11681
  "Reason",
12339
11682
  "reason",
12340
11683
  "HangupCause",
@@ -12350,7 +11693,7 @@ var parseVoiceTelephonyWebhookEvent = (input) => {
12350
11693
  var defaultSessionId = (input) => {
12351
11694
  const payload = flattenPayload(input.body);
12352
11695
  const metadataSessionId = input.event.metadata?.sessionId;
12353
- return firstString3(input.query, ["sessionId", "session_id"]) ?? firstString3(payload, [
11696
+ return firstString2(input.query, ["sessionId", "session_id"]) ?? firstString2(payload, [
12354
11697
  "sessionId",
12355
11698
  "session_id",
12356
11699
  "SessionId",
@@ -12365,7 +11708,7 @@ var defaultSessionId = (input) => {
12365
11708
  };
12366
11709
  var defaultIdempotencyKey = (input) => {
12367
11710
  const payload = flattenPayload(input.body);
12368
- const eventId = firstString3(payload, [
11711
+ const eventId = firstString2(payload, [
12369
11712
  "id",
12370
11713
  "event_id",
12371
11714
  "eventId",