@absolutejs/voice 0.0.22-beta.393 → 0.0.22-beta.395
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 +4 -0
- package/dist/index.js +260 -51
- package/dist/proofAssertions.d.ts +32 -0
- package/dist/proofRunner.d.ts +43 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,10 @@ export { assertVoiceCompetitiveCoverage, buildVoiceCompetitiveCoverageReport, cr
|
|
|
31
31
|
export type { VoiceCompetitiveCoverageAssertionInput, VoiceCompetitiveCoverageAssertionReport, VoiceCompetitiveCoverageIssue, VoiceCompetitiveCoverageLevel, VoiceCompetitiveCoverageReport, VoiceCompetitiveCoverageReportInput, VoiceCompetitiveCoverageRoutesOptions, VoiceCompetitiveCoverageStatus, VoiceCompetitiveCoverageSummary, VoiceCompetitiveDepthLevel, VoiceCompetitiveEvidence, VoiceCompetitiveSurface } from './competitiveCoverage';
|
|
32
32
|
export type { VoicePlatformCoverageAssertionInput, VoicePlatformCoverageAssertionReport, VoicePlatformCoverageEvidence, VoicePlatformCoverageRoutesOptions, VoicePlatformCoverageStatus, VoicePlatformCoverageSummary, VoicePlatformCoverageSummaryInput, VoicePlatformCoverageSurface } from './platformCoverage';
|
|
33
33
|
export { assertVoiceProofTrendEvidence, appendVoiceRealCallProfileRecoveryEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendProfileSummaries, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReportFromRealCallProfiles, buildVoiceProofTrendReport, buildVoiceRealCallProfileEvidenceFromTraceEvents, buildVoiceRealCallProfileDefaults, buildVoiceRealCallProfileHistoryReport, buildVoiceRealCallProfileReadinessCheck, buildVoiceRealCallProfileRecoveryJobHistoryCheck, buildVoiceRealCallProfileRecoveryActions, createVoiceInMemoryRealCallProfileRecoveryJobStore, createVoiceRealCallProfileTraceCollector, createVoiceSQLiteRealCallProfileRecoveryJobStore, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, createVoiceRealCallProfileHistoryRoutes, createVoiceRealCallProfileRecoveryActionRoutes, DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, loadVoiceRealCallProfileEvidenceFromTraceStore, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown, renderVoiceRealCallProfileHistoryHTML, renderVoiceRealCallProfileHistoryMarkdown, runVoiceRealCallProfileRecoveryLoop, resolveVoiceRealCallProfileProviderRoute } from './proofTrends';
|
|
34
|
+
export { createVoiceEvidenceAssertion, createVoiceProofAssertion, summarizeVoiceProofAssertions } from './proofAssertions';
|
|
35
|
+
export type { VoiceEvidenceAssertionInput, VoiceProofAssertionInput, VoiceProofAssertionResult, VoiceProofAssertionSummary } from './proofAssertions';
|
|
36
|
+
export { fetchVoiceProofTarget, getVoiceProofTargetLogicalFailure, mapVoiceProofTargetsWithConcurrency, runVoiceProofTargets } from './proofRunner';
|
|
37
|
+
export type { VoiceProofTarget, VoiceProofTargetMethod, VoiceProofTargetResult, VoiceProofTargetRunnerOptions, VoiceProofTargetRunOptions } from './proofRunner';
|
|
34
38
|
export { applyVoiceProfileSwitchGuard, buildVoiceProfileSwitchReadinessReport, buildVoiceProfileSwitchLiveDecisionReport, createVoiceProfileSwitchLiveDecisionRoutes, createVoiceProfileSwitchPolicyProofRoutes, createVoiceProfileSwitchReadinessRoutes, recommendVoiceProfileSwitch, renderVoiceProfileSwitchLiveDecisionHTML, renderVoiceProfileSwitchPolicyProofHTML, renderVoiceProfileSwitchReadinessHTML, runVoiceProfileSwitchPolicyProof } from './profileSwitchRecommendation';
|
|
35
39
|
export type { VoiceProfileSwitchGuardAction, VoiceProfileSwitchGuardDecision, VoiceProfileSwitchGuardMode, VoiceProfileSwitchGuardOptions, VoiceProfileSwitchObservedSignals, VoiceProfileSwitchLiveDecisionEvidence, VoiceProfileSwitchLiveDecisionReport, VoiceProfileSwitchLiveDecisionReportOptions, VoiceProfileSwitchLiveDecisionRoutesOptions, VoiceProfileSwitchLiveDecisionSession, VoiceProfileSwitchPolicyProofCase, VoiceProfileSwitchPolicyProofCaseResult, VoiceProfileSwitchPolicyProofOptions, VoiceProfileSwitchPolicyProofReport, VoiceProfileSwitchPolicyProofRoutesOptions, VoiceProfileSwitchReadinessIssue, VoiceProfileSwitchReadinessOptions, VoiceProfileSwitchReadinessReport, VoiceProfileSwitchReadinessRoutesOptions, VoiceProfileSwitchReadinessStatus, VoiceProfileSwitchRecommendation, VoiceProfileSwitchRecommendationOptions } from './profileSwitchRecommendation';
|
|
36
40
|
export { buildVoiceProviderDecisionTraceReport, createVoiceProviderDecisionTraceEvent, createVoiceProviderDecisionTraceRoutes, listVoiceProviderDecisionTraces, renderVoiceProviderDecisionTraceHTML, renderVoiceProviderDecisionTraceMarkdown } from './providerDecisionTraces';
|
package/dist/index.js
CHANGED
|
@@ -18347,6 +18347,208 @@ var formatVoiceProofTrendAge = (ageMs) => {
|
|
|
18347
18347
|
const days = Math.floor(hours / 24);
|
|
18348
18348
|
return `${days}d ${hours % 24}h`;
|
|
18349
18349
|
};
|
|
18350
|
+
// src/proofAssertions.ts
|
|
18351
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18352
|
+
var createVoiceProofAssertion = (input) => ({
|
|
18353
|
+
kind: "json-assertion",
|
|
18354
|
+
name: input.name,
|
|
18355
|
+
ok: input.ok === true,
|
|
18356
|
+
summary: input.summary ?? (input.ok === true ? undefined : {
|
|
18357
|
+
issues: [input.missingIssue ?? `${input.name} proof is missing.`]
|
|
18358
|
+
})
|
|
18359
|
+
});
|
|
18360
|
+
var createVoiceEvidenceAssertion = (input) => {
|
|
18361
|
+
if (input.evidence === undefined) {
|
|
18362
|
+
return createVoiceProofAssertion({
|
|
18363
|
+
missingIssue: input.missingIssue,
|
|
18364
|
+
name: input.name,
|
|
18365
|
+
ok: false
|
|
18366
|
+
});
|
|
18367
|
+
}
|
|
18368
|
+
return {
|
|
18369
|
+
kind: "json-assertion",
|
|
18370
|
+
name: input.name,
|
|
18371
|
+
ok: input.ok?.(input.evidence) ?? (isRecord(input.evidence) && input.evidence.ok === true),
|
|
18372
|
+
summary: input.summary?.(input.evidence) ?? (isRecord(input.evidence) ? input.evidence : undefined)
|
|
18373
|
+
};
|
|
18374
|
+
};
|
|
18375
|
+
var summarizeVoiceProofAssertions = (assertions) => {
|
|
18376
|
+
const failures = assertions.filter((assertion) => !assertion.ok).map((assertion) => ({
|
|
18377
|
+
name: assertion.name,
|
|
18378
|
+
summary: assertion.summary
|
|
18379
|
+
}));
|
|
18380
|
+
return {
|
|
18381
|
+
failed: failures.length,
|
|
18382
|
+
failures,
|
|
18383
|
+
ok: failures.length === 0,
|
|
18384
|
+
passed: assertions.length - failures.length,
|
|
18385
|
+
total: assertions.length
|
|
18386
|
+
};
|
|
18387
|
+
};
|
|
18388
|
+
// src/proofRunner.ts
|
|
18389
|
+
var encoder = new TextEncoder;
|
|
18390
|
+
var trimBaseUrl = (baseUrl) => baseUrl.replace(/\/$/, "");
|
|
18391
|
+
var safeArtifactName = (name) => name.replace(/[^a-z0-9_.-]/gi, "-");
|
|
18392
|
+
var summarizeValue = (value) => {
|
|
18393
|
+
if (Array.isArray(value)) {
|
|
18394
|
+
return { count: value.length };
|
|
18395
|
+
}
|
|
18396
|
+
if (!value || typeof value !== "object") {
|
|
18397
|
+
return value;
|
|
18398
|
+
}
|
|
18399
|
+
const record = value;
|
|
18400
|
+
const preferredKeys = [
|
|
18401
|
+
"status",
|
|
18402
|
+
"ok",
|
|
18403
|
+
"pass",
|
|
18404
|
+
"ready",
|
|
18405
|
+
"proof",
|
|
18406
|
+
"total",
|
|
18407
|
+
"passed",
|
|
18408
|
+
"failed",
|
|
18409
|
+
"issues",
|
|
18410
|
+
"summary",
|
|
18411
|
+
"links",
|
|
18412
|
+
"actions",
|
|
18413
|
+
"checks",
|
|
18414
|
+
"campaigns",
|
|
18415
|
+
"recipients",
|
|
18416
|
+
"attempts",
|
|
18417
|
+
"telephonyMedia",
|
|
18418
|
+
"operationsRecordHref",
|
|
18419
|
+
"sentEvents",
|
|
18420
|
+
"tasks",
|
|
18421
|
+
"reviews",
|
|
18422
|
+
"events",
|
|
18423
|
+
"eventsWithLatency",
|
|
18424
|
+
"observabilityExportReplay",
|
|
18425
|
+
"validationIssues",
|
|
18426
|
+
"deliveryDestinations",
|
|
18427
|
+
"failedDeliveryDestinations",
|
|
18428
|
+
"failedArtifacts",
|
|
18429
|
+
"artifacts",
|
|
18430
|
+
"kinds",
|
|
18431
|
+
"redaction",
|
|
18432
|
+
"retentionPlan",
|
|
18433
|
+
"zeroRetentionAvailable"
|
|
18434
|
+
];
|
|
18435
|
+
const summary = {};
|
|
18436
|
+
for (const key of preferredKeys) {
|
|
18437
|
+
if (key in record) {
|
|
18438
|
+
summary[key] = summarizeValue(record[key]);
|
|
18439
|
+
}
|
|
18440
|
+
}
|
|
18441
|
+
return Object.keys(summary).length > 0 ? summary : {
|
|
18442
|
+
keys: Object.keys(record).slice(0, 12)
|
|
18443
|
+
};
|
|
18444
|
+
};
|
|
18445
|
+
var getVoiceProofTargetLogicalFailure = (value) => {
|
|
18446
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
18447
|
+
return;
|
|
18448
|
+
}
|
|
18449
|
+
const record = value;
|
|
18450
|
+
if (record.status === "fail") {
|
|
18451
|
+
return 'Response status is "fail".';
|
|
18452
|
+
}
|
|
18453
|
+
if (record.pass === false) {
|
|
18454
|
+
return "Response pass is false.";
|
|
18455
|
+
}
|
|
18456
|
+
if (record.ok === false) {
|
|
18457
|
+
return "Response ok is false.";
|
|
18458
|
+
}
|
|
18459
|
+
return;
|
|
18460
|
+
};
|
|
18461
|
+
var mapVoiceProofTargetsWithConcurrency = async (items, limit, mapper) => {
|
|
18462
|
+
const results = new Array(items.length);
|
|
18463
|
+
let nextIndex = 0;
|
|
18464
|
+
const workerCount = Math.min(Math.max(1, limit), items.length);
|
|
18465
|
+
const workers = Array.from({ length: workerCount }, async () => {
|
|
18466
|
+
while (nextIndex < items.length) {
|
|
18467
|
+
const index = nextIndex;
|
|
18468
|
+
nextIndex += 1;
|
|
18469
|
+
const item = items[index];
|
|
18470
|
+
if (item !== undefined) {
|
|
18471
|
+
results[index] = await mapper(item);
|
|
18472
|
+
}
|
|
18473
|
+
}
|
|
18474
|
+
});
|
|
18475
|
+
await Promise.all(workers);
|
|
18476
|
+
return results;
|
|
18477
|
+
};
|
|
18478
|
+
var fetchVoiceProofTarget = async (target, options) => {
|
|
18479
|
+
const method = target.method ?? "GET";
|
|
18480
|
+
const baseUrl = trimBaseUrl(options.baseUrl);
|
|
18481
|
+
const url = `${baseUrl}${target.path}`;
|
|
18482
|
+
const fetcher = options.fetch ?? globalThis.fetch;
|
|
18483
|
+
const now = options.now ?? performance.now.bind(performance);
|
|
18484
|
+
const startedAt = now();
|
|
18485
|
+
const controller = new AbortController;
|
|
18486
|
+
const timeout = options.timeoutMs && options.timeoutMs > 0 ? setTimeout(() => controller.abort(), options.timeoutMs) : undefined;
|
|
18487
|
+
try {
|
|
18488
|
+
const response = await fetcher(url, {
|
|
18489
|
+
body: target.body === undefined ? undefined : JSON.stringify(target.body),
|
|
18490
|
+
headers: {
|
|
18491
|
+
accept: target.accept ?? (target.kind === "json" ? "application/json" : "text/markdown,text/plain,*/*"),
|
|
18492
|
+
...target.body === undefined ? {} : { "content-type": "application/json" }
|
|
18493
|
+
},
|
|
18494
|
+
method,
|
|
18495
|
+
signal: controller.signal
|
|
18496
|
+
});
|
|
18497
|
+
const text = await response.text();
|
|
18498
|
+
const bytes = encoder.encode(text).byteLength;
|
|
18499
|
+
let body = text;
|
|
18500
|
+
let parseError;
|
|
18501
|
+
if (target.kind === "json" && text.trim()) {
|
|
18502
|
+
try {
|
|
18503
|
+
body = JSON.parse(text);
|
|
18504
|
+
} catch (error) {
|
|
18505
|
+
parseError = error instanceof Error ? error.message : String(error);
|
|
18506
|
+
}
|
|
18507
|
+
}
|
|
18508
|
+
const missingText = target.kind === "text" ? (target.requiredText ?? []).filter((item) => !text.includes(item)) : [];
|
|
18509
|
+
const logicalFailure = target.kind === "json" && !parseError && !target.allowLogicalFail ? getVoiceProofTargetLogicalFailure(body) : undefined;
|
|
18510
|
+
await options.writeArtifact?.({
|
|
18511
|
+
content: target.kind === "json" ? `${JSON.stringify(parseError ? { parseError, text } : body, null, 2)}
|
|
18512
|
+
` : text,
|
|
18513
|
+
name: `${safeArtifactName(target.name)}.${target.kind === "json" ? "json" : "md"}`,
|
|
18514
|
+
target
|
|
18515
|
+
});
|
|
18516
|
+
return {
|
|
18517
|
+
body,
|
|
18518
|
+
bytes,
|
|
18519
|
+
elapsedMs: Math.round(now() - startedAt),
|
|
18520
|
+
error: parseError ?? logicalFailure ?? (missingText.length > 0 ? `Missing required text: ${missingText.join(", ")}` : undefined),
|
|
18521
|
+
kind: target.kind,
|
|
18522
|
+
method,
|
|
18523
|
+
name: target.name,
|
|
18524
|
+
ok: response.ok && !parseError && !logicalFailure && missingText.length === 0,
|
|
18525
|
+
path: target.path,
|
|
18526
|
+
status: response.status,
|
|
18527
|
+
summary: parseError ? { bytes, parseError } : target.kind === "json" ? summarizeValue(body) : {
|
|
18528
|
+
bytes,
|
|
18529
|
+
requiredTextFound: missingText.length === 0
|
|
18530
|
+
},
|
|
18531
|
+
url
|
|
18532
|
+
};
|
|
18533
|
+
} catch (error) {
|
|
18534
|
+
return {
|
|
18535
|
+
bytes: 0,
|
|
18536
|
+
elapsedMs: Math.round(now() - startedAt),
|
|
18537
|
+
error: error instanceof Error ? error.message : String(error),
|
|
18538
|
+
kind: target.kind,
|
|
18539
|
+
method,
|
|
18540
|
+
name: target.name,
|
|
18541
|
+
ok: false,
|
|
18542
|
+
path: target.path,
|
|
18543
|
+
url
|
|
18544
|
+
};
|
|
18545
|
+
} finally {
|
|
18546
|
+
if (timeout) {
|
|
18547
|
+
clearTimeout(timeout);
|
|
18548
|
+
}
|
|
18549
|
+
}
|
|
18550
|
+
};
|
|
18551
|
+
var runVoiceProofTargets = (targets, options) => mapVoiceProofTargetsWithConcurrency(targets, options.concurrency ?? 2, (target) => fetchVoiceProofTarget(target, options));
|
|
18350
18552
|
// src/providerRouterTraces.ts
|
|
18351
18553
|
var buildVoiceProviderRouterTraceEvent = (options) => ({
|
|
18352
18554
|
at: options.at ?? options.event.at,
|
|
@@ -23472,7 +23674,7 @@ var DEFAULT_MACHINE_VOICEMAIL_VALUES = [
|
|
|
23472
23674
|
"voicemail"
|
|
23473
23675
|
];
|
|
23474
23676
|
var DEFAULT_NO_ANSWER_SIP_CODES = [408, 480, 486, 487, 603];
|
|
23475
|
-
var
|
|
23677
|
+
var isRecord2 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
23476
23678
|
var uniqueSorted4 = (values) => Array.from(new Set(values)).sort();
|
|
23477
23679
|
var findMissing3 = (values, required) => {
|
|
23478
23680
|
if (!required?.length) {
|
|
@@ -23514,9 +23716,9 @@ var evaluateVoiceTelephonyWebhookNormalizationEvidence = (input = {}) => {
|
|
|
23514
23716
|
const duplicateDecisions = decisions.filter((decision) => decision.duplicate === true);
|
|
23515
23717
|
const duplicateProviders = uniqueSorted4(duplicateDecisions.map((decision) => decision.provider ?? decision.event?.provider).filter(isTelephonyWebhookProvider));
|
|
23516
23718
|
const duplicateIdempotencyKeys = new Set(duplicateDecisions.map((decision) => decision.idempotencyKey).filter((key) => typeof key === "string" && key.length > 0)).size;
|
|
23517
|
-
const duplicateCampaignOutcomesApplied = duplicateDecisions.filter((decision) =>
|
|
23518
|
-
const duplicateOutcomeReasons = uniqueSorted4(duplicateDecisions.map((decision) =>
|
|
23519
|
-
const routeResults = decisions.filter((decision) =>
|
|
23719
|
+
const duplicateCampaignOutcomesApplied = duplicateDecisions.filter((decision) => isRecord2(decision.campaignOutcome) && decision.campaignOutcome.applied === true).length;
|
|
23720
|
+
const duplicateOutcomeReasons = uniqueSorted4(duplicateDecisions.map((decision) => isRecord2(decision.campaignOutcome) ? decision.campaignOutcome.reason : undefined).filter((reason) => typeof reason === "string"));
|
|
23721
|
+
const routeResults = decisions.filter((decision) => isRecord2(decision.routeResult)).length;
|
|
23520
23722
|
const missingSessionIds = decisions.filter((decision) => !decision.sessionId).length;
|
|
23521
23723
|
const rejectedVerificationAttempts = verificationAttempts.filter((attempt) => attempt.rejected === true || attempt.status === 401 || attempt.verification?.ok === false && attempt.verification.reason === "invalid-signature");
|
|
23522
23724
|
const rejectedVerificationProviders = uniqueSorted4(rejectedVerificationAttempts.map((attempt) => attempt.provider).filter(isTelephonyWebhookProvider));
|
|
@@ -23636,25 +23838,25 @@ var parseMaybeJSON = (value) => {
|
|
|
23636
23838
|
}
|
|
23637
23839
|
};
|
|
23638
23840
|
var flattenPayload = (value) => {
|
|
23639
|
-
if (!
|
|
23841
|
+
if (!isRecord2(value)) {
|
|
23640
23842
|
return {};
|
|
23641
23843
|
}
|
|
23642
|
-
const data =
|
|
23643
|
-
const payload =
|
|
23644
|
-
const event =
|
|
23844
|
+
const data = isRecord2(value.data) ? value.data : undefined;
|
|
23845
|
+
const payload = isRecord2(value.payload) ? value.payload : undefined;
|
|
23846
|
+
const event = isRecord2(value.event) ? value.event : undefined;
|
|
23645
23847
|
return {
|
|
23646
23848
|
...value,
|
|
23647
23849
|
...payload,
|
|
23648
23850
|
...event,
|
|
23649
23851
|
...data,
|
|
23650
|
-
...
|
|
23852
|
+
...isRecord2(data?.payload) ? data.payload : undefined
|
|
23651
23853
|
};
|
|
23652
23854
|
};
|
|
23653
23855
|
var toBase64 = (bytes) => Buffer.from(new Uint8Array(bytes)).toString("base64");
|
|
23654
23856
|
var timingSafeEqual = (left, right) => {
|
|
23655
|
-
const
|
|
23656
|
-
const leftBytes =
|
|
23657
|
-
const rightBytes =
|
|
23857
|
+
const encoder2 = new TextEncoder;
|
|
23858
|
+
const leftBytes = encoder2.encode(left);
|
|
23859
|
+
const rightBytes = encoder2.encode(right);
|
|
23658
23860
|
if (leftBytes.length !== rightBytes.length) {
|
|
23659
23861
|
return false;
|
|
23660
23862
|
}
|
|
@@ -23665,12 +23867,12 @@ var timingSafeEqual = (left, right) => {
|
|
|
23665
23867
|
return diff === 0;
|
|
23666
23868
|
};
|
|
23667
23869
|
var signHmacSHA1Base64 = async (secret, payload) => {
|
|
23668
|
-
const
|
|
23669
|
-
const key = await crypto.subtle.importKey("raw",
|
|
23870
|
+
const encoder2 = new TextEncoder;
|
|
23871
|
+
const key = await crypto.subtle.importKey("raw", encoder2.encode(secret), {
|
|
23670
23872
|
hash: "SHA-1",
|
|
23671
23873
|
name: "HMAC"
|
|
23672
23874
|
}, false, ["sign"]);
|
|
23673
|
-
const signature = await crypto.subtle.sign("HMAC", key,
|
|
23875
|
+
const signature = await crypto.subtle.sign("HMAC", key, encoder2.encode(payload));
|
|
23674
23876
|
return toBase64(signature);
|
|
23675
23877
|
};
|
|
23676
23878
|
var sortedParamsForSignature = (body) => Object.entries(flattenPayload(body)).filter(([, value]) => value !== undefined && value !== null).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key}${String(value)}`).join("");
|
|
@@ -25270,9 +25472,9 @@ var createPlivoMediaStreamBridge = (socket, options) => {
|
|
|
25270
25472
|
};
|
|
25271
25473
|
var toBase642 = (bytes) => Buffer5.from(new Uint8Array(bytes)).toString("base64");
|
|
25272
25474
|
var timingSafeEqual2 = (left, right) => {
|
|
25273
|
-
const
|
|
25274
|
-
const leftBytes =
|
|
25275
|
-
const rightBytes =
|
|
25475
|
+
const encoder2 = new TextEncoder;
|
|
25476
|
+
const leftBytes = encoder2.encode(left);
|
|
25477
|
+
const rightBytes = encoder2.encode(right);
|
|
25276
25478
|
if (leftBytes.length !== rightBytes.length) {
|
|
25277
25479
|
return false;
|
|
25278
25480
|
}
|
|
@@ -25283,12 +25485,12 @@ var timingSafeEqual2 = (left, right) => {
|
|
|
25283
25485
|
return diff === 0;
|
|
25284
25486
|
};
|
|
25285
25487
|
var signHmacSHA256Base64 = async (secret, payload) => {
|
|
25286
|
-
const
|
|
25287
|
-
const key = await crypto.subtle.importKey("raw",
|
|
25488
|
+
const encoder2 = new TextEncoder;
|
|
25489
|
+
const key = await crypto.subtle.importKey("raw", encoder2.encode(secret), {
|
|
25288
25490
|
hash: "SHA-256",
|
|
25289
25491
|
name: "HMAC"
|
|
25290
25492
|
}, false, ["sign"]);
|
|
25291
|
-
const signature = await crypto.subtle.sign("HMAC", key,
|
|
25493
|
+
const signature = await crypto.subtle.sign("HMAC", key, encoder2.encode(payload));
|
|
25292
25494
|
return toBase642(signature);
|
|
25293
25495
|
};
|
|
25294
25496
|
var sortedParamsForSignature2 = (body) => {
|
|
@@ -31552,12 +31754,12 @@ var assertVoiceObservabilityExportSchema = (input) => {
|
|
|
31552
31754
|
throw new Error(`Unsupported voice observability export schema: ${input.schema?.id ?? "missing"}@${input.schema?.version ?? "missing"}`);
|
|
31553
31755
|
}
|
|
31554
31756
|
};
|
|
31555
|
-
var
|
|
31757
|
+
var isRecord3 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
31556
31758
|
var isStatus2 = (value) => value === "fail" || value === "pass" || value === "warn";
|
|
31557
|
-
var getRecord2 = (value, key) =>
|
|
31558
|
-
var getRecordArray = (value, key) =>
|
|
31759
|
+
var getRecord2 = (value, key) => isRecord3(value) && isRecord3(value[key]) ? value[key] : undefined;
|
|
31760
|
+
var getRecordArray = (value, key) => isRecord3(value) && Array.isArray(value[key]) ? value[key] : undefined;
|
|
31559
31761
|
var inferVoiceObservabilityExportRecordKind = (record) => {
|
|
31560
|
-
if (
|
|
31762
|
+
if (isRecord3(record.manifest) && isRecord3(record.artifactIndex)) {
|
|
31561
31763
|
return "database-record";
|
|
31562
31764
|
}
|
|
31563
31765
|
if (Array.isArray(record.receipts)) {
|
|
@@ -31566,10 +31768,10 @@ var inferVoiceObservabilityExportRecordKind = (record) => {
|
|
|
31566
31768
|
if (typeof record.runId === "string" && Array.isArray(record.destinations)) {
|
|
31567
31769
|
return "delivery-receipt";
|
|
31568
31770
|
}
|
|
31569
|
-
if (Array.isArray(record.destinations) &&
|
|
31771
|
+
if (Array.isArray(record.destinations) && isRecord3(record.summary) && typeof record.exportStatus === "string") {
|
|
31570
31772
|
return "delivery-report";
|
|
31571
31773
|
}
|
|
31572
|
-
if (Array.isArray(record.artifacts) &&
|
|
31774
|
+
if (Array.isArray(record.artifacts) && isRecord3(record.summary)) {
|
|
31573
31775
|
return Array.isArray(record.envelopes) ? "manifest" : "artifact-index";
|
|
31574
31776
|
}
|
|
31575
31777
|
return;
|
|
@@ -31635,7 +31837,7 @@ var validateDeliveryDestinations = (issues, destinations, path) => {
|
|
|
31635
31837
|
}
|
|
31636
31838
|
destinations.forEach((destination, index) => {
|
|
31637
31839
|
const destinationPath = `${path}.${index}`;
|
|
31638
|
-
if (!
|
|
31840
|
+
if (!isRecord3(destination)) {
|
|
31639
31841
|
pushValidationIssue(issues, {
|
|
31640
31842
|
code: "voice.observability.export.invalid_shape",
|
|
31641
31843
|
message: `${destinationPath} must be an object.`,
|
|
@@ -31656,7 +31858,7 @@ var validateDeliveryDestinations = (issues, destinations, path) => {
|
|
|
31656
31858
|
};
|
|
31657
31859
|
var validateVoiceObservabilityExportRecord = (input, options = {}) => {
|
|
31658
31860
|
const issues = [];
|
|
31659
|
-
if (!
|
|
31861
|
+
if (!isRecord3(input)) {
|
|
31660
31862
|
return {
|
|
31661
31863
|
issues: [
|
|
31662
31864
|
{
|
|
@@ -31691,21 +31893,21 @@ var validateVoiceObservabilityExportRecord = (input, options = {}) => {
|
|
|
31691
31893
|
requireArrayField(issues, input, "sessionIds", "$");
|
|
31692
31894
|
requireNumberField(issues, input, "checkedAt", "$");
|
|
31693
31895
|
requireStatusField(issues, input, "status", "$");
|
|
31694
|
-
if (!
|
|
31896
|
+
if (!isRecord3(input.deliveries)) {
|
|
31695
31897
|
pushValidationIssue(issues, {
|
|
31696
31898
|
code: "voice.observability.export.missing_field",
|
|
31697
31899
|
message: "$.deliveries must be an object.",
|
|
31698
31900
|
path: "$.deliveries"
|
|
31699
31901
|
});
|
|
31700
31902
|
}
|
|
31701
|
-
if (!
|
|
31903
|
+
if (!isRecord3(input.redaction)) {
|
|
31702
31904
|
pushValidationIssue(issues, {
|
|
31703
31905
|
code: "voice.observability.export.missing_field",
|
|
31704
31906
|
message: "$.redaction must be an object.",
|
|
31705
31907
|
path: "$.redaction"
|
|
31706
31908
|
});
|
|
31707
31909
|
}
|
|
31708
|
-
if (!
|
|
31910
|
+
if (!isRecord3(input.summary)) {
|
|
31709
31911
|
pushValidationIssue(issues, {
|
|
31710
31912
|
code: "voice.observability.export.missing_field",
|
|
31711
31913
|
message: "$.summary must be an object.",
|
|
@@ -31717,7 +31919,7 @@ var validateVoiceObservabilityExportRecord = (input, options = {}) => {
|
|
|
31717
31919
|
requireArrayField(issues, input, "artifacts", "$");
|
|
31718
31920
|
requireNumberField(issues, input, "checkedAt", "$");
|
|
31719
31921
|
requireStatusField(issues, input, "status", "$");
|
|
31720
|
-
if (!
|
|
31922
|
+
if (!isRecord3(input.summary)) {
|
|
31721
31923
|
pushValidationIssue(issues, {
|
|
31722
31924
|
code: "voice.observability.export.missing_field",
|
|
31723
31925
|
message: "$.summary must be an object.",
|
|
@@ -31729,7 +31931,7 @@ var validateVoiceObservabilityExportRecord = (input, options = {}) => {
|
|
|
31729
31931
|
requireNumberField(issues, input, "checkedAt", "$");
|
|
31730
31932
|
requireStatusField(issues, input, "status", "$");
|
|
31731
31933
|
requireStatusField(issues, input, "exportStatus", "$");
|
|
31732
|
-
if (!
|
|
31934
|
+
if (!isRecord3(input.manifest)) {
|
|
31733
31935
|
pushValidationIssue(issues, {
|
|
31734
31936
|
code: "voice.observability.export.missing_field",
|
|
31735
31937
|
message: "$.manifest must be an object.",
|
|
@@ -31743,7 +31945,7 @@ var validateVoiceObservabilityExportRecord = (input, options = {}) => {
|
|
|
31743
31945
|
path: `$.manifest${issue.path.slice(1)}`
|
|
31744
31946
|
})));
|
|
31745
31947
|
}
|
|
31746
|
-
if (!
|
|
31948
|
+
if (!isRecord3(input.artifactIndex)) {
|
|
31747
31949
|
pushValidationIssue(issues, {
|
|
31748
31950
|
code: "voice.observability.export.missing_field",
|
|
31749
31951
|
message: "$.artifactIndex must be an object.",
|
|
@@ -31881,11 +32083,11 @@ var buildObservabilityExportDatabaseRecord = (input) => ({
|
|
|
31881
32083
|
});
|
|
31882
32084
|
var parseObservabilityExportJson = (value) => typeof value === "string" ? JSON.parse(value) : value;
|
|
31883
32085
|
var collectReplayDeliveryDestinations = (value) => {
|
|
31884
|
-
if (!
|
|
32086
|
+
if (!isRecord3(value)) {
|
|
31885
32087
|
return [];
|
|
31886
32088
|
}
|
|
31887
32089
|
if (Array.isArray(value.destinations)) {
|
|
31888
|
-
return value.destinations.filter((destination) =>
|
|
32090
|
+
return value.destinations.filter((destination) => isRecord3(destination));
|
|
31889
32091
|
}
|
|
31890
32092
|
if (Array.isArray(value.receipts)) {
|
|
31891
32093
|
return value.receipts.flatMap((receipt) => collectReplayDeliveryDestinations(receipt));
|
|
@@ -31894,8 +32096,8 @@ var collectReplayDeliveryDestinations = (value) => {
|
|
|
31894
32096
|
};
|
|
31895
32097
|
var replayIssueSeverity = (status) => status === "fail" ? "fail" : "warn";
|
|
31896
32098
|
var buildVoiceObservabilityExportReplayReport = (records) => {
|
|
31897
|
-
const manifest = records.manifest ?? (
|
|
31898
|
-
const artifactIndex = records.artifactIndex ?? (
|
|
32099
|
+
const manifest = records.manifest ?? (isRecord3(records.databaseRecord) ? records.databaseRecord.manifest : undefined);
|
|
32100
|
+
const artifactIndex = records.artifactIndex ?? (isRecord3(records.databaseRecord) ? records.databaseRecord.artifactIndex : undefined);
|
|
31899
32101
|
const validations = {
|
|
31900
32102
|
artifactIndex: validateVoiceObservabilityExportRecord(artifactIndex, {
|
|
31901
32103
|
kind: "artifact-index"
|
|
@@ -31920,12 +32122,12 @@ var buildVoiceObservabilityExportReplayReport = (records) => {
|
|
|
31920
32122
|
kind,
|
|
31921
32123
|
issue
|
|
31922
32124
|
})) ?? []);
|
|
31923
|
-
const manifestRecord =
|
|
31924
|
-
const artifactIndexRecord =
|
|
32125
|
+
const manifestRecord = isRecord3(manifest) ? manifest : undefined;
|
|
32126
|
+
const artifactIndexRecord = isRecord3(artifactIndex) ? artifactIndex : undefined;
|
|
31925
32127
|
const artifacts = [
|
|
31926
32128
|
...Array.isArray(manifestRecord?.artifacts) ? manifestRecord.artifacts : [],
|
|
31927
32129
|
...Array.isArray(artifactIndexRecord?.artifacts) ? artifactIndexRecord.artifacts : []
|
|
31928
|
-
].filter((artifact) =>
|
|
32130
|
+
].filter((artifact) => isRecord3(artifact));
|
|
31929
32131
|
const failedArtifacts = artifacts.filter((artifact) => artifact.status === "fail");
|
|
31930
32132
|
const deliveryDestinations = [
|
|
31931
32133
|
...collectReplayDeliveryDestinations(records.deliveryReport),
|
|
@@ -31934,7 +32136,7 @@ var buildVoiceObservabilityExportReplayReport = (records) => {
|
|
|
31934
32136
|
];
|
|
31935
32137
|
const failedDeliveryDestinations = deliveryDestinations.filter((destination) => destination.status === "failed");
|
|
31936
32138
|
const issues = [
|
|
31937
|
-
...!records.manifest && !
|
|
32139
|
+
...!records.manifest && !isRecord3(records.databaseRecord) ? [
|
|
31938
32140
|
{
|
|
31939
32141
|
code: "voice.observability.export_replay.missing_record",
|
|
31940
32142
|
label: "Export manifest",
|
|
@@ -31942,7 +32144,7 @@ var buildVoiceObservabilityExportReplayReport = (records) => {
|
|
|
31942
32144
|
value: "manifest"
|
|
31943
32145
|
}
|
|
31944
32146
|
] : [],
|
|
31945
|
-
...!records.artifactIndex && !
|
|
32147
|
+
...!records.artifactIndex && !isRecord3(records.databaseRecord) ? [
|
|
31946
32148
|
{
|
|
31947
32149
|
code: "voice.observability.export_replay.missing_record",
|
|
31948
32150
|
label: "Artifact index",
|
|
@@ -32120,7 +32322,7 @@ var loadVoiceObservabilityExportReplaySource = async (source) => {
|
|
|
32120
32322
|
};
|
|
32121
32323
|
var replayVoiceObservabilityExport = async (source) => buildVoiceObservabilityExportReplayReport(await loadVoiceObservabilityExportReplaySource(source));
|
|
32122
32324
|
var escapeObservabilityReplayHtml = (value) => String(value).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
32123
|
-
var isVoiceObservabilityExportReplayReport = (value) =>
|
|
32325
|
+
var isVoiceObservabilityExportReplayReport = (value) => isRecord3(value) && isRecord3(value.summary) && isRecord3(value.records) && Array.isArray(value.issues) && typeof value.checkedAt === "number" && isStatus2(value.status);
|
|
32124
32326
|
var resolveVoiceObservabilityExportReplayReport = async (input) => {
|
|
32125
32327
|
const resolved = typeof input === "function" ? await input() : input;
|
|
32126
32328
|
return isVoiceObservabilityExportReplayReport(resolved) ? resolved : replayVoiceObservabilityExport(resolved);
|
|
@@ -37411,18 +37613,18 @@ var createVoiceMemoryStore = () => {
|
|
|
37411
37613
|
import { Elysia as Elysia61 } from "elysia";
|
|
37412
37614
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
37413
37615
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
37414
|
-
const
|
|
37415
|
-
const key = await crypto.subtle.importKey("raw",
|
|
37616
|
+
const encoder2 = new TextEncoder;
|
|
37617
|
+
const key = await crypto.subtle.importKey("raw", encoder2.encode(input.secret), {
|
|
37416
37618
|
hash: "SHA-256",
|
|
37417
37619
|
name: "HMAC"
|
|
37418
37620
|
}, false, ["sign"]);
|
|
37419
|
-
const signature = await crypto.subtle.sign("HMAC", key,
|
|
37621
|
+
const signature = await crypto.subtle.sign("HMAC", key, encoder2.encode(`${input.timestamp}.${input.body}`));
|
|
37420
37622
|
return `sha256=${toHex6(new Uint8Array(signature))}`;
|
|
37421
37623
|
};
|
|
37422
37624
|
var timingSafeEqual3 = (left, right) => {
|
|
37423
|
-
const
|
|
37424
|
-
const leftBytes =
|
|
37425
|
-
const rightBytes =
|
|
37625
|
+
const encoder2 = new TextEncoder;
|
|
37626
|
+
const leftBytes = encoder2.encode(left);
|
|
37627
|
+
const rightBytes = encoder2.encode(right);
|
|
37426
37628
|
if (leftBytes.length !== rightBytes.length) {
|
|
37427
37629
|
return false;
|
|
37428
37630
|
}
|
|
@@ -39311,6 +39513,7 @@ export {
|
|
|
39311
39513
|
summarizeVoiceProviderHealth,
|
|
39312
39514
|
summarizeVoiceProviderFallbackRecovery,
|
|
39313
39515
|
summarizeVoiceProviderCapabilities,
|
|
39516
|
+
summarizeVoiceProofAssertions,
|
|
39314
39517
|
summarizeVoiceProductionReadinessGate,
|
|
39315
39518
|
summarizeVoiceOpsTasks,
|
|
39316
39519
|
summarizeVoiceOpsTaskQueue,
|
|
@@ -39345,6 +39548,7 @@ export {
|
|
|
39345
39548
|
runVoiceReconnectContract,
|
|
39346
39549
|
runVoiceRealCallProfileRecoveryLoop,
|
|
39347
39550
|
runVoiceProviderRoutingContract,
|
|
39551
|
+
runVoiceProofTargets,
|
|
39348
39552
|
runVoiceProfileSwitchPolicyProof,
|
|
39349
39553
|
runVoicePhoneAgentProductionSmokeContract,
|
|
39350
39554
|
runVoiceOutcomeContractSuite,
|
|
@@ -39483,6 +39687,7 @@ export {
|
|
|
39483
39687
|
muteVoiceMonitorIssue,
|
|
39484
39688
|
matchesVoiceOpsTaskAssignmentRule,
|
|
39485
39689
|
markVoiceOpsTaskSLABreached,
|
|
39690
|
+
mapVoiceProofTargetsWithConcurrency,
|
|
39486
39691
|
loadVoiceRealCallProfileEvidenceFromTraceStore,
|
|
39487
39692
|
loadVoiceObservabilityExportReplaySource,
|
|
39488
39693
|
listVoiceRoutingEvents,
|
|
@@ -39492,6 +39697,7 @@ export {
|
|
|
39492
39697
|
importVoiceCampaignRecipients,
|
|
39493
39698
|
heartbeatVoiceOpsTask,
|
|
39494
39699
|
hasVoiceOpsTaskSLABreach,
|
|
39700
|
+
getVoiceProofTargetLogicalFailure,
|
|
39495
39701
|
getVoiceLiveOpsControlStatus,
|
|
39496
39702
|
getVoiceCampaignDialerProofStatus,
|
|
39497
39703
|
getLatestVoiceTelephonyMediaReport,
|
|
@@ -39500,6 +39706,7 @@ export {
|
|
|
39500
39706
|
formatVoiceProofTrendAge,
|
|
39501
39707
|
filterVoiceTraceEvents,
|
|
39502
39708
|
filterVoiceAuditEvents,
|
|
39709
|
+
fetchVoiceProofTarget,
|
|
39503
39710
|
failVoiceOpsTask,
|
|
39504
39711
|
exportVoiceTrace,
|
|
39505
39712
|
exportVoiceAuditTrail,
|
|
@@ -39670,6 +39877,7 @@ export {
|
|
|
39670
39877
|
createVoiceProviderCapabilityHTMLHandler,
|
|
39671
39878
|
createVoiceProofTrendRoutes,
|
|
39672
39879
|
createVoiceProofTrendRecommendationRoutes,
|
|
39880
|
+
createVoiceProofAssertion,
|
|
39673
39881
|
createVoiceProfileTraceTagger,
|
|
39674
39882
|
createVoiceProfileSwitchReadinessRoutes,
|
|
39675
39883
|
createVoiceProfileSwitchPolicyProofRoutes,
|
|
@@ -39780,6 +39988,7 @@ export {
|
|
|
39780
39988
|
createVoiceExternalObjectMapId,
|
|
39781
39989
|
createVoiceExternalObjectMap,
|
|
39782
39990
|
createVoiceExperiment,
|
|
39991
|
+
createVoiceEvidenceAssertion,
|
|
39783
39992
|
createVoiceEvalRoutes,
|
|
39784
39993
|
createVoiceDiagnosticsRoutes,
|
|
39785
39994
|
createVoiceDemoReadyRoutes,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type VoiceProofAssertionResult = {
|
|
2
|
+
kind: 'json-assertion';
|
|
3
|
+
name: string;
|
|
4
|
+
ok: boolean;
|
|
5
|
+
summary?: Record<string, unknown>;
|
|
6
|
+
};
|
|
7
|
+
export type VoiceProofAssertionSummary = {
|
|
8
|
+
failed: number;
|
|
9
|
+
failures: Array<{
|
|
10
|
+
name: string;
|
|
11
|
+
summary?: Record<string, unknown>;
|
|
12
|
+
}>;
|
|
13
|
+
ok: boolean;
|
|
14
|
+
passed: number;
|
|
15
|
+
total: number;
|
|
16
|
+
};
|
|
17
|
+
export type VoiceProofAssertionInput = {
|
|
18
|
+
missingIssue?: string;
|
|
19
|
+
name: string;
|
|
20
|
+
ok?: boolean;
|
|
21
|
+
summary?: Record<string, unknown>;
|
|
22
|
+
};
|
|
23
|
+
export type VoiceEvidenceAssertionInput<TEvidence> = {
|
|
24
|
+
evidence?: TEvidence;
|
|
25
|
+
missingIssue?: string;
|
|
26
|
+
name: string;
|
|
27
|
+
ok?: (evidence: TEvidence) => boolean;
|
|
28
|
+
summary?: (evidence: TEvidence) => Record<string, unknown>;
|
|
29
|
+
};
|
|
30
|
+
export declare const createVoiceProofAssertion: (input: VoiceProofAssertionInput) => VoiceProofAssertionResult;
|
|
31
|
+
export declare const createVoiceEvidenceAssertion: <TEvidence>(input: VoiceEvidenceAssertionInput<TEvidence>) => VoiceProofAssertionResult;
|
|
32
|
+
export declare const summarizeVoiceProofAssertions: (assertions: VoiceProofAssertionResult[]) => VoiceProofAssertionSummary;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export type VoiceProofTargetMethod = 'GET' | 'POST';
|
|
2
|
+
export type VoiceProofTarget = {
|
|
3
|
+
accept?: string;
|
|
4
|
+
allowLogicalFail?: boolean;
|
|
5
|
+
body?: unknown;
|
|
6
|
+
kind: 'json' | 'text';
|
|
7
|
+
method?: VoiceProofTargetMethod;
|
|
8
|
+
name: string;
|
|
9
|
+
path: string;
|
|
10
|
+
requiredText?: string[];
|
|
11
|
+
};
|
|
12
|
+
export type VoiceProofTargetResult = {
|
|
13
|
+
body?: unknown;
|
|
14
|
+
bytes: number;
|
|
15
|
+
elapsedMs: number;
|
|
16
|
+
error?: string;
|
|
17
|
+
kind: VoiceProofTarget['kind'];
|
|
18
|
+
method: VoiceProofTargetMethod;
|
|
19
|
+
name: string;
|
|
20
|
+
ok: boolean;
|
|
21
|
+
path: string;
|
|
22
|
+
status?: number;
|
|
23
|
+
summary?: Record<string, unknown>;
|
|
24
|
+
url: string;
|
|
25
|
+
};
|
|
26
|
+
export type VoiceProofTargetRunnerOptions = {
|
|
27
|
+
baseUrl: string;
|
|
28
|
+
fetch?: typeof fetch;
|
|
29
|
+
now?: () => number;
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
writeArtifact?: (input: {
|
|
32
|
+
content: string;
|
|
33
|
+
name: string;
|
|
34
|
+
target: VoiceProofTarget;
|
|
35
|
+
}) => Promise<void> | void;
|
|
36
|
+
};
|
|
37
|
+
export type VoiceProofTargetRunOptions = VoiceProofTargetRunnerOptions & {
|
|
38
|
+
concurrency?: number;
|
|
39
|
+
};
|
|
40
|
+
export declare const getVoiceProofTargetLogicalFailure: (value: unknown) => "Response status is \"fail\"." | "Response pass is false." | "Response ok is false." | undefined;
|
|
41
|
+
export declare const mapVoiceProofTargetsWithConcurrency: <TInput, TOutput>(items: TInput[], limit: number, mapper: (item: TInput) => Promise<TOutput>) => Promise<TOutput[]>;
|
|
42
|
+
export declare const fetchVoiceProofTarget: (target: VoiceProofTarget, options: VoiceProofTargetRunnerOptions) => Promise<VoiceProofTargetResult>;
|
|
43
|
+
export declare const runVoiceProofTargets: (targets: VoiceProofTarget[], options: VoiceProofTargetRunOptions) => Promise<VoiceProofTargetResult[]>;
|