@boltclaw/referrals 0.0.0-stage → 0.4.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 +500 -3
- package/dist/api-types.d.ts +245 -0
- package/dist/api-types.js +2 -0
- package/dist/api-types.js.map +1 -0
- package/dist/assistant-tools.d.ts +40 -0
- package/dist/assistant-tools.js +120 -0
- package/dist/assistant-tools.js.map +1 -0
- package/dist/assistant.d.ts +62 -0
- package/dist/assistant.js +305 -0
- package/dist/assistant.js.map +1 -0
- package/dist/case.d.ts +2 -0
- package/dist/case.js +30 -0
- package/dist/case.js.map +1 -0
- package/dist/client.d.ts +22 -0
- package/dist/client.js +80 -0
- package/dist/client.js.map +1 -0
- package/dist/element.d.ts +4 -0
- package/dist/element.js +204 -0
- package/dist/element.js.map +1 -0
- package/dist/errors.d.ts +19 -0
- package/dist/errors.js +62 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/api.d.ts +6477 -0
- package/dist/generated/api.js +891 -0
- package/dist/generated/api.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +118 -0
- package/dist/loader.js +524 -0
- package/dist/loader.js.map +1 -0
- package/dist/middleware.d.ts +100 -0
- package/dist/middleware.js +378 -0
- package/dist/middleware.js.map +1 -0
- package/dist/origin.d.ts +3 -0
- package/dist/origin.js +22 -0
- package/dist/origin.js.map +1 -0
- package/dist/react.d.ts +69 -0
- package/dist/react.js +328 -0
- package/dist/react.js.map +1 -0
- package/dist/server-index.d.ts +17 -0
- package/dist/server-index.js +9 -0
- package/dist/server-index.js.map +1 -0
- package/dist/server.d.ts +106 -0
- package/dist/server.js +511 -0
- package/dist/server.js.map +1 -0
- package/dist/typed-code.d.ts +78 -0
- package/dist/typed-code.js +234 -0
- package/dist/typed-code.js.map +1 -0
- package/dist/types.d.ts +254 -0
- package/dist/types.js +61 -0
- package/dist/types.js.map +1 -0
- package/dist/webhooks.d.ts +20 -0
- package/dist/webhooks.js +90 -0
- package/dist/webhooks.js.map +1 -0
- package/package.json +97 -6
package/dist/webhooks.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export class WebhookVerificationError extends Error {
|
|
2
|
+
reason;
|
|
3
|
+
constructor(reason) {
|
|
4
|
+
super(reason === "missing_header"
|
|
5
|
+
? "The delivery has no X-BoltClaw-Timestamp or X-BoltClaw-Signature header."
|
|
6
|
+
: reason === "stale"
|
|
7
|
+
? "The delivery's timestamp is outside the allowed window."
|
|
8
|
+
: reason === "bad_signature"
|
|
9
|
+
? "The delivery's signature does not match this secret."
|
|
10
|
+
: "The delivery's body is not a JSON object.");
|
|
11
|
+
this.name = "WebhookVerificationError";
|
|
12
|
+
this.reason = reason;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export const WEBHOOK_TOLERANCE_SECONDS = 300;
|
|
16
|
+
const encoder = new TextEncoder();
|
|
17
|
+
function header(headers, name) {
|
|
18
|
+
if (typeof headers.get === "function") {
|
|
19
|
+
return headers.get(name);
|
|
20
|
+
}
|
|
21
|
+
const bag = headers;
|
|
22
|
+
const wanted = name.toLowerCase();
|
|
23
|
+
for (const key of Object.keys(bag)) {
|
|
24
|
+
if (key.toLowerCase() !== wanted)
|
|
25
|
+
continue;
|
|
26
|
+
const value = bag[key];
|
|
27
|
+
return Array.isArray(value) ? (value[0] ?? null) : (value ?? null);
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function bodyBytes(raw) {
|
|
32
|
+
if (typeof raw === "string")
|
|
33
|
+
return encoder.encode(raw);
|
|
34
|
+
return raw instanceof Uint8Array ? raw : new Uint8Array(raw);
|
|
35
|
+
}
|
|
36
|
+
function sameHex(a, b) {
|
|
37
|
+
let diff = a.length ^ b.length;
|
|
38
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++)
|
|
39
|
+
diff |= (a.charCodeAt(i) || 0) ^ (b.charCodeAt(i) || 0);
|
|
40
|
+
return diff === 0;
|
|
41
|
+
}
|
|
42
|
+
async function hmacHex(secret, data) {
|
|
43
|
+
const subtle = globalThis.crypto?.subtle;
|
|
44
|
+
if (!subtle)
|
|
45
|
+
throw new Error("Web Crypto is not available in this runtime.");
|
|
46
|
+
const key = await subtle.importKey("raw", encoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
47
|
+
const copy = new Uint8Array(data.byteLength);
|
|
48
|
+
copy.set(data);
|
|
49
|
+
const mac = new Uint8Array(await subtle.sign("HMAC", key, copy));
|
|
50
|
+
let out = "";
|
|
51
|
+
for (const b of mac)
|
|
52
|
+
out += b.toString(16).padStart(2, "0");
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
export async function verifyWebhook(rawBody, headers, secret, options = {}) {
|
|
56
|
+
if (typeof secret !== "string" || secret.length === 0)
|
|
57
|
+
throw new TypeError("secret is the endpoint's signing secret.");
|
|
58
|
+
const timestamp = header(headers, "x-boltclaw-timestamp")?.trim() ?? "";
|
|
59
|
+
const signature = header(headers, "x-boltclaw-signature")?.trim() ?? "";
|
|
60
|
+
if (!timestamp || !signature)
|
|
61
|
+
throw new WebhookVerificationError("missing_header");
|
|
62
|
+
if (!/^\d{1,12}$/.test(timestamp))
|
|
63
|
+
throw new WebhookVerificationError("bad_signature");
|
|
64
|
+
const match = /^sha256=([0-9a-f]{64})$/.exec(signature);
|
|
65
|
+
if (!match)
|
|
66
|
+
throw new WebhookVerificationError("bad_signature");
|
|
67
|
+
const tolerance = options.toleranceSeconds ?? WEBHOOK_TOLERANCE_SECONDS;
|
|
68
|
+
const nowMs = options.now instanceof Date ? options.now.getTime() : typeof options.now === "number" ? options.now : Date.now();
|
|
69
|
+
if (Math.abs(Math.floor(nowMs / 1000) - Number(timestamp)) > tolerance)
|
|
70
|
+
throw new WebhookVerificationError("stale");
|
|
71
|
+
const body = bodyBytes(rawBody);
|
|
72
|
+
const prefix = encoder.encode(`${timestamp}.`);
|
|
73
|
+
const signed = new Uint8Array(prefix.byteLength + body.byteLength);
|
|
74
|
+
signed.set(prefix, 0);
|
|
75
|
+
signed.set(body, prefix.byteLength);
|
|
76
|
+
if (!sameHex(await hmacHex(secret, signed), match[1]))
|
|
77
|
+
throw new WebhookVerificationError("bad_signature");
|
|
78
|
+
let event;
|
|
79
|
+
try {
|
|
80
|
+
event = JSON.parse(new TextDecoder().decode(body));
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
throw new WebhookVerificationError("bad_body");
|
|
84
|
+
}
|
|
85
|
+
if (typeof event !== "object" || event === null || Array.isArray(event) || typeof event.event !== "string") {
|
|
86
|
+
throw new WebhookVerificationError("bad_body");
|
|
87
|
+
}
|
|
88
|
+
return event;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=webhooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../src/webhooks.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,97 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@boltclaw/referrals",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@boltclaw/referrals",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Bolt Claw referrals for your product: a typed client generated from the API's spec, report signups with both dates right, sales and refunds from your server, keep the referral code through Safari with a proxy for Next.js and Express, verify webhooks, read a program's numbers, and drop in the invite-a-friend panel (script, React or web component).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"boltclaw",
|
|
7
|
+
"bolt claw",
|
|
8
|
+
"referral",
|
|
9
|
+
"referrals",
|
|
10
|
+
"referral program",
|
|
11
|
+
"affiliate",
|
|
12
|
+
"invite a friend",
|
|
13
|
+
"refer a friend",
|
|
14
|
+
"embed",
|
|
15
|
+
"widget",
|
|
16
|
+
"react",
|
|
17
|
+
"web component",
|
|
18
|
+
"sdk",
|
|
19
|
+
"conversion tracking",
|
|
20
|
+
"webhook",
|
|
21
|
+
"middleware",
|
|
22
|
+
"nextjs",
|
|
23
|
+
"express"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"author": "Bolt Claw",
|
|
27
|
+
"homepage": "https://boltclaw.ai/docs/api",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"email": "support@boltclaw.ai"
|
|
30
|
+
},
|
|
31
|
+
"type": "module",
|
|
32
|
+
"sideEffects": [
|
|
33
|
+
"./dist/element.js"
|
|
34
|
+
],
|
|
35
|
+
"main": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"default": "./dist/index.js"
|
|
41
|
+
},
|
|
42
|
+
"./react": {
|
|
43
|
+
"types": "./dist/react.d.ts",
|
|
44
|
+
"default": "./dist/react.js"
|
|
45
|
+
},
|
|
46
|
+
"./element": {
|
|
47
|
+
"types": "./dist/element.d.ts",
|
|
48
|
+
"default": "./dist/element.js"
|
|
49
|
+
},
|
|
50
|
+
"./server": {
|
|
51
|
+
"types": "./dist/server-index.d.ts",
|
|
52
|
+
"default": "./dist/server-index.js"
|
|
53
|
+
},
|
|
54
|
+
"./api": {
|
|
55
|
+
"types": "./dist/generated/api.d.ts",
|
|
56
|
+
"default": "./dist/generated/api.js"
|
|
57
|
+
},
|
|
58
|
+
"./package.json": "./package.json"
|
|
59
|
+
},
|
|
60
|
+
"files": [
|
|
61
|
+
"dist",
|
|
62
|
+
"README.md",
|
|
63
|
+
"LICENSE"
|
|
64
|
+
],
|
|
65
|
+
"scripts": {
|
|
66
|
+
"build": "tsc",
|
|
67
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
|
|
68
|
+
"pretest": "tsc",
|
|
69
|
+
"test": "vitest run",
|
|
70
|
+
"smoke": "npm run build && node scripts/smoke.mjs",
|
|
71
|
+
"prepublishOnly": "npm run build && npm test && node scripts/smoke.mjs"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"react": ">=18"
|
|
75
|
+
},
|
|
76
|
+
"peerDependenciesMeta": {
|
|
77
|
+
"react": {
|
|
78
|
+
"optional": true
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"devDependencies": {
|
|
82
|
+
"@types/node": "20.19.33",
|
|
83
|
+
"@types/react": "19.2.7",
|
|
84
|
+
"@types/react-dom": "19.2.3",
|
|
85
|
+
"happy-dom": "20.0.11",
|
|
86
|
+
"react": "19.2.3",
|
|
87
|
+
"react-dom": "19.2.3",
|
|
88
|
+
"typescript": "5.9.3",
|
|
89
|
+
"vitest": "4.0.18"
|
|
90
|
+
},
|
|
91
|
+
"engines": {
|
|
92
|
+
"node": ">=20"
|
|
93
|
+
},
|
|
94
|
+
"publishConfig": {
|
|
95
|
+
"access": "public"
|
|
96
|
+
}
|
|
97
|
+
}
|