@absolutejs/voice 0.0.22-beta.484 → 0.0.22-beta.485
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 +2 -0
- package/dist/index.js +80 -4
- package/dist/webhookVerification.d.ts +27 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -80,6 +80,8 @@ export type { CreateVoiceCostAccountantOptions, VoiceCostAccountant, VoiceCostBr
|
|
|
80
80
|
export { describeVoiceAssistantMode, resolveVoiceAssistantMode, } from "./assistantMode";
|
|
81
81
|
export type { VoiceAssistantMode, VoiceAssistantModality, VoiceAssistantModeDescriptor, VoiceSemanticVADConfig, } from "./assistantMode";
|
|
82
82
|
export { createPunctuationSemanticTurnDetector, createRegexSemanticTurnDetector, } from "./semanticTurn";
|
|
83
|
+
export { VOICE_WEBHOOK_SIGNATURE_HEADER, VOICE_WEBHOOK_TIMESTAMP_HEADER, extractVoiceWebhookSignatureFromHeaders, signVoiceWebhookBody, verifyVoiceWebhookSignature, } from "./webhookVerification";
|
|
84
|
+
export type { VoiceWebhookVerificationInput, VoiceWebhookVerificationReason, VoiceWebhookVerificationResult, } from "./webhookVerification";
|
|
83
85
|
export type { CreatePunctuationSemanticTurnDetectorOptions, CreateRegexSemanticTurnDetectorOptions, VoiceSemanticTurnDetector, VoiceSemanticTurnInput, VoiceSemanticTurnVerdict, } from "./semanticTurn";
|
|
84
86
|
export { createMonologueAMDDetector } from "./amdDetector";
|
|
85
87
|
export type { MonologueAMDDetectorOptions, VoiceAMDDetector, VoiceAMDDetectorInput, VoiceAMDVerdict, } from "./amdDetector";
|
package/dist/index.js
CHANGED
|
@@ -35404,6 +35404,77 @@ var createRegexSemanticTurnDetector = (options) => {
|
|
|
35404
35404
|
}
|
|
35405
35405
|
};
|
|
35406
35406
|
};
|
|
35407
|
+
// src/webhookVerification.ts
|
|
35408
|
+
var VOICE_WEBHOOK_SIGNATURE_HEADER = "x-absolutejs-signature";
|
|
35409
|
+
var VOICE_WEBHOOK_TIMESTAMP_HEADER = "x-absolutejs-timestamp";
|
|
35410
|
+
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
35411
|
+
var timingSafeEqual3 = (left, right) => {
|
|
35412
|
+
if (left.length !== right.length) {
|
|
35413
|
+
return false;
|
|
35414
|
+
}
|
|
35415
|
+
let result = 0;
|
|
35416
|
+
for (let index = 0;index < left.length; index += 1) {
|
|
35417
|
+
result |= left.charCodeAt(index) ^ right.charCodeAt(index);
|
|
35418
|
+
}
|
|
35419
|
+
return result === 0;
|
|
35420
|
+
};
|
|
35421
|
+
var computeSignature = async (input) => {
|
|
35422
|
+
const encoder2 = new TextEncoder;
|
|
35423
|
+
const key = await crypto.subtle.importKey("raw", encoder2.encode(input.secret), { hash: "SHA-256", name: "HMAC" }, false, ["sign"]);
|
|
35424
|
+
const payload = encoder2.encode(`${input.timestamp}.${input.body}`);
|
|
35425
|
+
const signature = await crypto.subtle.sign("HMAC", key, payload);
|
|
35426
|
+
return `sha256=${toHex6(new Uint8Array(signature))}`;
|
|
35427
|
+
};
|
|
35428
|
+
var signVoiceWebhookBody = async (input) => computeSignature(input);
|
|
35429
|
+
var verifyVoiceWebhookSignature = async (input) => {
|
|
35430
|
+
if (!input.secret) {
|
|
35431
|
+
return { ok: false, reason: "missing-secret" };
|
|
35432
|
+
}
|
|
35433
|
+
if (!input.signature) {
|
|
35434
|
+
return { ok: false, reason: "missing-signature" };
|
|
35435
|
+
}
|
|
35436
|
+
if (!input.signature.startsWith("sha256=")) {
|
|
35437
|
+
return { ok: false, reason: "unsupported-algorithm" };
|
|
35438
|
+
}
|
|
35439
|
+
if (!input.timestamp) {
|
|
35440
|
+
return { ok: false, reason: "missing-timestamp" };
|
|
35441
|
+
}
|
|
35442
|
+
const timestampMs = Number(input.timestamp);
|
|
35443
|
+
const toleranceMs = Math.max(0, input.toleranceMs ?? 5 * 60 * 1000);
|
|
35444
|
+
if (!Number.isFinite(timestampMs) || toleranceMs > 0 && Math.abs((input.now ?? Date.now()) - timestampMs) > toleranceMs) {
|
|
35445
|
+
return { ok: false, reason: "stale-timestamp" };
|
|
35446
|
+
}
|
|
35447
|
+
const expected = await computeSignature({
|
|
35448
|
+
body: input.body,
|
|
35449
|
+
secret: input.secret,
|
|
35450
|
+
timestamp: input.timestamp
|
|
35451
|
+
});
|
|
35452
|
+
if (!timingSafeEqual3(expected, input.signature)) {
|
|
35453
|
+
return { ok: false, reason: "signature-mismatch" };
|
|
35454
|
+
}
|
|
35455
|
+
return { ok: true };
|
|
35456
|
+
};
|
|
35457
|
+
var extractVoiceWebhookSignatureFromHeaders = (headers) => {
|
|
35458
|
+
const get = (name) => {
|
|
35459
|
+
if (headers instanceof Headers) {
|
|
35460
|
+
return headers.get(name);
|
|
35461
|
+
}
|
|
35462
|
+
const lowerTarget = name.toLowerCase();
|
|
35463
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
35464
|
+
if (key.toLowerCase() === lowerTarget) {
|
|
35465
|
+
if (Array.isArray(value)) {
|
|
35466
|
+
return value[0] ?? null;
|
|
35467
|
+
}
|
|
35468
|
+
return value ?? null;
|
|
35469
|
+
}
|
|
35470
|
+
}
|
|
35471
|
+
return null;
|
|
35472
|
+
};
|
|
35473
|
+
return {
|
|
35474
|
+
signature: get(VOICE_WEBHOOK_SIGNATURE_HEADER),
|
|
35475
|
+
timestamp: get(VOICE_WEBHOOK_TIMESTAMP_HEADER)
|
|
35476
|
+
};
|
|
35477
|
+
};
|
|
35407
35478
|
// src/amdDetector.ts
|
|
35408
35479
|
var createMonologueAMDDetector = (options = {}) => {
|
|
35409
35480
|
const minMonologueMs = options.minMonologueMs ?? 8000;
|
|
@@ -41951,7 +42022,7 @@ var createVoiceMemoryStore = () => {
|
|
|
41951
42022
|
};
|
|
41952
42023
|
// src/opsWebhook.ts
|
|
41953
42024
|
import { Elysia as Elysia66 } from "elysia";
|
|
41954
|
-
var
|
|
42025
|
+
var toHex7 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
41955
42026
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
41956
42027
|
const encoder2 = new TextEncoder;
|
|
41957
42028
|
const key = await crypto.subtle.importKey("raw", encoder2.encode(input.secret), {
|
|
@@ -41959,9 +42030,9 @@ var signVoiceOpsWebhookBody = async (input) => {
|
|
|
41959
42030
|
name: "HMAC"
|
|
41960
42031
|
}, false, ["sign"]);
|
|
41961
42032
|
const signature = await crypto.subtle.sign("HMAC", key, encoder2.encode(`${input.timestamp}.${input.body}`));
|
|
41962
|
-
return `sha256=${
|
|
42033
|
+
return `sha256=${toHex7(new Uint8Array(signature))}`;
|
|
41963
42034
|
};
|
|
41964
|
-
var
|
|
42035
|
+
var timingSafeEqual4 = (left, right) => {
|
|
41965
42036
|
const encoder2 = new TextEncoder;
|
|
41966
42037
|
const leftBytes = encoder2.encode(left);
|
|
41967
42038
|
const rightBytes = encoder2.encode(right);
|
|
@@ -42068,7 +42139,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
42068
42139
|
secret: input.secret,
|
|
42069
42140
|
timestamp: input.timestamp
|
|
42070
42141
|
});
|
|
42071
|
-
if (!
|
|
42142
|
+
if (!timingSafeEqual4(expected, input.signature)) {
|
|
42072
42143
|
return {
|
|
42073
42144
|
ok: false,
|
|
42074
42145
|
reason: "invalid-signature"
|
|
@@ -45977,6 +46048,7 @@ export {
|
|
|
45977
46048
|
voiceGuardrailPolicyPresets,
|
|
45978
46049
|
voiceComplianceRedactionDefaults,
|
|
45979
46050
|
voice,
|
|
46051
|
+
verifyVoiceWebhookSignature,
|
|
45980
46052
|
verifyVoiceTwilioWebhookSignature,
|
|
45981
46053
|
verifyVoiceTelnyxWebhookSignature,
|
|
45982
46054
|
verifyVoicePlivoWebhookSignature,
|
|
@@ -46020,6 +46092,7 @@ export {
|
|
|
46020
46092
|
summarizeVoiceAssistantRuns,
|
|
46021
46093
|
summarizeVoiceAssistantHealth,
|
|
46022
46094
|
startVoiceOpsTask,
|
|
46095
|
+
signVoiceWebhookBody,
|
|
46023
46096
|
signVoiceTwilioWebhook,
|
|
46024
46097
|
signVoicePlivoWebhook,
|
|
46025
46098
|
shapeTelephonyAssistantText,
|
|
@@ -46219,6 +46292,7 @@ export {
|
|
|
46219
46292
|
filterVoiceAuditEvents,
|
|
46220
46293
|
fetchVoiceProofTarget,
|
|
46221
46294
|
failVoiceOpsTask,
|
|
46295
|
+
extractVoiceWebhookSignatureFromHeaders,
|
|
46222
46296
|
extractVoiceMediaPipelineIssueEntries,
|
|
46223
46297
|
exportVoiceTrace,
|
|
46224
46298
|
exportVoiceAuditTrail,
|
|
@@ -46765,6 +46839,8 @@ export {
|
|
|
46765
46839
|
appendVoiceProviderRouterTraceEvent,
|
|
46766
46840
|
appendVoiceIOProviderRouterTraceEvent,
|
|
46767
46841
|
acknowledgeVoiceMonitorIssue,
|
|
46842
|
+
VOICE_WEBHOOK_TIMESTAMP_HEADER,
|
|
46843
|
+
VOICE_WEBHOOK_SIGNATURE_HEADER,
|
|
46768
46844
|
VOICE_LIVE_OPS_ACTIONS,
|
|
46769
46845
|
TURN_PROFILE_DEFAULTS,
|
|
46770
46846
|
DEFAULT_VOICE_REDACTION_PATTERNS,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type VoiceWebhookVerificationReason = "missing-secret" | "missing-signature" | "missing-timestamp" | "signature-mismatch" | "stale-timestamp" | "unsupported-algorithm";
|
|
2
|
+
export type VoiceWebhookVerificationResult = {
|
|
3
|
+
ok: true;
|
|
4
|
+
} | {
|
|
5
|
+
ok: false;
|
|
6
|
+
reason: VoiceWebhookVerificationReason;
|
|
7
|
+
};
|
|
8
|
+
export type VoiceWebhookVerificationInput = {
|
|
9
|
+
body: string;
|
|
10
|
+
now?: number;
|
|
11
|
+
secret?: string;
|
|
12
|
+
signature?: string | null;
|
|
13
|
+
timestamp?: string | null;
|
|
14
|
+
toleranceMs?: number;
|
|
15
|
+
};
|
|
16
|
+
export declare const VOICE_WEBHOOK_SIGNATURE_HEADER = "x-absolutejs-signature";
|
|
17
|
+
export declare const VOICE_WEBHOOK_TIMESTAMP_HEADER = "x-absolutejs-timestamp";
|
|
18
|
+
export declare const signVoiceWebhookBody: (input: {
|
|
19
|
+
body: string;
|
|
20
|
+
secret: string;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
}) => Promise<string>;
|
|
23
|
+
export declare const verifyVoiceWebhookSignature: (input: VoiceWebhookVerificationInput) => Promise<VoiceWebhookVerificationResult>;
|
|
24
|
+
export declare const extractVoiceWebhookSignatureFromHeaders: (headers: Headers | Record<string, string | string[] | undefined>) => {
|
|
25
|
+
signature: string | null;
|
|
26
|
+
timestamp: string | null;
|
|
27
|
+
};
|