hookdash 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 +385 -0
- package/dashboard/dist/assets/index-BDjBwO-x.css +1 -0
- package/dashboard/dist/assets/index-DbQJ42V1.js +51 -0
- package/dashboard/dist/index.html +18 -0
- package/dist/index.js +1569 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 hookdash contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ∿ hookdash
|
|
4
|
+
|
|
5
|
+
**Zero-config, self-hosted webhook gateway with a beautiful dashboard.**
|
|
6
|
+
|
|
7
|
+
Receive, queue, retry, and monitor webhooks — no Redis, no Postgres, just SQLite.
|
|
8
|
+
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](https://nodejs.org)
|
|
11
|
+
[](https://www.typescriptlang.org/)
|
|
12
|
+
|
|
13
|
+
[Quick Start](#-quick-start) · [Configuration](#-configuration) · [Dashboard](#-dashboard) · [API](#-api-reference) · [Docker](#-docker) · [Contributing](#-contributing)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Why hookdash?
|
|
20
|
+
|
|
21
|
+
Every app that integrates with Stripe, GitHub, Twilio, or Shopify needs to handle webhooks. But webhooks are fragile — your server goes down, you lose events. You need retry logic, signature verification, monitoring, and replay capabilities.
|
|
22
|
+
|
|
23
|
+
**hookdash** gives you all of that in a single command:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx hookdash start
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
No Redis. No Postgres. No Kafka. Just a single SQLite file and a beautiful dashboard.
|
|
30
|
+
|
|
31
|
+
### How it compares
|
|
32
|
+
|
|
33
|
+
| Feature | hookdash | Svix | Convoy | Hookdeck |
|
|
34
|
+
|---|---|---|---|---|
|
|
35
|
+
| Zero external deps | ✅ SQLite only | ❌ PG + Redis + Kafka | ❌ PG + Redis | ❌ Cloud only |
|
|
36
|
+
| Setup time | `npx hookdash` | Hours | Hours | Minutes |
|
|
37
|
+
| Self-hosted | ✅ | ✅ | ✅ | ❌ |
|
|
38
|
+
| Dashboard | ✅ Beautiful | ✅ | ✅ | ✅ |
|
|
39
|
+
| Signature verification | ✅ Multi-provider | ✅ | ✅ | ✅ |
|
|
40
|
+
| License | MIT | MIT (server) | Varies | Proprietary |
|
|
41
|
+
| Target audience | Devs & small teams | Enterprise | Enterprise | Everyone |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## ✨ Features
|
|
46
|
+
|
|
47
|
+
- 🪝 **Webhook Ingestion** — Receive webhooks from any service at `/webhook/:source`
|
|
48
|
+
- 🔐 **Signature Verification** — Built-in support for Stripe, GitHub, Twilio, Shopify, and generic HMAC
|
|
49
|
+
- 🔄 **Smart Retries** — Exponential backoff with jitter, configurable per-endpoint
|
|
50
|
+
- ⚡ **Circuit Breaker** — Auto-disable failing endpoints, probe for recovery
|
|
51
|
+
- 💀 **Dead Letter Queue** — Events that exceed retries are preserved for inspection
|
|
52
|
+
- 🔁 **One-Click Replay** — Re-deliver any failed event from the dashboard
|
|
53
|
+
- 📊 **Real-time Dashboard** — Beautiful dark UI with live event stream
|
|
54
|
+
- 📡 **Server-Sent Events** — Real-time updates without WebSocket complexity
|
|
55
|
+
- 🗄️ **SQLite Storage** — Zero-config, single file, fast, reliable
|
|
56
|
+
- 🐳 **Docker Ready** — Single container deployment
|
|
57
|
+
- ⚙️ **YAML Config** — Simple configuration with environment variable interpolation
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 🚀 Quick Start
|
|
62
|
+
|
|
63
|
+
### Option 1: npx (quickest)
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Create a config file
|
|
67
|
+
npx hookdash init
|
|
68
|
+
|
|
69
|
+
# Edit hookdash.config.yml with your settings, then:
|
|
70
|
+
npx hookdash start
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Option 2: Install globally
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm install -g hookdash
|
|
77
|
+
hookdash init
|
|
78
|
+
hookdash start
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Option 3: Docker
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
docker run -p 9090:9090 -v hookdash-data:/app/data hookdash/hookdash
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Test it works
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Send a test webhook
|
|
91
|
+
curl -X POST http://localhost:9090/webhook/my-service \
|
|
92
|
+
-H "Content-Type: application/json" \
|
|
93
|
+
-d '{"event": "test.event", "data": {"hello": "world"}}'
|
|
94
|
+
|
|
95
|
+
# Open the dashboard
|
|
96
|
+
open http://localhost:9090
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 📋 Configuration
|
|
102
|
+
|
|
103
|
+
Create a `hookdash.config.yml` in your project root:
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
server:
|
|
107
|
+
port: 9090
|
|
108
|
+
host: 0.0.0.0
|
|
109
|
+
|
|
110
|
+
database:
|
|
111
|
+
path: ./hookdash.db
|
|
112
|
+
|
|
113
|
+
delivery:
|
|
114
|
+
poll_interval: 1000 # ms between delivery polls
|
|
115
|
+
default_timeout: 30000 # ms per delivery attempt
|
|
116
|
+
default_max_retries: 8 # retries before dead letter
|
|
117
|
+
|
|
118
|
+
sources:
|
|
119
|
+
# Stripe
|
|
120
|
+
- name: stripe
|
|
121
|
+
provider: stripe
|
|
122
|
+
signing_secret: ${STRIPE_WEBHOOK_SECRET}
|
|
123
|
+
endpoints:
|
|
124
|
+
- url: http://localhost:3000/api/webhooks/stripe
|
|
125
|
+
events: ["payment_intent.*", "charge.*"]
|
|
126
|
+
|
|
127
|
+
# GitHub
|
|
128
|
+
- name: github
|
|
129
|
+
provider: github
|
|
130
|
+
signing_secret: ${GITHUB_WEBHOOK_SECRET}
|
|
131
|
+
endpoints:
|
|
132
|
+
- url: http://localhost:3000/api/webhooks/github
|
|
133
|
+
|
|
134
|
+
# Generic HMAC-SHA256
|
|
135
|
+
- name: my-service
|
|
136
|
+
provider: generic
|
|
137
|
+
signing_secret: my-secret-key
|
|
138
|
+
endpoints:
|
|
139
|
+
- url: http://localhost:3000/hooks
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Environment Variables
|
|
143
|
+
|
|
144
|
+
Use `${ENV_VAR}` syntax in your config to reference environment variables:
|
|
145
|
+
|
|
146
|
+
```yaml
|
|
147
|
+
signing_secret: ${STRIPE_WEBHOOK_SECRET}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### CLI Options
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
hookdash start [options]
|
|
154
|
+
|
|
155
|
+
Options:
|
|
156
|
+
-p, --port <port> Server port (overrides config)
|
|
157
|
+
-h, --host <host> Server host (overrides config)
|
|
158
|
+
-c, --config <path> Path to config file
|
|
159
|
+
-d, --db <path> Database file path
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 📊 Dashboard
|
|
165
|
+
|
|
166
|
+
The dashboard is available at `http://localhost:9090` and provides:
|
|
167
|
+
|
|
168
|
+
- **Event Explorer** — Search and filter all incoming webhooks
|
|
169
|
+
- **Event Detail** — View full payload, headers, and delivery timeline
|
|
170
|
+
- **Replay** — One-click re-delivery of any event
|
|
171
|
+
- **Stats** — Success rates, event volume, top sources
|
|
172
|
+
- **Endpoint Manager** — Configure and test forwarding destinations
|
|
173
|
+
- **Real-time Updates** — Live event stream via SSE
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 📡 API Reference
|
|
178
|
+
|
|
179
|
+
All API endpoints are available at `/api/`.
|
|
180
|
+
|
|
181
|
+
### Events
|
|
182
|
+
|
|
183
|
+
| Method | Endpoint | Description |
|
|
184
|
+
|---|---|---|
|
|
185
|
+
| `GET` | `/api/events` | List events (paginated) |
|
|
186
|
+
| `GET` | `/api/events/:id` | Event detail + deliveries |
|
|
187
|
+
| `POST` | `/api/events/:id/replay` | Replay an event |
|
|
188
|
+
| `DELETE` | `/api/events/:id` | Delete an event |
|
|
189
|
+
|
|
190
|
+
**Query parameters for `GET /api/events`:**
|
|
191
|
+
|
|
192
|
+
| Param | Type | Description |
|
|
193
|
+
|---|---|---|
|
|
194
|
+
| `page` | number | Page number (default: 1) |
|
|
195
|
+
| `per_page` | number | Items per page (default: 20, max: 100) |
|
|
196
|
+
| `source` | string | Filter by source name |
|
|
197
|
+
| `status` | string | Filter by delivery status |
|
|
198
|
+
| `event_type` | string | Filter by event type |
|
|
199
|
+
| `from` | string | ISO date, events after |
|
|
200
|
+
| `to` | string | ISO date, events before |
|
|
201
|
+
| `search` | string | Search in event body |
|
|
202
|
+
|
|
203
|
+
### Endpoints
|
|
204
|
+
|
|
205
|
+
| Method | Endpoint | Description |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| `GET` | `/api/endpoints` | List endpoints |
|
|
208
|
+
| `POST` | `/api/endpoints` | Create endpoint |
|
|
209
|
+
| `PUT` | `/api/endpoints/:id` | Update endpoint |
|
|
210
|
+
| `DELETE` | `/api/endpoints/:id` | Delete endpoint |
|
|
211
|
+
| `POST` | `/api/endpoints/:id/test` | Test endpoint connectivity |
|
|
212
|
+
|
|
213
|
+
### Stats & Health
|
|
214
|
+
|
|
215
|
+
| Method | Endpoint | Description |
|
|
216
|
+
|---|---|---|
|
|
217
|
+
| `GET` | `/api/stats` | Aggregate statistics |
|
|
218
|
+
| `GET` | `/api/stream` | SSE real-time event stream |
|
|
219
|
+
| `GET` | `/api/health` | Health check |
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 🪝 Webhook Providers
|
|
224
|
+
|
|
225
|
+
### Stripe
|
|
226
|
+
|
|
227
|
+
```yaml
|
|
228
|
+
- name: stripe
|
|
229
|
+
provider: stripe
|
|
230
|
+
signing_secret: ${STRIPE_WEBHOOK_SECRET}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Verifies using the `Stripe-Signature` header with HMAC-SHA256. Validates timestamp tolerance (5 minutes).
|
|
234
|
+
|
|
235
|
+
### GitHub
|
|
236
|
+
|
|
237
|
+
```yaml
|
|
238
|
+
- name: github
|
|
239
|
+
provider: github
|
|
240
|
+
signing_secret: ${GITHUB_WEBHOOK_SECRET}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Verifies using the `X-Hub-Signature-256` header with HMAC-SHA256.
|
|
244
|
+
|
|
245
|
+
### Twilio
|
|
246
|
+
|
|
247
|
+
```yaml
|
|
248
|
+
- name: twilio
|
|
249
|
+
provider: twilio
|
|
250
|
+
signing_secret: ${TWILIO_AUTH_TOKEN}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Verifies using the `X-Twilio-Signature` header with HMAC-SHA1.
|
|
254
|
+
|
|
255
|
+
### Shopify
|
|
256
|
+
|
|
257
|
+
```yaml
|
|
258
|
+
- name: shopify
|
|
259
|
+
provider: shopify
|
|
260
|
+
signing_secret: ${SHOPIFY_WEBHOOK_SECRET}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Verifies using the `X-Shopify-Hmac-Sha256` header with HMAC-SHA256 (Base64).
|
|
264
|
+
|
|
265
|
+
### Generic HMAC
|
|
266
|
+
|
|
267
|
+
```yaml
|
|
268
|
+
- name: my-service
|
|
269
|
+
provider: generic
|
|
270
|
+
signing_secret: my-secret-key
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Verifies using `X-Webhook-Signature` or `X-Signature` header with HMAC-SHA256.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## 🔄 Retry Strategy
|
|
278
|
+
|
|
279
|
+
hookdash uses **exponential backoff with jitter**:
|
|
280
|
+
|
|
281
|
+
| Attempt | Delay (approx) |
|
|
282
|
+
|---|---|
|
|
283
|
+
| 1 | ~1s |
|
|
284
|
+
| 2 | ~2s |
|
|
285
|
+
| 3 | ~4s |
|
|
286
|
+
| 4 | ~8s |
|
|
287
|
+
| 5 | ~16s |
|
|
288
|
+
| 6 | ~32s |
|
|
289
|
+
| 7 | ~1 min |
|
|
290
|
+
| 8 | ~2 min |
|
|
291
|
+
|
|
292
|
+
After the configured max retries (default: 8), the event moves to the **dead letter queue** and can be replayed manually from the dashboard.
|
|
293
|
+
|
|
294
|
+
### Circuit Breaker
|
|
295
|
+
|
|
296
|
+
If an endpoint fails 5 times consecutively, hookdash **opens the circuit** and stops sending to that endpoint for 60 seconds. After the cooldown, it enters **half-open** state and probes with a single request.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## 🐳 Docker
|
|
301
|
+
|
|
302
|
+
### Using Docker Compose
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
# Clone the repo
|
|
306
|
+
git clone https://github.com/hookdash/hookdash.git
|
|
307
|
+
cd hookdash
|
|
308
|
+
|
|
309
|
+
# Create your config
|
|
310
|
+
cp hookdash.config.example.yml hookdash.config.yml
|
|
311
|
+
|
|
312
|
+
# Start
|
|
313
|
+
docker compose up -d
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Using Docker directly
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
docker build -t hookdash .
|
|
320
|
+
docker run -p 9090:9090 -v hookdash-data:/app/data hookdash
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## 🛠 Development
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
# Clone
|
|
329
|
+
git clone https://github.com/hookdash/hookdash.git
|
|
330
|
+
cd hookdash
|
|
331
|
+
|
|
332
|
+
# Install dependencies
|
|
333
|
+
npm install
|
|
334
|
+
cd dashboard && npm install && cd ..
|
|
335
|
+
|
|
336
|
+
# Start in dev mode (with hot reload)
|
|
337
|
+
npm run dev
|
|
338
|
+
|
|
339
|
+
# Run tests
|
|
340
|
+
npm test
|
|
341
|
+
|
|
342
|
+
# Build for production
|
|
343
|
+
npm run build
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## 🗺 Roadmap
|
|
349
|
+
|
|
350
|
+
- [ ] Web UI for creating sources (no YAML editing)
|
|
351
|
+
- [ ] Webhook forwarding transforms (modify payload before delivery)
|
|
352
|
+
- [ ] Rate limiting per source
|
|
353
|
+
- [ ] Authentication for dashboard (API key / basic auth)
|
|
354
|
+
- [ ] Metrics export (Prometheus)
|
|
355
|
+
- [ ] Webhook playground (send test events from dashboard)
|
|
356
|
+
- [ ] Plugin system for custom providers
|
|
357
|
+
- [ ] PostgreSQL adapter for high-volume deployments
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## 🤝 Contributing
|
|
362
|
+
|
|
363
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
364
|
+
|
|
365
|
+
1. Fork the repository
|
|
366
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
367
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
368
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
369
|
+
5. Open a Pull Request
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## 📄 License
|
|
374
|
+
|
|
375
|
+
MIT — see [LICENSE](LICENSE) for details.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
<div align="center">
|
|
380
|
+
|
|
381
|
+
**Built with ❤️ for developers who are tired of losing webhooks.**
|
|
382
|
+
|
|
383
|
+
[⭐ Star on GitHub](https://github.com/hookdash/hookdash) · [🐛 Report Bug](https://github.com/hookdash/hookdash/issues) · [💡 Request Feature](https://github.com/hookdash/hookdash/issues)
|
|
384
|
+
|
|
385
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--bg-color: #08080c;--card-bg: #11111a;--border-color: #1e1e2d;--text-primary: #f3f4f6;--text-secondary: #9ca3af;--text-muted: #6b7280;--accent-color: #3b82f6;--accent-glow: rgba(59, 130, 246, .15);--success-color: #10b981;--success-glow: rgba(16, 185, 129, .1);--warning-color: #f59e0b;--error-color: #ef4444;--dead-color: #4b5563;--sidebar-width: 260px;--font-sans: "Inter", system-ui, -apple-system, sans-serif;--font-mono: "JetBrains Mono", monospace}*{box-sizing:border-box;margin:0;padding:0}body{background-color:var(--bg-color);color:var(--text-primary);font-family:var(--font-sans);overflow-x:hidden;-webkit-font-smoothing:antialiased}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:var(--bg-color)}::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}.glass{background:#11111ab3;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border:1px solid var(--border-color)}@keyframes fadeIn{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes pulseLive{0%{transform:scale(.95);opacity:.5}50%{transform:scale(1.15);opacity:1}to{transform:scale(.95);opacity:.5}}.animate-fade-in{animation:fadeIn .25s ease-out forwards}.live-indicator{display:inline-block;width:8px;height:8px;border-radius:50%;background-color:var(--success-color);box-shadow:0 0 8px var(--success-color);animation:pulseLive 2s infinite ease-in-out}.btn{display:inline-flex;align-items:center;gap:8px;padding:8px 16px;border-radius:6px;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s ease;border:1px solid transparent;outline:none}.btn-primary{background:var(--accent-color);color:#fff;box-shadow:0 4px 12px var(--accent-glow)}.btn-primary:hover{filter:brightness(1.1);transform:translateY(-1px)}.btn-secondary{background:#ffffff0d;border-color:var(--border-color);color:var(--text-primary)}.btn-secondary:hover{background:#ffffff14}.btn-danger{background:#ef44441a;border-color:#ef444433;color:var(--error-color)}.btn-danger:hover{background:#ef444426}.input{background:#ffffff08;border:1px solid var(--border-color);color:var(--text-primary);padding:8px 12px;border-radius:6px;font-size:14px;font-family:var(--font-sans);outline:none;transition:border-color .2s}.input:focus{border-color:var(--accent-color)}.json-key{color:#93c5fd}.json-string{color:#86efac}.json-number{color:#fbbf24}.json-boolean{color:#c084fc}.json-null{color:#9ca3af}
|