@absolutejs/voice 0.0.22-beta.273 → 0.0.22-beta.275

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
@@ -159,13 +159,13 @@ export type { VoiceS3ReviewStoreClient, VoiceS3ReviewStoreFile, VoiceS3ReviewSto
159
159
  export type { VoiceSQLiteRuntimeStorage, VoiceSQLiteStoreOptions } from './sqliteStore';
160
160
  export type { StoredVoiceIntegrationEvent, StoredVoiceExternalObjectMap, StoredVoiceOpsTask, VoiceExternalObjectMap, VoiceExternalObjectMapStore, VoiceOpsTaskAgeBucket, VoiceOpsTaskAnalyticsOptions, VoiceOpsTaskAnalyticsSummary, VoiceOpsTaskAssignmentRule, VoiceOpsTaskAssignmentRuleCondition, VoiceOpsTaskAssignmentRules, VoiceOpsTaskAssigneeAnalytics, VoiceOpsDispositionTaskPolicies, VoiceOpsSLABreachPolicy, VoiceIntegrationDeliveryStatus, VoiceIntegrationEvent, VoiceIntegrationEventStore, VoiceIntegrationSinkDelivery, VoiceIntegrationEventType, VoiceIntegrationWebhookConfig, VoiceOpsTask, VoiceOpsTaskHistoryEntry, VoiceOpsTaskKind, VoiceOpsTaskPolicy, VoiceOpsTaskPriority, VoiceOpsTaskStatus, VoiceOpsTaskStore, VoiceOpsTaskSummary, VoiceOpsTaskWorkerAnalytics } from './ops';
161
161
  export { createTwilioMediaStreamBridge, createTwilioVoiceRoutes, createTwilioVoiceResponse, decodeTwilioMulawBase64, encodeTwilioMulawBase64, transcodePCMToTwilioOutboundPayload, transcodeTwilioInboundPayloadToPCM16 } from './telephony/twilio';
162
- export { createVoiceTelephonyWebhookSecurityPreset } from './telephony/security';
162
+ export { assertVoiceTelephonyWebhookSecurityEvidence, buildVoiceTelephonyWebhookSecurityReport, createVoiceTelephonyWebhookSecurityPreset, createVoiceTelephonyWebhookSecurityRoutes, evaluateVoiceTelephonyWebhookSecurityEvidence } from './telephony/security';
163
163
  export { evaluateVoiceTelephonyContract } from './telephony/contract';
164
164
  export { createMemoryVoiceTelnyxWebhookEventStore, createTelnyxMediaStreamBridge, createTelnyxVoiceResponse, createTelnyxVoiceRoutes, createVoicePostgresTelnyxWebhookEventStore, createVoiceRedisTelnyxWebhookEventStore, createVoiceSQLiteTelnyxWebhookEventStore, createVoiceTelnyxWebhookVerifier, verifyVoiceTelnyxWebhookSignature } from './telephony/telnyx';
165
165
  export { createMemoryVoicePlivoWebhookNonceStore, createPlivoMediaStreamBridge, createPlivoVoiceResponse, createPlivoVoiceRoutes, createVoicePostgresPlivoWebhookNonceStore, createVoicePlivoWebhookVerifier, createVoiceRedisPlivoWebhookNonceStore, createVoiceSQLitePlivoWebhookNonceStore, signVoicePlivoWebhook, verifyVoicePlivoWebhookSignature } from './telephony/plivo';
166
166
  export { createVoiceTelephonyCarrierMatrix, createVoiceTelephonyCarrierMatrixRoutes, renderVoiceTelephonyCarrierMatrixHTML } from './telephony/matrix';
167
167
  export type { TwilioInboundMessage, TwilioMediaStreamBridge, TwilioMediaStreamBridgeOptions, TwilioMediaStreamSocket, TwilioOutboundClearMessage, TwilioOutboundMarkMessage, TwilioOutboundMediaMessage, TwilioOutboundMessage, TwilioVoiceRouteParameters, TwilioVoiceResponseOptions, TwilioVoiceSmokeCheck, TwilioVoiceSmokeOptions, TwilioVoiceSmokeReport, TwilioVoiceSetupOptions, TwilioVoiceSetupStatus, TwilioVoiceRoutesOptions } from './telephony/twilio';
168
- export type { VoiceTelephonyWebhookSecurityOptions, VoiceTelephonyWebhookSecurityPreset, VoiceTelephonyWebhookSecurityStorePreset } from './telephony/security';
168
+ export type { VoiceTelephonyWebhookSecurityOptions, VoiceTelephonyWebhookSecurityPreset, VoiceTelephonyWebhookSecurityAssertionInput, VoiceTelephonyWebhookSecurityAssertionReport, VoiceTelephonyWebhookSecurityProviderStatus, VoiceTelephonyWebhookSecurityReport, VoiceTelephonyWebhookSecurityRoutesOptions, VoiceTelephonyWebhookSecurityStorePreset } from './telephony/security';
169
169
  export type { VoiceTelephonyContractIssue, VoiceTelephonyContractOptions, VoiceTelephonyContractReport, VoiceTelephonyContractRequirement, VoiceTelephonyProvider, VoiceTelephonySetupStatus, VoiceTelephonySmokeCheck, VoiceTelephonySmokeReport } from './telephony/contract';
170
170
  export type { TelnyxInboundMessage, TelnyxMediaPayload, TelnyxMediaStreamBridge, TelnyxMediaStreamBridgeOptions, TelnyxMediaStreamSocket, TelnyxOutboundClearMessage, TelnyxOutboundMarkMessage, TelnyxOutboundMediaMessage, TelnyxOutboundMessage, TelnyxVoiceResponseOptions, TelnyxVoiceRoutesOptions, TelnyxVoiceSetupOptions, TelnyxVoiceSetupStatus, TelnyxVoiceSmokeCheck, TelnyxVoiceSmokeOptions, TelnyxVoiceSmokeReport, VoicePostgresTelnyxWebhookEventStoreOptions, VoiceRedisTelnyxWebhookEventClient, VoiceRedisTelnyxWebhookEventStoreOptions, VoiceSQLiteTelnyxWebhookEventStoreOptions, VoiceTelnyxWebhookEventStore, VoiceTelnyxWebhookEventStoreOptions, VoiceTelnyxWebhookVerifierOptions } from './telephony/telnyx';
171
171
  export type { PlivoInboundMessage, PlivoMediaStreamBridge, PlivoMediaStreamBridgeOptions, PlivoMediaStreamSocket, PlivoOutboundCheckpointMessage, PlivoOutboundClearAudioMessage, PlivoOutboundMessage, PlivoOutboundPlayAudioMessage, PlivoVoiceResponseOptions, PlivoVoiceRoutesOptions, PlivoVoiceSetupOptions, PlivoVoiceSetupStatus, PlivoVoiceSmokeCheck, PlivoVoiceSmokeOptions, PlivoVoiceSmokeReport, VoicePostgresPlivoWebhookNonceStoreOptions, VoicePlivoWebhookNonceStore, VoicePlivoWebhookNonceStoreOptions, VoicePlivoWebhookVerifierOptions, VoiceRedisPlivoWebhookNonceClient, VoiceRedisPlivoWebhookNonceStoreOptions, VoiceSQLitePlivoWebhookNonceStoreOptions } from './telephony/plivo';
package/dist/index.js CHANGED
@@ -13757,6 +13757,17 @@ var buildRetentionPolicyFromQuery = (query, options) => ({
13757
13757
  scopes: parseRetentionScopes(query.scopes),
13758
13758
  traceFilter: typeof query.sessionId === "string" && query.sessionId.trim() ? { sessionId: query.sessionId } : undefined
13759
13759
  });
13760
+ var buildAuditFilterFromQuery = (query) => {
13761
+ const filter = {
13762
+ after: getNumberQuery(query.auditAfter),
13763
+ afterOrAt: getNumberQuery(query.auditAfterOrAt),
13764
+ before: getNumberQuery(query.auditBefore),
13765
+ beforeOrAt: getNumberQuery(query.auditBeforeOrAt),
13766
+ limit: getNumberQuery(query.auditLimit),
13767
+ sessionId: typeof query.sessionId === "string" && query.sessionId.trim() ? query.sessionId : undefined
13768
+ };
13769
+ return Object.values(filter).some((value) => value !== undefined) ? filter : undefined;
13770
+ };
13760
13771
  var parseRetentionPolicyBody = (body, options, dryRun) => {
13761
13772
  const input = body && typeof body === "object" ? body : {};
13762
13773
  return {
@@ -13777,6 +13788,7 @@ var createVoiceDataControlRoutes = (options) => {
13777
13788
  });
13778
13789
  routes.get(path, async ({ query }) => {
13779
13790
  const report = await buildVoiceDataControlReport({
13791
+ auditFilter: buildAuditFilterFromQuery(query),
13780
13792
  ...options,
13781
13793
  retention: buildRetentionPolicyFromQuery(query, options)
13782
13794
  });
@@ -13788,11 +13800,13 @@ var createVoiceDataControlRoutes = (options) => {
13788
13800
  });
13789
13801
  });
13790
13802
  routes.get(`${path}.json`, async ({ query }) => buildVoiceDataControlReport({
13803
+ auditFilter: buildAuditFilterFromQuery(query),
13791
13804
  ...options,
13792
13805
  retention: buildRetentionPolicyFromQuery(query, options)
13793
13806
  }));
13794
13807
  routes.get(`${path}.md`, async ({ query }) => {
13795
13808
  const report = await buildVoiceDataControlReport({
13809
+ auditFilter: buildAuditFilterFromQuery(query),
13796
13810
  ...options,
13797
13811
  retention: buildRetentionPolicyFromQuery(query, options)
13798
13812
  });
@@ -31665,6 +31679,7 @@ var createVoiceSTTRoutingCorrectionHandler = (mode = "generic") => {
31665
31679
  return createPhraseHintCorrectionHandler();
31666
31680
  };
31667
31681
  // src/telephony/security.ts
31682
+ import { Elysia as Elysia51 } from "elysia";
31668
31683
  var resolveVerificationUrl2 = (option, input) => typeof option === "function" ? option(input) : option ?? input.request.url;
31669
31684
  var createStores = (options) => {
31670
31685
  const ttlSeconds = options.ttlSeconds;
@@ -31746,6 +31761,135 @@ var createStores = (options) => {
31746
31761
  telnyx: options.telnyx?.eventStore ?? createMemoryVoiceTelnyxWebhookEventStore()
31747
31762
  };
31748
31763
  };
31764
+ var resolveStoreKind = (store) => store?.kind ?? "memory";
31765
+ var isPersistentStore = (store) => {
31766
+ const kind = resolveStoreKind(store);
31767
+ return kind === "postgres" || kind === "redis" || kind === "sqlite";
31768
+ };
31769
+ var providerStatus = (input) => {
31770
+ const issues = [];
31771
+ if (input.enabled && !input.checks.verification) {
31772
+ issues.push("Webhook verification is not configured.");
31773
+ }
31774
+ if (input.enabled && !input.checks.replayProtection) {
31775
+ issues.push("Replay protection is not configured.");
31776
+ }
31777
+ if (input.enabled && input.checks.idempotency === false) {
31778
+ issues.push("Webhook idempotency is not configured.");
31779
+ }
31780
+ if (input.enabled && !input.checks.persistentStore) {
31781
+ issues.push("Webhook security store is in-memory; use SQLite, Postgres, or Redis for production.");
31782
+ }
31783
+ return {
31784
+ ...input,
31785
+ issues,
31786
+ status: !input.enabled ? "warn" : issues.length === 0 ? "pass" : "fail"
31787
+ };
31788
+ };
31789
+ var buildVoiceTelephonyWebhookSecurityReport = (options = {}) => {
31790
+ const store = resolveStoreKind(options.store);
31791
+ const persistentStore = isPersistentStore(options.store);
31792
+ const providers = [
31793
+ providerStatus({
31794
+ checks: {
31795
+ idempotency: Boolean(options.twilio),
31796
+ persistentStore,
31797
+ replayProtection: Boolean(options.twilio),
31798
+ verification: Boolean(options.twilio?.authToken)
31799
+ },
31800
+ enabled: Boolean(options.twilio),
31801
+ provider: "twilio",
31802
+ store
31803
+ }),
31804
+ providerStatus({
31805
+ checks: {
31806
+ persistentStore,
31807
+ replayProtection: Boolean(options.telnyx),
31808
+ verification: Boolean(options.telnyx?.publicKey)
31809
+ },
31810
+ enabled: Boolean(options.telnyx),
31811
+ provider: "telnyx",
31812
+ store
31813
+ }),
31814
+ providerStatus({
31815
+ checks: {
31816
+ persistentStore,
31817
+ replayProtection: Boolean(options.plivo),
31818
+ verification: Boolean(options.plivo?.authToken)
31819
+ },
31820
+ enabled: Boolean(options.plivo),
31821
+ provider: "plivo",
31822
+ store
31823
+ })
31824
+ ];
31825
+ const enabled = providers.filter((provider) => provider.enabled);
31826
+ const failed = enabled.filter((provider) => provider.status === "fail").length;
31827
+ const warned = enabled.filter((provider) => provider.status === "warn").length;
31828
+ const passed = enabled.filter((provider) => provider.status === "pass").length;
31829
+ const status = failed > 0 ? "fail" : warned > 0 || enabled.length === 0 ? "warn" : "pass";
31830
+ return {
31831
+ generatedAt: Date.now(),
31832
+ ok: status === "pass",
31833
+ providers,
31834
+ status,
31835
+ summary: {
31836
+ enabled: enabled.length,
31837
+ failed,
31838
+ passed,
31839
+ warned
31840
+ }
31841
+ };
31842
+ };
31843
+ var evaluateVoiceTelephonyWebhookSecurityEvidence = (report, input = {}) => {
31844
+ const issues = [...report.providers.flatMap((provider) => provider.issues)];
31845
+ const enabledProviders = report.providers.filter((provider) => provider.enabled).map((provider) => provider.provider);
31846
+ const passingProviders = report.providers.filter((provider) => provider.enabled && provider.status === "pass").map((provider) => provider.provider);
31847
+ const failedProviders = report.providers.filter((provider) => provider.enabled && provider.status === "fail").map((provider) => provider.provider);
31848
+ const maxFailedProviders = input.maxFailedProviders ?? 0;
31849
+ const minEnabledProviders = input.minEnabledProviders ?? 1;
31850
+ const requirePersistentStores = input.requirePersistentStores ?? true;
31851
+ if (enabledProviders.length < minEnabledProviders) {
31852
+ issues.push(`Expected at least ${String(minEnabledProviders)} enabled telephony webhook provider(s), found ${String(enabledProviders.length)}.`);
31853
+ }
31854
+ if (failedProviders.length > maxFailedProviders) {
31855
+ issues.push(`Expected at most ${String(maxFailedProviders)} failing telephony webhook provider(s), found ${String(failedProviders.length)}.`);
31856
+ }
31857
+ for (const provider of input.requiredProviders ?? []) {
31858
+ if (!enabledProviders.includes(provider)) {
31859
+ issues.push(`Missing enabled telephony webhook provider: ${provider}.`);
31860
+ }
31861
+ if (!passingProviders.includes(provider)) {
31862
+ issues.push(`Telephony webhook provider is not passing: ${provider}.`);
31863
+ }
31864
+ }
31865
+ if (requirePersistentStores) {
31866
+ for (const provider of report.providers) {
31867
+ if (provider.enabled && !provider.checks.persistentStore) {
31868
+ issues.push(`Telephony webhook provider ${provider.provider} is not using a persistent security store.`);
31869
+ }
31870
+ }
31871
+ }
31872
+ return {
31873
+ failedProviders,
31874
+ issues,
31875
+ ok: issues.length === 0,
31876
+ passingProviders,
31877
+ status: report.status
31878
+ };
31879
+ };
31880
+ var assertVoiceTelephonyWebhookSecurityEvidence = (report, input = {}) => {
31881
+ const assertion = evaluateVoiceTelephonyWebhookSecurityEvidence(report, input);
31882
+ if (!assertion.ok) {
31883
+ throw new Error(`Voice telephony webhook security assertion failed: ${assertion.issues.join(" ")}`);
31884
+ }
31885
+ return assertion;
31886
+ };
31887
+ var createVoiceTelephonyWebhookSecurityRoutes = (options) => {
31888
+ const path = options.path ?? "/api/voice/telephony/webhook-security";
31889
+ return new Elysia51({
31890
+ name: options.name ?? "absolutejs-voice-telephony-webhook-security"
31891
+ }).get(path, () => buildVoiceTelephonyWebhookSecurityReport(options.options));
31892
+ };
31749
31893
  var createVoiceTelephonyWebhookSecurityPreset = (options = {}) => {
31750
31894
  const stores = createStores(options);
31751
31895
  const twilioVerificationUrl = options.twilio?.verificationUrl;
@@ -32030,6 +32174,7 @@ export {
32030
32174
  exportVoiceAuditTrail,
32031
32175
  evaluateVoiceTrace,
32032
32176
  evaluateVoiceToolContractEvidence,
32177
+ evaluateVoiceTelephonyWebhookSecurityEvidence,
32033
32178
  evaluateVoiceTelephonyWebhookNormalizationEvidence,
32034
32179
  evaluateVoiceTelephonyContract,
32035
32180
  evaluateVoiceSimulationSuiteEvidence,
@@ -32107,6 +32252,7 @@ export {
32107
32252
  createVoiceToolContract,
32108
32253
  createVoiceTelnyxWebhookVerifier,
32109
32254
  createVoiceTelnyxCampaignDialer,
32255
+ createVoiceTelephonyWebhookSecurityRoutes,
32110
32256
  createVoiceTelephonyWebhookSecurityPreset,
32111
32257
  createVoiceTelephonyWebhookRoutes,
32112
32258
  createVoiceTelephonyWebhookHandler,
@@ -32343,6 +32489,7 @@ export {
32343
32489
  claimVoiceOpsTask,
32344
32490
  buildVoiceTraceReplay,
32345
32491
  buildVoiceTraceDeliveryReport,
32492
+ buildVoiceTelephonyWebhookSecurityReport,
32346
32493
  buildVoiceProviderSloReport,
32347
32494
  buildVoiceProviderContractMatrix,
32348
32495
  buildVoiceProofTrendReport,
@@ -32378,6 +32525,7 @@ export {
32378
32525
  buildEmptyVoiceProofTrendReport,
32379
32526
  assignVoiceOpsTask,
32380
32527
  assertVoiceToolContractEvidence,
32528
+ assertVoiceTelephonyWebhookSecurityEvidence,
32381
32529
  assertVoiceTelephonyWebhookNormalizationEvidence,
32382
32530
  assertVoiceSimulationSuiteEvidence,
32383
32531
  assertVoiceProviderStackEvidence,
@@ -1,4 +1,5 @@
1
- import { type VoiceTelephonyWebhookIdempotencyStore, type VoiceTelephonyWebhookVerificationResult } from '../telephonyOutcome';
1
+ import { type VoiceTelephonyWebhookIdempotencyStore, type VoiceTelephonyWebhookProvider, type VoiceTelephonyWebhookVerificationResult } from '../telephonyOutcome';
2
+ import { Elysia } from 'elysia';
2
3
  import { type VoicePostgresClient } from '../postgresStore';
3
4
  import { type VoiceRedisTelephonyWebhookIdempotencyClient } from '../queue';
4
5
  import { type VoicePlivoWebhookNonceStore, type VoiceRedisPlivoWebhookNonceClient } from './plivo';
@@ -92,4 +93,90 @@ export type VoiceTelephonyWebhookSecurityPreset<TResult = unknown> = {
92
93
  twilio: VoiceTelephonyWebhookSecurityPreset<TResult>['twilio']['verify'];
93
94
  };
94
95
  };
96
+ export type VoiceTelephonyWebhookSecurityProviderStatus = {
97
+ checks: {
98
+ idempotency?: boolean;
99
+ persistentStore: boolean;
100
+ replayProtection: boolean;
101
+ verification: boolean;
102
+ };
103
+ enabled: boolean;
104
+ issues: string[];
105
+ provider: VoiceTelephonyWebhookProvider;
106
+ status: 'fail' | 'pass' | 'warn';
107
+ store: VoiceTelephonyWebhookSecurityStorePreset['kind'] | 'memory';
108
+ };
109
+ export type VoiceTelephonyWebhookSecurityReport = {
110
+ generatedAt: number;
111
+ ok: boolean;
112
+ providers: VoiceTelephonyWebhookSecurityProviderStatus[];
113
+ status: 'fail' | 'pass' | 'warn';
114
+ summary: {
115
+ enabled: number;
116
+ failed: number;
117
+ passed: number;
118
+ warned: number;
119
+ };
120
+ };
121
+ export type VoiceTelephonyWebhookSecurityAssertionInput = {
122
+ maxFailedProviders?: number;
123
+ minEnabledProviders?: number;
124
+ requirePersistentStores?: boolean;
125
+ requiredProviders?: VoiceTelephonyWebhookProvider[];
126
+ };
127
+ export type VoiceTelephonyWebhookSecurityAssertionReport = {
128
+ failedProviders: VoiceTelephonyWebhookProvider[];
129
+ issues: string[];
130
+ ok: boolean;
131
+ passingProviders: VoiceTelephonyWebhookProvider[];
132
+ status: VoiceTelephonyWebhookSecurityReport['status'];
133
+ };
134
+ export type VoiceTelephonyWebhookSecurityRoutesOptions<TResult = unknown> = {
135
+ name?: string;
136
+ options: VoiceTelephonyWebhookSecurityOptions<TResult>;
137
+ path?: string;
138
+ };
139
+ export declare const buildVoiceTelephonyWebhookSecurityReport: <TResult = unknown>(options?: VoiceTelephonyWebhookSecurityOptions<TResult>) => VoiceTelephonyWebhookSecurityReport;
140
+ export declare const evaluateVoiceTelephonyWebhookSecurityEvidence: (report: VoiceTelephonyWebhookSecurityReport, input?: VoiceTelephonyWebhookSecurityAssertionInput) => VoiceTelephonyWebhookSecurityAssertionReport;
141
+ export declare const assertVoiceTelephonyWebhookSecurityEvidence: (report: VoiceTelephonyWebhookSecurityReport, input?: VoiceTelephonyWebhookSecurityAssertionInput) => VoiceTelephonyWebhookSecurityAssertionReport;
142
+ export declare const createVoiceTelephonyWebhookSecurityRoutes: <TResult = unknown>(options: VoiceTelephonyWebhookSecurityRoutesOptions<TResult>) => Elysia<"", {
143
+ decorator: {};
144
+ store: {};
145
+ derive: {};
146
+ resolve: {};
147
+ }, {
148
+ typebox: {};
149
+ error: {};
150
+ }, {
151
+ schema: {};
152
+ standaloneSchema: {};
153
+ macro: {};
154
+ macroFn: {};
155
+ parser: {};
156
+ response: {};
157
+ }, {
158
+ [x: string]: {
159
+ get: {
160
+ body: unknown;
161
+ params: {};
162
+ query: unknown;
163
+ headers: unknown;
164
+ response: {
165
+ 200: VoiceTelephonyWebhookSecurityReport;
166
+ };
167
+ };
168
+ };
169
+ }, {
170
+ derive: {};
171
+ resolve: {};
172
+ schema: {};
173
+ standaloneSchema: {};
174
+ response: {};
175
+ }, {
176
+ derive: {};
177
+ resolve: {};
178
+ schema: {};
179
+ standaloneSchema: {};
180
+ response: {};
181
+ }>;
95
182
  export declare const createVoiceTelephonyWebhookSecurityPreset: <TResult = unknown>(options?: VoiceTelephonyWebhookSecurityOptions<TResult>) => VoiceTelephonyWebhookSecurityPreset<TResult>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.273",
3
+ "version": "0.0.22-beta.275",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",