@absolutejs/voice 0.0.22-beta.285 → 0.0.22-beta.287

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -18,8 +18,8 @@ export { assertVoicePlatformCoverage, buildVoicePlatformCoverageSummary, createV
18
18
  export type { VoicePlatformCoverageAssertionInput, VoicePlatformCoverageAssertionReport, VoicePlatformCoverageEvidence, VoicePlatformCoverageRoutesOptions, VoicePlatformCoverageStatus, VoicePlatformCoverageSummary, VoicePlatformCoverageSummaryInput, VoicePlatformCoverageSurface } from './platformCoverage';
19
19
  export { assertVoiceProofTrendEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendReport, createVoiceProofTrendRoutes, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile } from './proofTrends';
20
20
  export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendStatus, VoiceProofTrendSummary } from './proofTrends';
21
- export { assertVoiceSloCalibration, buildVoiceSloCalibrationReport, createVoiceSloThresholdProfile, createVoiceSloCalibrationRoutes, renderVoiceSloCalibrationMarkdown } from './sloCalibration';
22
- export type { VoiceSloCalibrationMetricKey, VoiceSloCalibrationOptions, VoiceSloCalibrationReport, VoiceSloCalibrationRoutesOptions, VoiceSloCalibrationSample, VoiceSloCalibrationStatus, VoiceSloCalibrationThreshold, VoiceSloCalibrationThresholds, VoiceSloThresholdProfile } from './sloCalibration';
21
+ export { assertVoiceSloCalibration, buildVoiceSloCalibrationReport, createVoiceSloReadinessThresholdOptions, createVoiceSloThresholdProfile, createVoiceSloCalibrationRoutes, renderVoiceSloCalibrationMarkdown } from './sloCalibration';
22
+ export type { VoiceSloCalibrationMetricKey, VoiceSloCalibrationOptions, VoiceSloCalibrationReport, VoiceSloCalibrationRoutesOptions, VoiceSloCalibrationSample, VoiceSloCalibrationStatus, VoiceSloCalibrationThreshold, VoiceSloCalibrationThresholds, VoiceSloReadinessThresholdOptions, VoiceSloThresholdProfile } from './sloCalibration';
23
23
  export { assertVoiceLiveOpsControlEvidence, assertVoiceLiveOpsEvidence, buildVoiceLiveOpsControlState, createVoiceLiveOpsController, createVoiceLiveOpsRoutes, createVoiceMemoryLiveOpsControlStore, evaluateVoiceLiveOpsControlEvidence, evaluateVoiceLiveOpsEvidence, getVoiceLiveOpsControlStatus, VOICE_LIVE_OPS_ACTIONS } from './liveOps';
24
24
  export type { VoiceLiveOpsAction, VoiceLiveOpsActionInput, VoiceLiveOpsActionResult, VoiceLiveOpsControllerOptions, VoiceLiveOpsControlState, VoiceLiveOpsControlStatus, VoiceLiveOpsControlStore, VoiceLiveOpsControlEvidenceInput, VoiceLiveOpsControlEvidenceReport, VoiceLiveOpsEvidenceInput, VoiceLiveOpsEvidenceReport, VoiceLiveOpsRoutesOptions } from './liveOps';
25
25
  export { buildVoiceDeliveryRuntimeReport, createVoiceDeliveryRuntime, createVoiceDeliveryRuntimePresetConfig, createVoiceDeliveryRuntimeRoutes, renderVoiceDeliveryRuntimeHTML } from './deliveryRuntime';
package/dist/index.js CHANGED
@@ -10798,6 +10798,18 @@ var findDuplicateTurnIds = (snapshots) => {
10798
10798
  }
10799
10799
  return [...duplicates].sort();
10800
10800
  };
10801
+ var percentile = (values, rank) => {
10802
+ if (values.length === 0) {
10803
+ return;
10804
+ }
10805
+ const sorted = [...values].sort((left, right) => left - right);
10806
+ const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil(rank / 100 * sorted.length) - 1));
10807
+ return sorted[index];
10808
+ };
10809
+ var getResumeLatencies = (snapshots) => snapshots.filter((snapshot) => snapshot.reconnect.status === "resumed" && typeof snapshot.reconnect.lastResumedAt === "number").map((snapshot) => {
10810
+ const previousReconnect = snapshots.filter((candidate) => candidate.at <= snapshot.at && candidate.reconnect.status === "reconnecting" && typeof candidate.reconnect.lastDisconnectAt === "number").at(-1);
10811
+ return previousReconnect?.reconnect.lastDisconnectAt === undefined ? undefined : snapshot.reconnect.lastResumedAt - previousReconnect.reconnect.lastDisconnectAt;
10812
+ }).filter((value) => typeof value === "number" && value >= 0);
10801
10813
  var runVoiceReconnectContract = (options) => {
10802
10814
  const snapshots = [...options.snapshots].sort((left, right) => left.at - right.at);
10803
10815
  const issues = [];
@@ -10808,6 +10820,7 @@ var runVoiceReconnectContract = (options) => {
10808
10820
  const resumed = statuses.includes("resumed");
10809
10821
  const exhausted = statuses.includes("exhausted");
10810
10822
  const duplicateTurnIds = findDuplicateTurnIds(snapshots);
10823
+ const resumeLatencyP95Ms = percentile(getResumeLatencies(snapshots), 95);
10811
10824
  const requireReconnect = options.requireReconnect ?? true;
10812
10825
  const requireResume = options.requireResume ?? true;
10813
10826
  const requireReplayProtection = options.requireReplayProtection ?? true;
@@ -10861,6 +10874,7 @@ var runVoiceReconnectContract = (options) => {
10861
10874
  checkedAt: Date.now(),
10862
10875
  issues,
10863
10876
  pass,
10877
+ resumeLatencyP95Ms,
10864
10878
  snapshotCount: snapshots.length,
10865
10879
  statuses,
10866
10880
  summary: {
@@ -12628,7 +12642,7 @@ var DEFAULT_WARN_RATIO = 0.8;
12628
12642
  var DEFAULT_MIN_PASSING_RUNS = 3;
12629
12643
  var roundMs = (value) => Math.max(1, Math.ceil(value));
12630
12644
  var finiteNumber = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
12631
- var percentile = (values, rank) => {
12645
+ var percentile2 = (values, rank) => {
12632
12646
  if (values.length === 0) {
12633
12647
  return;
12634
12648
  }
@@ -12651,7 +12665,7 @@ var normalizeSample = (input) => {
12651
12665
  return input;
12652
12666
  };
12653
12667
  var createThreshold = (metric, values, options) => {
12654
- const baselineP95Ms = percentile(values, 95);
12668
+ const baselineP95Ms = percentile2(values, 95);
12655
12669
  const maxObservedMs = values.length > 0 ? Math.max(...values) : undefined;
12656
12670
  const recommendedMs = baselineP95Ms === undefined ? undefined : roundMs(Math.max(options.minimumMs, baselineP95Ms * options.headroomMultiplier));
12657
12671
  const warnAfterMs = recommendedMs === undefined ? undefined : roundMs(Math.max(options.minimumMs, recommendedMs * options.warnRatio));
@@ -12776,6 +12790,16 @@ var createVoiceSloThresholdProfile = (input, options = {}) => {
12776
12790
  status: report.status
12777
12791
  };
12778
12792
  };
12793
+ var createVoiceSloReadinessThresholdOptions = (input, options = {}) => {
12794
+ const profile = "providerSlo" in input ? input : createVoiceSloThresholdProfile(input, options);
12795
+ return {
12796
+ liveLatencyFailAfterMs: profile.liveLatency.failAfterMs,
12797
+ liveLatencyWarnAfterMs: profile.liveLatency.warnAfterMs,
12798
+ monitoringNotifierDeliveryFailAfterMs: profile.monitoring.notifierDeliveryFailAfterMs,
12799
+ monitoringRunFailAfterMs: profile.monitoring.monitorRunFailAfterMs,
12800
+ reconnectResumeFailAfterMs: profile.reconnect.failAfterMs
12801
+ };
12802
+ };
12779
12803
  var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
12780
12804
  var renderVoiceSloCalibrationMarkdown = (report, options = {}) => {
12781
12805
  const rows = Object.values(report.thresholds).map((threshold) => `| ${escapeMarkdown(threshold.metric)} | ${threshold.status} | ${threshold.samples} | ${threshold.baselineP95Ms ?? "n/a"} | ${threshold.warnAfterMs ?? "n/a"} | ${threshold.failAfterMs ?? "n/a"} |`).join(`
@@ -17030,7 +17054,7 @@ var createVoiceTurnLatencyRoutes = (options) => {
17030
17054
  // src/liveLatency.ts
17031
17055
  import { Elysia as Elysia27 } from "elysia";
17032
17056
  var escapeHtml26 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
17033
- var percentile2 = (values, percentileValue) => {
17057
+ var percentile3 = (values, percentileValue) => {
17034
17058
  if (values.length === 0) {
17035
17059
  return;
17036
17060
  }
@@ -17066,8 +17090,8 @@ var summarizeVoiceLiveLatency = async (options) => {
17066
17090
  averageLatencyMs: latencies.length > 0 ? Math.round(latencies.reduce((total, value) => total + value, 0) / latencies.length) : undefined,
17067
17091
  checkedAt: Date.now(),
17068
17092
  failed,
17069
- p50LatencyMs: percentile2(latencies, 50),
17070
- p95LatencyMs: percentile2(latencies, 95),
17093
+ p50LatencyMs: percentile3(latencies, 50),
17094
+ p95LatencyMs: percentile3(latencies, 95),
17071
17095
  recent,
17072
17096
  status: latencies.length === 0 ? "empty" : failed > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
17073
17097
  total: latencies.length,
@@ -17143,7 +17167,7 @@ var TRACE_TYPES = [
17143
17167
  ];
17144
17168
  var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
17145
17169
  var getString12 = (value) => typeof value === "string" && value.trim() ? value : undefined;
17146
- var percentile3 = (values, percentileValue) => {
17170
+ var percentile4 = (values, percentileValue) => {
17147
17171
  if (values.length === 0) {
17148
17172
  return;
17149
17173
  }
@@ -17351,8 +17375,8 @@ var summarizeStage = (stage, measurements, options) => {
17351
17375
  label: STAGE_LABELS[stage],
17352
17376
  maxMs: latencies.length > 0 ? Math.max(...latencies) : undefined,
17353
17377
  measurements: stageMeasurements,
17354
- p50Ms: percentile3(latencies, 50),
17355
- p95Ms: percentile3(latencies, 95),
17378
+ p50Ms: percentile4(latencies, 50),
17379
+ p95Ms: percentile4(latencies, 95),
17356
17380
  stage,
17357
17381
  status: stageMeasurements.length === 0 ? "empty" : failed > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
17358
17382
  total: stageMeasurements.length,
@@ -23790,7 +23814,7 @@ var rate3 = (count, total) => count / Math.max(1, total);
23790
23814
  var uniqueSorted5 = (values) => [
23791
23815
  ...new Set(values.filter((value) => typeof value === "string"))
23792
23816
  ].sort();
23793
- var percentile4 = (values, rank) => {
23817
+ var percentile5 = (values, rank) => {
23794
23818
  if (values.length === 0) {
23795
23819
  return 0;
23796
23820
  }
@@ -23848,7 +23872,7 @@ var summarizeKind = (kind, events, thresholds, required) => {
23848
23872
  unit: "rate"
23849
23873
  }),
23850
23874
  p95ElapsedMs: createMetric2({
23851
- actual: percentile4(latencies, 95),
23875
+ actual: percentile5(latencies, 95),
23852
23876
  label: "P95 latency",
23853
23877
  threshold: thresholds.maxP95ElapsedMs,
23854
23878
  unit: "ms"
@@ -28166,15 +28190,17 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
28166
28190
  } : undefined;
28167
28191
  const monitoringSummary = monitoring ? {
28168
28192
  criticalOpen: monitoring.summary.criticalOpen,
28193
+ elapsedMs: monitoring.elapsedMs,
28169
28194
  open: monitoring.summary.open,
28170
- status: monitoring.status,
28195
+ status: options.monitoringRunFailAfterMs !== undefined && monitoring.elapsedMs > options.monitoringRunFailAfterMs ? "fail" : monitoring.status,
28171
28196
  total: monitoring.summary.total
28172
28197
  } : undefined;
28173
28198
  const monitoringNotifierDeliverySummary = monitoringNotifierDelivery ? {
28199
+ elapsedMs: monitoringNotifierDelivery.elapsedMs,
28174
28200
  failed: monitoringNotifierDelivery.summary.failed,
28175
28201
  notifiers: monitoringNotifierDelivery.summary.notifiers,
28176
28202
  sent: monitoringNotifierDelivery.summary.sent,
28177
- status: monitoringNotifierDelivery.status,
28203
+ status: options.monitoringNotifierDeliveryFailAfterMs !== undefined && monitoringNotifierDelivery.elapsedMs > options.monitoringNotifierDeliveryFailAfterMs ? "fail" : monitoringNotifierDelivery.status,
28178
28204
  total: monitoringNotifierDelivery.summary.total
28179
28205
  } : undefined;
28180
28206
  const telephonyWebhookSecuritySummary = telephonyWebhookSecurity ? {
@@ -28184,12 +28210,17 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
28184
28210
  status: telephonyWebhookSecurity.status,
28185
28211
  warned: telephonyWebhookSecurity.summary.warned
28186
28212
  } : undefined;
28187
- const reconnectContractSummary = reconnectContracts ? {
28188
- failed: reconnectContracts.filter((report) => !report.pass).length,
28189
- passed: reconnectContracts.filter((report) => report.pass).length,
28190
- status: reconnectContracts.some((report) => !report.pass) ? "fail" : reconnectContracts.length === 0 ? "warn" : "pass",
28191
- total: reconnectContracts.length
28192
- } : undefined;
28213
+ const reconnectContractSummary = reconnectContracts ? (() => {
28214
+ const failedReports = reconnectContracts.filter((report) => !report.pass || options.reconnectResumeFailAfterMs !== undefined && report.resumeLatencyP95Ms !== undefined && report.resumeLatencyP95Ms > options.reconnectResumeFailAfterMs);
28215
+ const resumeLatencies = reconnectContracts.map((report) => report.resumeLatencyP95Ms).filter((value) => typeof value === "number");
28216
+ return {
28217
+ failed: failedReports.length,
28218
+ passed: reconnectContracts.length - failedReports.length,
28219
+ resumeLatencyP95Ms: resumeLatencies.length > 0 ? Math.max(...resumeLatencies) : undefined,
28220
+ status: failedReports.length > 0 ? "fail" : reconnectContracts.length === 0 ? "warn" : "pass",
28221
+ total: reconnectContracts.length
28222
+ };
28223
+ })() : undefined;
28193
28224
  const bargeInSummary = bargeInReports ? {
28194
28225
  failed: bargeInReports.reduce((total, report) => total + report.failed, 0),
28195
28226
  passed: bargeInReports.reduce((total, report) => total + report.passed, 0),
@@ -28406,7 +28437,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
28406
28437
  }
28407
28438
  if (reconnectContractSummary) {
28408
28439
  checks.push({
28409
- detail: reconnectContractSummary.status === "pass" ? `${reconnectContractSummary.passed} reconnect contract(s) are passing.` : reconnectContractSummary.total === 0 ? "No reconnect contracts are configured." : `${reconnectContractSummary.failed} reconnect contract(s) failed.`,
28440
+ detail: reconnectContractSummary.status === "pass" ? `${reconnectContractSummary.passed} reconnect contract(s) are passing.` : reconnectContractSummary.total === 0 ? "No reconnect contracts are configured." : options.reconnectResumeFailAfterMs !== undefined && reconnectContractSummary.resumeLatencyP95Ms !== undefined && reconnectContractSummary.resumeLatencyP95Ms > options.reconnectResumeFailAfterMs ? `Reconnect resume p95 ${reconnectContractSummary.resumeLatencyP95Ms}ms exceeded ${options.reconnectResumeFailAfterMs}ms.` : `${reconnectContractSummary.failed} reconnect contract(s) failed.`,
28410
28441
  href: options.links?.reconnectContracts ?? options.links?.sessions ?? "/sessions",
28411
28442
  label: "Reconnect recovery contracts",
28412
28443
  proofSource: proofSource("reconnectContracts", "reconnect"),
@@ -28575,7 +28606,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
28575
28606
  }
28576
28607
  if (monitoring && monitoringSummary) {
28577
28608
  checks.push({
28578
- detail: monitoringSummary.status === "pass" ? `${monitoringSummary.total} monitor(s) are passing with no open issues.` : `${monitoringSummary.open} monitor issue(s) open, ${monitoringSummary.criticalOpen} critical.`,
28609
+ detail: monitoringSummary.status === "pass" ? `${monitoringSummary.total} monitor(s) are passing with no open issues.` : options.monitoringRunFailAfterMs !== undefined && monitoringSummary.elapsedMs !== undefined && monitoringSummary.elapsedMs > options.monitoringRunFailAfterMs ? `Monitor run took ${monitoringSummary.elapsedMs}ms, above ${options.monitoringRunFailAfterMs}ms.` : `${monitoringSummary.open} monitor issue(s) open, ${monitoringSummary.criticalOpen} critical.`,
28579
28610
  href: options.links?.monitoring ?? "/voice/monitors",
28580
28611
  label: "Monitoring issues",
28581
28612
  status: monitoringSummary.status,
@@ -28591,7 +28622,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
28591
28622
  }
28592
28623
  if (monitoringNotifierDelivery && monitoringNotifierDeliverySummary) {
28593
28624
  checks.push({
28594
- detail: monitoringNotifierDeliverySummary.status === "pass" ? `${monitoringNotifierDeliverySummary.sent} monitor notification(s) delivered.` : `${monitoringNotifierDeliverySummary.failed} monitor notification delivery failure(s).`,
28625
+ detail: monitoringNotifierDeliverySummary.status === "pass" ? `${monitoringNotifierDeliverySummary.sent} monitor notification(s) delivered.` : options.monitoringNotifierDeliveryFailAfterMs !== undefined && monitoringNotifierDeliverySummary.elapsedMs !== undefined && monitoringNotifierDeliverySummary.elapsedMs > options.monitoringNotifierDeliveryFailAfterMs ? `Monitor notification delivery took ${monitoringNotifierDeliverySummary.elapsedMs}ms, above ${options.monitoringNotifierDeliveryFailAfterMs}ms.` : `${monitoringNotifierDeliverySummary.failed} monitor notification delivery failure(s).`,
28595
28626
  href: options.links?.monitoringNotifierDelivery ?? "/api/voice/monitor-issues/notifications",
28596
28627
  label: "Monitor notifier delivery",
28597
28628
  status: monitoringNotifierDeliverySummary.status,
@@ -28823,7 +28854,8 @@ var createVoiceMemoryMonitorNotifierDeliveryReceiptStore = (initial = []) => {
28823
28854
  };
28824
28855
  };
28825
28856
  var buildVoiceMonitorRunReport = async (options) => {
28826
- const checkedAt = options.now ?? Date.now();
28857
+ const startedAt = Date.now();
28858
+ const checkedAt = options.now ?? startedAt;
28827
28859
  const runs = await Promise.all(options.monitors.map(async (monitor) => {
28828
28860
  const evaluation = await monitor.evaluate({
28829
28861
  evidence: options.evidence,
@@ -28863,6 +28895,7 @@ var buildVoiceMonitorRunReport = async (options) => {
28863
28895
  const criticalOpen = openIssues.filter((issue) => issue.severity === "critical").length;
28864
28896
  return {
28865
28897
  checkedAt,
28898
+ elapsedMs: Math.max(0, Date.now() - startedAt),
28866
28899
  issues,
28867
28900
  runs,
28868
28901
  status: criticalOpen > 0 ? "fail" : openIssues.length > 0 || rollupStatus4(runs) === "warn" ? "warn" : rollupStatus4(runs),
@@ -28923,7 +28956,8 @@ var createVoiceMonitorWebhookNotifier = (options) => ({
28923
28956
  }
28924
28957
  });
28925
28958
  var deliverVoiceMonitorIssueNotifications = async (options) => {
28926
- const checkedAt = options.now ?? Date.now();
28959
+ const startedAt = Date.now();
28960
+ const checkedAt = options.now ?? startedAt;
28927
28961
  const statuses = new Set(options.statuses ?? ["open"]);
28928
28962
  const issues = (await options.issueStore.list()).filter((issue) => statuses.has(issue.status));
28929
28963
  const receipts = [];
@@ -28949,6 +28983,7 @@ var deliverVoiceMonitorIssueNotifications = async (options) => {
28949
28983
  const skipped = allReceipts.filter((receipt) => receipt.status === "skipped").length;
28950
28984
  return {
28951
28985
  checkedAt,
28986
+ elapsedMs: Math.max(0, Date.now() - startedAt),
28952
28987
  receipts: allReceipts,
28953
28988
  status: failed > 0 ? "fail" : allReceipts.length === 0 ? "warn" : "pass",
28954
28989
  summary: {
@@ -32945,6 +32980,7 @@ export {
32945
32980
  createVoiceTaskCreatedEvent,
32946
32981
  createVoiceTTSProviderRouter,
32947
32982
  createVoiceSloThresholdProfile,
32983
+ createVoiceSloReadinessThresholdOptions,
32948
32984
  createVoiceSloCalibrationRoutes,
32949
32985
  createVoiceSimulationSuiteRoutes,
32950
32986
  createVoiceSessionsJSONHandler,
@@ -181,11 +181,13 @@ export type VoiceProductionReadinessReport = {
181
181
  };
182
182
  monitoring?: {
183
183
  criticalOpen: number;
184
+ elapsedMs?: number;
184
185
  open: number;
185
186
  status: VoiceProductionReadinessStatus;
186
187
  total: number;
187
188
  };
188
189
  monitoringNotifierDelivery?: {
190
+ elapsedMs?: number;
189
191
  failed: number;
190
192
  notifiers: number;
191
193
  sent: number;
@@ -259,6 +261,7 @@ export type VoiceProductionReadinessReport = {
259
261
  reconnectContracts?: {
260
262
  failed: number;
261
263
  passed: number;
264
+ resumeLatencyP95Ms?: number;
262
265
  status: VoiceProductionReadinessStatus;
263
266
  total: number;
264
267
  };
@@ -482,6 +485,9 @@ export type VoiceProductionReadinessRoutesOptions = {
482
485
  liveLatencyWarnAfterMs?: number;
483
486
  liveLatencyFailAfterMs?: number;
484
487
  liveLatencyMaxAgeMs?: number;
488
+ monitoringRunFailAfterMs?: number;
489
+ monitoringNotifierDeliveryFailAfterMs?: number;
490
+ reconnectResumeFailAfterMs?: number;
485
491
  };
486
492
  export declare const summarizeVoiceProductionReadinessGate: (report: VoiceProductionReadinessReport, options?: VoiceProductionReadinessGateOptions) => VoiceProductionReadinessGateReport;
487
493
  export declare const evaluateVoiceProductionReadinessEvidence: (report: VoiceProductionReadinessReport, input?: VoiceProductionReadinessAssertionInput) => VoiceProductionReadinessAssertionReport;
@@ -15,6 +15,7 @@ export type VoiceReconnectContractReport = {
15
15
  checkedAt: number;
16
16
  issues: VoiceReconnectContractIssue[];
17
17
  pass: boolean;
18
+ resumeLatencyP95Ms?: number;
18
19
  snapshotCount: number;
19
20
  statuses: VoiceReconnectClientState['status'][];
20
21
  summary: {
@@ -1,5 +1,6 @@
1
1
  import { Elysia } from 'elysia';
2
2
  import type { VoiceProviderSloThresholdConfig } from './providerSlo';
3
+ import type { VoiceProductionReadinessRoutesOptions } from './productionReadiness';
3
4
  import type { VoiceProofTrendReport } from './proofTrends';
4
5
  export type VoiceSloCalibrationStatus = 'fail' | 'pass' | 'warn';
5
6
  export type VoiceSloCalibrationMetricKey = 'interruption' | 'liveLatency' | 'monitorRun' | 'notifierDelivery' | 'provider' | 'reconnect' | 'turnLatency';
@@ -68,6 +69,7 @@ export type VoiceSloThresholdProfile = {
68
69
  };
69
70
  status: VoiceSloCalibrationStatus;
70
71
  };
72
+ export type VoiceSloReadinessThresholdOptions = Pick<VoiceProductionReadinessRoutesOptions, 'liveLatencyFailAfterMs' | 'liveLatencyWarnAfterMs' | 'monitoringNotifierDeliveryFailAfterMs' | 'monitoringRunFailAfterMs' | 'reconnectResumeFailAfterMs'>;
71
73
  export type VoiceSloCalibrationOptions = {
72
74
  headroomMultiplier?: number;
73
75
  liveLatencyMinimumMs?: number;
@@ -91,6 +93,7 @@ export type VoiceSloCalibrationRoutesOptions = VoiceSloCalibrationOptions & {
91
93
  export declare const buildVoiceSloCalibrationReport: (input: Array<VoiceProofTrendReport | VoiceSloCalibrationSample>, options?: VoiceSloCalibrationOptions) => VoiceSloCalibrationReport;
92
94
  export declare const assertVoiceSloCalibration: (input: Array<VoiceProofTrendReport | VoiceSloCalibrationSample>, options?: VoiceSloCalibrationOptions) => VoiceSloCalibrationReport;
93
95
  export declare const createVoiceSloThresholdProfile: (input: VoiceSloCalibrationReport | Array<VoiceProofTrendReport | VoiceSloCalibrationSample>, options?: VoiceSloCalibrationOptions) => VoiceSloThresholdProfile;
96
+ export declare const createVoiceSloReadinessThresholdOptions: (input: VoiceSloCalibrationReport | VoiceSloThresholdProfile | Array<VoiceProofTrendReport | VoiceSloCalibrationSample>, options?: VoiceSloCalibrationOptions) => VoiceSloReadinessThresholdOptions;
94
97
  export declare const renderVoiceSloCalibrationMarkdown: (report: VoiceSloCalibrationReport, options?: {
95
98
  title?: string;
96
99
  }) => string;
@@ -83,6 +83,7 @@ export type VoiceMonitorNotifierDeliveryReceiptStore = {
83
83
  };
84
84
  export type VoiceMonitorNotifierDeliveryReport = {
85
85
  checkedAt: number;
86
+ elapsedMs: number;
86
87
  receipts: VoiceMonitorNotifierDeliveryReceipt[];
87
88
  status: VoiceMonitorStatus;
88
89
  summary: {
@@ -95,6 +96,7 @@ export type VoiceMonitorNotifierDeliveryReport = {
95
96
  };
96
97
  export type VoiceMonitorRunReport = {
97
98
  checkedAt: number;
99
+ elapsedMs: number;
98
100
  issues: VoiceMonitorIssue[];
99
101
  runs: VoiceMonitorRun[];
100
102
  status: VoiceMonitorStatus;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.285",
3
+ "version": "0.0.22-beta.287",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",