@absolutejs/voice 0.0.22-beta.450 → 0.0.22-beta.452

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.
@@ -3430,6 +3430,7 @@ var readString = (value) => typeof value === "string" && value.trim() ? value :
3430
3430
  var readNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
3431
3431
  var readProofTrendMaxLiveP95 = (report) => report.summary.maxLiveP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.liveLatency?.p95Ms));
3432
3432
  var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms ?? maxNumber((report.summary.providers ?? []).map((provider) => provider.p95Ms)) ?? maxNumber(report.cycles.flatMap((cycle) => (cycle.providers ?? []).map((provider) => provider.p95Ms)));
3433
+ var readProofTrendMaxReconnectP95 = (report) => report.summary.maxReconnectP95Ms ?? report.summary.reconnect?.resumeLatencyP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.reconnect?.resumeLatencyP95Ms));
3433
3434
  var readProofTrendMaxTurnP95 = (report) => report.summary.maxTurnP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.turnLatency?.p95Ms));
3434
3435
  var readRuntimeChannelMetric = (report, key) => {
3435
3436
  const summaryValue = report.summary.runtimeChannel?.[key];
@@ -3491,6 +3492,42 @@ var aggregateProofTrendRuntimeChannel = (channels) => {
3491
3492
  status: channels.some((channel) => channel.status === "fail") ? "fail" : channels.some((channel) => channel.status === "warn") ? "warn" : channels.every((channel) => channel.status === "pass") ? "pass" : undefined
3492
3493
  };
3493
3494
  };
3495
+ var aggregateProofTrendReconnect = (reconnects) => {
3496
+ if (reconnects.length === 0) {
3497
+ return;
3498
+ }
3499
+ const hasFailure = reconnects.some((reconnect) => reconnect.status === "fail" || reconnect.exhausted === true || reconnect.reconnected === false || reconnect.resumed === false);
3500
+ return {
3501
+ attempts: maxNumber(reconnects.map((reconnect) => reconnect.attempts)),
3502
+ exhausted: reconnects.some((reconnect) => reconnect.exhausted === true),
3503
+ maxAttempts: maxNumber(reconnects.map((reconnect) => reconnect.maxAttempts)),
3504
+ resumeLatencyP95Ms: maxNumber(reconnects.map((reconnect) => reconnect.resumeLatencyP95Ms)),
3505
+ reconnected: reconnects.some((reconnect) => reconnect.reconnected === true),
3506
+ resumed: reconnects.some((reconnect) => reconnect.resumed === true),
3507
+ samples: reconnects.reduce((total, reconnect) => total + (reconnect.samples ?? 0), 0),
3508
+ snapshotCount: reconnects.reduce((total, reconnect) => total + (reconnect.snapshotCount ?? 0), 0),
3509
+ status: hasFailure ? "fail" : reconnects.some((reconnect) => reconnect.status === "warn") ? "warn" : "pass"
3510
+ };
3511
+ };
3512
+ var summarizeReconnectTraceEvidence = (events) => {
3513
+ const reconnectEvents = events.filter((event) => event.type === "client.reconnect");
3514
+ if (reconnectEvents.length === 0) {
3515
+ return;
3516
+ }
3517
+ const statuses = reconnectEvents.map((event) => readString(readTraceRecord(event).status)).filter((status) => status !== undefined);
3518
+ const reconnectPayloads = reconnectEvents.map((event) => readTraceRecord(event));
3519
+ return {
3520
+ attempts: maxNumber(reconnectPayloads.map((payload) => readNumber2(payload.attempts))),
3521
+ exhausted: statuses.includes("exhausted"),
3522
+ maxAttempts: maxNumber(reconnectPayloads.map((payload) => readNumber2(payload.maxAttempts))),
3523
+ resumeLatencyP95Ms: percentile(reconnectPayloads.map((payload) => readNumber2(payload.resumeLatencyP95Ms) ?? readNumber2(payload.resumeLatencyMs)).filter((value) => value !== undefined), 95),
3524
+ reconnected: statuses.includes("reconnecting"),
3525
+ resumed: statuses.includes("resumed") || statuses.includes("pass"),
3526
+ samples: reconnectEvents.length,
3527
+ snapshotCount: reconnectEvents.length,
3528
+ status: reconnectEvents.some((event) => isFailingTraceStatus(readTraceStatus(readTraceRecord(event)))) ? "fail" : "pass"
3529
+ };
3530
+ };
3494
3531
  var readTraceRecord = (event) => event.payload;
3495
3532
  var readTraceProfileId = (events, options) => {
3496
3533
  for (const event of events) {
@@ -3638,6 +3675,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
3638
3675
  }).filter((value) => value !== undefined);
3639
3676
  const turnP95Ms = summarizeTurnTraceP95(sessionEvents);
3640
3677
  const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
3678
+ const reconnect = summarizeReconnectTraceEvidence(sessionEvents);
3641
3679
  const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
3642
3680
  const surfaces = readRealCallProfileTraceSurfaces(sessionEvents);
3643
3681
  if (providers.length === 0 && runtimeChannel === undefined && liveLatencies.length === 0 && surfaces.length === 0) {
@@ -3653,6 +3691,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
3653
3691
  profileLabel: options.profileLabels?.[profileId] ?? (profileId === options.defaultProfileId ? options.defaultProfileLabel : undefined),
3654
3692
  providerP95Ms,
3655
3693
  providers,
3694
+ reconnect,
3656
3695
  runtimeChannel,
3657
3696
  sessionId,
3658
3697
  surfaces: surfaces.length > 0 ? surfaces : undefined,
@@ -3660,11 +3699,45 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
3660
3699
  };
3661
3700
  }).filter((evidence) => evidence !== undefined);
3662
3701
  };
3702
+ var normalizeReconnectReport = (report) => ("contract" in report) ? report.contract : report;
3703
+ var buildVoiceRealCallProfileEvidenceFromReconnectProofReports = (input, options = {}) => {
3704
+ const reports = Array.isArray(input) ? input : [input];
3705
+ const profileId = options.profileId ?? "reconnect-resume";
3706
+ return reports.map((report, index) => {
3707
+ const contract = normalizeReconnectReport(report);
3708
+ const generatedAt = "generatedAt" in report ? report.generatedAt : new Date(contract.checkedAt).toISOString();
3709
+ const ok = "ok" in report ? report.ok : contract.pass;
3710
+ const operationsRecordHref = typeof options.operationsRecordHref === "function" ? options.operationsRecordHref(report, index) : options.operationsRecordHref;
3711
+ const sessionId = typeof options.sessionId === "function" ? options.sessionId(report, index) : options.sessionId ?? `reconnect-proof-${String(index + 1)}-${String(contract.checkedAt)}`;
3712
+ return {
3713
+ generatedAt,
3714
+ ok,
3715
+ operationsRecordHref,
3716
+ profileDescription: options.profileDescription,
3717
+ profileId,
3718
+ profileLabel: options.profileLabel,
3719
+ reconnect: {
3720
+ attempts: contract.summary.attempts,
3721
+ exhausted: contract.summary.exhausted,
3722
+ maxAttempts: contract.summary.maxAttempts,
3723
+ resumeLatencyP95Ms: contract.resumeLatencyP95Ms,
3724
+ reconnected: contract.summary.reconnected,
3725
+ resumed: contract.summary.resumed,
3726
+ samples: 1,
3727
+ snapshotCount: contract.snapshotCount,
3728
+ status: ok ? "pass" : "fail"
3729
+ },
3730
+ sessionId,
3731
+ surfaces: [...new Set(["reconnect", ...options.surfaces ?? []])].sort()
3732
+ };
3733
+ });
3734
+ };
3663
3735
  var loadVoiceRealCallProfileEvidenceFromTraceStore = async (options) => buildVoiceRealCallProfileEvidenceFromTraceEvents(await options.store.list({ limit: options.limit ?? 5000 }), options);
3664
3736
  var realCallProfileTraceSignalTypes = new Set([
3665
3737
  "client.barge_in",
3666
3738
  "client.browser_media",
3667
3739
  "client.live_latency",
3740
+ "client.reconnect",
3668
3741
  "client.telephony_media",
3669
3742
  "provider.decision",
3670
3743
  "session.error",
@@ -3727,15 +3800,16 @@ var readProofTrendProviders = (reports) => aggregateProofTrendProviders(reports.
3727
3800
  var exceedsProofTrendBudget = (value, budget) => value !== undefined && (!Number.isFinite(value) || value > budget);
3728
3801
  var readProofTrendProfileStatus = (profile, budgets) => {
3729
3802
  const runtimeChannel = profile.runtimeChannel;
3730
- const hasBudgetEvidence = profile.maxLiveP95Ms !== undefined || profile.maxProviderP95Ms !== undefined || profile.maxTurnP95Ms !== undefined || profile.providers?.some((provider) => provider.p95Ms !== undefined) === true || runtimeChannel?.maxFirstAudioLatencyMs !== undefined || runtimeChannel?.maxInterruptionP95Ms !== undefined || runtimeChannel?.maxJitterMs !== undefined || runtimeChannel?.maxTimestampDriftMs !== undefined || runtimeChannel?.maxBackpressureEvents !== undefined;
3731
- const budgetFailed = exceedsProofTrendBudget(profile.maxLiveP95Ms, budgets.maxLiveP95Ms) || exceedsProofTrendBudget(profile.maxProviderP95Ms, budgets.maxProviderP95Ms) || exceedsProofTrendBudget(profile.maxTurnP95Ms, budgets.maxTurnP95Ms) || exceedsProofTrendBudget(runtimeChannel?.maxFirstAudioLatencyMs, budgets.maxRuntimeFirstAudioLatencyMs) || exceedsProofTrendBudget(runtimeChannel?.maxInterruptionP95Ms, budgets.maxRuntimeInterruptionP95Ms) || exceedsProofTrendBudget(runtimeChannel?.maxJitterMs, budgets.maxRuntimeJitterMs) || exceedsProofTrendBudget(runtimeChannel?.maxTimestampDriftMs, budgets.maxRuntimeTimestampDriftMs) || exceedsProofTrendBudget(runtimeChannel?.maxBackpressureEvents, 0);
3803
+ const reconnect = profile.reconnect;
3804
+ const hasBudgetEvidence = profile.maxLiveP95Ms !== undefined || profile.maxProviderP95Ms !== undefined || profile.maxReconnectP95Ms !== undefined || profile.maxTurnP95Ms !== undefined || profile.providers?.some((provider) => provider.p95Ms !== undefined) === true || runtimeChannel?.maxFirstAudioLatencyMs !== undefined || runtimeChannel?.maxInterruptionP95Ms !== undefined || runtimeChannel?.maxJitterMs !== undefined || runtimeChannel?.maxTimestampDriftMs !== undefined || runtimeChannel?.maxBackpressureEvents !== undefined || reconnect?.resumeLatencyP95Ms !== undefined || reconnect?.samples !== undefined;
3805
+ const budgetFailed = exceedsProofTrendBudget(profile.maxLiveP95Ms, budgets.maxLiveP95Ms) || exceedsProofTrendBudget(profile.maxProviderP95Ms, budgets.maxProviderP95Ms) || exceedsProofTrendBudget(profile.maxReconnectP95Ms ?? reconnect?.resumeLatencyP95Ms, budgets.maxReconnectP95Ms) || exceedsProofTrendBudget(profile.maxTurnP95Ms, budgets.maxTurnP95Ms) || exceedsProofTrendBudget(runtimeChannel?.maxFirstAudioLatencyMs, budgets.maxRuntimeFirstAudioLatencyMs) || exceedsProofTrendBudget(runtimeChannel?.maxInterruptionP95Ms, budgets.maxRuntimeInterruptionP95Ms) || exceedsProofTrendBudget(runtimeChannel?.maxJitterMs, budgets.maxRuntimeJitterMs) || exceedsProofTrendBudget(runtimeChannel?.maxTimestampDriftMs, budgets.maxRuntimeTimestampDriftMs) || exceedsProofTrendBudget(runtimeChannel?.maxBackpressureEvents, 0) || reconnect?.status === "fail";
3732
3806
  if (budgetFailed || !hasBudgetEvidence && profile.status === "fail") {
3733
3807
  return "fail";
3734
3808
  }
3735
- if (profile.status === "warn" || runtimeChannel?.status === "warn" || profile.providers?.some((provider) => provider.status === "warn") === true) {
3809
+ if (profile.status === "warn" || reconnect?.status === "warn" || runtimeChannel?.status === "warn" || profile.providers?.some((provider) => provider.status === "warn") === true) {
3736
3810
  return "warn";
3737
3811
  }
3738
- if (hasBudgetEvidence || profile.status === "pass" || runtimeChannel?.status === "pass" || profile.providers?.some((provider) => provider.status === "pass") === true) {
3812
+ if (hasBudgetEvidence || profile.status === "pass" || reconnect?.status === "pass" || runtimeChannel?.status === "pass" || profile.providers?.some((provider) => provider.status === "pass") === true) {
3739
3813
  return "pass";
3740
3814
  }
3741
3815
  return;
@@ -3745,6 +3819,7 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
3745
3819
  const definitions = options.profiles ?? DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS;
3746
3820
  const providerCap = options.maxProviderP95Ms ?? 1000;
3747
3821
  const liveCap = options.maxLiveP95Ms ?? 800;
3822
+ const reconnectCap = options.maxReconnectP95Ms ?? 1500;
3748
3823
  const turnCap = options.maxTurnP95Ms ?? 700;
3749
3824
  const runtimeFirstAudioCap = options.maxRuntimeFirstAudioLatencyMs ?? 600;
3750
3825
  const runtimeInterruptionCap = options.maxRuntimeInterruptionP95Ms ?? 300;
@@ -3753,6 +3828,7 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
3753
3828
  const budgets = {
3754
3829
  maxLiveP95Ms: liveCap,
3755
3830
  maxProviderP95Ms: providerCap,
3831
+ maxReconnectP95Ms: reconnectCap,
3756
3832
  maxRuntimeFirstAudioLatencyMs: runtimeFirstAudioCap,
3757
3833
  maxRuntimeInterruptionP95Ms: runtimeInterruptionCap,
3758
3834
  maxRuntimeJitterMs: runtimeJitterCap,
@@ -3775,8 +3851,10 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
3775
3851
  label: definition.label ?? profiles.find(Boolean)?.label,
3776
3852
  maxLiveP95Ms: maxNumber(profiles.map((profile) => profile.maxLiveP95Ms)),
3777
3853
  maxProviderP95Ms: maxNumber(profiles.map((profile) => profile.maxProviderP95Ms)),
3854
+ maxReconnectP95Ms: maxNumber(profiles.map((profile) => profile.maxReconnectP95Ms)),
3778
3855
  maxTurnP95Ms: maxNumber(profiles.map((profile) => profile.maxTurnP95Ms)),
3779
3856
  providers: aggregateProofTrendProviders(profiles.flatMap((profile) => profile.providers ?? [])),
3857
+ reconnect: aggregateProofTrendReconnect(profiles.map((profile) => profile.reconnect).filter((reconnect) => reconnect !== undefined)),
3780
3858
  runtimeChannel: aggregateProofTrendRuntimeChannel(profiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined)),
3781
3859
  sessionCount: profiles.reduce((total, profile) => total + (profile.sessionCount ?? 0), 0),
3782
3860
  surfaces: [
@@ -3816,6 +3894,7 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
3816
3894
  var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
3817
3895
  const providerCap = options.maxProviderP95Ms ?? 1000;
3818
3896
  const liveCap = options.maxLiveP95Ms ?? 800;
3897
+ const reconnectCap = options.maxReconnectP95Ms ?? 1500;
3819
3898
  const turnCap = options.maxTurnP95Ms ?? 700;
3820
3899
  const runtimeFirstAudioCap = options.maxRuntimeFirstAudioLatencyMs ?? 600;
3821
3900
  const runtimeInterruptionCap = options.maxRuntimeInterruptionP95Ms ?? 300;
@@ -3824,6 +3903,7 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
3824
3903
  const budgets = {
3825
3904
  maxLiveP95Ms: liveCap,
3826
3905
  maxProviderP95Ms: providerCap,
3906
+ maxReconnectP95Ms: reconnectCap,
3827
3907
  maxRuntimeFirstAudioLatencyMs: runtimeFirstAudioCap,
3828
3908
  maxRuntimeInterruptionP95Ms: runtimeInterruptionCap,
3829
3909
  maxRuntimeJitterMs: runtimeJitterCap,
@@ -3853,8 +3933,10 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
3853
3933
  label: definition.label ?? matchingEvidence.find((evidence) => evidence.profileLabel)?.profileLabel,
3854
3934
  maxLiveP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.liveP95Ms)),
3855
3935
  maxProviderP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.providerP95Ms)),
3936
+ maxReconnectP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.reconnect?.resumeLatencyP95Ms)),
3856
3937
  maxTurnP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.turnP95Ms)),
3857
3938
  providers: aggregateProofTrendProviders(matchingEvidence.flatMap((evidence) => evidence.providers ?? [])),
3939
+ reconnect: aggregateProofTrendReconnect(matchingEvidence.map((evidence) => evidence.reconnect).filter((reconnect) => reconnect !== undefined)),
3858
3940
  runtimeChannel: aggregateProofTrendRuntimeChannel(matchingEvidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined)),
3859
3941
  sessionCount: new Set(matchingEvidence.map((evidence) => evidence.sessionId)).size,
3860
3942
  surfaces: [
@@ -3873,6 +3955,7 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
3873
3955
  ok: evidence.ok !== false,
3874
3956
  providers: evidence.providers,
3875
3957
  runtimeChannel: evidence.runtimeChannel,
3958
+ reconnect: evidence.reconnect,
3876
3959
  turnLatency: evidence.turnP95Ms === undefined ? undefined : {
3877
3960
  p95Ms: evidence.turnP95Ms,
3878
3961
  samples: 1,
@@ -3883,9 +3966,11 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
3883
3966
  cycles: options.evidence.length,
3884
3967
  maxLiveP95Ms: maxNumber(options.evidence.map((evidence) => evidence.liveP95Ms)),
3885
3968
  maxProviderP95Ms: maxNumber(options.evidence.map((evidence) => evidence.providerP95Ms)),
3969
+ maxReconnectP95Ms: maxNumber(options.evidence.map((evidence) => evidence.reconnect?.resumeLatencyP95Ms)),
3886
3970
  maxTurnP95Ms: maxNumber(options.evidence.map((evidence) => evidence.turnP95Ms)),
3887
3971
  profiles,
3888
3972
  providers: aggregateProofTrendProviders(options.evidence.flatMap((evidence) => evidence.providers ?? [])),
3973
+ reconnect: aggregateProofTrendReconnect(options.evidence.map((evidence) => evidence.reconnect).filter((reconnect) => reconnect !== undefined)),
3889
3974
  runtimeChannel: aggregateProofTrendRuntimeChannel(options.evidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined))
3890
3975
  };
3891
3976
  return buildVoiceProofTrendReport({
@@ -4704,10 +4789,12 @@ var buildVoiceRealCallProfileHistoryReport = (options = {}) => {
4704
4789
  failedReports: history.filter((report) => report.ok !== true).length,
4705
4790
  maxLiveP95Ms: maxNumber(profileHistory.map(readProofTrendMaxLiveP95)),
4706
4791
  maxProviderP95Ms: maxNumber(profileHistory.map(readProofTrendMaxProviderP95)),
4792
+ maxReconnectP95Ms: maxNumber(profileHistory.map(readProofTrendMaxReconnectP95)),
4707
4793
  maxTurnP95Ms: maxNumber(profileHistory.map(readProofTrendMaxTurnP95)),
4708
4794
  profileCount: profiles.length,
4709
4795
  profiles,
4710
4796
  providers: readProofTrendProviders(profileHistory),
4797
+ reconnect: aggregateProofTrendReconnect(profileHistory.map((report) => report.summary.reconnect).filter((reconnect) => reconnect !== undefined)),
4711
4798
  runtimeChannel: aggregateProofTrendRuntimeChannel(profileHistory.map(readProofTrendRuntimeChannel).filter((channel) => channel !== undefined))
4712
4799
  };
4713
4800
  const trend = buildVoiceProofTrendReport({
package/dist/vue/index.js CHANGED
@@ -3351,6 +3351,7 @@ var readString = (value) => typeof value === "string" && value.trim() ? value :
3351
3351
  var readNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
3352
3352
  var readProofTrendMaxLiveP95 = (report) => report.summary.maxLiveP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.liveLatency?.p95Ms));
3353
3353
  var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms ?? maxNumber((report.summary.providers ?? []).map((provider) => provider.p95Ms)) ?? maxNumber(report.cycles.flatMap((cycle) => (cycle.providers ?? []).map((provider) => provider.p95Ms)));
3354
+ var readProofTrendMaxReconnectP95 = (report) => report.summary.maxReconnectP95Ms ?? report.summary.reconnect?.resumeLatencyP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.reconnect?.resumeLatencyP95Ms));
3354
3355
  var readProofTrendMaxTurnP95 = (report) => report.summary.maxTurnP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.turnLatency?.p95Ms));
3355
3356
  var readRuntimeChannelMetric = (report, key) => {
3356
3357
  const summaryValue = report.summary.runtimeChannel?.[key];
@@ -3412,6 +3413,42 @@ var aggregateProofTrendRuntimeChannel = (channels) => {
3412
3413
  status: channels.some((channel) => channel.status === "fail") ? "fail" : channels.some((channel) => channel.status === "warn") ? "warn" : channels.every((channel) => channel.status === "pass") ? "pass" : undefined
3413
3414
  };
3414
3415
  };
3416
+ var aggregateProofTrendReconnect = (reconnects) => {
3417
+ if (reconnects.length === 0) {
3418
+ return;
3419
+ }
3420
+ const hasFailure = reconnects.some((reconnect) => reconnect.status === "fail" || reconnect.exhausted === true || reconnect.reconnected === false || reconnect.resumed === false);
3421
+ return {
3422
+ attempts: maxNumber(reconnects.map((reconnect) => reconnect.attempts)),
3423
+ exhausted: reconnects.some((reconnect) => reconnect.exhausted === true),
3424
+ maxAttempts: maxNumber(reconnects.map((reconnect) => reconnect.maxAttempts)),
3425
+ resumeLatencyP95Ms: maxNumber(reconnects.map((reconnect) => reconnect.resumeLatencyP95Ms)),
3426
+ reconnected: reconnects.some((reconnect) => reconnect.reconnected === true),
3427
+ resumed: reconnects.some((reconnect) => reconnect.resumed === true),
3428
+ samples: reconnects.reduce((total, reconnect) => total + (reconnect.samples ?? 0), 0),
3429
+ snapshotCount: reconnects.reduce((total, reconnect) => total + (reconnect.snapshotCount ?? 0), 0),
3430
+ status: hasFailure ? "fail" : reconnects.some((reconnect) => reconnect.status === "warn") ? "warn" : "pass"
3431
+ };
3432
+ };
3433
+ var summarizeReconnectTraceEvidence = (events) => {
3434
+ const reconnectEvents = events.filter((event) => event.type === "client.reconnect");
3435
+ if (reconnectEvents.length === 0) {
3436
+ return;
3437
+ }
3438
+ const statuses = reconnectEvents.map((event) => readString(readTraceRecord(event).status)).filter((status) => status !== undefined);
3439
+ const reconnectPayloads = reconnectEvents.map((event) => readTraceRecord(event));
3440
+ return {
3441
+ attempts: maxNumber(reconnectPayloads.map((payload) => readNumber2(payload.attempts))),
3442
+ exhausted: statuses.includes("exhausted"),
3443
+ maxAttempts: maxNumber(reconnectPayloads.map((payload) => readNumber2(payload.maxAttempts))),
3444
+ resumeLatencyP95Ms: percentile(reconnectPayloads.map((payload) => readNumber2(payload.resumeLatencyP95Ms) ?? readNumber2(payload.resumeLatencyMs)).filter((value) => value !== undefined), 95),
3445
+ reconnected: statuses.includes("reconnecting"),
3446
+ resumed: statuses.includes("resumed") || statuses.includes("pass"),
3447
+ samples: reconnectEvents.length,
3448
+ snapshotCount: reconnectEvents.length,
3449
+ status: reconnectEvents.some((event) => isFailingTraceStatus(readTraceStatus(readTraceRecord(event)))) ? "fail" : "pass"
3450
+ };
3451
+ };
3415
3452
  var readTraceRecord = (event) => event.payload;
3416
3453
  var readTraceProfileId = (events, options) => {
3417
3454
  for (const event of events) {
@@ -3559,6 +3596,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
3559
3596
  }).filter((value) => value !== undefined);
3560
3597
  const turnP95Ms = summarizeTurnTraceP95(sessionEvents);
3561
3598
  const providerP95Ms = maxNumber(providers.map((provider) => provider.p95Ms));
3599
+ const reconnect = summarizeReconnectTraceEvidence(sessionEvents);
3562
3600
  const runtimeChannel = summarizeRuntimeChannelTraceEvidence(sessionEvents);
3563
3601
  const surfaces = readRealCallProfileTraceSurfaces(sessionEvents);
3564
3602
  if (providers.length === 0 && runtimeChannel === undefined && liveLatencies.length === 0 && surfaces.length === 0) {
@@ -3574,6 +3612,7 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
3574
3612
  profileLabel: options.profileLabels?.[profileId] ?? (profileId === options.defaultProfileId ? options.defaultProfileLabel : undefined),
3575
3613
  providerP95Ms,
3576
3614
  providers,
3615
+ reconnect,
3577
3616
  runtimeChannel,
3578
3617
  sessionId,
3579
3618
  surfaces: surfaces.length > 0 ? surfaces : undefined,
@@ -3581,11 +3620,45 @@ var buildVoiceRealCallProfileEvidenceFromTraceEvents = (events, options = {}) =>
3581
3620
  };
3582
3621
  }).filter((evidence) => evidence !== undefined);
3583
3622
  };
3623
+ var normalizeReconnectReport = (report) => ("contract" in report) ? report.contract : report;
3624
+ var buildVoiceRealCallProfileEvidenceFromReconnectProofReports = (input, options = {}) => {
3625
+ const reports = Array.isArray(input) ? input : [input];
3626
+ const profileId = options.profileId ?? "reconnect-resume";
3627
+ return reports.map((report, index) => {
3628
+ const contract = normalizeReconnectReport(report);
3629
+ const generatedAt = "generatedAt" in report ? report.generatedAt : new Date(contract.checkedAt).toISOString();
3630
+ const ok = "ok" in report ? report.ok : contract.pass;
3631
+ const operationsRecordHref = typeof options.operationsRecordHref === "function" ? options.operationsRecordHref(report, index) : options.operationsRecordHref;
3632
+ const sessionId = typeof options.sessionId === "function" ? options.sessionId(report, index) : options.sessionId ?? `reconnect-proof-${String(index + 1)}-${String(contract.checkedAt)}`;
3633
+ return {
3634
+ generatedAt,
3635
+ ok,
3636
+ operationsRecordHref,
3637
+ profileDescription: options.profileDescription,
3638
+ profileId,
3639
+ profileLabel: options.profileLabel,
3640
+ reconnect: {
3641
+ attempts: contract.summary.attempts,
3642
+ exhausted: contract.summary.exhausted,
3643
+ maxAttempts: contract.summary.maxAttempts,
3644
+ resumeLatencyP95Ms: contract.resumeLatencyP95Ms,
3645
+ reconnected: contract.summary.reconnected,
3646
+ resumed: contract.summary.resumed,
3647
+ samples: 1,
3648
+ snapshotCount: contract.snapshotCount,
3649
+ status: ok ? "pass" : "fail"
3650
+ },
3651
+ sessionId,
3652
+ surfaces: [...new Set(["reconnect", ...options.surfaces ?? []])].sort()
3653
+ };
3654
+ });
3655
+ };
3584
3656
  var loadVoiceRealCallProfileEvidenceFromTraceStore = async (options) => buildVoiceRealCallProfileEvidenceFromTraceEvents(await options.store.list({ limit: options.limit ?? 5000 }), options);
3585
3657
  var realCallProfileTraceSignalTypes = new Set([
3586
3658
  "client.barge_in",
3587
3659
  "client.browser_media",
3588
3660
  "client.live_latency",
3661
+ "client.reconnect",
3589
3662
  "client.telephony_media",
3590
3663
  "provider.decision",
3591
3664
  "session.error",
@@ -3648,15 +3721,16 @@ var readProofTrendProviders = (reports) => aggregateProofTrendProviders(reports.
3648
3721
  var exceedsProofTrendBudget = (value, budget) => value !== undefined && (!Number.isFinite(value) || value > budget);
3649
3722
  var readProofTrendProfileStatus = (profile, budgets) => {
3650
3723
  const runtimeChannel = profile.runtimeChannel;
3651
- const hasBudgetEvidence = profile.maxLiveP95Ms !== undefined || profile.maxProviderP95Ms !== undefined || profile.maxTurnP95Ms !== undefined || profile.providers?.some((provider) => provider.p95Ms !== undefined) === true || runtimeChannel?.maxFirstAudioLatencyMs !== undefined || runtimeChannel?.maxInterruptionP95Ms !== undefined || runtimeChannel?.maxJitterMs !== undefined || runtimeChannel?.maxTimestampDriftMs !== undefined || runtimeChannel?.maxBackpressureEvents !== undefined;
3652
- const budgetFailed = exceedsProofTrendBudget(profile.maxLiveP95Ms, budgets.maxLiveP95Ms) || exceedsProofTrendBudget(profile.maxProviderP95Ms, budgets.maxProviderP95Ms) || exceedsProofTrendBudget(profile.maxTurnP95Ms, budgets.maxTurnP95Ms) || exceedsProofTrendBudget(runtimeChannel?.maxFirstAudioLatencyMs, budgets.maxRuntimeFirstAudioLatencyMs) || exceedsProofTrendBudget(runtimeChannel?.maxInterruptionP95Ms, budgets.maxRuntimeInterruptionP95Ms) || exceedsProofTrendBudget(runtimeChannel?.maxJitterMs, budgets.maxRuntimeJitterMs) || exceedsProofTrendBudget(runtimeChannel?.maxTimestampDriftMs, budgets.maxRuntimeTimestampDriftMs) || exceedsProofTrendBudget(runtimeChannel?.maxBackpressureEvents, 0);
3724
+ const reconnect = profile.reconnect;
3725
+ const hasBudgetEvidence = profile.maxLiveP95Ms !== undefined || profile.maxProviderP95Ms !== undefined || profile.maxReconnectP95Ms !== undefined || profile.maxTurnP95Ms !== undefined || profile.providers?.some((provider) => provider.p95Ms !== undefined) === true || runtimeChannel?.maxFirstAudioLatencyMs !== undefined || runtimeChannel?.maxInterruptionP95Ms !== undefined || runtimeChannel?.maxJitterMs !== undefined || runtimeChannel?.maxTimestampDriftMs !== undefined || runtimeChannel?.maxBackpressureEvents !== undefined || reconnect?.resumeLatencyP95Ms !== undefined || reconnect?.samples !== undefined;
3726
+ const budgetFailed = exceedsProofTrendBudget(profile.maxLiveP95Ms, budgets.maxLiveP95Ms) || exceedsProofTrendBudget(profile.maxProviderP95Ms, budgets.maxProviderP95Ms) || exceedsProofTrendBudget(profile.maxReconnectP95Ms ?? reconnect?.resumeLatencyP95Ms, budgets.maxReconnectP95Ms) || exceedsProofTrendBudget(profile.maxTurnP95Ms, budgets.maxTurnP95Ms) || exceedsProofTrendBudget(runtimeChannel?.maxFirstAudioLatencyMs, budgets.maxRuntimeFirstAudioLatencyMs) || exceedsProofTrendBudget(runtimeChannel?.maxInterruptionP95Ms, budgets.maxRuntimeInterruptionP95Ms) || exceedsProofTrendBudget(runtimeChannel?.maxJitterMs, budgets.maxRuntimeJitterMs) || exceedsProofTrendBudget(runtimeChannel?.maxTimestampDriftMs, budgets.maxRuntimeTimestampDriftMs) || exceedsProofTrendBudget(runtimeChannel?.maxBackpressureEvents, 0) || reconnect?.status === "fail";
3653
3727
  if (budgetFailed || !hasBudgetEvidence && profile.status === "fail") {
3654
3728
  return "fail";
3655
3729
  }
3656
- if (profile.status === "warn" || runtimeChannel?.status === "warn" || profile.providers?.some((provider) => provider.status === "warn") === true) {
3730
+ if (profile.status === "warn" || reconnect?.status === "warn" || runtimeChannel?.status === "warn" || profile.providers?.some((provider) => provider.status === "warn") === true) {
3657
3731
  return "warn";
3658
3732
  }
3659
- if (hasBudgetEvidence || profile.status === "pass" || runtimeChannel?.status === "pass" || profile.providers?.some((provider) => provider.status === "pass") === true) {
3733
+ if (hasBudgetEvidence || profile.status === "pass" || reconnect?.status === "pass" || runtimeChannel?.status === "pass" || profile.providers?.some((provider) => provider.status === "pass") === true) {
3660
3734
  return "pass";
3661
3735
  }
3662
3736
  return;
@@ -3666,6 +3740,7 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
3666
3740
  const definitions = options.profiles ?? DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS;
3667
3741
  const providerCap = options.maxProviderP95Ms ?? 1000;
3668
3742
  const liveCap = options.maxLiveP95Ms ?? 800;
3743
+ const reconnectCap = options.maxReconnectP95Ms ?? 1500;
3669
3744
  const turnCap = options.maxTurnP95Ms ?? 700;
3670
3745
  const runtimeFirstAudioCap = options.maxRuntimeFirstAudioLatencyMs ?? 600;
3671
3746
  const runtimeInterruptionCap = options.maxRuntimeInterruptionP95Ms ?? 300;
@@ -3674,6 +3749,7 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
3674
3749
  const budgets = {
3675
3750
  maxLiveP95Ms: liveCap,
3676
3751
  maxProviderP95Ms: providerCap,
3752
+ maxReconnectP95Ms: reconnectCap,
3677
3753
  maxRuntimeFirstAudioLatencyMs: runtimeFirstAudioCap,
3678
3754
  maxRuntimeInterruptionP95Ms: runtimeInterruptionCap,
3679
3755
  maxRuntimeJitterMs: runtimeJitterCap,
@@ -3696,8 +3772,10 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
3696
3772
  label: definition.label ?? profiles.find(Boolean)?.label,
3697
3773
  maxLiveP95Ms: maxNumber(profiles.map((profile) => profile.maxLiveP95Ms)),
3698
3774
  maxProviderP95Ms: maxNumber(profiles.map((profile) => profile.maxProviderP95Ms)),
3775
+ maxReconnectP95Ms: maxNumber(profiles.map((profile) => profile.maxReconnectP95Ms)),
3699
3776
  maxTurnP95Ms: maxNumber(profiles.map((profile) => profile.maxTurnP95Ms)),
3700
3777
  providers: aggregateProofTrendProviders(profiles.flatMap((profile) => profile.providers ?? [])),
3778
+ reconnect: aggregateProofTrendReconnect(profiles.map((profile) => profile.reconnect).filter((reconnect) => reconnect !== undefined)),
3701
3779
  runtimeChannel: aggregateProofTrendRuntimeChannel(profiles.map((profile) => profile.runtimeChannel).filter((channel) => channel !== undefined)),
3702
3780
  sessionCount: profiles.reduce((total, profile) => total + (profile.sessionCount ?? 0), 0),
3703
3781
  surfaces: [
@@ -3737,6 +3815,7 @@ var buildVoiceProofTrendProfileSummaries = (input, options = {}) => {
3737
3815
  var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
3738
3816
  const providerCap = options.maxProviderP95Ms ?? 1000;
3739
3817
  const liveCap = options.maxLiveP95Ms ?? 800;
3818
+ const reconnectCap = options.maxReconnectP95Ms ?? 1500;
3740
3819
  const turnCap = options.maxTurnP95Ms ?? 700;
3741
3820
  const runtimeFirstAudioCap = options.maxRuntimeFirstAudioLatencyMs ?? 600;
3742
3821
  const runtimeInterruptionCap = options.maxRuntimeInterruptionP95Ms ?? 300;
@@ -3745,6 +3824,7 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
3745
3824
  const budgets = {
3746
3825
  maxLiveP95Ms: liveCap,
3747
3826
  maxProviderP95Ms: providerCap,
3827
+ maxReconnectP95Ms: reconnectCap,
3748
3828
  maxRuntimeFirstAudioLatencyMs: runtimeFirstAudioCap,
3749
3829
  maxRuntimeInterruptionP95Ms: runtimeInterruptionCap,
3750
3830
  maxRuntimeJitterMs: runtimeJitterCap,
@@ -3774,8 +3854,10 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
3774
3854
  label: definition.label ?? matchingEvidence.find((evidence) => evidence.profileLabel)?.profileLabel,
3775
3855
  maxLiveP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.liveP95Ms)),
3776
3856
  maxProviderP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.providerP95Ms)),
3857
+ maxReconnectP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.reconnect?.resumeLatencyP95Ms)),
3777
3858
  maxTurnP95Ms: maxNumber(matchingEvidence.map((evidence) => evidence.turnP95Ms)),
3778
3859
  providers: aggregateProofTrendProviders(matchingEvidence.flatMap((evidence) => evidence.providers ?? [])),
3860
+ reconnect: aggregateProofTrendReconnect(matchingEvidence.map((evidence) => evidence.reconnect).filter((reconnect) => reconnect !== undefined)),
3779
3861
  runtimeChannel: aggregateProofTrendRuntimeChannel(matchingEvidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined)),
3780
3862
  sessionCount: new Set(matchingEvidence.map((evidence) => evidence.sessionId)).size,
3781
3863
  surfaces: [
@@ -3794,6 +3876,7 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
3794
3876
  ok: evidence.ok !== false,
3795
3877
  providers: evidence.providers,
3796
3878
  runtimeChannel: evidence.runtimeChannel,
3879
+ reconnect: evidence.reconnect,
3797
3880
  turnLatency: evidence.turnP95Ms === undefined ? undefined : {
3798
3881
  p95Ms: evidence.turnP95Ms,
3799
3882
  samples: 1,
@@ -3804,9 +3887,11 @@ var buildVoiceProofTrendReportFromRealCallProfiles = (options) => {
3804
3887
  cycles: options.evidence.length,
3805
3888
  maxLiveP95Ms: maxNumber(options.evidence.map((evidence) => evidence.liveP95Ms)),
3806
3889
  maxProviderP95Ms: maxNumber(options.evidence.map((evidence) => evidence.providerP95Ms)),
3890
+ maxReconnectP95Ms: maxNumber(options.evidence.map((evidence) => evidence.reconnect?.resumeLatencyP95Ms)),
3807
3891
  maxTurnP95Ms: maxNumber(options.evidence.map((evidence) => evidence.turnP95Ms)),
3808
3892
  profiles,
3809
3893
  providers: aggregateProofTrendProviders(options.evidence.flatMap((evidence) => evidence.providers ?? [])),
3894
+ reconnect: aggregateProofTrendReconnect(options.evidence.map((evidence) => evidence.reconnect).filter((reconnect) => reconnect !== undefined)),
3810
3895
  runtimeChannel: aggregateProofTrendRuntimeChannel(options.evidence.map((evidence) => evidence.runtimeChannel).filter((channel) => channel !== undefined))
3811
3896
  };
3812
3897
  return buildVoiceProofTrendReport({
@@ -4625,10 +4710,12 @@ var buildVoiceRealCallProfileHistoryReport = (options = {}) => {
4625
4710
  failedReports: history.filter((report) => report.ok !== true).length,
4626
4711
  maxLiveP95Ms: maxNumber(profileHistory.map(readProofTrendMaxLiveP95)),
4627
4712
  maxProviderP95Ms: maxNumber(profileHistory.map(readProofTrendMaxProviderP95)),
4713
+ maxReconnectP95Ms: maxNumber(profileHistory.map(readProofTrendMaxReconnectP95)),
4628
4714
  maxTurnP95Ms: maxNumber(profileHistory.map(readProofTrendMaxTurnP95)),
4629
4715
  profileCount: profiles.length,
4630
4716
  profiles,
4631
4717
  providers: readProofTrendProviders(profileHistory),
4718
+ reconnect: aggregateProofTrendReconnect(profileHistory.map((report) => report.summary.reconnect).filter((reconnect) => reconnect !== undefined)),
4632
4719
  runtimeChannel: aggregateProofTrendRuntimeChannel(profileHistory.map(readProofTrendRuntimeChannel).filter((channel) => channel !== undefined))
4633
4720
  };
4634
4721
  const trend = buildVoiceProofTrendReport({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.450",
3
+ "version": "0.0.22-beta.452",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",