@zap-studio/webhooks 0.1.2 → 0.1.4
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/CHANGELOG.md +14 -0
- package/bin/intent.js +4 -0
- package/package.json +11 -5
- package/skills/zap-webhooks-routing-and-verification/SKILL.md +171 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @zap-studio/webhooks
|
|
2
2
|
|
|
3
|
+
## 0.1.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e26293e: Updated dependencies.
|
|
8
|
+
- @zap-studio/validation@0.3.2
|
|
9
|
+
|
|
10
|
+
## 0.1.3
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 5ea3d3b: Updated dependencies.
|
|
15
|
+
- @zap-studio/validation@0.3.1
|
|
16
|
+
|
|
3
17
|
## 0.1.2
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/bin/intent.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zap-studio/webhooks",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -33,11 +33,14 @@
|
|
|
33
33
|
"dist",
|
|
34
34
|
"CHANGELOG.md",
|
|
35
35
|
"LICENSE",
|
|
36
|
-
"README.md"
|
|
36
|
+
"README.md",
|
|
37
|
+
"skills",
|
|
38
|
+
"bin",
|
|
39
|
+
"!skills/_artifacts"
|
|
37
40
|
],
|
|
38
41
|
"dependencies": {
|
|
39
42
|
"@standard-schema/spec": "^1.1.0",
|
|
40
|
-
"@zap-studio/validation": "0.3.
|
|
43
|
+
"@zap-studio/validation": "0.3.2"
|
|
41
44
|
},
|
|
42
45
|
"devDependencies": {
|
|
43
46
|
"@types/node": "^25.0.2",
|
|
@@ -46,9 +49,9 @@
|
|
|
46
49
|
"typescript": "^5.9.3",
|
|
47
50
|
"vitest": "^4.0.18",
|
|
48
51
|
"zod": "^4.2.0",
|
|
52
|
+
"@zap-studio/typescript-config": "0.0.0",
|
|
49
53
|
"@zap-studio/vitest-config": "0.0.0",
|
|
50
|
-
"@zap-studio/tsdown-config": "0.0.0"
|
|
51
|
-
"@zap-studio/typescript-config": "0.0.0"
|
|
54
|
+
"@zap-studio/tsdown-config": "0.0.0"
|
|
52
55
|
},
|
|
53
56
|
"exports": {
|
|
54
57
|
".": "./dist/index.mjs",
|
|
@@ -61,6 +64,9 @@
|
|
|
61
64
|
"main": "./dist/index.mjs",
|
|
62
65
|
"module": "./dist/index.mjs",
|
|
63
66
|
"types": "./dist/index.d.mts",
|
|
67
|
+
"bin": {
|
|
68
|
+
"intent": "./bin/intent.js"
|
|
69
|
+
},
|
|
64
70
|
"scripts": {
|
|
65
71
|
"build": "tsdown --config tsdown.config.ts",
|
|
66
72
|
"typecheck": "tsc --noEmit",
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zap-webhooks-routing-and-verification
|
|
3
|
+
description: >
|
|
4
|
+
Build webhook ingestion with @zap-studio/webhooks using createWebhookRouter,
|
|
5
|
+
register path keys, prefix normalization, schema validation, lifecycle hooks,
|
|
6
|
+
createHmacVerifier, and BaseAdapter request/response mapping.
|
|
7
|
+
type: core
|
|
8
|
+
library: '@zap-studio/webhooks'
|
|
9
|
+
library_version: '0.1.3'
|
|
10
|
+
sources:
|
|
11
|
+
- 'zap-studio/monorepo:packages/webhooks/README.md'
|
|
12
|
+
- 'zap-studio/monorepo:packages/webhooks/src/index.ts'
|
|
13
|
+
- 'zap-studio/monorepo:packages/webhooks/src/verify.ts'
|
|
14
|
+
- 'zap-studio/monorepo:packages/webhooks/src/adapters/base.ts'
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# @zap-studio/webhooks — Routing and Verification
|
|
18
|
+
|
|
19
|
+
## Setup
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { createWebhookRouter } from '@zap-studio/webhooks';
|
|
23
|
+
import { createHmacVerifier } from '@zap-studio/webhooks/verify';
|
|
24
|
+
import { z } from 'zod';
|
|
25
|
+
|
|
26
|
+
const router = createWebhookRouter({
|
|
27
|
+
prefix: '/webhooks/',
|
|
28
|
+
verify: createHmacVerifier({
|
|
29
|
+
headerName: 'x-hub-signature-256',
|
|
30
|
+
secret: process.env.WEBHOOK_SECRET!,
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
router.register('github/push', {
|
|
35
|
+
schema: z.object({ ref: z.string() }),
|
|
36
|
+
handler: async ({ payload, ack }) => {
|
|
37
|
+
console.log(payload.ref);
|
|
38
|
+
return ack({ status: 200, body: 'ok' });
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Core Patterns
|
|
44
|
+
|
|
45
|
+
### Add global hooks for observability and error shaping
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const router = createWebhookRouter({
|
|
49
|
+
before: (req) => {
|
|
50
|
+
console.log('incoming', req.path);
|
|
51
|
+
},
|
|
52
|
+
after: (_req, res) => {
|
|
53
|
+
console.log('status', res.status);
|
|
54
|
+
},
|
|
55
|
+
onError: (error) => ({
|
|
56
|
+
status: 500,
|
|
57
|
+
body: { error: error.message },
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Register route-specific hooks
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
router.register('payments/succeeded', {
|
|
66
|
+
schema: PaymentSchema,
|
|
67
|
+
before: (req) => {
|
|
68
|
+
req.headers.set('x-processed', '1');
|
|
69
|
+
},
|
|
70
|
+
after: (_req, res) => {
|
|
71
|
+
console.log('finished', res.status);
|
|
72
|
+
},
|
|
73
|
+
handler: async ({ payload, ack }) => ack({ body: { id: payload.id } }),
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Implement an adapter with `BaseAdapter`
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { BaseAdapter } from '@zap-studio/webhooks/adapters/base';
|
|
81
|
+
|
|
82
|
+
class MyAdapter extends BaseAdapter {
|
|
83
|
+
async toNormalizedRequest(req: Request) {
|
|
84
|
+
return {
|
|
85
|
+
method: req.method,
|
|
86
|
+
path: req.url,
|
|
87
|
+
headers: req.headers,
|
|
88
|
+
rawBody: Buffer.from(await req.text()),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async toFrameworkResponse(res: Response, normalized) {
|
|
93
|
+
return new Response(JSON.stringify(normalized.body), {
|
|
94
|
+
status: normalized.status,
|
|
95
|
+
headers: normalized.headers,
|
|
96
|
+
}) as unknown as Response;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Common Mistakes
|
|
102
|
+
|
|
103
|
+
### HIGH Registering paths with leading slash
|
|
104
|
+
|
|
105
|
+
Wrong:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
router.register('/github/push', {
|
|
109
|
+
schema: PushSchema,
|
|
110
|
+
handler,
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Correct:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
router.register('github/push', {
|
|
118
|
+
schema: PushSchema,
|
|
119
|
+
handler,
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Incoming paths normalize to slashless keys; leading slash route keys do not match and return 404.
|
|
124
|
+
|
|
125
|
+
Source: zap-studio/monorepo:packages/webhooks/src/index.ts
|
|
126
|
+
|
|
127
|
+
### CRITICAL Verifying a transformed payload instead of raw body
|
|
128
|
+
|
|
129
|
+
Wrong:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
const parsed = JSON.parse(req.rawBody.toString());
|
|
133
|
+
await verifyProvider(JSON.stringify(parsed));
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Correct:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
await verify(req); // uses req.rawBody bytes
|
|
140
|
+
const parsed = JSON.parse(req.rawBody.toString());
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Signature checks must run on exact raw bytes; any parse/serialize transformation can invalidate signatures.
|
|
144
|
+
|
|
145
|
+
Source: zap-studio/monorepo:packages/webhooks/src/verify.ts
|
|
146
|
+
|
|
147
|
+
### HIGH Using Node HMAC verifier in non-Node runtime
|
|
148
|
+
|
|
149
|
+
Wrong:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const verify = createHmacVerifier({
|
|
153
|
+
headerName: 'x-signature',
|
|
154
|
+
secret: env.WEBHOOK_SECRET,
|
|
155
|
+
});
|
|
156
|
+
// used in edge runtime
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Correct:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
const verify = async (req) => {
|
|
163
|
+
// implement provider verification with Web Crypto in edge runtimes
|
|
164
|
+
};
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`createHmacVerifier` imports `node:crypto` and is intended for Node-compatible runtimes.
|
|
168
|
+
|
|
169
|
+
Source: zap-studio/monorepo:packages/webhooks/src/verify.ts
|
|
170
|
+
|
|
171
|
+
See also: zap-validation-standard-schema/SKILL.md — payload validation result handling.
|