@absolutejs/voice 0.0.22-beta.392 → 0.0.22-beta.394

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.
@@ -390,6 +390,31 @@ export type VoiceCampaignTelephonyOutcomeResult = {
390
390
  status?: 'failed' | 'succeeded';
391
391
  attemptId?: string;
392
392
  };
393
+ export type VoiceCampaignTelephonyOutcomeSnapshot<TResult = unknown> = {
394
+ action: VoiceTelephonyOutcomeDecision['action'];
395
+ at: number;
396
+ campaignOutcome: VoiceCampaignTelephonyOutcomeResult;
397
+ disposition?: VoiceTelephonyOutcomeDecision['disposition'];
398
+ duplicate?: boolean;
399
+ idempotencyKey?: string;
400
+ provider?: string;
401
+ routeResult?: TResult;
402
+ sessionId?: string;
403
+ source?: VoiceTelephonyOutcomeDecision['source'];
404
+ };
405
+ export type VoiceCampaignTelephonyOutcomeRecorderOptions<TResult = unknown> = VoiceCampaignTelephonyOutcomeOptions<TResult> & {
406
+ maxSnapshots?: number;
407
+ now?: () => number;
408
+ };
409
+ export type VoiceCampaignTelephonyOutcomeRecorderRecordInput<TResult = unknown> = VoiceTelephonyWebhookDecision<TResult> & {
410
+ provider?: string;
411
+ };
412
+ export type VoiceCampaignTelephonyOutcomeRecorder<TResult = unknown> = {
413
+ clear: () => void;
414
+ handler: (provider?: string) => (input: VoiceTelephonyWebhookDecision<TResult>) => Promise<void>;
415
+ list: () => VoiceCampaignTelephonyOutcomeSnapshot<TResult>[];
416
+ record: (input: VoiceCampaignTelephonyOutcomeRecorderRecordInput<TResult>) => Promise<VoiceCampaignTelephonyOutcomeSnapshot<TResult>>;
417
+ };
393
418
  export declare const importVoiceCampaignRecipients: (options: VoiceCampaignRecipientImportOptions) => VoiceCampaignRecipientImportResult;
394
419
  export declare const createVoiceMemoryCampaignStore: () => VoiceCampaignStore;
395
420
  export declare const summarizeVoiceCampaigns: (records: VoiceCampaignRecord[]) => VoiceCampaignSummary;
@@ -399,6 +424,7 @@ export declare const createVoiceCampaignWorker: (options: VoiceCampaignWorkerOpt
399
424
  export declare const createVoiceCampaignWorkerLoop: (options: VoiceCampaignWorkerLoopOptions) => VoiceCampaignWorkerLoop;
400
425
  export declare const applyVoiceCampaignTelephonyOutcome: <TResult = unknown>(input: VoiceCampaignTelephonyOutcomeInput<TResult>, options?: VoiceCampaignTelephonyOutcomeOptions<TResult>) => Promise<VoiceCampaignTelephonyOutcomeResult>;
401
426
  export declare const createVoiceCampaignTelephonyOutcomeHandler: <TResult = unknown>(options: VoiceCampaignTelephonyOutcomeOptions<TResult>) => (input: VoiceTelephonyWebhookDecision<TResult>) => Promise<VoiceCampaignTelephonyOutcomeResult>;
427
+ export declare const createVoiceCampaignTelephonyOutcomeRecorder: <TResult = unknown>(options?: VoiceCampaignTelephonyOutcomeRecorderOptions<TResult>) => VoiceCampaignTelephonyOutcomeRecorder<TResult>;
402
428
  export declare const runVoiceCampaignProof: (options?: VoiceCampaignProofOptions) => Promise<VoiceCampaignProofReport>;
403
429
  export declare const runVoiceCampaignReadinessProof: (options?: VoiceCampaignReadinessProofOptions) => Promise<VoiceCampaignReadinessProofReport>;
404
430
  export declare const evaluateVoiceCampaignReadinessEvidence: (report: VoiceCampaignReadinessProofReport, input?: VoiceCampaignReadinessAssertionInput) => VoiceCampaignReadinessAssertionReport;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { voice } from './plugin';
2
- export { applyVoiceCampaignTelephonyOutcome, assertVoiceCampaignReadinessEvidence, buildVoiceCampaignObservabilityReport, createVoiceCampaignTelephonyOutcomeHandler, createVoiceCampaign, createVoiceCampaignRoutes, createVoiceCampaignWorker, createVoiceCampaignWorkerLoop, createVoiceMemoryCampaignStore, evaluateVoiceCampaignReadinessEvidence, importVoiceCampaignRecipients, renderVoiceCampaignObservabilityHTML, renderVoiceCampaignsHTML, runVoiceCampaignProof, runVoiceCampaignReadinessProof, summarizeVoiceCampaigns } from './campaign';
2
+ export { applyVoiceCampaignTelephonyOutcome, assertVoiceCampaignReadinessEvidence, buildVoiceCampaignObservabilityReport, createVoiceCampaignTelephonyOutcomeHandler, createVoiceCampaignTelephonyOutcomeRecorder, createVoiceCampaign, createVoiceCampaignRoutes, createVoiceCampaignWorker, createVoiceCampaignWorkerLoop, createVoiceMemoryCampaignStore, evaluateVoiceCampaignReadinessEvidence, importVoiceCampaignRecipients, renderVoiceCampaignObservabilityHTML, renderVoiceCampaignsHTML, runVoiceCampaignProof, runVoiceCampaignReadinessProof, summarizeVoiceCampaigns } from './campaign';
3
3
  export { assertVoiceCampaignDialerProofEvidence, createVoicePlivoCampaignDialer, createVoiceTelnyxCampaignDialer, createVoiceTwilioCampaignDialer, evaluateVoiceCampaignDialerProofEvidence, getVoiceCampaignDialerProofStatus, runVoiceCampaignDialerProof } from './campaignDialers';
4
4
  export { createVoiceAssistant, createVoiceExperiment, summarizeVoiceAssistantRuns } from './assistant';
5
5
  export { createVoiceAssistantHealthHTMLHandler, createVoiceAssistantHealthJSONHandler, createVoiceAssistantHealthRoutes, renderVoiceAssistantHealthHTML, summarizeVoiceAssistantHealth } from './assistantHealth';
@@ -31,6 +31,8 @@ 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';
34
36
  export { applyVoiceProfileSwitchGuard, buildVoiceProfileSwitchReadinessReport, buildVoiceProfileSwitchLiveDecisionReport, createVoiceProfileSwitchLiveDecisionRoutes, createVoiceProfileSwitchPolicyProofRoutes, createVoiceProfileSwitchReadinessRoutes, recommendVoiceProfileSwitch, renderVoiceProfileSwitchLiveDecisionHTML, renderVoiceProfileSwitchPolicyProofHTML, renderVoiceProfileSwitchReadinessHTML, runVoiceProfileSwitchPolicyProof } from './profileSwitchRecommendation';
35
37
  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
38
  export { buildVoiceProviderDecisionTraceReport, createVoiceProviderDecisionTraceEvent, createVoiceProviderDecisionTraceRoutes, listVoiceProviderDecisionTraces, renderVoiceProviderDecisionTraceHTML, renderVoiceProviderDecisionTraceMarkdown } from './providerDecisionTraces';
@@ -116,7 +118,7 @@ export { resolveVoiceRuntimePreset } from './presets';
116
118
  export { resolveTurnDetectionConfig, TURN_PROFILE_DEFAULTS } from './turnProfiles';
117
119
  export { createVoiceCallReviewFromLiveTelephonyReport, createVoiceCallReviewRecorder, renderVoiceCallReviewHTML, renderVoiceCallReviewMarkdown } from './testing/review';
118
120
  export { getDefaultVoiceTelephonyBenchmarkScenarios, runVoiceTelephonyBenchmark, runVoiceTelephonyBenchmarkScenario, runVoiceTelephonyMediaOperationsSmoke, summarizeVoiceTelephonyBenchmark } from './testing/telephony';
119
- export type { VoiceCampaign, VoiceCampaignAttempt, VoiceCampaignAttemptResultInput, VoiceCampaignAttemptStatus, VoiceCampaignCreateInput, VoiceCampaignDialer, VoiceCampaignDialerInput, VoiceCampaignDialerResult, VoiceCampaignProofOptions, VoiceCampaignProofReport, VoiceCampaignReadinessAssertionInput, VoiceCampaignReadinessAssertionReport, VoiceCampaignReadinessCheck, VoiceCampaignReadinessProofOptions, VoiceCampaignReadinessProofReport, VoiceCampaignRecipient, VoiceCampaignRecipientImportIssue, VoiceCampaignRecipientImportIssueCode, VoiceCampaignRecipientImportOptions, VoiceCampaignRecipientImportResult, VoiceCampaignRecipientImportRow, VoiceCampaignRecipientInput, VoiceCampaignRecipientStatus, VoiceCampaignRecord, VoiceCampaignRoutesOptions, VoiceCampaignRuntime, VoiceCampaignRuntimeOptions, VoiceCampaignRateLimit, VoiceCampaignRetryPolicy, VoiceCampaignSchedule, VoiceCampaignStatus, VoiceCampaignStore, VoiceCampaignSummary, VoiceCampaignTimeWindow, VoiceCampaignTickResult } from './campaign';
121
+ export type { VoiceCampaign, VoiceCampaignAttempt, VoiceCampaignAttemptResultInput, VoiceCampaignAttemptStatus, VoiceCampaignCreateInput, VoiceCampaignDialer, VoiceCampaignDialerInput, VoiceCampaignDialerResult, VoiceCampaignProofOptions, VoiceCampaignProofReport, VoiceCampaignReadinessAssertionInput, VoiceCampaignReadinessAssertionReport, VoiceCampaignReadinessCheck, VoiceCampaignReadinessProofOptions, VoiceCampaignReadinessProofReport, VoiceCampaignRecipient, VoiceCampaignRecipientImportIssue, VoiceCampaignRecipientImportIssueCode, VoiceCampaignRecipientImportOptions, VoiceCampaignRecipientImportResult, VoiceCampaignRecipientImportRow, VoiceCampaignRecipientInput, VoiceCampaignRecipientStatus, VoiceCampaignRecord, VoiceCampaignRoutesOptions, VoiceCampaignRuntime, VoiceCampaignRuntimeOptions, VoiceCampaignRateLimit, VoiceCampaignRetryPolicy, VoiceCampaignSchedule, VoiceCampaignStatus, VoiceCampaignStore, VoiceCampaignSummary, VoiceCampaignTelephonyOutcomeInput, VoiceCampaignTelephonyOutcomeOptions, VoiceCampaignTelephonyOutcomeRecorder, VoiceCampaignTelephonyOutcomeRecorderOptions, VoiceCampaignTelephonyOutcomeRecorderRecordInput, VoiceCampaignTelephonyOutcomeResult, VoiceCampaignTelephonyOutcomeSnapshot, VoiceCampaignTelephonyOutcomeStatus, VoiceCampaignTimeWindow, VoiceCampaignTickResult } from './campaign';
120
122
  export type { VoiceCampaignDialerProofAssertionInput, VoiceCampaignDialerProofAssertionReport, VoiceCampaignDialerProofCarrierRequest, VoiceCampaignDialerProofOptions, VoiceCampaignDialerProofProvider, VoiceCampaignDialerProofProviderResult, VoiceCampaignDialerProofReport, VoiceCampaignDialerProofStatus, VoicePlivoCampaignDialerOptions, VoiceTelnyxCampaignDialerOptions, VoiceTwilioCampaignDialerOptions } from './campaignDialers';
121
123
  export type { VoiceBargeInReport, VoiceBargeInRoutesOptions } from './bargeInRoutes';
122
124
  export type { VoiceAssistant, VoiceAssistantArtifactPlan, VoiceAssistantExperiment, VoiceAssistantExperimentOptions, VoiceAssistantGuardrailInput, VoiceAssistantGuardrails, VoiceAssistantMemoryLifecycle, VoiceAssistantMemoryLifecycleInput, VoiceAssistantOptions, VoiceAssistantOutputGuardrailInput, VoiceAssistantPreset, VoiceAssistantRunsSummary, VoiceAssistantRunSummary, VoiceAssistantVariant } from './assistant';
package/dist/index.js CHANGED
@@ -7310,6 +7310,49 @@ var createVoiceCampaignTelephonyOutcomeHandler = (options) => (input) => applyVo
7310
7310
  routeResult: input.routeResult,
7311
7311
  sessionId: input.sessionId
7312
7312
  }, options);
7313
+ var createVoiceCampaignTelephonyOutcomeRecorder = (options = {}) => {
7314
+ const snapshots = [];
7315
+ const maxSnapshots = Math.max(0, options.maxSnapshots ?? 20);
7316
+ const now = options.now ?? Date.now;
7317
+ const record = async (input) => {
7318
+ const campaignOutcome = await applyVoiceCampaignTelephonyOutcome({
7319
+ decision: input.decision,
7320
+ event: input.event,
7321
+ routeResult: input.routeResult,
7322
+ sessionId: input.sessionId
7323
+ }, options);
7324
+ const snapshot = {
7325
+ action: input.decision.action,
7326
+ at: now(),
7327
+ campaignOutcome,
7328
+ disposition: input.decision.disposition,
7329
+ duplicate: input.duplicate,
7330
+ idempotencyKey: input.idempotencyKey,
7331
+ provider: input.provider ?? input.event.provider,
7332
+ routeResult: input.routeResult,
7333
+ sessionId: input.sessionId,
7334
+ source: input.decision.source
7335
+ };
7336
+ if (maxSnapshots > 0) {
7337
+ snapshots.unshift(snapshot);
7338
+ snapshots.splice(maxSnapshots);
7339
+ }
7340
+ return snapshot;
7341
+ };
7342
+ return {
7343
+ clear: () => {
7344
+ snapshots.splice(0);
7345
+ },
7346
+ handler: (provider) => async (input) => {
7347
+ await record({
7348
+ ...input,
7349
+ provider: provider ?? input.event.provider
7350
+ });
7351
+ },
7352
+ list: () => snapshots.map((snapshot) => ({ ...snapshot })),
7353
+ record
7354
+ };
7355
+ };
7313
7356
  var defaultProofRecipients = () => [
7314
7357
  {
7315
7358
  id: "campaign-proof-recipient-1",
@@ -18304,6 +18347,44 @@ var formatVoiceProofTrendAge = (ageMs) => {
18304
18347
  const days = Math.floor(hours / 24);
18305
18348
  return `${days}d ${hours % 24}h`;
18306
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
+ };
18307
18388
  // src/providerRouterTraces.ts
18308
18389
  var buildVoiceProviderRouterTraceEvent = (options) => ({
18309
18390
  at: options.at ?? options.event.at,
@@ -23429,7 +23510,7 @@ var DEFAULT_MACHINE_VOICEMAIL_VALUES = [
23429
23510
  "voicemail"
23430
23511
  ];
23431
23512
  var DEFAULT_NO_ANSWER_SIP_CODES = [408, 480, 486, 487, 603];
23432
- var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
23513
+ var isRecord2 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
23433
23514
  var uniqueSorted4 = (values) => Array.from(new Set(values)).sort();
23434
23515
  var findMissing3 = (values, required) => {
23435
23516
  if (!required?.length) {
@@ -23471,9 +23552,9 @@ var evaluateVoiceTelephonyWebhookNormalizationEvidence = (input = {}) => {
23471
23552
  const duplicateDecisions = decisions.filter((decision) => decision.duplicate === true);
23472
23553
  const duplicateProviders = uniqueSorted4(duplicateDecisions.map((decision) => decision.provider ?? decision.event?.provider).filter(isTelephonyWebhookProvider));
23473
23554
  const duplicateIdempotencyKeys = new Set(duplicateDecisions.map((decision) => decision.idempotencyKey).filter((key) => typeof key === "string" && key.length > 0)).size;
23474
- const duplicateCampaignOutcomesApplied = duplicateDecisions.filter((decision) => isRecord(decision.campaignOutcome) && decision.campaignOutcome.applied === true).length;
23475
- const duplicateOutcomeReasons = uniqueSorted4(duplicateDecisions.map((decision) => isRecord(decision.campaignOutcome) ? decision.campaignOutcome.reason : undefined).filter((reason) => typeof reason === "string"));
23476
- const routeResults = decisions.filter((decision) => isRecord(decision.routeResult)).length;
23555
+ const duplicateCampaignOutcomesApplied = duplicateDecisions.filter((decision) => isRecord2(decision.campaignOutcome) && decision.campaignOutcome.applied === true).length;
23556
+ const duplicateOutcomeReasons = uniqueSorted4(duplicateDecisions.map((decision) => isRecord2(decision.campaignOutcome) ? decision.campaignOutcome.reason : undefined).filter((reason) => typeof reason === "string"));
23557
+ const routeResults = decisions.filter((decision) => isRecord2(decision.routeResult)).length;
23477
23558
  const missingSessionIds = decisions.filter((decision) => !decision.sessionId).length;
23478
23559
  const rejectedVerificationAttempts = verificationAttempts.filter((attempt) => attempt.rejected === true || attempt.status === 401 || attempt.verification?.ok === false && attempt.verification.reason === "invalid-signature");
23479
23560
  const rejectedVerificationProviders = uniqueSorted4(rejectedVerificationAttempts.map((attempt) => attempt.provider).filter(isTelephonyWebhookProvider));
@@ -23593,18 +23674,18 @@ var parseMaybeJSON = (value) => {
23593
23674
  }
23594
23675
  };
23595
23676
  var flattenPayload = (value) => {
23596
- if (!isRecord(value)) {
23677
+ if (!isRecord2(value)) {
23597
23678
  return {};
23598
23679
  }
23599
- const data = isRecord(value.data) ? value.data : undefined;
23600
- const payload = isRecord(value.payload) ? value.payload : undefined;
23601
- const event = isRecord(value.event) ? value.event : undefined;
23680
+ const data = isRecord2(value.data) ? value.data : undefined;
23681
+ const payload = isRecord2(value.payload) ? value.payload : undefined;
23682
+ const event = isRecord2(value.event) ? value.event : undefined;
23602
23683
  return {
23603
23684
  ...value,
23604
23685
  ...payload,
23605
23686
  ...event,
23606
23687
  ...data,
23607
- ...isRecord(data?.payload) ? data.payload : undefined
23688
+ ...isRecord2(data?.payload) ? data.payload : undefined
23608
23689
  };
23609
23690
  };
23610
23691
  var toBase64 = (bytes) => Buffer.from(new Uint8Array(bytes)).toString("base64");
@@ -31509,12 +31590,12 @@ var assertVoiceObservabilityExportSchema = (input) => {
31509
31590
  throw new Error(`Unsupported voice observability export schema: ${input.schema?.id ?? "missing"}@${input.schema?.version ?? "missing"}`);
31510
31591
  }
31511
31592
  };
31512
- var isRecord2 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
31593
+ var isRecord3 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
31513
31594
  var isStatus2 = (value) => value === "fail" || value === "pass" || value === "warn";
31514
- var getRecord2 = (value, key) => isRecord2(value) && isRecord2(value[key]) ? value[key] : undefined;
31515
- var getRecordArray = (value, key) => isRecord2(value) && Array.isArray(value[key]) ? value[key] : undefined;
31595
+ var getRecord2 = (value, key) => isRecord3(value) && isRecord3(value[key]) ? value[key] : undefined;
31596
+ var getRecordArray = (value, key) => isRecord3(value) && Array.isArray(value[key]) ? value[key] : undefined;
31516
31597
  var inferVoiceObservabilityExportRecordKind = (record) => {
31517
- if (isRecord2(record.manifest) && isRecord2(record.artifactIndex)) {
31598
+ if (isRecord3(record.manifest) && isRecord3(record.artifactIndex)) {
31518
31599
  return "database-record";
31519
31600
  }
31520
31601
  if (Array.isArray(record.receipts)) {
@@ -31523,10 +31604,10 @@ var inferVoiceObservabilityExportRecordKind = (record) => {
31523
31604
  if (typeof record.runId === "string" && Array.isArray(record.destinations)) {
31524
31605
  return "delivery-receipt";
31525
31606
  }
31526
- if (Array.isArray(record.destinations) && isRecord2(record.summary) && typeof record.exportStatus === "string") {
31607
+ if (Array.isArray(record.destinations) && isRecord3(record.summary) && typeof record.exportStatus === "string") {
31527
31608
  return "delivery-report";
31528
31609
  }
31529
- if (Array.isArray(record.artifacts) && isRecord2(record.summary)) {
31610
+ if (Array.isArray(record.artifacts) && isRecord3(record.summary)) {
31530
31611
  return Array.isArray(record.envelopes) ? "manifest" : "artifact-index";
31531
31612
  }
31532
31613
  return;
@@ -31592,7 +31673,7 @@ var validateDeliveryDestinations = (issues, destinations, path) => {
31592
31673
  }
31593
31674
  destinations.forEach((destination, index) => {
31594
31675
  const destinationPath = `${path}.${index}`;
31595
- if (!isRecord2(destination)) {
31676
+ if (!isRecord3(destination)) {
31596
31677
  pushValidationIssue(issues, {
31597
31678
  code: "voice.observability.export.invalid_shape",
31598
31679
  message: `${destinationPath} must be an object.`,
@@ -31613,7 +31694,7 @@ var validateDeliveryDestinations = (issues, destinations, path) => {
31613
31694
  };
31614
31695
  var validateVoiceObservabilityExportRecord = (input, options = {}) => {
31615
31696
  const issues = [];
31616
- if (!isRecord2(input)) {
31697
+ if (!isRecord3(input)) {
31617
31698
  return {
31618
31699
  issues: [
31619
31700
  {
@@ -31648,21 +31729,21 @@ var validateVoiceObservabilityExportRecord = (input, options = {}) => {
31648
31729
  requireArrayField(issues, input, "sessionIds", "$");
31649
31730
  requireNumberField(issues, input, "checkedAt", "$");
31650
31731
  requireStatusField(issues, input, "status", "$");
31651
- if (!isRecord2(input.deliveries)) {
31732
+ if (!isRecord3(input.deliveries)) {
31652
31733
  pushValidationIssue(issues, {
31653
31734
  code: "voice.observability.export.missing_field",
31654
31735
  message: "$.deliveries must be an object.",
31655
31736
  path: "$.deliveries"
31656
31737
  });
31657
31738
  }
31658
- if (!isRecord2(input.redaction)) {
31739
+ if (!isRecord3(input.redaction)) {
31659
31740
  pushValidationIssue(issues, {
31660
31741
  code: "voice.observability.export.missing_field",
31661
31742
  message: "$.redaction must be an object.",
31662
31743
  path: "$.redaction"
31663
31744
  });
31664
31745
  }
31665
- if (!isRecord2(input.summary)) {
31746
+ if (!isRecord3(input.summary)) {
31666
31747
  pushValidationIssue(issues, {
31667
31748
  code: "voice.observability.export.missing_field",
31668
31749
  message: "$.summary must be an object.",
@@ -31674,7 +31755,7 @@ var validateVoiceObservabilityExportRecord = (input, options = {}) => {
31674
31755
  requireArrayField(issues, input, "artifacts", "$");
31675
31756
  requireNumberField(issues, input, "checkedAt", "$");
31676
31757
  requireStatusField(issues, input, "status", "$");
31677
- if (!isRecord2(input.summary)) {
31758
+ if (!isRecord3(input.summary)) {
31678
31759
  pushValidationIssue(issues, {
31679
31760
  code: "voice.observability.export.missing_field",
31680
31761
  message: "$.summary must be an object.",
@@ -31686,7 +31767,7 @@ var validateVoiceObservabilityExportRecord = (input, options = {}) => {
31686
31767
  requireNumberField(issues, input, "checkedAt", "$");
31687
31768
  requireStatusField(issues, input, "status", "$");
31688
31769
  requireStatusField(issues, input, "exportStatus", "$");
31689
- if (!isRecord2(input.manifest)) {
31770
+ if (!isRecord3(input.manifest)) {
31690
31771
  pushValidationIssue(issues, {
31691
31772
  code: "voice.observability.export.missing_field",
31692
31773
  message: "$.manifest must be an object.",
@@ -31700,7 +31781,7 @@ var validateVoiceObservabilityExportRecord = (input, options = {}) => {
31700
31781
  path: `$.manifest${issue.path.slice(1)}`
31701
31782
  })));
31702
31783
  }
31703
- if (!isRecord2(input.artifactIndex)) {
31784
+ if (!isRecord3(input.artifactIndex)) {
31704
31785
  pushValidationIssue(issues, {
31705
31786
  code: "voice.observability.export.missing_field",
31706
31787
  message: "$.artifactIndex must be an object.",
@@ -31838,11 +31919,11 @@ var buildObservabilityExportDatabaseRecord = (input) => ({
31838
31919
  });
31839
31920
  var parseObservabilityExportJson = (value) => typeof value === "string" ? JSON.parse(value) : value;
31840
31921
  var collectReplayDeliveryDestinations = (value) => {
31841
- if (!isRecord2(value)) {
31922
+ if (!isRecord3(value)) {
31842
31923
  return [];
31843
31924
  }
31844
31925
  if (Array.isArray(value.destinations)) {
31845
- return value.destinations.filter((destination) => isRecord2(destination));
31926
+ return value.destinations.filter((destination) => isRecord3(destination));
31846
31927
  }
31847
31928
  if (Array.isArray(value.receipts)) {
31848
31929
  return value.receipts.flatMap((receipt) => collectReplayDeliveryDestinations(receipt));
@@ -31851,8 +31932,8 @@ var collectReplayDeliveryDestinations = (value) => {
31851
31932
  };
31852
31933
  var replayIssueSeverity = (status) => status === "fail" ? "fail" : "warn";
31853
31934
  var buildVoiceObservabilityExportReplayReport = (records) => {
31854
- const manifest = records.manifest ?? (isRecord2(records.databaseRecord) ? records.databaseRecord.manifest : undefined);
31855
- const artifactIndex = records.artifactIndex ?? (isRecord2(records.databaseRecord) ? records.databaseRecord.artifactIndex : undefined);
31935
+ const manifest = records.manifest ?? (isRecord3(records.databaseRecord) ? records.databaseRecord.manifest : undefined);
31936
+ const artifactIndex = records.artifactIndex ?? (isRecord3(records.databaseRecord) ? records.databaseRecord.artifactIndex : undefined);
31856
31937
  const validations = {
31857
31938
  artifactIndex: validateVoiceObservabilityExportRecord(artifactIndex, {
31858
31939
  kind: "artifact-index"
@@ -31877,12 +31958,12 @@ var buildVoiceObservabilityExportReplayReport = (records) => {
31877
31958
  kind,
31878
31959
  issue
31879
31960
  })) ?? []);
31880
- const manifestRecord = isRecord2(manifest) ? manifest : undefined;
31881
- const artifactIndexRecord = isRecord2(artifactIndex) ? artifactIndex : undefined;
31961
+ const manifestRecord = isRecord3(manifest) ? manifest : undefined;
31962
+ const artifactIndexRecord = isRecord3(artifactIndex) ? artifactIndex : undefined;
31882
31963
  const artifacts = [
31883
31964
  ...Array.isArray(manifestRecord?.artifacts) ? manifestRecord.artifacts : [],
31884
31965
  ...Array.isArray(artifactIndexRecord?.artifacts) ? artifactIndexRecord.artifacts : []
31885
- ].filter((artifact) => isRecord2(artifact));
31966
+ ].filter((artifact) => isRecord3(artifact));
31886
31967
  const failedArtifacts = artifacts.filter((artifact) => artifact.status === "fail");
31887
31968
  const deliveryDestinations = [
31888
31969
  ...collectReplayDeliveryDestinations(records.deliveryReport),
@@ -31891,7 +31972,7 @@ var buildVoiceObservabilityExportReplayReport = (records) => {
31891
31972
  ];
31892
31973
  const failedDeliveryDestinations = deliveryDestinations.filter((destination) => destination.status === "failed");
31893
31974
  const issues = [
31894
- ...!records.manifest && !isRecord2(records.databaseRecord) ? [
31975
+ ...!records.manifest && !isRecord3(records.databaseRecord) ? [
31895
31976
  {
31896
31977
  code: "voice.observability.export_replay.missing_record",
31897
31978
  label: "Export manifest",
@@ -31899,7 +31980,7 @@ var buildVoiceObservabilityExportReplayReport = (records) => {
31899
31980
  value: "manifest"
31900
31981
  }
31901
31982
  ] : [],
31902
- ...!records.artifactIndex && !isRecord2(records.databaseRecord) ? [
31983
+ ...!records.artifactIndex && !isRecord3(records.databaseRecord) ? [
31903
31984
  {
31904
31985
  code: "voice.observability.export_replay.missing_record",
31905
31986
  label: "Artifact index",
@@ -32077,7 +32158,7 @@ var loadVoiceObservabilityExportReplaySource = async (source) => {
32077
32158
  };
32078
32159
  var replayVoiceObservabilityExport = async (source) => buildVoiceObservabilityExportReplayReport(await loadVoiceObservabilityExportReplaySource(source));
32079
32160
  var escapeObservabilityReplayHtml = (value) => String(value).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
32080
- var isVoiceObservabilityExportReplayReport = (value) => isRecord2(value) && isRecord2(value.summary) && isRecord2(value.records) && Array.isArray(value.issues) && typeof value.checkedAt === "number" && isStatus2(value.status);
32161
+ var isVoiceObservabilityExportReplayReport = (value) => isRecord3(value) && isRecord3(value.summary) && isRecord3(value.records) && Array.isArray(value.issues) && typeof value.checkedAt === "number" && isStatus2(value.status);
32081
32162
  var resolveVoiceObservabilityExportReplayReport = async (input) => {
32082
32163
  const resolved = typeof input === "function" ? await input() : input;
32083
32164
  return isVoiceObservabilityExportReplayReport(resolved) ? resolved : replayVoiceObservabilityExport(resolved);
@@ -39268,6 +39349,7 @@ export {
39268
39349
  summarizeVoiceProviderHealth,
39269
39350
  summarizeVoiceProviderFallbackRecovery,
39270
39351
  summarizeVoiceProviderCapabilities,
39352
+ summarizeVoiceProofAssertions,
39271
39353
  summarizeVoiceProductionReadinessGate,
39272
39354
  summarizeVoiceOpsTasks,
39273
39355
  summarizeVoiceOpsTaskQueue,
@@ -39627,6 +39709,7 @@ export {
39627
39709
  createVoiceProviderCapabilityHTMLHandler,
39628
39710
  createVoiceProofTrendRoutes,
39629
39711
  createVoiceProofTrendRecommendationRoutes,
39712
+ createVoiceProofAssertion,
39630
39713
  createVoiceProfileTraceTagger,
39631
39714
  createVoiceProfileSwitchReadinessRoutes,
39632
39715
  createVoiceProfileSwitchPolicyProofRoutes,
@@ -39737,6 +39820,7 @@ export {
39737
39820
  createVoiceExternalObjectMapId,
39738
39821
  createVoiceExternalObjectMap,
39739
39822
  createVoiceExperiment,
39823
+ createVoiceEvidenceAssertion,
39740
39824
  createVoiceEvalRoutes,
39741
39825
  createVoiceDiagnosticsRoutes,
39742
39826
  createVoiceDemoReadyRoutes,
@@ -39750,6 +39834,7 @@ export {
39750
39834
  createVoiceCompetitiveCoverageRoutes,
39751
39835
  createVoiceCampaignWorkerLoop,
39752
39836
  createVoiceCampaignWorker,
39837
+ createVoiceCampaignTelephonyOutcomeRecorder,
39753
39838
  createVoiceCampaignTelephonyOutcomeHandler,
39754
39839
  createVoiceCampaignRoutes,
39755
39840
  createVoiceCampaign,
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.392",
3
+ "version": "0.0.22-beta.394",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",