@better-webhook/cli 0.3.1 → 3.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 +519 -180
- package/dist/index.cjs +2331 -659
- package/dist/index.d.cts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +2351 -663
- package/package.json +19 -6
package/README.md
CHANGED
|
@@ -5,287 +5,624 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://nodejs.org/)
|
|
7
7
|
|
|
8
|
-
A
|
|
8
|
+
A modern CLI tool for webhook development, testing, and debugging. Capture incoming webhooks, replay them against your local server, manage reusable templates, and generate provider-specific signatures automatically.
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
🎯 **
|
|
12
|
+
- 🎣 **Capture** — Start a local server to capture incoming webhooks from any provider
|
|
13
|
+
- 🔄 **Replay** — Replay captured webhooks to any endpoint with full header preservation
|
|
14
|
+
- 📋 **Templates** — Download and run curated webhook templates from the community
|
|
15
|
+
- 🔐 **Signatures** — Automatic signature generation for Stripe, GitHub, Shopify, Slack, and more
|
|
16
|
+
- 🌐 **WebSocket** — Real-time capture notifications via WebSocket for dashboard integration
|
|
17
|
+
- 🎯 **Provider Detection** — Automatically identifies webhook providers from headers
|
|
18
|
+
|
|
19
|
+
## Supported Providers
|
|
20
|
+
|
|
21
|
+
| Provider | Signature Algorithm | Auto-Detection |
|
|
22
|
+
| ------------ | ------------------------------- | -------------- |
|
|
23
|
+
| Stripe | HMAC-SHA256 (`t={ts},v1={sig}`) | ✅ |
|
|
24
|
+
| GitHub | HMAC-SHA256 (`sha256={sig}`) | ✅ |
|
|
25
|
+
| Shopify | HMAC-SHA256 (Base64) | ✅ |
|
|
26
|
+
| Slack | HMAC-SHA256 (`v0={sig}`) | ✅ |
|
|
27
|
+
| Twilio | HMAC-SHA1 (Base64) | ✅ |
|
|
28
|
+
| SendGrid | HMAC-SHA256 (Base64) | ✅ |
|
|
29
|
+
| Linear | HMAC-SHA256 (Hex) | ✅ |
|
|
30
|
+
| Clerk (Svix) | HMAC-SHA256 (`v1,{sig}`) | ✅ |
|
|
31
|
+
| Discord | Ed25519 | ✅ |
|
|
32
|
+
| Custom | — | — |
|
|
18
33
|
|
|
19
34
|
## Installation
|
|
20
35
|
|
|
21
|
-
### NPM/YARN/PNPM
|
|
22
|
-
|
|
23
36
|
```bash
|
|
24
|
-
#
|
|
37
|
+
# NPM
|
|
25
38
|
npm install -g @better-webhook/cli
|
|
26
|
-
# or use with npx
|
|
27
|
-
npx @better-webhook/cli --help
|
|
28
39
|
|
|
29
|
-
#
|
|
40
|
+
# Yarn
|
|
30
41
|
yarn global add @better-webhook/cli
|
|
31
42
|
|
|
32
|
-
#
|
|
43
|
+
# PNPM
|
|
33
44
|
pnpm add -g @better-webhook/cli
|
|
45
|
+
|
|
46
|
+
# Or use with npx (no installation required)
|
|
47
|
+
npx @better-webhook/cli --help
|
|
34
48
|
```
|
|
35
49
|
|
|
36
50
|
### Verify Installation
|
|
37
51
|
|
|
38
52
|
```bash
|
|
39
|
-
better-webhook --
|
|
53
|
+
better-webhook --version
|
|
54
|
+
# 2.0.0
|
|
40
55
|
```
|
|
41
56
|
|
|
42
57
|
## Quick Start
|
|
43
58
|
|
|
44
|
-
### 1.
|
|
59
|
+
### 1. Capture Webhooks
|
|
45
60
|
|
|
46
|
-
|
|
47
|
-
# List available webhook definitions
|
|
48
|
-
better-webhook webhooks list
|
|
61
|
+
Start a local server to capture incoming webhooks:
|
|
49
62
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
better-webhook
|
|
63
|
+
```bash
|
|
64
|
+
# Start capture server on default port 3001
|
|
65
|
+
better-webhook capture
|
|
53
66
|
|
|
54
|
-
#
|
|
55
|
-
better-webhook
|
|
56
|
-
better-webhook webhooks run mywebhook --url https://example.com/hook --method POST
|
|
67
|
+
# Use a custom port
|
|
68
|
+
better-webhook capture --port 4000
|
|
57
69
|
```
|
|
58
70
|
|
|
59
|
-
|
|
71
|
+
Point your webhook provider (Stripe, GitHub, etc.) to `http://localhost:3001` or use a tunneling service like ngrok.
|
|
60
72
|
|
|
61
|
-
|
|
62
|
-
# Start capture server (default port 3001)
|
|
63
|
-
better-webhook capture
|
|
64
|
-
better-webhook capture --port 3000
|
|
73
|
+
### 2. View & Manage Captures
|
|
65
74
|
|
|
75
|
+
```bash
|
|
66
76
|
# List captured webhooks
|
|
67
|
-
better-webhook
|
|
68
|
-
better-webhook capture list --limit 20
|
|
77
|
+
better-webhook captures list
|
|
69
78
|
|
|
70
|
-
#
|
|
71
|
-
better-webhook
|
|
79
|
+
# Show detailed information about a capture
|
|
80
|
+
better-webhook captures show abc123
|
|
81
|
+
|
|
82
|
+
# Search captures
|
|
83
|
+
better-webhook captures search "github"
|
|
84
|
+
|
|
85
|
+
# Delete a capture
|
|
86
|
+
better-webhook captures delete abc123
|
|
72
87
|
```
|
|
73
88
|
|
|
74
89
|
### 3. Replay Webhooks
|
|
75
90
|
|
|
91
|
+
Replay a captured webhook to your local development server:
|
|
92
|
+
|
|
76
93
|
```bash
|
|
77
|
-
#
|
|
78
|
-
better-webhook replay
|
|
79
|
-
|
|
94
|
+
# Interactive mode (select capture and enter URL)
|
|
95
|
+
better-webhook replay
|
|
96
|
+
|
|
97
|
+
# Direct replay
|
|
98
|
+
better-webhook replay abc123 http://localhost:3000/api/webhooks/github
|
|
80
99
|
```
|
|
81
100
|
|
|
82
|
-
|
|
101
|
+
### 4. Use Templates
|
|
102
|
+
|
|
103
|
+
Download and run curated webhook templates:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# List available templates
|
|
107
|
+
better-webhook templates list
|
|
83
108
|
|
|
84
|
-
|
|
109
|
+
# Download a template
|
|
110
|
+
better-webhook templates download github-push
|
|
85
111
|
|
|
86
|
-
|
|
112
|
+
# Run a template against your endpoint
|
|
113
|
+
better-webhook run github-push --url http://localhost:3000/webhooks/github
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
87
117
|
|
|
88
|
-
|
|
89
|
-
| -------------------------- | ---------------------------------- | ------------------- |
|
|
90
|
-
| `webhooks list` | List available webhook definitions | - |
|
|
91
|
-
| `webhooks run <name>` | Execute a webhook definition | `--url`, `--method` |
|
|
92
|
-
| `webhooks download [name]` | Download community templates | `--all`, `--force` |
|
|
118
|
+
## Commands Reference
|
|
93
119
|
|
|
94
120
|
### `better-webhook capture`
|
|
95
121
|
|
|
96
|
-
|
|
122
|
+
Start a server to capture incoming webhooks. All captured webhooks are saved to `~/.better-webhook/captures/`.
|
|
97
123
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
| `capture list` | List captured webhook requests | `--limit` |
|
|
102
|
-
| `capture template <id> [name]` | Generate template from capture | `--url`, `--output-dir` |
|
|
124
|
+
```bash
|
|
125
|
+
better-webhook capture [options]
|
|
126
|
+
```
|
|
103
127
|
|
|
104
|
-
|
|
128
|
+
| Option | Description | Default |
|
|
129
|
+
| ------------------- | ----------------- | --------- |
|
|
130
|
+
| `-p, --port <port>` | Port to listen on | `3001` |
|
|
131
|
+
| `-h, --host <host>` | Host to bind to | `0.0.0.0` |
|
|
105
132
|
|
|
106
|
-
|
|
133
|
+
**Features:**
|
|
107
134
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
135
|
+
- Automatically detects webhook provider from headers
|
|
136
|
+
- Saves full request including headers, body, query params
|
|
137
|
+
- WebSocket server for real-time notifications
|
|
138
|
+
- Returns capture ID in response for easy reference
|
|
111
139
|
|
|
112
|
-
|
|
140
|
+
**Example:**
|
|
113
141
|
|
|
114
|
-
|
|
142
|
+
```bash
|
|
143
|
+
better-webhook capture --port 4000 --host localhost
|
|
144
|
+
```
|
|
115
145
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### `better-webhook captures` (alias: `c`)
|
|
149
|
+
|
|
150
|
+
Manage captured webhooks.
|
|
151
|
+
|
|
152
|
+
#### `captures list` (alias: `ls`)
|
|
153
|
+
|
|
154
|
+
List captured webhooks, sorted by most recent first.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
better-webhook captures list [options]
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
| Option | Description | Default |
|
|
161
|
+
| --------------------------- | ----------------------------------------- | ------- |
|
|
162
|
+
| `-l, --limit <limit>` | Maximum captures to show | `20` |
|
|
163
|
+
| `-p, --provider <provider>` | Filter by provider (stripe, github, etc.) | — |
|
|
164
|
+
|
|
165
|
+
#### `captures show <captureId>`
|
|
166
|
+
|
|
167
|
+
Show detailed information about a specific capture.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
better-webhook captures show <captureId> [options]
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
| Option | Description |
|
|
174
|
+
| ------------ | ---------------------- |
|
|
175
|
+
| `-b, --body` | Show full body content |
|
|
176
|
+
|
|
177
|
+
**Arguments:**
|
|
178
|
+
|
|
179
|
+
- `<captureId>` — Full or partial capture ID
|
|
180
|
+
|
|
181
|
+
#### `captures search <query>`
|
|
182
|
+
|
|
183
|
+
Search captures by ID, path, method, provider, or filename.
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
better-webhook captures search <query>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### `captures delete` (alias: `rm`)
|
|
190
|
+
|
|
191
|
+
Delete a specific captured webhook.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
better-webhook captures delete <captureId> [options]
|
|
132
195
|
```
|
|
133
196
|
|
|
134
|
-
|
|
197
|
+
| Option | Description |
|
|
198
|
+
| ------------- | ------------------------ |
|
|
199
|
+
| `-f, --force` | Skip confirmation prompt |
|
|
135
200
|
|
|
136
|
-
|
|
137
|
-
| --------- | ------ | -------- | --------------------------- |
|
|
138
|
-
| `url` | string | ✅ | Target webhook URL |
|
|
139
|
-
| `method` | string | ❌ | HTTP method (default: POST) |
|
|
140
|
-
| `headers` | array | ❌ | Array of header objects |
|
|
141
|
-
| `body` | any | ❌ | Request payload |
|
|
201
|
+
#### `captures clean` (alias: `remove-all`)
|
|
142
202
|
|
|
143
|
-
|
|
203
|
+
Remove all captured webhooks.
|
|
144
204
|
|
|
205
|
+
```bash
|
|
206
|
+
better-webhook captures clean [options]
|
|
145
207
|
```
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
208
|
+
|
|
209
|
+
| Option | Description |
|
|
210
|
+
| ------------- | ------------------------ |
|
|
211
|
+
| `-f, --force` | Skip confirmation prompt |
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
### `better-webhook templates` (alias: `t`)
|
|
216
|
+
|
|
217
|
+
Manage webhook templates. Templates are fetched from the [better-webhook repository](https://github.com/endalk200/better-webhook/tree/main/templates).
|
|
218
|
+
|
|
219
|
+
#### `templates list` (alias: `ls`)
|
|
220
|
+
|
|
221
|
+
List available remote templates from the repository.
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
better-webhook templates list [options]
|
|
154
225
|
```
|
|
155
226
|
|
|
156
|
-
|
|
227
|
+
| Option | Description |
|
|
228
|
+
| --------------------------- | -------------------------------------- |
|
|
229
|
+
| `-p, --provider <provider>` | Filter by provider |
|
|
230
|
+
| `-r, --refresh` | Force refresh the template index cache |
|
|
231
|
+
|
|
232
|
+
#### `templates download` (alias: `get`)
|
|
157
233
|
|
|
158
|
-
|
|
234
|
+
Download a template to local storage (`~/.better-webhook/templates/`).
|
|
159
235
|
|
|
160
236
|
```bash
|
|
161
|
-
|
|
162
|
-
|
|
237
|
+
better-webhook templates download [templateId] [options]
|
|
238
|
+
```
|
|
163
239
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
240
|
+
| Option | Description |
|
|
241
|
+
| ----------- | -------------------------------- |
|
|
242
|
+
| `-a, --all` | Download all available templates |
|
|
243
|
+
|
|
244
|
+
If no `templateId` is provided, shows an interactive selection menu.
|
|
245
|
+
|
|
246
|
+
#### `templates local`
|
|
247
|
+
|
|
248
|
+
List downloaded local templates.
|
|
167
249
|
|
|
168
|
-
|
|
169
|
-
better-webhook
|
|
250
|
+
```bash
|
|
251
|
+
better-webhook templates local [options]
|
|
170
252
|
```
|
|
171
253
|
|
|
172
|
-
|
|
254
|
+
| Option | Description |
|
|
255
|
+
| --------------------------- | ------------------ |
|
|
256
|
+
| `-p, --provider <provider>` | Filter by provider |
|
|
257
|
+
|
|
258
|
+
#### `templates search <query>`
|
|
259
|
+
|
|
260
|
+
Search templates by name, provider, or event type.
|
|
173
261
|
|
|
174
262
|
```bash
|
|
175
|
-
|
|
176
|
-
|
|
263
|
+
better-webhook templates search <query>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### `templates cache`
|
|
267
|
+
|
|
268
|
+
Manage the template index cache.
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
better-webhook templates cache [options]
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
| Option | Description |
|
|
275
|
+
| ------------- | ------------------------ |
|
|
276
|
+
| `-c, --clear` | Clear the template cache |
|
|
277
|
+
|
|
278
|
+
#### `templates clean` (alias: `remove-all`)
|
|
279
|
+
|
|
280
|
+
Remove all downloaded templates.
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
better-webhook templates clean [options]
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
| Option | Description |
|
|
287
|
+
| ------------- | ------------------------ |
|
|
288
|
+
| `-f, --force` | Skip confirmation prompt |
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
### `better-webhook run`
|
|
293
|
+
|
|
294
|
+
Run a webhook template against a target URL. Automatically generates provider-specific signatures when a secret is provided.
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
better-webhook run [templateId] [options]
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
| Option | Description | Required |
|
|
301
|
+
| ----------------------- | ------------------------------------------ | -------- |
|
|
302
|
+
| `-u, --url <url>` | Target URL to send the webhook to | ✅ |
|
|
303
|
+
| `-s, --secret <secret>` | Secret for signature generation | — |
|
|
304
|
+
| `-H, --header <header>` | Add custom header (format: `key:value`) | — |
|
|
305
|
+
| `-v, --verbose` | Show detailed request/response information | — |
|
|
306
|
+
|
|
307
|
+
**Arguments:**
|
|
308
|
+
|
|
309
|
+
- `[templateId]` — Template ID to run (interactive selection if omitted)
|
|
177
310
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
311
|
+
**Signature Generation:**
|
|
312
|
+
|
|
313
|
+
When you provide a secret (`--secret`), the CLI automatically generates the correct signature header based on the template's provider. You can also use environment variables (see [Environment Variables](#environment-variables)).
|
|
314
|
+
|
|
315
|
+
**Example:**
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
# Run with inline secret
|
|
319
|
+
better-webhook run github-push \
|
|
320
|
+
--url http://localhost:3000/api/webhooks/github \
|
|
321
|
+
--secret "your-webhook-secret"
|
|
322
|
+
|
|
323
|
+
# Run with custom headers
|
|
324
|
+
better-webhook run github-push \
|
|
325
|
+
--url http://localhost:3000/api/webhooks/github \
|
|
326
|
+
--secret "$GITHUB_WEBHOOK_SECRET" \
|
|
327
|
+
--header "X-Custom-Header:value" \
|
|
328
|
+
--verbose
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
### `better-webhook replay`
|
|
334
|
+
|
|
335
|
+
Replay a captured webhook to a target URL. Preserves original headers (except connection-related ones) and allows overrides.
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
better-webhook replay [captureId] [targetUrl] [options]
|
|
183
339
|
```
|
|
184
340
|
|
|
185
|
-
|
|
341
|
+
| Option | Description |
|
|
342
|
+
| ----------------------- | -------------------------------------------- |
|
|
343
|
+
| `-m, --method <method>` | Override HTTP method |
|
|
344
|
+
| `-H, --header <header>` | Add or override header (format: `key:value`) |
|
|
345
|
+
| `-v, --verbose` | Show detailed request/response information |
|
|
346
|
+
|
|
347
|
+
**Arguments:**
|
|
348
|
+
|
|
349
|
+
- `[captureId]` — Capture ID to replay (interactive selection if omitted)
|
|
350
|
+
- `[targetUrl]` — Target URL (prompts if omitted, defaults to original path on localhost:3000)
|
|
351
|
+
|
|
352
|
+
**Example:**
|
|
186
353
|
|
|
187
354
|
```bash
|
|
188
|
-
#
|
|
189
|
-
better-webhook
|
|
190
|
-
|
|
355
|
+
# Interactive mode
|
|
356
|
+
better-webhook replay
|
|
357
|
+
|
|
358
|
+
# Direct replay with options
|
|
359
|
+
better-webhook replay abc123 http://localhost:3000/webhooks \
|
|
360
|
+
--method POST \
|
|
361
|
+
--header "X-Debug:true" \
|
|
362
|
+
--verbose
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
### `better-webhook dashboard`
|
|
368
|
+
|
|
369
|
+
Start the local **dashboard UI + API + WebSocket** server.
|
|
370
|
+
|
|
371
|
+
By default, this command starts:
|
|
191
372
|
|
|
192
|
-
|
|
193
|
-
|
|
373
|
+
- **Dashboard UI**: `http://localhost:4000/`
|
|
374
|
+
- **API**: `http://localhost:4000/api/*`
|
|
375
|
+
- **WebSocket**: `ws://localhost:4000/ws`
|
|
376
|
+
- **Capture server** (in-process): `http://localhost:3001/*`
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
better-webhook dashboard [options]
|
|
194
380
|
```
|
|
195
381
|
|
|
196
|
-
|
|
382
|
+
| Option | Description | Default |
|
|
383
|
+
| ------------------------- | ------------------------------- | ----------- |
|
|
384
|
+
| `-p, --port <port>` | Dashboard server port | `4000` |
|
|
385
|
+
| `-h, --host <host>` | Dashboard server host | `localhost` |
|
|
386
|
+
| `--capture-port <port>` | Capture server port | `3001` |
|
|
387
|
+
| `--capture-host <host>` | Capture server host | `0.0.0.0` |
|
|
388
|
+
| `--no-capture` | Do not start capture server | — |
|
|
389
|
+
| `--captures-dir <dir>` | Override captures directory | — |
|
|
390
|
+
| `--templates-dir <dir>` | Override templates base dir | — |
|
|
391
|
+
|
|
392
|
+
**Security note:**
|
|
393
|
+
Keep the dashboard bound to `localhost` unless you trust your network. The API includes endpoints that can send HTTP requests to arbitrary URLs (run/replay).
|
|
394
|
+
|
|
395
|
+
---
|
|
396
|
+
|
|
397
|
+
## Environment Variables
|
|
398
|
+
|
|
399
|
+
The CLI automatically reads webhook secrets from environment variables based on the provider:
|
|
197
400
|
|
|
198
|
-
|
|
401
|
+
| Provider | Environment Variable |
|
|
402
|
+
| -------- | ------------------------- |
|
|
403
|
+
| Stripe | `STRIPE_WEBHOOK_SECRET` |
|
|
404
|
+
| GitHub | `GITHUB_WEBHOOK_SECRET` |
|
|
405
|
+
| Shopify | `SHOPIFY_WEBHOOK_SECRET` |
|
|
406
|
+
| Twilio | `TWILIO_WEBHOOK_SECRET` |
|
|
407
|
+
| Slack | `SLACK_WEBHOOK_SECRET` |
|
|
408
|
+
| Linear | `LINEAR_WEBHOOK_SECRET` |
|
|
409
|
+
| Clerk | `CLERK_WEBHOOK_SECRET` |
|
|
410
|
+
| SendGrid | `SENDGRID_WEBHOOK_SECRET` |
|
|
411
|
+
| Discord | `DISCORD_WEBHOOK_SECRET` |
|
|
412
|
+
| Custom | `WEBHOOK_SECRET` |
|
|
413
|
+
|
|
414
|
+
**Usage:**
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
export GITHUB_WEBHOOK_SECRET="your-secret-here"
|
|
418
|
+
better-webhook run github-push --url http://localhost:3000/webhooks/github
|
|
419
|
+
# Secret is automatically used for signature generation
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## Storage Locations
|
|
425
|
+
|
|
426
|
+
All CLI data is stored in `~/.better-webhook/`:
|
|
427
|
+
|
|
428
|
+
```
|
|
429
|
+
~/.better-webhook/
|
|
430
|
+
├── captures/ # Captured webhook requests
|
|
431
|
+
│ ├── 2024-01-15_10-30-00_abc12345.json
|
|
432
|
+
│ └── 2024-01-15_11-00-00_def67890.json
|
|
433
|
+
├── templates/ # Downloaded templates
|
|
434
|
+
│ ├── github/
|
|
435
|
+
│ │ ├── github-push.json
|
|
436
|
+
│ │ └── github-pull_request.json
|
|
437
|
+
│ └── stripe/
|
|
438
|
+
│ └── stripe-invoice.json
|
|
439
|
+
└── templates-cache.json # Template index cache (1 hour TTL)
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## Webhook Template Format
|
|
445
|
+
|
|
446
|
+
Templates follow this JSON schema:
|
|
199
447
|
|
|
200
448
|
```json
|
|
201
449
|
{
|
|
202
|
-
"url": "https://api.
|
|
450
|
+
"url": "https://api.example.com/webhook",
|
|
203
451
|
"method": "POST",
|
|
204
452
|
"headers": [
|
|
205
|
-
{ "key": "
|
|
453
|
+
{ "key": "Content-Type", "value": "application/json" },
|
|
454
|
+
{ "key": "X-Custom-Header", "value": "custom-value" }
|
|
206
455
|
],
|
|
207
456
|
"body": {
|
|
208
|
-
"
|
|
209
|
-
"object": "event",
|
|
210
|
-
"type": "payment_intent.succeeded",
|
|
457
|
+
"event": "user.created",
|
|
211
458
|
"data": {
|
|
212
|
-
"
|
|
213
|
-
|
|
214
|
-
"amount": 2000,
|
|
215
|
-
"currency": "usd",
|
|
216
|
-
"status": "succeeded"
|
|
217
|
-
}
|
|
459
|
+
"id": "12345",
|
|
460
|
+
"email": "user@example.com"
|
|
218
461
|
}
|
|
219
|
-
}
|
|
462
|
+
},
|
|
463
|
+
"provider": "custom",
|
|
464
|
+
"event": "user.created",
|
|
465
|
+
"description": "Triggered when a new user is created"
|
|
220
466
|
}
|
|
221
467
|
```
|
|
222
468
|
|
|
223
|
-
|
|
469
|
+
| Field | Type | Required | Description |
|
|
470
|
+
| ------------- | ------ | -------- | --------------------------------------------------- |
|
|
471
|
+
| `url` | string | — | Default target URL (can be overridden with `--url`) |
|
|
472
|
+
| `method` | string | — | HTTP method (default: `POST`) |
|
|
473
|
+
| `headers` | array | — | Array of `{ key, value }` header objects |
|
|
474
|
+
| `body` | any | — | Request payload (object or string) |
|
|
475
|
+
| `provider` | string | — | Provider name for signature generation |
|
|
476
|
+
| `event` | string | — | Event type identifier |
|
|
477
|
+
| `description` | string | — | Human-readable description |
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## Captured Webhook Format
|
|
482
|
+
|
|
483
|
+
Captured webhooks are stored with full request details:
|
|
224
484
|
|
|
225
485
|
```json
|
|
226
486
|
{
|
|
227
|
-
"
|
|
487
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
488
|
+
"timestamp": "2024-01-15T10:30:00.000Z",
|
|
228
489
|
"method": "POST",
|
|
229
|
-
"
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
"
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
]
|
|
245
|
-
}
|
|
490
|
+
"url": "/webhooks/github?action=opened",
|
|
491
|
+
"path": "/webhooks/github",
|
|
492
|
+
"headers": {
|
|
493
|
+
"content-type": "application/json",
|
|
494
|
+
"x-github-event": "push",
|
|
495
|
+
"x-hub-signature-256": "sha256=..."
|
|
496
|
+
},
|
|
497
|
+
"body": { "...parsed JSON..." },
|
|
498
|
+
"rawBody": "{...original string...}",
|
|
499
|
+
"query": { "action": "opened" },
|
|
500
|
+
"provider": "github",
|
|
501
|
+
"contentType": "application/json",
|
|
502
|
+
"contentLength": 1234
|
|
246
503
|
}
|
|
247
504
|
```
|
|
248
505
|
|
|
249
|
-
|
|
506
|
+
---
|
|
250
507
|
|
|
251
|
-
|
|
508
|
+
## Use Cases
|
|
252
509
|
|
|
253
|
-
|
|
254
|
-
|
|
510
|
+
### Local Development
|
|
511
|
+
|
|
512
|
+
Test your webhook endpoints during development:
|
|
255
513
|
|
|
256
514
|
```bash
|
|
257
|
-
#
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
#
|
|
261
|
-
|
|
515
|
+
# Terminal 1: Start your app
|
|
516
|
+
npm run dev
|
|
517
|
+
|
|
518
|
+
# Terminal 2: Capture webhooks
|
|
519
|
+
better-webhook capture --port 4000
|
|
262
520
|
|
|
263
|
-
#
|
|
264
|
-
|
|
265
|
-
|
|
521
|
+
# Configure your webhook provider to send to http://localhost:4000
|
|
522
|
+
# (use ngrok for external providers: ngrok http 4000)
|
|
523
|
+
|
|
524
|
+
# Terminal 3: Replay captured webhooks to your app
|
|
525
|
+
better-webhook replay abc123 http://localhost:3000/api/webhooks
|
|
266
526
|
```
|
|
267
527
|
|
|
268
|
-
|
|
528
|
+
### Debugging Webhook Issues
|
|
269
529
|
|
|
270
|
-
|
|
530
|
+
```bash
|
|
531
|
+
# Capture the problematic webhook
|
|
532
|
+
better-webhook capture
|
|
271
533
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
| `WEBHOOKS_DIR` | Directory for webhook definitions | `.webhooks` |
|
|
275
|
-
| `CAPTURES_DIR` | Directory for captured webhooks | `.webhook-captures` |
|
|
534
|
+
# Inspect the full request
|
|
535
|
+
better-webhook captures show abc123 --body
|
|
276
536
|
|
|
277
|
-
|
|
537
|
+
# Replay to your local server with verbose output
|
|
538
|
+
better-webhook replay abc123 http://localhost:3000/webhooks --verbose
|
|
539
|
+
```
|
|
278
540
|
|
|
279
|
-
|
|
280
|
-
| ----------- | ------------------------ |
|
|
281
|
-
| `--help` | Show help information |
|
|
282
|
-
| `--version` | Show version information |
|
|
541
|
+
### Testing Signature Verification
|
|
283
542
|
|
|
284
|
-
|
|
543
|
+
```bash
|
|
544
|
+
# Run a template with your production secret
|
|
545
|
+
better-webhook run stripe-invoice.payment_succeeded \
|
|
546
|
+
--url http://localhost:3000/api/webhooks/stripe \
|
|
547
|
+
--secret "whsec_your_stripe_secret" \
|
|
548
|
+
--verbose
|
|
549
|
+
```
|
|
285
550
|
|
|
286
|
-
|
|
551
|
+
### CI/CD Integration
|
|
552
|
+
|
|
553
|
+
```bash
|
|
554
|
+
# Test webhook endpoints in your pipeline
|
|
555
|
+
better-webhook templates download github-push
|
|
556
|
+
better-webhook run github-push \
|
|
557
|
+
--url "$TEST_ENDPOINT" \
|
|
558
|
+
--secret "$GITHUB_WEBHOOK_SECRET"
|
|
559
|
+
|
|
560
|
+
# Check exit code
|
|
561
|
+
if [ $? -eq 0 ]; then
|
|
562
|
+
echo "Webhook test passed"
|
|
563
|
+
fi
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## WebSocket API
|
|
569
|
+
|
|
570
|
+
The capture server exposes a WebSocket endpoint on the same port for real-time notifications:
|
|
571
|
+
|
|
572
|
+
```javascript
|
|
573
|
+
const ws = new WebSocket("ws://localhost:3001");
|
|
574
|
+
|
|
575
|
+
ws.onmessage = (event) => {
|
|
576
|
+
const message = JSON.parse(event.data);
|
|
577
|
+
|
|
578
|
+
switch (message.type) {
|
|
579
|
+
case "capture":
|
|
580
|
+
console.log("New capture:", message.payload.capture);
|
|
581
|
+
break;
|
|
582
|
+
case "captures_updated":
|
|
583
|
+
console.log("Captures list:", message.payload.captures);
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
```
|
|
287
588
|
|
|
288
|
-
|
|
589
|
+
**Message Types:**
|
|
590
|
+
|
|
591
|
+
| Type | Description | Payload |
|
|
592
|
+
| ------------------ | --------------------------- | --------------------- |
|
|
593
|
+
| `capture` | New webhook captured | `{ file, capture }` |
|
|
594
|
+
| `captures_updated` | Initial state on connection | `{ captures, count }` |
|
|
595
|
+
|
|
596
|
+
---
|
|
597
|
+
|
|
598
|
+
## Error Handling
|
|
599
|
+
|
|
600
|
+
The CLI uses standard exit codes:
|
|
601
|
+
|
|
602
|
+
| Code | Description |
|
|
603
|
+
| ---- | ------------------------------------------------- |
|
|
604
|
+
| `0` | Success |
|
|
605
|
+
| `1` | Error (validation, network, file not found, etc.) |
|
|
606
|
+
|
|
607
|
+
Detailed error messages are displayed in the terminal:
|
|
608
|
+
|
|
609
|
+
```bash
|
|
610
|
+
better-webhook run nonexistent-template --url http://localhost:3000
|
|
611
|
+
# ❌ Template not found: nonexistent-template
|
|
612
|
+
# Download it with: better-webhook templates download nonexistent-template
|
|
613
|
+
|
|
614
|
+
better-webhook capture --port 99999
|
|
615
|
+
# Invalid port number
|
|
616
|
+
|
|
617
|
+
better-webhook replay abc123 invalid-url
|
|
618
|
+
# Please enter a valid URL
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
## Development
|
|
624
|
+
|
|
625
|
+
### Building from Source
|
|
289
626
|
|
|
290
627
|
```bash
|
|
291
628
|
git clone https://github.com/endalk200/better-webhook.git
|
|
@@ -294,15 +631,22 @@ pnpm install
|
|
|
294
631
|
pnpm --filter @better-webhook/cli build
|
|
295
632
|
```
|
|
296
633
|
|
|
297
|
-
### Running
|
|
634
|
+
### Running Locally
|
|
298
635
|
|
|
299
636
|
```bash
|
|
300
|
-
|
|
637
|
+
cd apps/webhook-cli
|
|
638
|
+
pnpm start -- capture --port 3001
|
|
301
639
|
```
|
|
302
640
|
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
## Contributing
|
|
644
|
+
|
|
645
|
+
We welcome contributions! Please see our [Contributing Guide](https://github.com/endalk200/better-webhook/blob/main/CONTRIBUTING.md) for details.
|
|
646
|
+
|
|
303
647
|
## Changelog
|
|
304
648
|
|
|
305
|
-
See [CHANGELOG.md](
|
|
649
|
+
See [CHANGELOG.md](./CHANGELOG.md) for version history.
|
|
306
650
|
|
|
307
651
|
## License
|
|
308
652
|
|
|
@@ -313,8 +657,3 @@ MIT © [Endalk](https://github.com/endalk200)
|
|
|
313
657
|
- 🐛 [Report bugs](https://github.com/endalk200/better-webhook/issues)
|
|
314
658
|
- 💡 [Request features](https://github.com/endalk200/better-webhook/issues)
|
|
315
659
|
- 📖 [Documentation](https://github.com/endalk200/better-webhook#readme)
|
|
316
|
-
|
|
317
|
-
---
|
|
318
|
-
|
|
319
|
-
Made with ❤️ by [Endalk](https://github.com/endalk200)
|
|
320
|
-
|