@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 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 isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
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) => isRecord(decision.campaignOutcome) && decision.campaignOutcome.applied === true).length;
23518
- const duplicateOutcomeReasons = uniqueSorted4(duplicateDecisions.map((decision) => isRecord(decision.campaignOutcome) ? decision.campaignOutcome.reason : undefined).filter((reason) => typeof reason === "string"));
23519
- const routeResults = decisions.filter((decision) => isRecord(decision.routeResult)).length;
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 (!isRecord(value)) {
23841
+ if (!isRecord2(value)) {
23640
23842
  return {};
23641
23843
  }
23642
- const data = isRecord(value.data) ? value.data : undefined;
23643
- const payload = isRecord(value.payload) ? value.payload : undefined;
23644
- const event = isRecord(value.event) ? value.event : undefined;
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
- ...isRecord(data?.payload) ? data.payload : undefined
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 encoder = new TextEncoder;
23656
- const leftBytes = encoder.encode(left);
23657
- const rightBytes = encoder.encode(right);
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 encoder = new TextEncoder;
23669
- const key = await crypto.subtle.importKey("raw", encoder.encode(secret), {
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, encoder.encode(payload));
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 encoder = new TextEncoder;
25274
- const leftBytes = encoder.encode(left);
25275
- const rightBytes = encoder.encode(right);
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 encoder = new TextEncoder;
25287
- const key = await crypto.subtle.importKey("raw", encoder.encode(secret), {
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, encoder.encode(payload));
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 isRecord2 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
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) => isRecord2(value) && isRecord2(value[key]) ? value[key] : undefined;
31558
- var getRecordArray = (value, key) => isRecord2(value) && Array.isArray(value[key]) ? value[key] : undefined;
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 (isRecord2(record.manifest) && isRecord2(record.artifactIndex)) {
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) && isRecord2(record.summary) && typeof record.exportStatus === "string") {
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) && isRecord2(record.summary)) {
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 (!isRecord2(destination)) {
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 (!isRecord2(input)) {
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 (!isRecord2(input.deliveries)) {
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 (!isRecord2(input.redaction)) {
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 (!isRecord2(input.summary)) {
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 (!isRecord2(input.summary)) {
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 (!isRecord2(input.manifest)) {
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 (!isRecord2(input.artifactIndex)) {
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 (!isRecord2(value)) {
32086
+ if (!isRecord3(value)) {
31885
32087
  return [];
31886
32088
  }
31887
32089
  if (Array.isArray(value.destinations)) {
31888
- return value.destinations.filter((destination) => isRecord2(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 ?? (isRecord2(records.databaseRecord) ? records.databaseRecord.manifest : undefined);
31898
- const artifactIndex = records.artifactIndex ?? (isRecord2(records.databaseRecord) ? records.databaseRecord.artifactIndex : undefined);
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 = isRecord2(manifest) ? manifest : undefined;
31924
- const artifactIndexRecord = isRecord2(artifactIndex) ? artifactIndex : undefined;
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) => isRecord2(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 && !isRecord2(records.databaseRecord) ? [
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 && !isRecord2(records.databaseRecord) ? [
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("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
32123
- var isVoiceObservabilityExportReplayReport = (value) => isRecord2(value) && isRecord2(value.summary) && isRecord2(value.records) && Array.isArray(value.issues) && typeof value.checkedAt === "number" && isStatus2(value.status);
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 encoder = new TextEncoder;
37415
- const key = await crypto.subtle.importKey("raw", encoder.encode(input.secret), {
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, encoder.encode(`${input.timestamp}.${input.body}`));
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 encoder = new TextEncoder;
37424
- const leftBytes = encoder.encode(left);
37425
- const rightBytes = encoder.encode(right);
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[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.393",
3
+ "version": "0.0.22-beta.395",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",