@dudousxd/nestjs-notifications-webhook 0.6.0 → 0.7.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/dist/index.cjs +161 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +107 -48
- package/dist/index.d.ts +107 -48
- package/dist/index.js +156 -57
- package/dist/index.js.map +1 -1
- package/package.json +18 -5
package/dist/index.d.cts
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
import * as _dudousxd_nestjs_notifications_core from '@dudousxd/nestjs-notifications-core';
|
|
2
2
|
import { BaseChannel, Notifiable, Notification, DeliveryContext, ChannelContext } from '@dudousxd/nestjs-notifications-core';
|
|
3
|
+
import { OutboxInbox } from '@nestjs/outbox';
|
|
4
|
+
import { HttpWebhookTransportOptions, WebhookTransport, Webhooks, WebhookMessage as WebhookMessage$1 } from '@nestjs/webhooks';
|
|
3
5
|
import { DynamicModule } from '@nestjs/common';
|
|
4
6
|
|
|
5
|
-
/** The HTTP method used for a webhook request. */
|
|
6
|
-
type WebhookMethod = 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'GET';
|
|
7
7
|
/** The resolved request description produced by {@link WebhookMessage.toRequest}. */
|
|
8
8
|
interface WebhookRequest {
|
|
9
9
|
/** Target URL, when set on the message; otherwise resolved by the channel. */
|
|
10
10
|
url?: string | undefined;
|
|
11
|
-
method: WebhookMethod;
|
|
12
11
|
headers: Record<string, string>;
|
|
13
|
-
/** The JSON body to
|
|
12
|
+
/** The JSON body to POST (a plain object). */
|
|
14
13
|
body: Record<string, unknown>;
|
|
15
14
|
}
|
|
16
15
|
/**
|
|
17
|
-
* A fluent builder for a webhook request.
|
|
16
|
+
* A fluent builder for a direct webhook request (always a `POST` with a JSON body).
|
|
18
17
|
*
|
|
19
18
|
* ```ts
|
|
20
19
|
* new WebhookMessage()
|
|
21
20
|
* .url('https://example.com/hooks/orders')
|
|
22
|
-
* .header('X-
|
|
21
|
+
* .header('X-App', 'shop')
|
|
23
22
|
* .payload({ event: 'order.paid', id: 42 });
|
|
24
23
|
* ```
|
|
25
24
|
*/
|
|
26
25
|
declare class WebhookMessage {
|
|
27
26
|
private _url?;
|
|
28
|
-
private _method;
|
|
29
27
|
private _headers;
|
|
30
28
|
private _payload;
|
|
31
29
|
/** Set the target URL (overrides the route and configured default). */
|
|
@@ -36,84 +34,134 @@ declare class WebhookMessage {
|
|
|
36
34
|
header(key: string, value: string): this;
|
|
37
35
|
/** Merge multiple request headers. */
|
|
38
36
|
headers(obj: Record<string, string>): this;
|
|
39
|
-
/** Set the HTTP method (default `POST`). */
|
|
40
|
-
method(m: WebhookMethod): this;
|
|
41
37
|
get urlValue(): string | undefined;
|
|
42
|
-
get methodValue(): WebhookMethod;
|
|
43
38
|
get headerValues(): Record<string, string>;
|
|
44
39
|
get payloadValue(): Record<string, unknown>;
|
|
45
40
|
/** Serialize to a {@link WebhookRequest}. */
|
|
46
41
|
toRequest(): WebhookRequest;
|
|
47
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* A webhook event for subscription delivery: `@nestjs/webhooks` fans it out to every endpoint of
|
|
45
|
+
* the tenant subscribed to `type`, signs it (Standard Webhooks), retries and logs each delivery.
|
|
46
|
+
* Return one from `toWebhook(ctx)` instead of a {@link WebhookMessage}.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* toWebhook() { return new WebhookEvent('invoice.paid', { id: this.invoice.id }); }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare class WebhookEvent<D = unknown> {
|
|
53
|
+
/** Full-stop delimited: `invoice.paid`. In `WebhooksModule`'s `eventTypes` when that is set. */
|
|
54
|
+
readonly type: string;
|
|
55
|
+
/** JSON-serializable data, sent as the body's `data`. */
|
|
56
|
+
readonly data: D;
|
|
57
|
+
constructor(
|
|
58
|
+
/** Full-stop delimited: `invoice.paid`. In `WebhooksModule`'s `eventTypes` when that is set. */
|
|
59
|
+
type: string,
|
|
60
|
+
/** JSON-serializable data, sent as the body's `data`. */
|
|
61
|
+
data: D);
|
|
62
|
+
}
|
|
48
63
|
|
|
64
|
+
/**
|
|
65
|
+
* The outbox inbox consumer under which subscription deliveries record the `webhook-id`s they
|
|
66
|
+
* dispatched, so a retried notification doesn't dispatch the same event twice.
|
|
67
|
+
*/
|
|
68
|
+
declare const WEBHOOK_DISPATCH_CONSUMER = "aviary.notifications.webhook-dispatch";
|
|
49
69
|
/** Channel handle: use as `@Webhook()` on a payload method, or as a token in `via()`. */
|
|
50
70
|
declare const Webhook: _dudousxd_nestjs_notifications_core.ChannelHandle;
|
|
51
|
-
/**
|
|
71
|
+
/** Opens a transaction for subscription delivery, e.g. `(work) => db.transaction(work)`. */
|
|
72
|
+
type WebhookTransactionRunner = <T>(work: (tx: unknown) => Promise<T>) => Promise<T>;
|
|
73
|
+
/** Resolved runtime options for direct-URL delivery. */
|
|
52
74
|
interface WebhookChannelOptions {
|
|
53
75
|
/** Default URL used when neither the message nor the route supplies one. */
|
|
54
76
|
url?: string;
|
|
55
77
|
/** Default headers merged into every request. */
|
|
56
78
|
headers?: Record<string, string>;
|
|
79
|
+
/** Signing secret. Unset: requests are not signed. */
|
|
80
|
+
secret?: string;
|
|
57
81
|
/**
|
|
58
|
-
*
|
|
59
|
-
* `
|
|
60
|
-
*
|
|
82
|
+
* `'sha256'` (default): `<signatureHeader>: sha256=<hex HMAC of the body>`.
|
|
83
|
+
* `'standard'`: Standard Webhooks headers, verifiable with `@nestjs/webhooks`'
|
|
84
|
+
* `@VerifyWebhook()` and a `scheme: 'standard'` receiver; `secret` is then `whsec_…`.
|
|
61
85
|
*/
|
|
62
|
-
|
|
63
|
-
/** Header
|
|
86
|
+
signing?: 'sha256' | 'standard';
|
|
87
|
+
/** Header for the `'sha256'` signature. Default `X-Signature-256`. */
|
|
64
88
|
signatureHeader?: string;
|
|
65
|
-
/** Abort a request that takes longer than this (ms).
|
|
89
|
+
/** Abort a request that takes longer than this (ms). Default 15000. */
|
|
66
90
|
timeoutMs?: number;
|
|
67
91
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
92
|
+
* The SSRF policy of `@nestjs/webhooks`' `HttpWebhookTransport` (https only, every resolved
|
|
93
|
+
* address checked and pinned, redirects never followed): `allowHttp`, `allowPrivateNetworks`,
|
|
94
|
+
* `allowedAddresses`, `ca`, `maxResponseSize`, `lookup`.
|
|
95
|
+
*/
|
|
96
|
+
delivery?: HttpWebhookTransportOptions;
|
|
97
|
+
/**
|
|
98
|
+
* A `@nestjs/webhooks` transport instance to send through instead (a proxy, mTLS, or
|
|
99
|
+
* `InMemoryWebhookTransport` in tests). Takes precedence over `delivery`.
|
|
70
100
|
*/
|
|
71
|
-
|
|
101
|
+
transport?: WebhookTransport;
|
|
72
102
|
}
|
|
73
103
|
/**
|
|
74
|
-
* Implement this on a notification to define its webhook payload
|
|
75
|
-
*
|
|
76
|
-
*
|
|
104
|
+
* Implement this on a notification to define its webhook payload: a plain object (the JSON body),
|
|
105
|
+
* a {@link WebhookMessage} (url, headers, body), or a {@link WebhookEvent} for subscription
|
|
106
|
+
* delivery through `@nestjs/webhooks`.
|
|
77
107
|
*/
|
|
78
108
|
interface WebhookNotification extends Notification {
|
|
79
|
-
toWebhook(ctx: ChannelContext): WebhookMessage | Record<string, unknown>;
|
|
109
|
+
toWebhook(ctx: ChannelContext): WebhookMessage | WebhookEvent | Record<string, unknown>;
|
|
80
110
|
}
|
|
81
111
|
/** Resolves per-tenant {@link WebhookChannelOptions} from a tenant id. */
|
|
82
112
|
type WebhookOptionsResolver = (tenant: string) => WebhookChannelOptions;
|
|
113
|
+
/** What a direct delivery returns (the channel response). */
|
|
114
|
+
interface WebhookDeliveryResult {
|
|
115
|
+
/** The `webhook-id` (Standard signing) or a generated id. */
|
|
116
|
+
id: string;
|
|
117
|
+
statusCode: number;
|
|
118
|
+
}
|
|
83
119
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
|
|
120
|
+
* What a subscription delivery returns when its `webhook-id` was already dispatched by an earlier
|
|
121
|
+
* attempt of the same delivery: nothing was dispatched this time.
|
|
122
|
+
*/
|
|
123
|
+
interface WebhookAlreadyDispatched {
|
|
124
|
+
id: string;
|
|
125
|
+
duplicate: true;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Delivers a notification as a webhook, two ways:
|
|
129
|
+
*
|
|
130
|
+
* - **Direct**: a signed `POST` of the JSON body to one URL (the message's, else the
|
|
131
|
+
* `routeNotificationFor('webhook')` URL, else the configured default), through `@nestjs/webhooks`'
|
|
132
|
+
* SSRF-guarded `HttpWebhookTransport`. A non-2xx answer fails the delivery.
|
|
133
|
+
* - **Subscriptions**: a {@link WebhookEvent} is handed to `Webhooks.dispatch()`, which fans it
|
|
134
|
+
* out to the endpoints subscribed to its type (for the delivery's tenant), with retries and a
|
|
135
|
+
* delivery log. Needs `WebhooksModule` + `OutboxModule` and the `transaction` option. A
|
|
136
|
+
* delivery with an `idempotencyKey` (the outbox dispatcher's message id) records its
|
|
137
|
+
* `webhook-id` in the outbox inbox in the same transaction as the dispatch, so a retry of it
|
|
138
|
+
* dispatches nothing and returns {@link WebhookAlreadyDispatched}.
|
|
87
139
|
*/
|
|
88
140
|
declare class WebhookChannel extends BaseChannel {
|
|
89
141
|
private readonly options;
|
|
90
142
|
private readonly resolveOptions?;
|
|
143
|
+
private readonly transaction?;
|
|
144
|
+
private readonly webhooks?;
|
|
145
|
+
private readonly inbox?;
|
|
91
146
|
readonly channel = "webhook";
|
|
92
|
-
|
|
93
|
-
|
|
147
|
+
private readonly transports;
|
|
148
|
+
constructor(options: WebhookChannelOptions, resolveOptions?: WebhookOptionsResolver | undefined, transaction?: WebhookTransactionRunner | undefined, webhooks?: Webhooks | undefined, inbox?: OutboxInbox | undefined);
|
|
149
|
+
send(notifiable: Notifiable, notification: Notification, context?: DeliveryContext): Promise<WebhookDeliveryResult | WebhookMessage$1 | WebhookAlreadyDispatched>;
|
|
150
|
+
private dispatch;
|
|
151
|
+
private transportFor;
|
|
94
152
|
}
|
|
95
153
|
|
|
96
|
-
interface WebhookChannelModuleOptions {
|
|
97
|
-
/** Default URL used when neither the message nor the route supplies one. */
|
|
98
|
-
url?: string;
|
|
99
|
-
/** Default headers merged into every request. */
|
|
100
|
-
headers?: Record<string, string>;
|
|
101
|
-
/**
|
|
102
|
-
* HMAC-SHA256 signing secret. When set, every request carries
|
|
103
|
-
* `<signatureHeader>: sha256=<hex digest of the JSON body>`.
|
|
104
|
-
*/
|
|
105
|
-
secret?: string;
|
|
106
|
-
/** Header name for the signature. Default `X-Signature-256`. */
|
|
107
|
-
signatureHeader?: string;
|
|
108
|
-
/** Abort a request that takes longer than this (ms). Unset = no timeout. */
|
|
109
|
-
timeoutMs?: number;
|
|
110
|
-
/** Redirect handling: `'follow'` (default), `'error'` or `'manual'`. */
|
|
111
|
-
redirect?: 'follow' | 'error' | 'manual';
|
|
154
|
+
interface WebhookChannelModuleOptions extends WebhookChannelOptions {
|
|
112
155
|
/**
|
|
113
156
|
* Optional per-tenant options resolver. When a notification is delivered with a
|
|
114
157
|
* `context.tenant`, the returned options are used instead of the defaults.
|
|
115
158
|
*/
|
|
116
159
|
resolveOptions?: WebhookOptionsResolver;
|
|
160
|
+
/**
|
|
161
|
+
* Opens a transaction for subscription delivery ({@link WebhookEvent}): `@nestjs/webhooks`
|
|
162
|
+
* writes the event to the outbox through it, e.g. `(work) => db.transaction(work)`.
|
|
163
|
+
*/
|
|
164
|
+
transaction?: WebhookTransactionRunner;
|
|
117
165
|
/** Register globally so the channel is discoverable app-wide. Default true. */
|
|
118
166
|
global?: boolean;
|
|
119
167
|
}
|
|
@@ -121,16 +169,27 @@ interface WebhookChannelModuleOptions {
|
|
|
121
169
|
* Registers the webhook channel.
|
|
122
170
|
*
|
|
123
171
|
* ```ts
|
|
124
|
-
* WebhookChannelModule.forRoot({ url: 'https://example.com/hooks
|
|
172
|
+
* WebhookChannelModule.forRoot({ url: 'https://example.com/hooks', secret: 'whsec_…', signing: 'standard' });
|
|
125
173
|
* ```
|
|
126
174
|
*/
|
|
127
175
|
declare class WebhookChannelModule {
|
|
128
176
|
static forRoot(options?: WebhookChannelModuleOptions): DynamicModule;
|
|
129
177
|
}
|
|
130
178
|
|
|
131
|
-
/**
|
|
179
|
+
/**
|
|
180
|
+
* Standard Webhooks headers (`webhook-id`, `webhook-timestamp`, `webhook-signature: v1,…`) for
|
|
181
|
+
* `body`, verifiable by a `@nestjs/webhooks` receiver with `scheme: 'standard'` (`@VerifyWebhook`).
|
|
182
|
+
* `secret` is `whsec_` + base64 (the prefix is optional).
|
|
183
|
+
*/
|
|
184
|
+
declare function standardWebhookHeaders(secret: string, id: string, body: string, now?: Date): Record<string, string>;
|
|
185
|
+
/** The legacy `sha256=<hex HMAC of the body>` signature (GitHub-style). */
|
|
186
|
+
declare function sha256Signature(secret: string, body: string): string;
|
|
187
|
+
|
|
188
|
+
/** DI token for the resolved {@link WebhookChannelOptions}. */
|
|
132
189
|
declare const WEBHOOK_OPTIONS: unique symbol;
|
|
133
190
|
/** DI token for the optional per-tenant {@link WebhookChannelOptions} resolver. */
|
|
134
191
|
declare const WEBHOOK_OPTIONS_RESOLVER: unique symbol;
|
|
192
|
+
/** DI token for the transaction opener used by subscription delivery. */
|
|
193
|
+
declare const WEBHOOK_TRANSACTION: unique symbol;
|
|
135
194
|
|
|
136
|
-
export { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER, Webhook, WebhookChannel, WebhookChannelModule, type WebhookChannelModuleOptions, type WebhookChannelOptions,
|
|
195
|
+
export { WEBHOOK_DISPATCH_CONSUMER, WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER, WEBHOOK_TRANSACTION, Webhook, type WebhookAlreadyDispatched, WebhookChannel, WebhookChannelModule, type WebhookChannelModuleOptions, type WebhookChannelOptions, type WebhookDeliveryResult, WebhookEvent, WebhookMessage, type WebhookNotification, type WebhookOptionsResolver, type WebhookRequest, type WebhookTransactionRunner, sha256Signature, standardWebhookHeaders };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
import * as _dudousxd_nestjs_notifications_core from '@dudousxd/nestjs-notifications-core';
|
|
2
2
|
import { BaseChannel, Notifiable, Notification, DeliveryContext, ChannelContext } from '@dudousxd/nestjs-notifications-core';
|
|
3
|
+
import { OutboxInbox } from '@nestjs/outbox';
|
|
4
|
+
import { HttpWebhookTransportOptions, WebhookTransport, Webhooks, WebhookMessage as WebhookMessage$1 } from '@nestjs/webhooks';
|
|
3
5
|
import { DynamicModule } from '@nestjs/common';
|
|
4
6
|
|
|
5
|
-
/** The HTTP method used for a webhook request. */
|
|
6
|
-
type WebhookMethod = 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'GET';
|
|
7
7
|
/** The resolved request description produced by {@link WebhookMessage.toRequest}. */
|
|
8
8
|
interface WebhookRequest {
|
|
9
9
|
/** Target URL, when set on the message; otherwise resolved by the channel. */
|
|
10
10
|
url?: string | undefined;
|
|
11
|
-
method: WebhookMethod;
|
|
12
11
|
headers: Record<string, string>;
|
|
13
|
-
/** The JSON body to
|
|
12
|
+
/** The JSON body to POST (a plain object). */
|
|
14
13
|
body: Record<string, unknown>;
|
|
15
14
|
}
|
|
16
15
|
/**
|
|
17
|
-
* A fluent builder for a webhook request.
|
|
16
|
+
* A fluent builder for a direct webhook request (always a `POST` with a JSON body).
|
|
18
17
|
*
|
|
19
18
|
* ```ts
|
|
20
19
|
* new WebhookMessage()
|
|
21
20
|
* .url('https://example.com/hooks/orders')
|
|
22
|
-
* .header('X-
|
|
21
|
+
* .header('X-App', 'shop')
|
|
23
22
|
* .payload({ event: 'order.paid', id: 42 });
|
|
24
23
|
* ```
|
|
25
24
|
*/
|
|
26
25
|
declare class WebhookMessage {
|
|
27
26
|
private _url?;
|
|
28
|
-
private _method;
|
|
29
27
|
private _headers;
|
|
30
28
|
private _payload;
|
|
31
29
|
/** Set the target URL (overrides the route and configured default). */
|
|
@@ -36,84 +34,134 @@ declare class WebhookMessage {
|
|
|
36
34
|
header(key: string, value: string): this;
|
|
37
35
|
/** Merge multiple request headers. */
|
|
38
36
|
headers(obj: Record<string, string>): this;
|
|
39
|
-
/** Set the HTTP method (default `POST`). */
|
|
40
|
-
method(m: WebhookMethod): this;
|
|
41
37
|
get urlValue(): string | undefined;
|
|
42
|
-
get methodValue(): WebhookMethod;
|
|
43
38
|
get headerValues(): Record<string, string>;
|
|
44
39
|
get payloadValue(): Record<string, unknown>;
|
|
45
40
|
/** Serialize to a {@link WebhookRequest}. */
|
|
46
41
|
toRequest(): WebhookRequest;
|
|
47
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* A webhook event for subscription delivery: `@nestjs/webhooks` fans it out to every endpoint of
|
|
45
|
+
* the tenant subscribed to `type`, signs it (Standard Webhooks), retries and logs each delivery.
|
|
46
|
+
* Return one from `toWebhook(ctx)` instead of a {@link WebhookMessage}.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* toWebhook() { return new WebhookEvent('invoice.paid', { id: this.invoice.id }); }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare class WebhookEvent<D = unknown> {
|
|
53
|
+
/** Full-stop delimited: `invoice.paid`. In `WebhooksModule`'s `eventTypes` when that is set. */
|
|
54
|
+
readonly type: string;
|
|
55
|
+
/** JSON-serializable data, sent as the body's `data`. */
|
|
56
|
+
readonly data: D;
|
|
57
|
+
constructor(
|
|
58
|
+
/** Full-stop delimited: `invoice.paid`. In `WebhooksModule`'s `eventTypes` when that is set. */
|
|
59
|
+
type: string,
|
|
60
|
+
/** JSON-serializable data, sent as the body's `data`. */
|
|
61
|
+
data: D);
|
|
62
|
+
}
|
|
48
63
|
|
|
64
|
+
/**
|
|
65
|
+
* The outbox inbox consumer under which subscription deliveries record the `webhook-id`s they
|
|
66
|
+
* dispatched, so a retried notification doesn't dispatch the same event twice.
|
|
67
|
+
*/
|
|
68
|
+
declare const WEBHOOK_DISPATCH_CONSUMER = "aviary.notifications.webhook-dispatch";
|
|
49
69
|
/** Channel handle: use as `@Webhook()` on a payload method, or as a token in `via()`. */
|
|
50
70
|
declare const Webhook: _dudousxd_nestjs_notifications_core.ChannelHandle;
|
|
51
|
-
/**
|
|
71
|
+
/** Opens a transaction for subscription delivery, e.g. `(work) => db.transaction(work)`. */
|
|
72
|
+
type WebhookTransactionRunner = <T>(work: (tx: unknown) => Promise<T>) => Promise<T>;
|
|
73
|
+
/** Resolved runtime options for direct-URL delivery. */
|
|
52
74
|
interface WebhookChannelOptions {
|
|
53
75
|
/** Default URL used when neither the message nor the route supplies one. */
|
|
54
76
|
url?: string;
|
|
55
77
|
/** Default headers merged into every request. */
|
|
56
78
|
headers?: Record<string, string>;
|
|
79
|
+
/** Signing secret. Unset: requests are not signed. */
|
|
80
|
+
secret?: string;
|
|
57
81
|
/**
|
|
58
|
-
*
|
|
59
|
-
* `
|
|
60
|
-
*
|
|
82
|
+
* `'sha256'` (default): `<signatureHeader>: sha256=<hex HMAC of the body>`.
|
|
83
|
+
* `'standard'`: Standard Webhooks headers, verifiable with `@nestjs/webhooks`'
|
|
84
|
+
* `@VerifyWebhook()` and a `scheme: 'standard'` receiver; `secret` is then `whsec_…`.
|
|
61
85
|
*/
|
|
62
|
-
|
|
63
|
-
/** Header
|
|
86
|
+
signing?: 'sha256' | 'standard';
|
|
87
|
+
/** Header for the `'sha256'` signature. Default `X-Signature-256`. */
|
|
64
88
|
signatureHeader?: string;
|
|
65
|
-
/** Abort a request that takes longer than this (ms).
|
|
89
|
+
/** Abort a request that takes longer than this (ms). Default 15000. */
|
|
66
90
|
timeoutMs?: number;
|
|
67
91
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
92
|
+
* The SSRF policy of `@nestjs/webhooks`' `HttpWebhookTransport` (https only, every resolved
|
|
93
|
+
* address checked and pinned, redirects never followed): `allowHttp`, `allowPrivateNetworks`,
|
|
94
|
+
* `allowedAddresses`, `ca`, `maxResponseSize`, `lookup`.
|
|
95
|
+
*/
|
|
96
|
+
delivery?: HttpWebhookTransportOptions;
|
|
97
|
+
/**
|
|
98
|
+
* A `@nestjs/webhooks` transport instance to send through instead (a proxy, mTLS, or
|
|
99
|
+
* `InMemoryWebhookTransport` in tests). Takes precedence over `delivery`.
|
|
70
100
|
*/
|
|
71
|
-
|
|
101
|
+
transport?: WebhookTransport;
|
|
72
102
|
}
|
|
73
103
|
/**
|
|
74
|
-
* Implement this on a notification to define its webhook payload
|
|
75
|
-
*
|
|
76
|
-
*
|
|
104
|
+
* Implement this on a notification to define its webhook payload: a plain object (the JSON body),
|
|
105
|
+
* a {@link WebhookMessage} (url, headers, body), or a {@link WebhookEvent} for subscription
|
|
106
|
+
* delivery through `@nestjs/webhooks`.
|
|
77
107
|
*/
|
|
78
108
|
interface WebhookNotification extends Notification {
|
|
79
|
-
toWebhook(ctx: ChannelContext): WebhookMessage | Record<string, unknown>;
|
|
109
|
+
toWebhook(ctx: ChannelContext): WebhookMessage | WebhookEvent | Record<string, unknown>;
|
|
80
110
|
}
|
|
81
111
|
/** Resolves per-tenant {@link WebhookChannelOptions} from a tenant id. */
|
|
82
112
|
type WebhookOptionsResolver = (tenant: string) => WebhookChannelOptions;
|
|
113
|
+
/** What a direct delivery returns (the channel response). */
|
|
114
|
+
interface WebhookDeliveryResult {
|
|
115
|
+
/** The `webhook-id` (Standard signing) or a generated id. */
|
|
116
|
+
id: string;
|
|
117
|
+
statusCode: number;
|
|
118
|
+
}
|
|
83
119
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
|
|
120
|
+
* What a subscription delivery returns when its `webhook-id` was already dispatched by an earlier
|
|
121
|
+
* attempt of the same delivery: nothing was dispatched this time.
|
|
122
|
+
*/
|
|
123
|
+
interface WebhookAlreadyDispatched {
|
|
124
|
+
id: string;
|
|
125
|
+
duplicate: true;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Delivers a notification as a webhook, two ways:
|
|
129
|
+
*
|
|
130
|
+
* - **Direct**: a signed `POST` of the JSON body to one URL (the message's, else the
|
|
131
|
+
* `routeNotificationFor('webhook')` URL, else the configured default), through `@nestjs/webhooks`'
|
|
132
|
+
* SSRF-guarded `HttpWebhookTransport`. A non-2xx answer fails the delivery.
|
|
133
|
+
* - **Subscriptions**: a {@link WebhookEvent} is handed to `Webhooks.dispatch()`, which fans it
|
|
134
|
+
* out to the endpoints subscribed to its type (for the delivery's tenant), with retries and a
|
|
135
|
+
* delivery log. Needs `WebhooksModule` + `OutboxModule` and the `transaction` option. A
|
|
136
|
+
* delivery with an `idempotencyKey` (the outbox dispatcher's message id) records its
|
|
137
|
+
* `webhook-id` in the outbox inbox in the same transaction as the dispatch, so a retry of it
|
|
138
|
+
* dispatches nothing and returns {@link WebhookAlreadyDispatched}.
|
|
87
139
|
*/
|
|
88
140
|
declare class WebhookChannel extends BaseChannel {
|
|
89
141
|
private readonly options;
|
|
90
142
|
private readonly resolveOptions?;
|
|
143
|
+
private readonly transaction?;
|
|
144
|
+
private readonly webhooks?;
|
|
145
|
+
private readonly inbox?;
|
|
91
146
|
readonly channel = "webhook";
|
|
92
|
-
|
|
93
|
-
|
|
147
|
+
private readonly transports;
|
|
148
|
+
constructor(options: WebhookChannelOptions, resolveOptions?: WebhookOptionsResolver | undefined, transaction?: WebhookTransactionRunner | undefined, webhooks?: Webhooks | undefined, inbox?: OutboxInbox | undefined);
|
|
149
|
+
send(notifiable: Notifiable, notification: Notification, context?: DeliveryContext): Promise<WebhookDeliveryResult | WebhookMessage$1 | WebhookAlreadyDispatched>;
|
|
150
|
+
private dispatch;
|
|
151
|
+
private transportFor;
|
|
94
152
|
}
|
|
95
153
|
|
|
96
|
-
interface WebhookChannelModuleOptions {
|
|
97
|
-
/** Default URL used when neither the message nor the route supplies one. */
|
|
98
|
-
url?: string;
|
|
99
|
-
/** Default headers merged into every request. */
|
|
100
|
-
headers?: Record<string, string>;
|
|
101
|
-
/**
|
|
102
|
-
* HMAC-SHA256 signing secret. When set, every request carries
|
|
103
|
-
* `<signatureHeader>: sha256=<hex digest of the JSON body>`.
|
|
104
|
-
*/
|
|
105
|
-
secret?: string;
|
|
106
|
-
/** Header name for the signature. Default `X-Signature-256`. */
|
|
107
|
-
signatureHeader?: string;
|
|
108
|
-
/** Abort a request that takes longer than this (ms). Unset = no timeout. */
|
|
109
|
-
timeoutMs?: number;
|
|
110
|
-
/** Redirect handling: `'follow'` (default), `'error'` or `'manual'`. */
|
|
111
|
-
redirect?: 'follow' | 'error' | 'manual';
|
|
154
|
+
interface WebhookChannelModuleOptions extends WebhookChannelOptions {
|
|
112
155
|
/**
|
|
113
156
|
* Optional per-tenant options resolver. When a notification is delivered with a
|
|
114
157
|
* `context.tenant`, the returned options are used instead of the defaults.
|
|
115
158
|
*/
|
|
116
159
|
resolveOptions?: WebhookOptionsResolver;
|
|
160
|
+
/**
|
|
161
|
+
* Opens a transaction for subscription delivery ({@link WebhookEvent}): `@nestjs/webhooks`
|
|
162
|
+
* writes the event to the outbox through it, e.g. `(work) => db.transaction(work)`.
|
|
163
|
+
*/
|
|
164
|
+
transaction?: WebhookTransactionRunner;
|
|
117
165
|
/** Register globally so the channel is discoverable app-wide. Default true. */
|
|
118
166
|
global?: boolean;
|
|
119
167
|
}
|
|
@@ -121,16 +169,27 @@ interface WebhookChannelModuleOptions {
|
|
|
121
169
|
* Registers the webhook channel.
|
|
122
170
|
*
|
|
123
171
|
* ```ts
|
|
124
|
-
* WebhookChannelModule.forRoot({ url: 'https://example.com/hooks
|
|
172
|
+
* WebhookChannelModule.forRoot({ url: 'https://example.com/hooks', secret: 'whsec_…', signing: 'standard' });
|
|
125
173
|
* ```
|
|
126
174
|
*/
|
|
127
175
|
declare class WebhookChannelModule {
|
|
128
176
|
static forRoot(options?: WebhookChannelModuleOptions): DynamicModule;
|
|
129
177
|
}
|
|
130
178
|
|
|
131
|
-
/**
|
|
179
|
+
/**
|
|
180
|
+
* Standard Webhooks headers (`webhook-id`, `webhook-timestamp`, `webhook-signature: v1,…`) for
|
|
181
|
+
* `body`, verifiable by a `@nestjs/webhooks` receiver with `scheme: 'standard'` (`@VerifyWebhook`).
|
|
182
|
+
* `secret` is `whsec_` + base64 (the prefix is optional).
|
|
183
|
+
*/
|
|
184
|
+
declare function standardWebhookHeaders(secret: string, id: string, body: string, now?: Date): Record<string, string>;
|
|
185
|
+
/** The legacy `sha256=<hex HMAC of the body>` signature (GitHub-style). */
|
|
186
|
+
declare function sha256Signature(secret: string, body: string): string;
|
|
187
|
+
|
|
188
|
+
/** DI token for the resolved {@link WebhookChannelOptions}. */
|
|
132
189
|
declare const WEBHOOK_OPTIONS: unique symbol;
|
|
133
190
|
/** DI token for the optional per-tenant {@link WebhookChannelOptions} resolver. */
|
|
134
191
|
declare const WEBHOOK_OPTIONS_RESOLVER: unique symbol;
|
|
192
|
+
/** DI token for the transaction opener used by subscription delivery. */
|
|
193
|
+
declare const WEBHOOK_TRANSACTION: unique symbol;
|
|
135
194
|
|
|
136
|
-
export { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER, Webhook, WebhookChannel, WebhookChannelModule, type WebhookChannelModuleOptions, type WebhookChannelOptions,
|
|
195
|
+
export { WEBHOOK_DISPATCH_CONSUMER, WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER, WEBHOOK_TRANSACTION, Webhook, type WebhookAlreadyDispatched, WebhookChannel, WebhookChannelModule, type WebhookChannelModuleOptions, type WebhookChannelOptions, type WebhookDeliveryResult, WebhookEvent, WebhookMessage, type WebhookNotification, type WebhookOptionsResolver, type WebhookRequest, type WebhookTransactionRunner, sha256Signature, standardWebhookHeaders };
|