@agentisend/sdk-node 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/README.md +97 -0
- package/dist/cli/args.d.ts +24 -0
- package/dist/cli/args.js +71 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/commands.d.ts +29 -0
- package/dist/cli/commands.js +147 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/config.d.ts +31 -0
- package/dist/cli/config.js +73 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/doctor.d.ts +36 -0
- package/dist/cli/doctor.js +161 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/listen.d.ts +28 -0
- package/dist/cli/listen.js +140 -0
- package/dist/cli/listen.js.map +1 -0
- package/dist/cli/main.d.ts +14 -0
- package/dist/cli/main.js +369 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.d.ts +40 -0
- package/dist/cli/output.js +35 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/scheduled-at.d.ts +19 -0
- package/dist/cli/scheduled-at.js +108 -0
- package/dist/cli/scheduled-at.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +17 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +426 -0
- package/dist/client.js +542 -0
- package/dist/client.js.map +1 -0
- package/dist/compat-resend.d.ts +194 -0
- package/dist/compat-resend.js +233 -0
- package/dist/compat-resend.js.map +1 -0
- package/dist/errors.d.ts +82 -0
- package/dist/errors.js +92 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +499 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +8 -0
- package/dist/version.js +9 -0
- package/dist/version.js.map +1 -0
- package/dist/webhook-signing.d.ts +64 -0
- package/dist/webhook-signing.js +125 -0
- package/dist/webhook-signing.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Webhook signing — Stripe-shaped HMAC-SHA256.
|
|
4
|
+
*
|
|
5
|
+
* Header value format: `t=<unix seconds>,v1=<hmac_hex>`
|
|
6
|
+
* where hmac = HMAC-SHA256(secret, `${t}.${raw_body}`).
|
|
7
|
+
*
|
|
8
|
+
* Ported from a proven webhook-signing.ts; branding
|
|
9
|
+
* renamed X-Warmy-* -> X-AgentiSend-*, timestamps are unix seconds
|
|
10
|
+
* per the AgentiSend wire spec (PRD F4 / B2).
|
|
11
|
+
*/
|
|
12
|
+
/** 5-minute tolerance window for signature freshness. */
|
|
13
|
+
export const SIGNATURE_TOLERANCE_SECONDS = 5 * 60;
|
|
14
|
+
export const SIGNATURE_HEADER = 'x-agentisend-signature';
|
|
15
|
+
export const EVENT_ID_HEADER = 'x-agentisend-event-id';
|
|
16
|
+
export const EVENT_TYPE_HEADER = 'x-agentisend-event-type';
|
|
17
|
+
export const TIMESTAMP_HEADER = 'x-agentisend-timestamp';
|
|
18
|
+
export const REPLAY_HEADER = 'x-agentisend-replay';
|
|
19
|
+
/**
|
|
20
|
+
* M5.11 — Svix's header set, beside ours, opt-in per endpoint.
|
|
21
|
+
*
|
|
22
|
+
* A receiver migrating from Resend already has a verifier: the `svix` library,
|
|
23
|
+
* or the twenty lines it documents. Making them rewrite it to accept our
|
|
24
|
+
* header is a migration cost with nothing on the other side of it, so an
|
|
25
|
+
* endpoint can ask for both and keep the verifier it has.
|
|
26
|
+
*
|
|
27
|
+
* The scheme is Svix's, exactly: HMAC-SHA256 over `${id}.${timestamp}.${body}`
|
|
28
|
+
* with the key being the base64-decoded bytes after the `whsec_` prefix, and
|
|
29
|
+
* the value a space-separated list of `v1,<base64>` — a list because Svix
|
|
30
|
+
* rotates by sending old and new signatures together.
|
|
31
|
+
*/
|
|
32
|
+
export const SVIX_ID_HEADER = 'svix-id';
|
|
33
|
+
export const SVIX_TIMESTAMP_HEADER = 'svix-timestamp';
|
|
34
|
+
export const SVIX_SIGNATURE_HEADER = 'svix-signature';
|
|
35
|
+
/** The key bytes Svix derives from a `whsec_`-prefixed secret. */
|
|
36
|
+
function svixKey(secret) {
|
|
37
|
+
const raw = secret.startsWith('whsec_') ? secret.slice('whsec_'.length) : secret;
|
|
38
|
+
return Buffer.from(raw, 'base64');
|
|
39
|
+
}
|
|
40
|
+
/** `v1,<base64 hmac>` over `${messageId}.${timestampSeconds}.${body}`. */
|
|
41
|
+
export function signSvixPayload(secret, messageId, timestampSeconds, body) {
|
|
42
|
+
const hmac = crypto.createHmac('sha256', svixKey(secret));
|
|
43
|
+
hmac.update(`${messageId}.${timestampSeconds}.${body}`);
|
|
44
|
+
return `v1,${hmac.digest('base64')}`;
|
|
45
|
+
}
|
|
46
|
+
/** The three headers a Svix-shaped verifier reads. */
|
|
47
|
+
export function generateSvixHeaders(secret, messageId, timestampSeconds, body) {
|
|
48
|
+
return {
|
|
49
|
+
[SVIX_ID_HEADER]: messageId,
|
|
50
|
+
[SVIX_TIMESTAMP_HEADER]: String(timestampSeconds),
|
|
51
|
+
[SVIX_SIGNATURE_HEADER]: signSvixPayload(secret, messageId, timestampSeconds, body),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Sign a raw body at a given unix-second timestamp. Pure. */
|
|
55
|
+
export function signWebhookPayload(secret, timestampSeconds, body) {
|
|
56
|
+
const hmac = crypto.createHmac('sha256', secret);
|
|
57
|
+
hmac.update(`${timestampSeconds}.${body}`);
|
|
58
|
+
return `t=${timestampSeconds},v1=${hmac.digest('hex')}`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Verify a signature header against a raw body. Timing-safe on the
|
|
62
|
+
* comparison path; every malformed input returns false, never throws.
|
|
63
|
+
*/
|
|
64
|
+
export function verifyWebhookSignature(secret, signatureHeader, body, options = {}) {
|
|
65
|
+
const nowSeconds = options.nowSeconds ?? Math.floor(Date.now() / 1000);
|
|
66
|
+
const toleranceSeconds = options.toleranceSeconds ?? SIGNATURE_TOLERANCE_SECONDS;
|
|
67
|
+
try {
|
|
68
|
+
let timestamp = null;
|
|
69
|
+
let signature = null;
|
|
70
|
+
for (const part of signatureHeader.split(',')) {
|
|
71
|
+
const eq = part.indexOf('=');
|
|
72
|
+
if (eq === -1)
|
|
73
|
+
continue;
|
|
74
|
+
const key = part.slice(0, eq).trim();
|
|
75
|
+
const value = part.slice(eq + 1).trim();
|
|
76
|
+
if (key === 't') {
|
|
77
|
+
timestamp = Number.parseInt(value, 10);
|
|
78
|
+
if (Number.isNaN(timestamp))
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
else if (key === 'v1') {
|
|
82
|
+
signature = value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (timestamp === null || timestamp <= 0 || signature === null) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
if (Math.abs(nowSeconds - timestamp) > toleranceSeconds) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
const hmac = crypto.createHmac('sha256', secret);
|
|
92
|
+
hmac.update(`${timestamp}.${body}`);
|
|
93
|
+
const expected = Buffer.from(hmac.digest('hex'), 'hex');
|
|
94
|
+
// Hex-decoding arbitrary input can yield a buffer of any length;
|
|
95
|
+
// timingSafeEqual throws on length mismatch, so guard first.
|
|
96
|
+
const provided = Buffer.from(signature, 'hex');
|
|
97
|
+
if (provided.length !== expected.length) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return crypto.timingSafeEqual(provided, expected);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Full delivery header set for an event payload. */
|
|
107
|
+
export function generateWebhookHeaders(eventId, eventType, timestampSeconds, signature, replay = false, options = {}) {
|
|
108
|
+
const headers = {
|
|
109
|
+
'content-type': 'application/json',
|
|
110
|
+
[EVENT_ID_HEADER]: eventId,
|
|
111
|
+
[EVENT_TYPE_HEADER]: eventType,
|
|
112
|
+
[TIMESTAMP_HEADER]: String(timestampSeconds),
|
|
113
|
+
[SIGNATURE_HEADER]: signature,
|
|
114
|
+
};
|
|
115
|
+
if (replay) {
|
|
116
|
+
headers[REPLAY_HEADER] = 'true';
|
|
117
|
+
}
|
|
118
|
+
if (options.svixCompat) {
|
|
119
|
+
// Beside, never instead: an endpoint that opted in still gets our header,
|
|
120
|
+
// so turning the flag on cannot break a receiver that reads it.
|
|
121
|
+
Object.assign(headers, generateSvixHeaders(options.svixCompat.secret, eventId, timestampSeconds, options.svixCompat.body));
|
|
122
|
+
}
|
|
123
|
+
return headers;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=webhook-signing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-signing.js","sourceRoot":"","sources":["../src/webhook-signing.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentisend/sdk-node",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Typed Node client for the AgentiSend API.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://agentisend.com/docs",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"email": "hello@agentisend.com"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/fortuneflick/agentisend-claude-plugin.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"email",
|
|
17
|
+
"email-api",
|
|
18
|
+
"transactional-email",
|
|
19
|
+
"webhooks",
|
|
20
|
+
"agents",
|
|
21
|
+
"resend-alternative"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=20"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"bin": {
|
|
30
|
+
"agentisend": "./dist/cli.js"
|
|
31
|
+
},
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"default": "./dist/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./compat-resend": {
|
|
38
|
+
"types": "./dist/compat-resend.d.ts",
|
|
39
|
+
"default": "./dist/compat-resend.js"
|
|
40
|
+
},
|
|
41
|
+
"./cli-commands": {
|
|
42
|
+
"types": "./dist/cli/commands.d.ts",
|
|
43
|
+
"default": "./dist/cli/commands.js"
|
|
44
|
+
},
|
|
45
|
+
"./webhook-signing": {
|
|
46
|
+
"types": "./dist/webhook-signing.d.ts",
|
|
47
|
+
"default": "./dist/webhook-signing.js"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"dist",
|
|
52
|
+
"README.md"
|
|
53
|
+
],
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsc -p tsconfig.build.json",
|
|
56
|
+
"typecheck": "tsc --noEmit",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"prepublishOnly": "pnpm run build"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"fastify": "^5.12.1",
|
|
62
|
+
"typescript": "^5.6.0",
|
|
63
|
+
"vitest": "^3.0.0"
|
|
64
|
+
}
|
|
65
|
+
}
|