@absolutejs/voice 0.0.22-beta.285 → 0.0.22-beta.286
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.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
|
|
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 =
|
|
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));
|
|
@@ -17030,7 +17044,7 @@ var createVoiceTurnLatencyRoutes = (options) => {
|
|
|
17030
17044
|
// src/liveLatency.ts
|
|
17031
17045
|
import { Elysia as Elysia27 } from "elysia";
|
|
17032
17046
|
var escapeHtml26 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
17033
|
-
var
|
|
17047
|
+
var percentile3 = (values, percentileValue) => {
|
|
17034
17048
|
if (values.length === 0) {
|
|
17035
17049
|
return;
|
|
17036
17050
|
}
|
|
@@ -17066,8 +17080,8 @@ var summarizeVoiceLiveLatency = async (options) => {
|
|
|
17066
17080
|
averageLatencyMs: latencies.length > 0 ? Math.round(latencies.reduce((total, value) => total + value, 0) / latencies.length) : undefined,
|
|
17067
17081
|
checkedAt: Date.now(),
|
|
17068
17082
|
failed,
|
|
17069
|
-
p50LatencyMs:
|
|
17070
|
-
p95LatencyMs:
|
|
17083
|
+
p50LatencyMs: percentile3(latencies, 50),
|
|
17084
|
+
p95LatencyMs: percentile3(latencies, 95),
|
|
17071
17085
|
recent,
|
|
17072
17086
|
status: latencies.length === 0 ? "empty" : failed > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
|
|
17073
17087
|
total: latencies.length,
|
|
@@ -17143,7 +17157,7 @@ var TRACE_TYPES = [
|
|
|
17143
17157
|
];
|
|
17144
17158
|
var getNumber6 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
17145
17159
|
var getString12 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
17146
|
-
var
|
|
17160
|
+
var percentile4 = (values, percentileValue) => {
|
|
17147
17161
|
if (values.length === 0) {
|
|
17148
17162
|
return;
|
|
17149
17163
|
}
|
|
@@ -17351,8 +17365,8 @@ var summarizeStage = (stage, measurements, options) => {
|
|
|
17351
17365
|
label: STAGE_LABELS[stage],
|
|
17352
17366
|
maxMs: latencies.length > 0 ? Math.max(...latencies) : undefined,
|
|
17353
17367
|
measurements: stageMeasurements,
|
|
17354
|
-
p50Ms:
|
|
17355
|
-
p95Ms:
|
|
17368
|
+
p50Ms: percentile4(latencies, 50),
|
|
17369
|
+
p95Ms: percentile4(latencies, 95),
|
|
17356
17370
|
stage,
|
|
17357
17371
|
status: stageMeasurements.length === 0 ? "empty" : failed > 0 ? "fail" : warnings > 0 ? "warn" : "pass",
|
|
17358
17372
|
total: stageMeasurements.length,
|
|
@@ -23790,7 +23804,7 @@ var rate3 = (count, total) => count / Math.max(1, total);
|
|
|
23790
23804
|
var uniqueSorted5 = (values) => [
|
|
23791
23805
|
...new Set(values.filter((value) => typeof value === "string"))
|
|
23792
23806
|
].sort();
|
|
23793
|
-
var
|
|
23807
|
+
var percentile5 = (values, rank) => {
|
|
23794
23808
|
if (values.length === 0) {
|
|
23795
23809
|
return 0;
|
|
23796
23810
|
}
|
|
@@ -23848,7 +23862,7 @@ var summarizeKind = (kind, events, thresholds, required) => {
|
|
|
23848
23862
|
unit: "rate"
|
|
23849
23863
|
}),
|
|
23850
23864
|
p95ElapsedMs: createMetric2({
|
|
23851
|
-
actual:
|
|
23865
|
+
actual: percentile5(latencies, 95),
|
|
23852
23866
|
label: "P95 latency",
|
|
23853
23867
|
threshold: thresholds.maxP95ElapsedMs,
|
|
23854
23868
|
unit: "ms"
|
|
@@ -28166,15 +28180,17 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
28166
28180
|
} : undefined;
|
|
28167
28181
|
const monitoringSummary = monitoring ? {
|
|
28168
28182
|
criticalOpen: monitoring.summary.criticalOpen,
|
|
28183
|
+
elapsedMs: monitoring.elapsedMs,
|
|
28169
28184
|
open: monitoring.summary.open,
|
|
28170
|
-
status: monitoring.status,
|
|
28185
|
+
status: options.monitoringRunFailAfterMs !== undefined && monitoring.elapsedMs > options.monitoringRunFailAfterMs ? "fail" : monitoring.status,
|
|
28171
28186
|
total: monitoring.summary.total
|
|
28172
28187
|
} : undefined;
|
|
28173
28188
|
const monitoringNotifierDeliverySummary = monitoringNotifierDelivery ? {
|
|
28189
|
+
elapsedMs: monitoringNotifierDelivery.elapsedMs,
|
|
28174
28190
|
failed: monitoringNotifierDelivery.summary.failed,
|
|
28175
28191
|
notifiers: monitoringNotifierDelivery.summary.notifiers,
|
|
28176
28192
|
sent: monitoringNotifierDelivery.summary.sent,
|
|
28177
|
-
status: monitoringNotifierDelivery.status,
|
|
28193
|
+
status: options.monitoringNotifierDeliveryFailAfterMs !== undefined && monitoringNotifierDelivery.elapsedMs > options.monitoringNotifierDeliveryFailAfterMs ? "fail" : monitoringNotifierDelivery.status,
|
|
28178
28194
|
total: monitoringNotifierDelivery.summary.total
|
|
28179
28195
|
} : undefined;
|
|
28180
28196
|
const telephonyWebhookSecuritySummary = telephonyWebhookSecurity ? {
|
|
@@ -28184,12 +28200,17 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
28184
28200
|
status: telephonyWebhookSecurity.status,
|
|
28185
28201
|
warned: telephonyWebhookSecurity.summary.warned
|
|
28186
28202
|
} : undefined;
|
|
28187
|
-
const reconnectContractSummary = reconnectContracts ? {
|
|
28188
|
-
|
|
28189
|
-
|
|
28190
|
-
|
|
28191
|
-
|
|
28192
|
-
|
|
28203
|
+
const reconnectContractSummary = reconnectContracts ? (() => {
|
|
28204
|
+
const failedReports = reconnectContracts.filter((report) => !report.pass || options.reconnectResumeFailAfterMs !== undefined && report.resumeLatencyP95Ms !== undefined && report.resumeLatencyP95Ms > options.reconnectResumeFailAfterMs);
|
|
28205
|
+
const resumeLatencies = reconnectContracts.map((report) => report.resumeLatencyP95Ms).filter((value) => typeof value === "number");
|
|
28206
|
+
return {
|
|
28207
|
+
failed: failedReports.length,
|
|
28208
|
+
passed: reconnectContracts.length - failedReports.length,
|
|
28209
|
+
resumeLatencyP95Ms: resumeLatencies.length > 0 ? Math.max(...resumeLatencies) : undefined,
|
|
28210
|
+
status: failedReports.length > 0 ? "fail" : reconnectContracts.length === 0 ? "warn" : "pass",
|
|
28211
|
+
total: reconnectContracts.length
|
|
28212
|
+
};
|
|
28213
|
+
})() : undefined;
|
|
28193
28214
|
const bargeInSummary = bargeInReports ? {
|
|
28194
28215
|
failed: bargeInReports.reduce((total, report) => total + report.failed, 0),
|
|
28195
28216
|
passed: bargeInReports.reduce((total, report) => total + report.passed, 0),
|
|
@@ -28406,7 +28427,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
28406
28427
|
}
|
|
28407
28428
|
if (reconnectContractSummary) {
|
|
28408
28429
|
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.`,
|
|
28430
|
+
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
28431
|
href: options.links?.reconnectContracts ?? options.links?.sessions ?? "/sessions",
|
|
28411
28432
|
label: "Reconnect recovery contracts",
|
|
28412
28433
|
proofSource: proofSource("reconnectContracts", "reconnect"),
|
|
@@ -28575,7 +28596,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
28575
28596
|
}
|
|
28576
28597
|
if (monitoring && monitoringSummary) {
|
|
28577
28598
|
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.`,
|
|
28599
|
+
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
28600
|
href: options.links?.monitoring ?? "/voice/monitors",
|
|
28580
28601
|
label: "Monitoring issues",
|
|
28581
28602
|
status: monitoringSummary.status,
|
|
@@ -28591,7 +28612,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
28591
28612
|
}
|
|
28592
28613
|
if (monitoringNotifierDelivery && monitoringNotifierDeliverySummary) {
|
|
28593
28614
|
checks.push({
|
|
28594
|
-
detail: monitoringNotifierDeliverySummary.status === "pass" ? `${monitoringNotifierDeliverySummary.sent} monitor notification(s) delivered.` : `${monitoringNotifierDeliverySummary.failed} monitor notification delivery failure(s).`,
|
|
28615
|
+
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
28616
|
href: options.links?.monitoringNotifierDelivery ?? "/api/voice/monitor-issues/notifications",
|
|
28596
28617
|
label: "Monitor notifier delivery",
|
|
28597
28618
|
status: monitoringNotifierDeliverySummary.status,
|
|
@@ -28823,7 +28844,8 @@ var createVoiceMemoryMonitorNotifierDeliveryReceiptStore = (initial = []) => {
|
|
|
28823
28844
|
};
|
|
28824
28845
|
};
|
|
28825
28846
|
var buildVoiceMonitorRunReport = async (options) => {
|
|
28826
|
-
const
|
|
28847
|
+
const startedAt = Date.now();
|
|
28848
|
+
const checkedAt = options.now ?? startedAt;
|
|
28827
28849
|
const runs = await Promise.all(options.monitors.map(async (monitor) => {
|
|
28828
28850
|
const evaluation = await monitor.evaluate({
|
|
28829
28851
|
evidence: options.evidence,
|
|
@@ -28863,6 +28885,7 @@ var buildVoiceMonitorRunReport = async (options) => {
|
|
|
28863
28885
|
const criticalOpen = openIssues.filter((issue) => issue.severity === "critical").length;
|
|
28864
28886
|
return {
|
|
28865
28887
|
checkedAt,
|
|
28888
|
+
elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
28866
28889
|
issues,
|
|
28867
28890
|
runs,
|
|
28868
28891
|
status: criticalOpen > 0 ? "fail" : openIssues.length > 0 || rollupStatus4(runs) === "warn" ? "warn" : rollupStatus4(runs),
|
|
@@ -28923,7 +28946,8 @@ var createVoiceMonitorWebhookNotifier = (options) => ({
|
|
|
28923
28946
|
}
|
|
28924
28947
|
});
|
|
28925
28948
|
var deliverVoiceMonitorIssueNotifications = async (options) => {
|
|
28926
|
-
const
|
|
28949
|
+
const startedAt = Date.now();
|
|
28950
|
+
const checkedAt = options.now ?? startedAt;
|
|
28927
28951
|
const statuses = new Set(options.statuses ?? ["open"]);
|
|
28928
28952
|
const issues = (await options.issueStore.list()).filter((issue) => statuses.has(issue.status));
|
|
28929
28953
|
const receipts = [];
|
|
@@ -28949,6 +28973,7 @@ var deliverVoiceMonitorIssueNotifications = async (options) => {
|
|
|
28949
28973
|
const skipped = allReceipts.filter((receipt) => receipt.status === "skipped").length;
|
|
28950
28974
|
return {
|
|
28951
28975
|
checkedAt,
|
|
28976
|
+
elapsedMs: Math.max(0, Date.now() - startedAt),
|
|
28952
28977
|
receipts: allReceipts,
|
|
28953
28978
|
status: failed > 0 ? "fail" : allReceipts.length === 0 ? "warn" : "pass",
|
|
28954
28979
|
summary: {
|
|
@@ -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;
|
|
@@ -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;
|