@dudousxd/nestjs-notifications-webhook 0.5.2 → 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.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 send (a plain object). */
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-Signature', sign(payload))
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,66 +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
- /** Resolved runtime options for the webhook channel. */
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
- * HMAC-SHA256 secret. When set, the request is signed: the header (default
59
- * `X-Signature-256`) is set to `sha256=<hex digest of the raw JSON body>`, so the receiver
60
- * can verify authenticity. Per-tenant secrets work via `resolveOptions`.
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
- secret?: string;
63
- /** Header name for the signature. Default `X-Signature-256`. */
86
+ signing?: 'sha256' | 'standard';
87
+ /** Header for the `'sha256'` signature. Default `X-Signature-256`. */
64
88
  signatureHeader?: string;
89
+ /** Abort a request that takes longer than this (ms). Default 15000. */
90
+ timeoutMs?: number;
91
+ /**
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`.
100
+ */
101
+ transport?: WebhookTransport;
65
102
  }
66
103
  /**
67
- * Implement this on a notification to define its webhook payload. Returning a plain
68
- * object is treated as the JSON body to POST; return a {@link WebhookMessage} for full
69
- * control over the url, method and headers.
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`.
70
107
  */
71
108
  interface WebhookNotification extends Notification {
72
- toWebhook(ctx: ChannelContext): WebhookMessage | Record<string, unknown>;
109
+ toWebhook(ctx: ChannelContext): WebhookMessage | WebhookEvent | Record<string, unknown>;
73
110
  }
74
111
  /** Resolves per-tenant {@link WebhookChannelOptions} from a tenant id. */
75
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
+ }
76
119
  /**
77
- * Delivers a notification by sending an HTTP request (JSON body) to a webhook endpoint.
78
- * The target URL comes from the {@link WebhookMessage}, else from
79
- * `routeNotificationFor('webhook')` (a URL string), else from the configured default.
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}.
80
139
  */
81
140
  declare class WebhookChannel extends BaseChannel {
82
141
  private readonly options;
83
142
  private readonly resolveOptions?;
143
+ private readonly transaction?;
144
+ private readonly webhooks?;
145
+ private readonly inbox?;
84
146
  readonly channel = "webhook";
85
- constructor(options: WebhookChannelOptions, resolveOptions?: WebhookOptionsResolver | undefined);
86
- send(notifiable: Notifiable, notification: Notification, context?: DeliveryContext): Promise<void>;
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;
87
152
  }
88
153
 
89
- interface WebhookChannelModuleOptions {
90
- /** Default URL used when neither the message nor the route supplies one. */
91
- url?: string;
92
- /** Default headers merged into every request. */
93
- headers?: Record<string, string>;
154
+ interface WebhookChannelModuleOptions extends WebhookChannelOptions {
94
155
  /**
95
156
  * Optional per-tenant options resolver. When a notification is delivered with a
96
157
  * `context.tenant`, the returned options are used instead of the defaults.
97
158
  */
98
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;
99
165
  /** Register globally so the channel is discoverable app-wide. Default true. */
100
166
  global?: boolean;
101
167
  }
@@ -103,16 +169,27 @@ interface WebhookChannelModuleOptions {
103
169
  * Registers the webhook channel.
104
170
  *
105
171
  * ```ts
106
- * WebhookChannelModule.forRoot({ url: 'https://example.com/hooks/notifications' });
172
+ * WebhookChannelModule.forRoot({ url: 'https://example.com/hooks', secret: 'whsec_…', signing: 'standard' });
107
173
  * ```
108
174
  */
109
175
  declare class WebhookChannelModule {
110
176
  static forRoot(options?: WebhookChannelModuleOptions): DynamicModule;
111
177
  }
112
178
 
113
- /** DI token for the resolved {@link WebhookChannelOptions} (default url, headers). */
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}. */
114
189
  declare const WEBHOOK_OPTIONS: unique symbol;
115
190
  /** DI token for the optional per-tenant {@link WebhookChannelOptions} resolver. */
116
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;
117
194
 
118
- export { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER, Webhook, WebhookChannel, WebhookChannelModule, type WebhookChannelModuleOptions, type WebhookChannelOptions, WebhookMessage, type WebhookMethod, type WebhookNotification, type WebhookOptionsResolver, type WebhookRequest };
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 send (a plain object). */
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-Signature', sign(payload))
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,66 +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
- /** Resolved runtime options for the webhook channel. */
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
- * HMAC-SHA256 secret. When set, the request is signed: the header (default
59
- * `X-Signature-256`) is set to `sha256=<hex digest of the raw JSON body>`, so the receiver
60
- * can verify authenticity. Per-tenant secrets work via `resolveOptions`.
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
- secret?: string;
63
- /** Header name for the signature. Default `X-Signature-256`. */
86
+ signing?: 'sha256' | 'standard';
87
+ /** Header for the `'sha256'` signature. Default `X-Signature-256`. */
64
88
  signatureHeader?: string;
89
+ /** Abort a request that takes longer than this (ms). Default 15000. */
90
+ timeoutMs?: number;
91
+ /**
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`.
100
+ */
101
+ transport?: WebhookTransport;
65
102
  }
66
103
  /**
67
- * Implement this on a notification to define its webhook payload. Returning a plain
68
- * object is treated as the JSON body to POST; return a {@link WebhookMessage} for full
69
- * control over the url, method and headers.
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`.
70
107
  */
71
108
  interface WebhookNotification extends Notification {
72
- toWebhook(ctx: ChannelContext): WebhookMessage | Record<string, unknown>;
109
+ toWebhook(ctx: ChannelContext): WebhookMessage | WebhookEvent | Record<string, unknown>;
73
110
  }
74
111
  /** Resolves per-tenant {@link WebhookChannelOptions} from a tenant id. */
75
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
+ }
76
119
  /**
77
- * Delivers a notification by sending an HTTP request (JSON body) to a webhook endpoint.
78
- * The target URL comes from the {@link WebhookMessage}, else from
79
- * `routeNotificationFor('webhook')` (a URL string), else from the configured default.
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}.
80
139
  */
81
140
  declare class WebhookChannel extends BaseChannel {
82
141
  private readonly options;
83
142
  private readonly resolveOptions?;
143
+ private readonly transaction?;
144
+ private readonly webhooks?;
145
+ private readonly inbox?;
84
146
  readonly channel = "webhook";
85
- constructor(options: WebhookChannelOptions, resolveOptions?: WebhookOptionsResolver | undefined);
86
- send(notifiable: Notifiable, notification: Notification, context?: DeliveryContext): Promise<void>;
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;
87
152
  }
88
153
 
89
- interface WebhookChannelModuleOptions {
90
- /** Default URL used when neither the message nor the route supplies one. */
91
- url?: string;
92
- /** Default headers merged into every request. */
93
- headers?: Record<string, string>;
154
+ interface WebhookChannelModuleOptions extends WebhookChannelOptions {
94
155
  /**
95
156
  * Optional per-tenant options resolver. When a notification is delivered with a
96
157
  * `context.tenant`, the returned options are used instead of the defaults.
97
158
  */
98
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;
99
165
  /** Register globally so the channel is discoverable app-wide. Default true. */
100
166
  global?: boolean;
101
167
  }
@@ -103,16 +169,27 @@ interface WebhookChannelModuleOptions {
103
169
  * Registers the webhook channel.
104
170
  *
105
171
  * ```ts
106
- * WebhookChannelModule.forRoot({ url: 'https://example.com/hooks/notifications' });
172
+ * WebhookChannelModule.forRoot({ url: 'https://example.com/hooks', secret: 'whsec_…', signing: 'standard' });
107
173
  * ```
108
174
  */
109
175
  declare class WebhookChannelModule {
110
176
  static forRoot(options?: WebhookChannelModuleOptions): DynamicModule;
111
177
  }
112
178
 
113
- /** DI token for the resolved {@link WebhookChannelOptions} (default url, headers). */
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}. */
114
189
  declare const WEBHOOK_OPTIONS: unique symbol;
115
190
  /** DI token for the optional per-tenant {@link WebhookChannelOptions} resolver. */
116
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;
117
194
 
118
- export { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER, Webhook, WebhookChannel, WebhookChannelModule, type WebhookChannelModuleOptions, type WebhookChannelOptions, WebhookMessage, type WebhookMethod, type WebhookNotification, type WebhookOptionsResolver, type WebhookRequest };
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 };