@voiflow/sdk 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +82 -2
- package/dist/cjs/client.js +43 -0
- package/dist/cjs/errors.js +49 -0
- package/dist/cjs/http.js +280 -0
- package/dist/cjs/index.js +17 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/pagination.js +15 -0
- package/dist/cjs/resources.generated.js +573 -0
- package/dist/cjs/sse.js +46 -0
- package/dist/cjs/webhooks.js +46 -0
- package/dist/client.d.ts +14 -0
- package/dist/client.js +18 -0
- package/dist/errors.d.ts +37 -0
- package/dist/errors.js +43 -0
- package/dist/http.d.ts +66 -0
- package/dist/http.js +276 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/pagination.d.ts +7 -0
- package/dist/pagination.js +12 -0
- package/dist/resources.generated.d.ts +1999 -0
- package/dist/resources.generated.js +544 -0
- package/dist/sse.d.ts +7 -0
- package/dist/sse.js +43 -0
- package/dist/webhooks.d.ts +26 -0
- package/dist/webhooks.js +40 -0
- package/package.json +45 -4
package/dist/webhooks.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
export const SIGNATURE_HEADER = "VoiFlow-Signature";
|
|
3
|
+
export class WebhookSignatureError extends Error {
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Verifies `VoiFlow-Signature: t=<unix_seconds>,v1=<hex_hmac_sha256>` against the raw request
|
|
7
|
+
* body bytes. Signed payload is the UTF-8 timestamp, a literal period, then the raw bytes.
|
|
8
|
+
*/
|
|
9
|
+
export function verifyWebhookSignature(rawBody, signatureHeader, secret, options = {}) {
|
|
10
|
+
const tolerance = options.toleranceSeconds ?? 300;
|
|
11
|
+
const now = options.now ?? (() => Date.now() / 1000);
|
|
12
|
+
const parts = Object.fromEntries(signatureHeader.split(",").map((part) => {
|
|
13
|
+
const [key, value] = part.split("=", 2);
|
|
14
|
+
return [key, value];
|
|
15
|
+
}));
|
|
16
|
+
const timestamp = parts["t"];
|
|
17
|
+
const signature = parts["v1"];
|
|
18
|
+
if (!timestamp || !signature) {
|
|
19
|
+
throw new WebhookSignatureError("Malformed VoiFlow-Signature header.");
|
|
20
|
+
}
|
|
21
|
+
const timestampSeconds = Number(timestamp);
|
|
22
|
+
if (!Number.isFinite(timestampSeconds) || Math.abs(now() - timestampSeconds) > tolerance) {
|
|
23
|
+
throw new WebhookSignatureError("Webhook timestamp is outside the allowed tolerance.");
|
|
24
|
+
}
|
|
25
|
+
const signedPayload = Buffer.concat([
|
|
26
|
+
Buffer.from(timestamp, "utf8"),
|
|
27
|
+
Buffer.from(".", "utf8"),
|
|
28
|
+
Buffer.from(rawBody),
|
|
29
|
+
]);
|
|
30
|
+
const expected = createHmac("sha256", secret).update(signedPayload).digest("hex");
|
|
31
|
+
const expectedBuf = Buffer.from(expected, "utf8");
|
|
32
|
+
const actualBuf = Buffer.from(signature, "utf8");
|
|
33
|
+
if (expectedBuf.length !== actualBuf.length || !timingSafeEqual(expectedBuf, actualBuf)) {
|
|
34
|
+
throw new WebhookSignatureError("Webhook signature does not match.");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Parses the verified webhook body. Call verifyWebhookSignature first. */
|
|
38
|
+
export function parseWebhookEvent(rawBody) {
|
|
39
|
+
return JSON.parse(Buffer.from(rawBody).toString("utf8"));
|
|
40
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voiflow/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "VoiFlow 4.0 server-side SDK for the public /v1 API: businesses, agents, journeys, calls, conversations, campaigns, AI work, webhooks.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://voiflow.ai",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"voiflow",
|
|
9
|
+
"voice",
|
|
10
|
+
"ai",
|
|
11
|
+
"phone",
|
|
12
|
+
"calls",
|
|
13
|
+
"sdk",
|
|
14
|
+
"api"
|
|
15
|
+
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "./dist/cjs/index.js",
|
|
18
|
+
"module": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"require": "./dist/cjs/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "rm -rf dist && tsc -p tsconfig.json && tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
|
|
40
|
+
"check": "node --test test/*.test.mjs",
|
|
41
|
+
"prepack": "npm run build"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"typescript": "^5.6.0",
|
|
45
|
+
"@types/node": "^20.0.0"
|
|
46
|
+
}
|
|
47
|
+
}
|