@nestarc/webhook 0.8.0 → 0.10.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 +76 -25
- package/dist/adapters/fetch-http-client.d.ts.map +1 -1
- package/dist/adapters/fetch-http-client.js +1 -1
- package/dist/adapters/fetch-http-client.js.map +1 -1
- package/dist/adapters/plaintext-secret-vault.d.ts.map +1 -1
- package/dist/adapters/plaintext-secret-vault.js +12 -2
- package/dist/adapters/plaintext-secret-vault.js.map +1 -1
- package/dist/adapters/prisma-delivery.repository.d.ts +12 -6
- package/dist/adapters/prisma-delivery.repository.d.ts.map +1 -1
- package/dist/adapters/prisma-delivery.repository.js +234 -46
- package/dist/adapters/prisma-delivery.repository.js.map +1 -1
- package/dist/adapters/prisma-endpoint.repository.d.ts +4 -3
- package/dist/adapters/prisma-endpoint.repository.d.ts.map +1 -1
- package/dist/adapters/prisma-endpoint.repository.js +41 -6
- package/dist/adapters/prisma-endpoint.repository.js.map +1 -1
- package/dist/index.d.ts +11 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/interfaces/webhook-delivery.interface.d.ts +17 -0
- package/dist/interfaces/webhook-delivery.interface.d.ts.map +1 -1
- package/dist/interfaces/webhook-endpoint.interface.d.ts +11 -1
- package/dist/interfaces/webhook-endpoint.interface.d.ts.map +1 -1
- package/dist/interfaces/webhook-options.interface.d.ts +8 -6
- package/dist/interfaces/webhook-options.interface.d.ts.map +1 -1
- package/dist/ports/webhook-delivery.repository.d.ts +30 -10
- package/dist/ports/webhook-delivery.repository.d.ts.map +1 -1
- package/dist/ports/webhook-endpoint.repository.d.ts +24 -4
- package/dist/ports/webhook-endpoint.repository.d.ts.map +1 -1
- package/dist/ports/webhook-event.repository.d.ts +3 -1
- package/dist/ports/webhook-event.repository.d.ts.map +1 -1
- package/dist/ports/webhook-http-client.d.ts +4 -0
- package/dist/ports/webhook-http-client.d.ts.map +1 -1
- package/dist/ports/webhook-secret-vault.d.ts +1 -0
- package/dist/ports/webhook-secret-vault.d.ts.map +1 -1
- package/dist/webhook.admin.service.d.ts +6 -4
- package/dist/webhook.admin.service.d.ts.map +1 -1
- package/dist/webhook.admin.service.js +8 -2
- package/dist/webhook.admin.service.js.map +1 -1
- package/dist/webhook.circuit-breaker.d.ts +6 -4
- package/dist/webhook.circuit-breaker.d.ts.map +1 -1
- package/dist/webhook.circuit-breaker.js +10 -8
- package/dist/webhook.circuit-breaker.js.map +1 -1
- package/dist/webhook.constants.d.ts +9 -2
- package/dist/webhook.constants.d.ts.map +1 -1
- package/dist/webhook.constants.js +11 -4
- package/dist/webhook.constants.js.map +1 -1
- package/dist/webhook.delivery-admin.service.d.ts +2 -1
- package/dist/webhook.delivery-admin.service.d.ts.map +1 -1
- package/dist/webhook.delivery-admin.service.js +3 -0
- package/dist/webhook.delivery-admin.service.js.map +1 -1
- package/dist/webhook.delivery-worker.d.ts +4 -0
- package/dist/webhook.delivery-worker.d.ts.map +1 -1
- package/dist/webhook.delivery-worker.js +49 -22
- package/dist/webhook.delivery-worker.js.map +1 -1
- package/dist/webhook.dispatcher.d.ts +1 -0
- package/dist/webhook.dispatcher.d.ts.map +1 -1
- package/dist/webhook.dispatcher.js +13 -6
- package/dist/webhook.dispatcher.js.map +1 -1
- package/dist/webhook.endpoint-admin.service.d.ts +4 -1
- package/dist/webhook.endpoint-admin.service.d.ts.map +1 -1
- package/dist/webhook.endpoint-admin.service.js +36 -9
- package/dist/webhook.endpoint-admin.service.js.map +1 -1
- package/dist/webhook.module.d.ts.map +1 -1
- package/dist/webhook.module.js +22 -13
- package/dist/webhook.module.js.map +1 -1
- package/dist/webhook.signer.d.ts +2 -0
- package/dist/webhook.signer.d.ts.map +1 -1
- package/dist/webhook.signer.js +28 -14
- package/dist/webhook.signer.js.map +1 -1
- package/package.json +4 -4
- package/src/sql/create-webhook-tables.sql +27 -1
- package/src/sql/migrations/v0.9.0.sql +32 -0
package/README.md
CHANGED
|
@@ -6,14 +6,21 @@ Outbound webhook delivery for NestJS — HMAC signing, exponential retry, circui
|
|
|
6
6
|
|
|
7
7
|
[](https://github.com/nestarc/webhook/actions/workflows/ci.yml)
|
|
8
8
|
|
|
9
|
+
[Changelog](./CHANGELOG.md) · [Security policy](./SECURITY.md)
|
|
10
|
+
|
|
11
|
+
> **Pre-1.0:** minor version bumps may include breaking changes. Pin exact versions in production until `1.0.0`.
|
|
12
|
+
|
|
9
13
|
## Features
|
|
10
14
|
|
|
11
15
|
- **Fan-out delivery** — one event to many endpoints
|
|
12
16
|
- **HMAC-SHA256 signing** — Standard Webhooks compatible headers
|
|
17
|
+
- **Secret rotation overlap** — sign with both old and new secrets during rotation windows
|
|
13
18
|
- **Exponential backoff** — 30s, 5m, 30m, 2h, 24h (with jitter)
|
|
14
19
|
- **Circuit breaker** — auto-disable failing endpoints, auto-recover after cooldown
|
|
15
20
|
- **Dead letter queue** — failed deliveries tracked for manual retry
|
|
16
21
|
- **Delivery logs** — full audit trail (status code, latency, response body)
|
|
22
|
+
- **Per-attempt audit log** — every attempt recorded with status, latency, response body, and errors
|
|
23
|
+
- **Endpoint snapshotting** — queued deliveries keep their original URL and signing secret during retries
|
|
17
24
|
- **Multi-instance safe** — `FOR UPDATE SKIP LOCKED` prevents duplicate delivery
|
|
18
25
|
- **Graceful shutdown** — waits for in-flight deliveries on process exit
|
|
19
26
|
- **SSRF defense** — DNS resolution validation at registration and dispatch time
|
|
@@ -41,10 +48,20 @@ Run the migration SQL against your PostgreSQL database:
|
|
|
41
48
|
psql -d your_database -f node_modules/@nestarc/webhook/src/sql/create-webhook-tables.sql
|
|
42
49
|
```
|
|
43
50
|
|
|
44
|
-
This creates
|
|
51
|
+
This creates four tables: `webhook_endpoints`, `webhook_events`, `webhook_deliveries`, and `webhook_delivery_attempts`.
|
|
45
52
|
|
|
46
53
|
The migration includes `CREATE EXTENSION IF NOT EXISTS pgcrypto` for PostgreSQL < 13 compatibility.
|
|
47
54
|
|
|
55
|
+
### Upgrading from versions before 0.9.0
|
|
56
|
+
|
|
57
|
+
Existing databases need the v0.9.0 additive migration for per-attempt audit logs, endpoint snapshots, and secret rotation overlap:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
psql -d your_database -f node_modules/@nestarc/webhook/src/sql/migrations/v0.9.0.sql
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
See [CHANGELOG.md](./CHANGELOG.md) for release-specific migration notes.
|
|
64
|
+
|
|
48
65
|
## Quick Start
|
|
49
66
|
|
|
50
67
|
### 1. Register the module
|
|
@@ -55,11 +72,12 @@ import { WebhookModule } from '@nestarc/webhook';
|
|
|
55
72
|
@Module({
|
|
56
73
|
imports: [
|
|
57
74
|
WebhookModule.forRoot({
|
|
75
|
+
// prismaService is your PrismaClient/PrismaService instance.
|
|
76
|
+
// See "Async configuration" below for NestJS DI wiring.
|
|
58
77
|
prisma: prismaService,
|
|
59
78
|
delivery: {
|
|
60
79
|
timeout: 10_000,
|
|
61
80
|
maxRetries: 5,
|
|
62
|
-
backoff: 'exponential',
|
|
63
81
|
jitter: true,
|
|
64
82
|
},
|
|
65
83
|
circuitBreaker: {
|
|
@@ -126,7 +144,8 @@ export class WebhookController {
|
|
|
126
144
|
return this.endpointAdmin.createEndpoint({
|
|
127
145
|
url: 'https://customer.com/webhooks',
|
|
128
146
|
events: ['order.created', 'order.paid'],
|
|
129
|
-
|
|
147
|
+
tenantId: 'tenant_123', // optional; omit for global endpoints (returned as null)
|
|
148
|
+
secret: 'auto', // case-sensitive; omit or pass "auto" to generate a secret
|
|
130
149
|
});
|
|
131
150
|
}
|
|
132
151
|
}
|
|
@@ -149,7 +168,8 @@ export class WebhookController {
|
|
|
149
168
|
| `createEndpoint(dto)` | Register a new webhook endpoint (returns secret) |
|
|
150
169
|
| `listEndpoints(tenantId?)` | List all endpoints (secret excluded) |
|
|
151
170
|
| `getEndpoint(id)` | Get endpoint details (secret excluded) |
|
|
152
|
-
| `updateEndpoint(id, dto)` | Update endpoint URL, events,
|
|
171
|
+
| `updateEndpoint(id, dto)` | Update endpoint URL, events, description, metadata, or active status |
|
|
172
|
+
| `rotateSecret(endpointId, dto)` | Rotate the endpoint signing secret and keep the previous secret valid until `previousSecretExpiresAt` |
|
|
153
173
|
| `deleteEndpoint(id)` | Delete an endpoint |
|
|
154
174
|
| `sendTestEvent(endpointId)` | Send a `webhook.test` ping event |
|
|
155
175
|
|
|
@@ -158,6 +178,7 @@ export class WebhookController {
|
|
|
158
178
|
| Method | Description |
|
|
159
179
|
|--------|-------------|
|
|
160
180
|
| `getDeliveryLogs(endpointId, filters?)` | Query delivery history |
|
|
181
|
+
| `getDeliveryAttempts(deliveryId)` | Query per-attempt audit records for a delivery |
|
|
161
182
|
| `retryDelivery(deliveryId)` | Manually retry a failed delivery |
|
|
162
183
|
|
|
163
184
|
### WebhookSigner
|
|
@@ -165,10 +186,11 @@ export class WebhookController {
|
|
|
165
186
|
| Method | Description |
|
|
166
187
|
|--------|-------------|
|
|
167
188
|
| `sign(eventId, timestamp, body, secret)` | Generate Standard Webhooks signature headers |
|
|
189
|
+
| `signAll(eventId, timestamp, body, secrets[])` | Generate multi-signature headers for secret rotation overlap |
|
|
168
190
|
| `verify(eventId, timestamp, body, secret, signature)` | Verify a webhook signature |
|
|
169
191
|
| `generateSecret()` | Generate a random base64 signing secret |
|
|
170
192
|
|
|
171
|
-
> **Deprecated:** `WebhookAdminService` is a facade that delegates to `WebhookEndpointAdminService` and `WebhookDeliveryAdminService`. It will be removed in
|
|
193
|
+
> **Deprecated:** `WebhookAdminService` is a facade that delegates to `WebhookEndpointAdminService` and `WebhookDeliveryAdminService`. It has been deprecated since `v0.2.0` and will be removed in `v1.0.0`.
|
|
172
194
|
|
|
173
195
|
## Configuration
|
|
174
196
|
|
|
@@ -189,6 +211,8 @@ export class WebhookController {
|
|
|
189
211
|
| `onDeliveryFailed` | — | Fire-and-forget callback when a delivery exhausts all retries. Receives `DeliveryFailedContext` (`tenantId` is `null` for global endpoints). See **Delivery failure classification** below. |
|
|
190
212
|
| `onEndpointDisabled` | — | Fire-and-forget callback when the circuit breaker disables an endpoint. Fires once at exact threshold crossing. |
|
|
191
213
|
|
|
214
|
+
The retry schedule is fixed exponential (`30s`, `5m`, `30m`, `2h`, `24h`). Use `delivery.jitter` to enable or disable random jitter.
|
|
215
|
+
|
|
192
216
|
**Delivery failure classification.** `DeliveryFailedContext.failureKind` categorizes why a delivery was abandoned after all retries:
|
|
193
217
|
|
|
194
218
|
| `failureKind` | When | Extra fields |
|
|
@@ -250,7 +274,7 @@ webhook-timestamp: <unix-seconds>
|
|
|
250
274
|
webhook-signature: v1,<base64-hmac-sha256>
|
|
251
275
|
```
|
|
252
276
|
|
|
253
|
-
**Secret format:** Secrets must be valid base64 strings decoding to at least 16 bytes. Use `"auto"` for automatic generation.
|
|
277
|
+
**Secret format:** Secrets must be valid base64 strings decoding to at least 16 bytes. Use `"auto"` (case-sensitive) or omit `secret` for automatic generation.
|
|
254
278
|
|
|
255
279
|
### SSRF defense
|
|
256
280
|
|
|
@@ -284,6 +308,38 @@ try {
|
|
|
284
308
|
- Secrets are only returned on `createEndpoint` (initial provisioning)
|
|
285
309
|
- Delivery enrichment uses an internal path that does not expose secrets through admin APIs
|
|
286
310
|
- **At-rest encryption** — provide a custom `WebhookSecretVault` to encrypt secrets before storage and decrypt before HMAC signing. The default `PlaintextSecretVault` passes values through unchanged.
|
|
311
|
+
- **Rotation overlap** — use `rotateSecret()` to move the current stored secret to `previous_secret`, set a new current secret, and sign queued deliveries with both secrets until `previousSecretExpiresAt`.
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
const rotated = await endpointAdmin.rotateSecret(endpointId, {
|
|
315
|
+
previousSecretExpiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Provision this value to the receiver immediately. It is returned only once.
|
|
319
|
+
console.log(rotated?.secret);
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
`WebhookSigner.verify()` accepts a request when any signature in the space-separated `webhook-signature` header matches the provided secret.
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
const signer = new WebhookSigner();
|
|
326
|
+
const isValid = signer.verify(
|
|
327
|
+
headers['webhook-id'],
|
|
328
|
+
Number(headers['webhook-timestamp']),
|
|
329
|
+
rawBody,
|
|
330
|
+
signingSecret,
|
|
331
|
+
headers['webhook-signature'],
|
|
332
|
+
);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Delivery audit data
|
|
336
|
+
|
|
337
|
+
Delivery logs expose the snapshotted destination URL through `DeliveryRecord.destinationUrl`. Per-attempt audit records are available through `WebhookDeliveryAdminService.getDeliveryAttempts(deliveryId)`:
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
const [delivery] = await deliveryAdmin.getDeliveryLogs(endpointId);
|
|
341
|
+
const attempts = await deliveryAdmin.getDeliveryAttempts(delivery.id);
|
|
342
|
+
```
|
|
287
343
|
|
|
288
344
|
## Webhook Payload Format
|
|
289
345
|
|
|
@@ -326,34 +382,29 @@ export class WorkerModule {}
|
|
|
326
382
|
|
|
327
383
|
// main.ts
|
|
328
384
|
const app = await NestFactory.createApplicationContext(WorkerModule);
|
|
385
|
+
process.on('SIGTERM', () => void app.close());
|
|
386
|
+
process.on('SIGINT', () => void app.close());
|
|
329
387
|
```
|
|
330
388
|
|
|
331
389
|
Both processes share the same PostgreSQL database. Workers scale horizontally — `FOR UPDATE SKIP LOCKED` prevents duplicate delivery.
|
|
390
|
+
During shutdown, the worker waits up to 30 seconds for the active poll cycle and in-flight deliveries. If the process exits earlier, the next worker recovers stuck `SENDING` rows after `polling.staleSendingMinutes`.
|
|
332
391
|
|
|
333
392
|
## Architecture
|
|
334
393
|
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
v v v
|
|
346
|
-
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
347
|
-
│Dispatcher│ │RetryPolicy│ │CircuitBkr│
|
|
348
|
-
└────┬─────┘ └──────────┘ └──────────┘
|
|
349
|
-
│
|
|
350
|
-
┌────┴─────┐
|
|
351
|
-
│HttpClient│──> customer endpoints
|
|
352
|
-
└──────────┘
|
|
394
|
+
```mermaid
|
|
395
|
+
flowchart LR
|
|
396
|
+
A[Your Service] -->|publish| B[WebhookService]
|
|
397
|
+
B -->|transactional insert| C[(PostgreSQL)]
|
|
398
|
+
D[DeliveryWorker] -->|poll and claim| C
|
|
399
|
+
D --> E[Dispatcher]
|
|
400
|
+
D --> F[RetryPolicy]
|
|
401
|
+
D --> G[CircuitBreaker]
|
|
402
|
+
E --> H[HttpClient]
|
|
403
|
+
H --> I[Customer endpoints]
|
|
353
404
|
```
|
|
354
405
|
|
|
355
406
|
All components depend on **port interfaces**, not concrete implementations. Default adapters use Prisma and Node.js fetch.
|
|
356
407
|
|
|
357
408
|
## License
|
|
358
409
|
|
|
359
|
-
MIT
|
|
410
|
+
MIT — see [LICENSE](./LICENSE).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-http-client.d.ts","sourceRoot":"","sources":["../../src/adapters/fetch-http-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;
|
|
1
|
+
{"version":3,"file":"fetch-http-client.d.ts","sourceRoot":"","sources":["../../src/adapters/fetch-http-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAM1E,qBACa,eAAgB,YAAW,iBAAiB;IACjD,IAAI,CACR,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,CAAC;CAuC3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-http-client.js","sourceRoot":"","sources":["../../src/adapters/fetch-http-client.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAG5C,
|
|
1
|
+
{"version":3,"file":"fetch-http-client.js","sourceRoot":"","sources":["../../src/adapters/fetch-http-client.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAG5C,4DAG8B;AAGvB,IAAM,eAAe,GAArB,MAAM,eAAe;IAC1B,KAAK,CAAC,IAAI,CACR,GAAW,EACX,OAA+B,EAC/B,IAAY,EACZ,OAAe;QAEf,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEzB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,YAAY,EAAE,sCAAkB;oBAChC,GAAG,OAAO;iBACX;gBACD,IAAI;gBACJ,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,QAAQ,EAAE,QAAQ;aACnB,CAAC,CAAC;YAEH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACrC,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAE3C,OAAO;gBACL,OAAO,EAAE,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG;gBACxD,UAAU,EAAE,QAAQ,CAAC,MAAM;gBAC3B,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,4CAAwB,CAAC;gBACrD,SAAS;aACV,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACrC,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,SAAS;gBACT,KAAK,EAAE,OAAO;aACf,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;CACF,CAAA;AA7CY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;GACA,eAAe,CA6C3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plaintext-secret-vault.d.ts","sourceRoot":"","sources":["../../src/adapters/plaintext-secret-vault.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plaintext-secret-vault.d.ts","sourceRoot":"","sources":["../../src/adapters/plaintext-secret-vault.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAEnE;;;GAGG;AACH,qBACa,oBAAqB,YAAW,kBAAkB;IACvD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIxC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAG/C"}
|
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
2
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
9
|
exports.PlaintextSecretVault = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
4
11
|
/**
|
|
5
12
|
* Default no-op vault — secrets are stored and retrieved as-is.
|
|
6
13
|
* Replace with a real implementation (e.g. AES-256-GCM) for production.
|
|
7
14
|
*/
|
|
8
|
-
class PlaintextSecretVault {
|
|
15
|
+
let PlaintextSecretVault = class PlaintextSecretVault {
|
|
9
16
|
async encrypt(secret) {
|
|
10
17
|
return secret;
|
|
11
18
|
}
|
|
12
19
|
async decrypt(secret) {
|
|
13
20
|
return secret;
|
|
14
21
|
}
|
|
15
|
-
}
|
|
22
|
+
};
|
|
16
23
|
exports.PlaintextSecretVault = PlaintextSecretVault;
|
|
24
|
+
exports.PlaintextSecretVault = PlaintextSecretVault = __decorate([
|
|
25
|
+
(0, common_1.Injectable)()
|
|
26
|
+
], PlaintextSecretVault);
|
|
17
27
|
//# sourceMappingURL=plaintext-secret-vault.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plaintext-secret-vault.js","sourceRoot":"","sources":["../../src/adapters/plaintext-secret-vault.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"plaintext-secret-vault.js","sourceRoot":"","sources":["../../src/adapters/plaintext-secret-vault.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAG5C;;;GAGG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAC/B,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAA;AARY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;GACA,oBAAoB,CAQhC"}
|
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import { PendingDelivery, WebhookDeliveryRepository } from '../ports/webhook-delivery.repository';
|
|
2
|
-
import { DeliveryLogFilters, DeliveryRecord, DeliveryResult } from '../interfaces/webhook-delivery.interface';
|
|
1
|
+
import { ClaimedDelivery, PendingDelivery, WebhookDeliveryRepository, WebhookTransaction } from '../ports/webhook-delivery.repository';
|
|
2
|
+
import { DeliveryAttemptRecord, DeliveryLogFilters, DeliveryRecord, DeliveryResult } from '../interfaces/webhook-delivery.interface';
|
|
3
3
|
import { WebhookSecretVault } from '../ports/webhook-secret-vault';
|
|
4
|
+
type AttemptLogClient = {
|
|
5
|
+
$executeRaw: <T = unknown>(strings: TemplateStringsArray, ...values: unknown[]) => Promise<T>;
|
|
6
|
+
};
|
|
4
7
|
export declare class PrismaDeliveryRepository implements WebhookDeliveryRepository {
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
protected readonly prisma: any;
|
|
9
|
+
protected readonly vault?: WebhookSecretVault | undefined;
|
|
7
10
|
constructor(prisma: any, vault?: WebhookSecretVault | undefined);
|
|
8
11
|
createDeliveriesInTransaction(tx: any, eventId: string, endpointIds: string[], maxAttempts: number): Promise<void>;
|
|
9
|
-
runInTransaction<T>(fn: (tx:
|
|
10
|
-
claimPendingDeliveries(batchSize: number): Promise<
|
|
12
|
+
runInTransaction<T>(fn: (tx: WebhookTransaction) => Promise<T>): Promise<T>;
|
|
13
|
+
claimPendingDeliveries(batchSize: number): Promise<ClaimedDelivery[]>;
|
|
11
14
|
enrichDeliveries(deliveryIds: string[]): Promise<PendingDelivery[]>;
|
|
12
15
|
markSent(deliveryId: string, attempts: number, result: DeliveryResult): Promise<void>;
|
|
13
16
|
markFailed(deliveryId: string, attempts: number, result: DeliveryResult): Promise<void>;
|
|
14
17
|
markRetry(deliveryId: string, attempts: number, nextAt: Date, result: DeliveryResult): Promise<void>;
|
|
15
18
|
recoverStaleSending(stalenessMinutes: number): Promise<number>;
|
|
16
19
|
getDeliveryLogs(endpointId: string, filters?: DeliveryLogFilters): Promise<DeliveryRecord[]>;
|
|
20
|
+
getDeliveryAttempts(deliveryId: string): Promise<DeliveryAttemptRecord[]>;
|
|
17
21
|
retryDelivery(deliveryId: string): Promise<boolean>;
|
|
18
22
|
createTestDelivery(eventId: string, endpointId: string): Promise<void>;
|
|
23
|
+
protected appendAttemptLog(client: AttemptLogClient, deliveryId: string, attempts: number, status: 'PENDING' | 'SENT' | 'FAILED', result: DeliveryResult): Promise<void>;
|
|
19
24
|
}
|
|
25
|
+
export {};
|
|
20
26
|
//# sourceMappingURL=prisma-delivery.repository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prisma-delivery.repository.d.ts","sourceRoot":"","sources":["../../src/adapters/prisma-delivery.repository.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,yBAAyB,
|
|
1
|
+
{"version":3,"file":"prisma-delivery.repository.d.ts","sourceRoot":"","sources":["../../src/adapters/prisma-delivery.repository.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,eAAe,EACf,yBAAyB,EACzB,kBAAkB,EACnB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACd,cAAc,EACf,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,KAAK,gBAAgB,GAAG;IACtB,WAAW,EAAE,CAAC,CAAC,GAAG,OAAO,EACvB,OAAO,EAAE,oBAAoB,EAC7B,GAAG,MAAM,EAAE,OAAO,EAAE,KACjB,OAAO,CAAC,CAAC,CAAC,CAAC;CACjB,CAAC;AA0BF,qBACa,wBAAyB,YAAW,yBAAyB;IAEtE,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG;IAC9B,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,kBAAkB;gBAD1B,MAAM,EAAE,GAAG,EACX,KAAK,CAAC,EAAE,kBAAkB,YAAA;IAGzC,6BAA6B,CACjC,EAAE,EAAE,GAAG,EACP,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE,EACrB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;IAqCV,gBAAgB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,kBAAkB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAI3E,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAqBrE,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA4CnE,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrF,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAevF,SAAS,CACb,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;IAeV,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA2D9D,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,cAAc,EAAE,CAAC;IAmDtB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAkBzE,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQnD,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;cA+B5D,gBAAgB,CAC9B,MAAM,EAAE,gBAAgB,EACxB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,EACrC,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;CA0BjB"}
|