@dudousxd/nestjs-notifications-webhook 0.5.0 → 0.5.1

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 CHANGED
@@ -121,7 +121,7 @@ function _ts_param(paramIndex, decorator) {
121
121
  __name(_ts_param, "_ts_param");
122
122
  var DEFAULT_SIGNATURE_HEADER = "X-Signature-256";
123
123
  var Webhook = (0, import_nestjs_notifications_core.createChannel)("webhook");
124
- var WebhookChannel = class {
124
+ var WebhookChannel = class extends import_nestjs_notifications_core.BaseChannel {
125
125
  static {
126
126
  __name(this, "WebhookChannel");
127
127
  }
@@ -129,21 +129,11 @@ var WebhookChannel = class {
129
129
  resolveOptions;
130
130
  channel = "webhook";
131
131
  constructor(options, resolveOptions) {
132
- this.options = options;
133
- this.resolveOptions = resolveOptions;
132
+ super(), this.options = options, this.resolveOptions = resolveOptions;
134
133
  }
135
134
  async send(notifiable, notification, context) {
136
- const options = context?.tenant && this.resolveOptions ? this.resolveOptions(context.tenant) : this.options;
137
- const handler = (0, import_nestjs_notifications_core.getHandler)(notification, "webhook", "toWebhook");
138
- if (!handler) {
139
- const name = notification.constructor.notificationName ?? notification.constructor.name;
140
- throw new import_nestjs_notifications_core.MissingChannelMethodError("webhook", "toWebhook()", name);
141
- }
142
- const result = handler({
143
- notifiable,
144
- localization: context?.localization,
145
- tenant: context?.tenant
146
- });
135
+ const options = this.forTenant(this.options, context, this.resolveOptions);
136
+ const result = this.buildPayload(notification, notifiable, "toWebhook", context);
147
137
  const message = result instanceof WebhookMessage ? result : new WebhookMessage().payload(result);
148
138
  const request = message.toRequest();
149
139
  const route = (0, import_nestjs_notifications_core.routeFor)(notifiable, "webhook", notification);
@@ -151,27 +141,19 @@ var WebhookChannel = class {
151
141
  if (!url) {
152
142
  throw new Error('The webhook channel needs a target URL. Set one on the WebhookMessage via .url(), return one from routeNotificationFor("webhook"), or set url in forRoot().');
153
143
  }
154
- await this.post(options, url, request.method, request.body, request.headers);
155
- }
156
- async post(options, url, method, body, messageHeaders) {
157
- const payload = JSON.stringify(body);
158
144
  const headers = {
159
145
  ...options.headers,
160
- ...messageHeaders,
161
- "Content-Type": "application/json"
146
+ ...request.headers
162
147
  };
163
148
  if (options.secret) {
164
- const signature = (0, import_node_crypto.createHmac)("sha256", options.secret).update(payload).digest("hex");
149
+ const signature = (0, import_node_crypto.createHmac)("sha256", options.secret).update(JSON.stringify(request.body)).digest("hex");
165
150
  headers[options.signatureHeader ?? DEFAULT_SIGNATURE_HEADER] = `sha256=${signature}`;
166
151
  }
167
- const response = await fetch(url, {
168
- method,
169
- headers,
170
- body: payload
152
+ await (0, import_nestjs_notifications_core.postJson)(url, request.body, {
153
+ label: "Webhook",
154
+ method: request.method,
155
+ headers
171
156
  });
172
- if (!response.ok) {
173
- throw new Error(`Webhook request to ${url} failed with status ${response.status}.`);
174
- }
175
157
  }
176
158
  };
177
159
  WebhookChannel = _ts_decorate([
@@ -187,6 +169,7 @@ WebhookChannel = _ts_decorate([
187
169
  ], WebhookChannel);
188
170
 
189
171
  // src/webhook.module.ts
172
+ var import_nestjs_notifications_core2 = require("@dudousxd/nestjs-notifications-core");
190
173
  var import_common2 = require("@nestjs/common");
191
174
  function _ts_decorate2(decorators, target, key, desc) {
192
175
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -210,25 +193,19 @@ var WebhookChannelModule = class _WebhookChannelModule {
210
193
  headers: options.headers
211
194
  } : {}
212
195
  };
213
- const providers = [
214
- {
215
- provide: WEBHOOK_OPTIONS,
216
- useValue: webhookOptions
217
- },
218
- {
219
- provide: WEBHOOK_OPTIONS_RESOLVER,
220
- useValue: options.resolveOptions ?? null
221
- },
222
- WebhookChannel
223
- ];
224
- return {
196
+ return (0, import_nestjs_notifications_core2.defineChannelModule)({
225
197
  module: _WebhookChannelModule,
226
- global: options.global ?? true,
227
- providers,
228
- exports: [
229
- WebhookChannel
230
- ]
231
- };
198
+ channel: WebhookChannel,
199
+ optionsToken: WEBHOOK_OPTIONS,
200
+ options: webhookOptions,
201
+ resolver: {
202
+ token: WEBHOOK_OPTIONS_RESOLVER,
203
+ value: options.resolveOptions
204
+ },
205
+ ...options.global !== void 0 ? {
206
+ global: options.global
207
+ } : {}
208
+ });
232
209
  }
233
210
  };
234
211
  WebhookChannelModule = _ts_decorate2([
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/webhook-message.ts","../src/webhook.channel.ts","../src/tokens.ts","../src/webhook.module.ts"],"sourcesContent":["export {\n WebhookMessage,\n type WebhookMethod,\n type WebhookRequest,\n} from './webhook-message';\nexport {\n Webhook,\n WebhookChannel,\n type WebhookChannelOptions,\n type WebhookNotification,\n type WebhookOptionsResolver,\n} from './webhook.channel';\nexport {\n WebhookChannelModule,\n type WebhookChannelModuleOptions,\n} from './webhook.module';\nexport { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER } from './tokens';\n","/** The HTTP method used for a webhook request. */\nexport type WebhookMethod = 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'GET';\n\n/** The resolved request description produced by {@link WebhookMessage.toRequest}. */\nexport interface WebhookRequest {\n /** Target URL, when set on the message; otherwise resolved by the channel. */\n url?: string | undefined;\n method: WebhookMethod;\n headers: Record<string, string>;\n /** The JSON body to send (a plain object). */\n body: Record<string, unknown>;\n}\n\n/**\n * A fluent builder for a webhook request.\n *\n * ```ts\n * new WebhookMessage()\n * .url('https://example.com/hooks/orders')\n * .header('X-Signature', sign(payload))\n * .payload({ event: 'order.paid', id: 42 });\n * ```\n */\nexport class WebhookMessage {\n private _url?: string;\n private _method: WebhookMethod = 'POST';\n private _headers: Record<string, string> = {};\n private _payload: Record<string, unknown> = {};\n\n /** Set the target URL (overrides the route and configured default). */\n url(u: string): this {\n this._url = u;\n return this;\n }\n\n /** Set the JSON body to send. */\n payload(obj: Record<string, unknown>): this {\n this._payload = obj;\n return this;\n }\n\n /** Set a single request header. */\n header(key: string, value: string): this {\n this._headers[key] = value;\n return this;\n }\n\n /** Merge multiple request headers. */\n headers(obj: Record<string, string>): this {\n this._headers = { ...this._headers, ...obj };\n return this;\n }\n\n /** Set the HTTP method (default `POST`). */\n method(m: WebhookMethod): this {\n this._method = m;\n return this;\n }\n\n get urlValue(): string | undefined {\n return this._url;\n }\n\n get methodValue(): WebhookMethod {\n return this._method;\n }\n\n get headerValues(): Record<string, string> {\n return this._headers;\n }\n\n get payloadValue(): Record<string, unknown> {\n return this._payload;\n }\n\n /** Serialize to a {@link WebhookRequest}. */\n toRequest(): WebhookRequest {\n return {\n url: this._url,\n method: this._method,\n headers: { ...this._headers },\n body: this._payload,\n };\n }\n}\n","import { createHmac } from 'node:crypto';\nimport {\n type ChannelContext,\n type ChannelDriver,\n type DeliveryContext,\n MissingChannelMethodError,\n type Notifiable,\n type Notification,\n createChannel,\n getHandler,\n routeFor,\n} from '@dudousxd/nestjs-notifications-core';\nimport { Inject, Injectable, Optional } from '@nestjs/common';\nimport { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER } from './tokens';\nimport { WebhookMessage } from './webhook-message';\nimport type { WebhookMethod } from './webhook-message';\n\nconst DEFAULT_SIGNATURE_HEADER = 'X-Signature-256';\n\n/** Channel handle: use as `@Webhook()` on a payload method, or as a token in `via()`. */\nexport const Webhook = createChannel('webhook');\n\n/** Resolved runtime options for the webhook channel. */\nexport interface WebhookChannelOptions {\n /** Default URL used when neither the message nor the route supplies one. */\n url?: string;\n /** Default headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * HMAC-SHA256 secret. When set, the request is signed: the header (default\n * `X-Signature-256`) is set to `sha256=<hex digest of the raw JSON body>`, so the receiver\n * can verify authenticity. Per-tenant secrets work via `resolveOptions`.\n */\n secret?: string;\n /** Header name for the signature. Default `X-Signature-256`. */\n signatureHeader?: string;\n}\n\n/**\n * Implement this on a notification to define its webhook payload. Returning a plain\n * object is treated as the JSON body to POST; return a {@link WebhookMessage} for full\n * control over the url, method and headers.\n */\nexport interface WebhookNotification extends Notification {\n toWebhook(ctx: ChannelContext): WebhookMessage | Record<string, unknown>;\n}\n\n/** Resolves per-tenant {@link WebhookChannelOptions} from a tenant id. */\nexport type WebhookOptionsResolver = (tenant: string) => WebhookChannelOptions;\n\n/**\n * Delivers a notification by sending an HTTP request (JSON body) to a webhook endpoint.\n * The target URL comes from the {@link WebhookMessage}, else from\n * `routeNotificationFor('webhook')` (a URL string), else from the configured default.\n */\n@Injectable()\nexport class WebhookChannel implements ChannelDriver {\n readonly channel = 'webhook';\n\n constructor(\n @Inject(WEBHOOK_OPTIONS)\n private readonly options: WebhookChannelOptions,\n @Optional()\n @Inject(WEBHOOK_OPTIONS_RESOLVER)\n private readonly resolveOptions?: WebhookOptionsResolver,\n ) {}\n\n async send(\n notifiable: Notifiable,\n notification: Notification,\n context?: DeliveryContext,\n ): Promise<void> {\n const options =\n context?.tenant && this.resolveOptions ? this.resolveOptions(context.tenant) : this.options;\n\n const handler = getHandler(notification, 'webhook', 'toWebhook');\n if (!handler) {\n const name =\n (notification.constructor as { notificationName?: string }).notificationName ??\n notification.constructor.name;\n throw new MissingChannelMethodError('webhook', 'toWebhook()', name);\n }\n\n const result = handler({\n notifiable,\n localization: context?.localization,\n tenant: context?.tenant,\n }) as WebhookMessage | Record<string, unknown>;\n const message =\n result instanceof WebhookMessage ? result : new WebhookMessage().payload(result);\n const request = message.toRequest();\n\n const route = routeFor(notifiable, 'webhook', notification);\n const url = request.url ?? (typeof route === 'string' ? route : undefined) ?? options.url;\n\n if (!url) {\n throw new Error(\n 'The webhook channel needs a target URL. Set one on the WebhookMessage via .url(), ' +\n 'return one from routeNotificationFor(\"webhook\"), or set url in forRoot().',\n );\n }\n\n await this.post(options, url, request.method, request.body, request.headers);\n }\n\n private async post(\n options: WebhookChannelOptions,\n url: string,\n method: WebhookMethod,\n body: Record<string, unknown>,\n messageHeaders: Record<string, string>,\n ): Promise<void> {\n const payload = JSON.stringify(body);\n const headers: Record<string, string> = {\n ...options.headers,\n ...messageHeaders,\n 'Content-Type': 'application/json',\n };\n\n if (options.secret) {\n const signature = createHmac('sha256', options.secret).update(payload).digest('hex');\n headers[options.signatureHeader ?? DEFAULT_SIGNATURE_HEADER] = `sha256=${signature}`;\n }\n\n const response = await fetch(url, {\n method,\n headers,\n body: payload,\n });\n\n if (!response.ok) {\n throw new Error(`Webhook request to ${url} failed with status ${response.status}.`);\n }\n }\n}\n","/** DI token for the resolved {@link WebhookChannelOptions} (default url, headers). */\nexport const WEBHOOK_OPTIONS = Symbol('WEBHOOK_OPTIONS');\n\n/** DI token for the optional per-tenant {@link WebhookChannelOptions} resolver. */\nexport const WEBHOOK_OPTIONS_RESOLVER = Symbol('WEBHOOK_OPTIONS_RESOLVER');\n","import { type DynamicModule, Module, type Provider } from '@nestjs/common';\nimport { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER } from './tokens';\nimport {\n WebhookChannel,\n type WebhookChannelOptions,\n type WebhookOptionsResolver,\n} from './webhook.channel';\n\nexport interface WebhookChannelModuleOptions {\n /** Default URL used when neither the message nor the route supplies one. */\n url?: string;\n /** Default headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * Optional per-tenant options resolver. When a notification is delivered with a\n * `context.tenant`, the returned options are used instead of the defaults.\n */\n resolveOptions?: WebhookOptionsResolver;\n /** Register globally so the channel is discoverable app-wide. Default true. */\n global?: boolean;\n}\n\n/**\n * Registers the webhook channel.\n *\n * ```ts\n * WebhookChannelModule.forRoot({ url: 'https://example.com/hooks/notifications' });\n * ```\n */\n@Module({})\nexport class WebhookChannelModule {\n static forRoot(options: WebhookChannelModuleOptions = {}): DynamicModule {\n const webhookOptions: WebhookChannelOptions = {\n // Set each field only when provided (exactOptionalPropertyTypes); the channel resolves a\n // per-notifiable URL and default headers when these are absent.\n ...(options.url !== undefined ? { url: options.url } : {}),\n ...(options.headers !== undefined ? { headers: options.headers } : {}),\n };\n\n const providers: Provider[] = [\n { provide: WEBHOOK_OPTIONS, useValue: webhookOptions },\n { provide: WEBHOOK_OPTIONS_RESOLVER, useValue: options.resolveOptions ?? null },\n WebhookChannel,\n ];\n\n return {\n module: WebhookChannelModule,\n global: options.global ?? true,\n providers,\n exports: [WebhookChannel],\n };\n }\n}\n"],"mappings":"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","names":["WebhookMessage","_url","_method","_headers","_payload","url","u","payload","obj","header","key","value","headers","method","m","urlValue","methodValue","headerValues","payloadValue","toRequest","body","WEBHOOK_OPTIONS","Symbol","WEBHOOK_OPTIONS_RESOLVER","DEFAULT_SIGNATURE_HEADER","Webhook","createChannel","WebhookChannel","channel","options","resolveOptions","send","notifiable","notification","context","tenant","handler","getHandler","name","notificationName","MissingChannelMethodError","result","localization","message","WebhookMessage","payload","request","toRequest","route","routeFor","url","undefined","Error","post","method","body","headers","messageHeaders","JSON","stringify","secret","signature","createHmac","update","digest","signatureHeader","response","fetch","ok","status","import_common","WebhookChannelModule","forRoot","options","webhookOptions","url","undefined","headers","providers","provide","WEBHOOK_OPTIONS","useValue","WEBHOOK_OPTIONS_RESOLVER","resolveOptions","WebhookChannel","module","global","exports"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/webhook-message.ts","../src/webhook.channel.ts","../src/tokens.ts","../src/webhook.module.ts"],"sourcesContent":["export {\n WebhookMessage,\n type WebhookMethod,\n type WebhookRequest,\n} from './webhook-message';\nexport {\n Webhook,\n WebhookChannel,\n type WebhookChannelOptions,\n type WebhookNotification,\n type WebhookOptionsResolver,\n} from './webhook.channel';\nexport {\n WebhookChannelModule,\n type WebhookChannelModuleOptions,\n} from './webhook.module';\nexport { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER } from './tokens';\n","/** The HTTP method used for a webhook request. */\nexport type WebhookMethod = 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'GET';\n\n/** The resolved request description produced by {@link WebhookMessage.toRequest}. */\nexport interface WebhookRequest {\n /** Target URL, when set on the message; otherwise resolved by the channel. */\n url?: string | undefined;\n method: WebhookMethod;\n headers: Record<string, string>;\n /** The JSON body to send (a plain object). */\n body: Record<string, unknown>;\n}\n\n/**\n * A fluent builder for a webhook request.\n *\n * ```ts\n * new WebhookMessage()\n * .url('https://example.com/hooks/orders')\n * .header('X-Signature', sign(payload))\n * .payload({ event: 'order.paid', id: 42 });\n * ```\n */\nexport class WebhookMessage {\n private _url?: string;\n private _method: WebhookMethod = 'POST';\n private _headers: Record<string, string> = {};\n private _payload: Record<string, unknown> = {};\n\n /** Set the target URL (overrides the route and configured default). */\n url(u: string): this {\n this._url = u;\n return this;\n }\n\n /** Set the JSON body to send. */\n payload(obj: Record<string, unknown>): this {\n this._payload = obj;\n return this;\n }\n\n /** Set a single request header. */\n header(key: string, value: string): this {\n this._headers[key] = value;\n return this;\n }\n\n /** Merge multiple request headers. */\n headers(obj: Record<string, string>): this {\n this._headers = { ...this._headers, ...obj };\n return this;\n }\n\n /** Set the HTTP method (default `POST`). */\n method(m: WebhookMethod): this {\n this._method = m;\n return this;\n }\n\n get urlValue(): string | undefined {\n return this._url;\n }\n\n get methodValue(): WebhookMethod {\n return this._method;\n }\n\n get headerValues(): Record<string, string> {\n return this._headers;\n }\n\n get payloadValue(): Record<string, unknown> {\n return this._payload;\n }\n\n /** Serialize to a {@link WebhookRequest}. */\n toRequest(): WebhookRequest {\n return {\n url: this._url,\n method: this._method,\n headers: { ...this._headers },\n body: this._payload,\n };\n }\n}\n","import { createHmac } from 'node:crypto';\nimport {\n BaseChannel,\n type ChannelContext,\n type DeliveryContext,\n type Notifiable,\n type Notification,\n createChannel,\n postJson,\n routeFor,\n} from '@dudousxd/nestjs-notifications-core';\nimport { Inject, Injectable, Optional } from '@nestjs/common';\nimport { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER } from './tokens';\nimport { WebhookMessage } from './webhook-message';\n\nconst DEFAULT_SIGNATURE_HEADER = 'X-Signature-256';\n\n/** Channel handle: use as `@Webhook()` on a payload method, or as a token in `via()`. */\nexport const Webhook = createChannel('webhook');\n\n/** Resolved runtime options for the webhook channel. */\nexport interface WebhookChannelOptions {\n /** Default URL used when neither the message nor the route supplies one. */\n url?: string;\n /** Default headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * HMAC-SHA256 secret. When set, the request is signed: the header (default\n * `X-Signature-256`) is set to `sha256=<hex digest of the raw JSON body>`, so the receiver\n * can verify authenticity. Per-tenant secrets work via `resolveOptions`.\n */\n secret?: string;\n /** Header name for the signature. Default `X-Signature-256`. */\n signatureHeader?: string;\n}\n\n/**\n * Implement this on a notification to define its webhook payload. Returning a plain\n * object is treated as the JSON body to POST; return a {@link WebhookMessage} for full\n * control over the url, method and headers.\n */\nexport interface WebhookNotification extends Notification {\n toWebhook(ctx: ChannelContext): WebhookMessage | Record<string, unknown>;\n}\n\n/** Resolves per-tenant {@link WebhookChannelOptions} from a tenant id. */\nexport type WebhookOptionsResolver = (tenant: string) => WebhookChannelOptions;\n\n/**\n * Delivers a notification by sending an HTTP request (JSON body) to a webhook endpoint.\n * The target URL comes from the {@link WebhookMessage}, else from\n * `routeNotificationFor('webhook')` (a URL string), else from the configured default.\n */\n@Injectable()\nexport class WebhookChannel extends BaseChannel {\n readonly channel = 'webhook';\n\n constructor(\n @Inject(WEBHOOK_OPTIONS)\n private readonly options: WebhookChannelOptions,\n @Optional()\n @Inject(WEBHOOK_OPTIONS_RESOLVER)\n private readonly resolveOptions?: WebhookOptionsResolver,\n ) {\n super();\n }\n\n async send(\n notifiable: Notifiable,\n notification: Notification,\n context?: DeliveryContext,\n ): Promise<void> {\n const options = this.forTenant(this.options, context, this.resolveOptions);\n const result = this.buildPayload<WebhookMessage | Record<string, unknown>>(\n notification,\n notifiable,\n 'toWebhook',\n context,\n );\n const message =\n result instanceof WebhookMessage ? result : new WebhookMessage().payload(result);\n const request = message.toRequest();\n\n const route = routeFor(notifiable, 'webhook', notification);\n const url = request.url ?? (typeof route === 'string' ? route : undefined) ?? options.url;\n\n if (!url) {\n throw new Error(\n 'The webhook channel needs a target URL. Set one on the WebhookMessage via .url(), ' +\n 'return one from routeNotificationFor(\"webhook\"), or set url in forRoot().',\n );\n }\n\n const headers: Record<string, string> = { ...options.headers, ...request.headers };\n if (options.secret) {\n const signature = createHmac('sha256', options.secret)\n .update(JSON.stringify(request.body))\n .digest('hex');\n headers[options.signatureHeader ?? DEFAULT_SIGNATURE_HEADER] = `sha256=${signature}`;\n }\n\n await postJson(url, request.body, { label: 'Webhook', method: request.method, headers });\n }\n}\n","/** DI token for the resolved {@link WebhookChannelOptions} (default url, headers). */\nexport const WEBHOOK_OPTIONS = Symbol('WEBHOOK_OPTIONS');\n\n/** DI token for the optional per-tenant {@link WebhookChannelOptions} resolver. */\nexport const WEBHOOK_OPTIONS_RESOLVER = Symbol('WEBHOOK_OPTIONS_RESOLVER');\n","import { defineChannelModule } from '@dudousxd/nestjs-notifications-core';\nimport { type DynamicModule, Module } from '@nestjs/common';\nimport { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER } from './tokens';\nimport {\n WebhookChannel,\n type WebhookChannelOptions,\n type WebhookOptionsResolver,\n} from './webhook.channel';\n\nexport interface WebhookChannelModuleOptions {\n /** Default URL used when neither the message nor the route supplies one. */\n url?: string;\n /** Default headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * Optional per-tenant options resolver. When a notification is delivered with a\n * `context.tenant`, the returned options are used instead of the defaults.\n */\n resolveOptions?: WebhookOptionsResolver;\n /** Register globally so the channel is discoverable app-wide. Default true. */\n global?: boolean;\n}\n\n/**\n * Registers the webhook channel.\n *\n * ```ts\n * WebhookChannelModule.forRoot({ url: 'https://example.com/hooks/notifications' });\n * ```\n */\n@Module({})\nexport class WebhookChannelModule {\n static forRoot(options: WebhookChannelModuleOptions = {}): DynamicModule {\n const webhookOptions: WebhookChannelOptions = {\n // Set each field only when provided (exactOptionalPropertyTypes); the channel resolves a\n // per-notifiable URL and default headers when these are absent.\n ...(options.url !== undefined ? { url: options.url } : {}),\n ...(options.headers !== undefined ? { headers: options.headers } : {}),\n };\n\n return defineChannelModule({\n module: WebhookChannelModule,\n channel: WebhookChannel,\n optionsToken: WEBHOOK_OPTIONS,\n options: webhookOptions,\n resolver: { token: WEBHOOK_OPTIONS_RESOLVER, value: options.resolveOptions },\n ...(options.global !== undefined ? { global: options.global } : {}),\n });\n }\n}\n"],"mappings":"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","names":["WebhookMessage","_url","_method","_headers","_payload","url","u","payload","obj","header","key","value","headers","method","m","urlValue","methodValue","headerValues","payloadValue","toRequest","body","WEBHOOK_OPTIONS","Symbol","WEBHOOK_OPTIONS_RESOLVER","DEFAULT_SIGNATURE_HEADER","Webhook","createChannel","WebhookChannel","BaseChannel","channel","options","resolveOptions","send","notifiable","notification","context","forTenant","result","buildPayload","message","WebhookMessage","payload","request","toRequest","route","routeFor","url","undefined","Error","headers","secret","signature","createHmac","update","JSON","stringify","body","digest","signatureHeader","postJson","label","method","import_nestjs_notifications_core","import_common","WebhookChannelModule","forRoot","options","webhookOptions","url","undefined","headers","defineChannelModule","module","channel","WebhookChannel","optionsToken","WEBHOOK_OPTIONS","resolver","token","WEBHOOK_OPTIONS_RESOLVER","value","resolveOptions","global"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _dudousxd_nestjs_notifications_core from '@dudousxd/nestjs-notifications-core';
2
- import { ChannelDriver, Notifiable, Notification, DeliveryContext, ChannelContext } from '@dudousxd/nestjs-notifications-core';
2
+ import { BaseChannel, Notifiable, Notification, DeliveryContext, ChannelContext } from '@dudousxd/nestjs-notifications-core';
3
3
  import { DynamicModule } from '@nestjs/common';
4
4
 
5
5
  /** The HTTP method used for a webhook request. */
@@ -78,13 +78,12 @@ type WebhookOptionsResolver = (tenant: string) => WebhookChannelOptions;
78
78
  * The target URL comes from the {@link WebhookMessage}, else from
79
79
  * `routeNotificationFor('webhook')` (a URL string), else from the configured default.
80
80
  */
81
- declare class WebhookChannel implements ChannelDriver {
81
+ declare class WebhookChannel extends BaseChannel {
82
82
  private readonly options;
83
83
  private readonly resolveOptions?;
84
84
  readonly channel = "webhook";
85
85
  constructor(options: WebhookChannelOptions, resolveOptions?: WebhookOptionsResolver | undefined);
86
86
  send(notifiable: Notifiable, notification: Notification, context?: DeliveryContext): Promise<void>;
87
- private post;
88
87
  }
89
88
 
90
89
  interface WebhookChannelModuleOptions {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _dudousxd_nestjs_notifications_core from '@dudousxd/nestjs-notifications-core';
2
- import { ChannelDriver, Notifiable, Notification, DeliveryContext, ChannelContext } from '@dudousxd/nestjs-notifications-core';
2
+ import { BaseChannel, Notifiable, Notification, DeliveryContext, ChannelContext } from '@dudousxd/nestjs-notifications-core';
3
3
  import { DynamicModule } from '@nestjs/common';
4
4
 
5
5
  /** The HTTP method used for a webhook request. */
@@ -78,13 +78,12 @@ type WebhookOptionsResolver = (tenant: string) => WebhookChannelOptions;
78
78
  * The target URL comes from the {@link WebhookMessage}, else from
79
79
  * `routeNotificationFor('webhook')` (a URL string), else from the configured default.
80
80
  */
81
- declare class WebhookChannel implements ChannelDriver {
81
+ declare class WebhookChannel extends BaseChannel {
82
82
  private readonly options;
83
83
  private readonly resolveOptions?;
84
84
  readonly channel = "webhook";
85
85
  constructor(options: WebhookChannelOptions, resolveOptions?: WebhookOptionsResolver | undefined);
86
86
  send(notifiable: Notifiable, notification: Notification, context?: DeliveryContext): Promise<void>;
87
- private post;
88
87
  }
89
88
 
90
89
  interface WebhookChannelModuleOptions {
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ var WebhookMessage = class {
65
65
 
66
66
  // src/webhook.channel.ts
67
67
  import { createHmac } from "crypto";
68
- import { MissingChannelMethodError, createChannel, getHandler, routeFor } from "@dudousxd/nestjs-notifications-core";
68
+ import { BaseChannel, createChannel, postJson, routeFor } from "@dudousxd/nestjs-notifications-core";
69
69
  import { Inject, Injectable, Optional } from "@nestjs/common";
70
70
 
71
71
  // src/tokens.ts
@@ -92,7 +92,7 @@ function _ts_param(paramIndex, decorator) {
92
92
  __name(_ts_param, "_ts_param");
93
93
  var DEFAULT_SIGNATURE_HEADER = "X-Signature-256";
94
94
  var Webhook = createChannel("webhook");
95
- var WebhookChannel = class {
95
+ var WebhookChannel = class extends BaseChannel {
96
96
  static {
97
97
  __name(this, "WebhookChannel");
98
98
  }
@@ -100,21 +100,11 @@ var WebhookChannel = class {
100
100
  resolveOptions;
101
101
  channel = "webhook";
102
102
  constructor(options, resolveOptions) {
103
- this.options = options;
104
- this.resolveOptions = resolveOptions;
103
+ super(), this.options = options, this.resolveOptions = resolveOptions;
105
104
  }
106
105
  async send(notifiable, notification, context) {
107
- const options = context?.tenant && this.resolveOptions ? this.resolveOptions(context.tenant) : this.options;
108
- const handler = getHandler(notification, "webhook", "toWebhook");
109
- if (!handler) {
110
- const name = notification.constructor.notificationName ?? notification.constructor.name;
111
- throw new MissingChannelMethodError("webhook", "toWebhook()", name);
112
- }
113
- const result = handler({
114
- notifiable,
115
- localization: context?.localization,
116
- tenant: context?.tenant
117
- });
106
+ const options = this.forTenant(this.options, context, this.resolveOptions);
107
+ const result = this.buildPayload(notification, notifiable, "toWebhook", context);
118
108
  const message = result instanceof WebhookMessage ? result : new WebhookMessage().payload(result);
119
109
  const request = message.toRequest();
120
110
  const route = routeFor(notifiable, "webhook", notification);
@@ -122,27 +112,19 @@ var WebhookChannel = class {
122
112
  if (!url) {
123
113
  throw new Error('The webhook channel needs a target URL. Set one on the WebhookMessage via .url(), return one from routeNotificationFor("webhook"), or set url in forRoot().');
124
114
  }
125
- await this.post(options, url, request.method, request.body, request.headers);
126
- }
127
- async post(options, url, method, body, messageHeaders) {
128
- const payload = JSON.stringify(body);
129
115
  const headers = {
130
116
  ...options.headers,
131
- ...messageHeaders,
132
- "Content-Type": "application/json"
117
+ ...request.headers
133
118
  };
134
119
  if (options.secret) {
135
- const signature = createHmac("sha256", options.secret).update(payload).digest("hex");
120
+ const signature = createHmac("sha256", options.secret).update(JSON.stringify(request.body)).digest("hex");
136
121
  headers[options.signatureHeader ?? DEFAULT_SIGNATURE_HEADER] = `sha256=${signature}`;
137
122
  }
138
- const response = await fetch(url, {
139
- method,
140
- headers,
141
- body: payload
123
+ await postJson(url, request.body, {
124
+ label: "Webhook",
125
+ method: request.method,
126
+ headers
142
127
  });
143
- if (!response.ok) {
144
- throw new Error(`Webhook request to ${url} failed with status ${response.status}.`);
145
- }
146
128
  }
147
129
  };
148
130
  WebhookChannel = _ts_decorate([
@@ -158,6 +140,7 @@ WebhookChannel = _ts_decorate([
158
140
  ], WebhookChannel);
159
141
 
160
142
  // src/webhook.module.ts
143
+ import { defineChannelModule } from "@dudousxd/nestjs-notifications-core";
161
144
  import { Module } from "@nestjs/common";
162
145
  function _ts_decorate2(decorators, target, key, desc) {
163
146
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -181,25 +164,19 @@ var WebhookChannelModule = class _WebhookChannelModule {
181
164
  headers: options.headers
182
165
  } : {}
183
166
  };
184
- const providers = [
185
- {
186
- provide: WEBHOOK_OPTIONS,
187
- useValue: webhookOptions
188
- },
189
- {
190
- provide: WEBHOOK_OPTIONS_RESOLVER,
191
- useValue: options.resolveOptions ?? null
192
- },
193
- WebhookChannel
194
- ];
195
- return {
167
+ return defineChannelModule({
196
168
  module: _WebhookChannelModule,
197
- global: options.global ?? true,
198
- providers,
199
- exports: [
200
- WebhookChannel
201
- ]
202
- };
169
+ channel: WebhookChannel,
170
+ optionsToken: WEBHOOK_OPTIONS,
171
+ options: webhookOptions,
172
+ resolver: {
173
+ token: WEBHOOK_OPTIONS_RESOLVER,
174
+ value: options.resolveOptions
175
+ },
176
+ ...options.global !== void 0 ? {
177
+ global: options.global
178
+ } : {}
179
+ });
203
180
  }
204
181
  };
205
182
  WebhookChannelModule = _ts_decorate2([
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/webhook-message.ts","../src/webhook.channel.ts","../src/tokens.ts","../src/webhook.module.ts"],"sourcesContent":["/** The HTTP method used for a webhook request. */\nexport type WebhookMethod = 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'GET';\n\n/** The resolved request description produced by {@link WebhookMessage.toRequest}. */\nexport interface WebhookRequest {\n /** Target URL, when set on the message; otherwise resolved by the channel. */\n url?: string | undefined;\n method: WebhookMethod;\n headers: Record<string, string>;\n /** The JSON body to send (a plain object). */\n body: Record<string, unknown>;\n}\n\n/**\n * A fluent builder for a webhook request.\n *\n * ```ts\n * new WebhookMessage()\n * .url('https://example.com/hooks/orders')\n * .header('X-Signature', sign(payload))\n * .payload({ event: 'order.paid', id: 42 });\n * ```\n */\nexport class WebhookMessage {\n private _url?: string;\n private _method: WebhookMethod = 'POST';\n private _headers: Record<string, string> = {};\n private _payload: Record<string, unknown> = {};\n\n /** Set the target URL (overrides the route and configured default). */\n url(u: string): this {\n this._url = u;\n return this;\n }\n\n /** Set the JSON body to send. */\n payload(obj: Record<string, unknown>): this {\n this._payload = obj;\n return this;\n }\n\n /** Set a single request header. */\n header(key: string, value: string): this {\n this._headers[key] = value;\n return this;\n }\n\n /** Merge multiple request headers. */\n headers(obj: Record<string, string>): this {\n this._headers = { ...this._headers, ...obj };\n return this;\n }\n\n /** Set the HTTP method (default `POST`). */\n method(m: WebhookMethod): this {\n this._method = m;\n return this;\n }\n\n get urlValue(): string | undefined {\n return this._url;\n }\n\n get methodValue(): WebhookMethod {\n return this._method;\n }\n\n get headerValues(): Record<string, string> {\n return this._headers;\n }\n\n get payloadValue(): Record<string, unknown> {\n return this._payload;\n }\n\n /** Serialize to a {@link WebhookRequest}. */\n toRequest(): WebhookRequest {\n return {\n url: this._url,\n method: this._method,\n headers: { ...this._headers },\n body: this._payload,\n };\n }\n}\n","import { createHmac } from 'node:crypto';\nimport {\n type ChannelContext,\n type ChannelDriver,\n type DeliveryContext,\n MissingChannelMethodError,\n type Notifiable,\n type Notification,\n createChannel,\n getHandler,\n routeFor,\n} from '@dudousxd/nestjs-notifications-core';\nimport { Inject, Injectable, Optional } from '@nestjs/common';\nimport { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER } from './tokens';\nimport { WebhookMessage } from './webhook-message';\nimport type { WebhookMethod } from './webhook-message';\n\nconst DEFAULT_SIGNATURE_HEADER = 'X-Signature-256';\n\n/** Channel handle: use as `@Webhook()` on a payload method, or as a token in `via()`. */\nexport const Webhook = createChannel('webhook');\n\n/** Resolved runtime options for the webhook channel. */\nexport interface WebhookChannelOptions {\n /** Default URL used when neither the message nor the route supplies one. */\n url?: string;\n /** Default headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * HMAC-SHA256 secret. When set, the request is signed: the header (default\n * `X-Signature-256`) is set to `sha256=<hex digest of the raw JSON body>`, so the receiver\n * can verify authenticity. Per-tenant secrets work via `resolveOptions`.\n */\n secret?: string;\n /** Header name for the signature. Default `X-Signature-256`. */\n signatureHeader?: string;\n}\n\n/**\n * Implement this on a notification to define its webhook payload. Returning a plain\n * object is treated as the JSON body to POST; return a {@link WebhookMessage} for full\n * control over the url, method and headers.\n */\nexport interface WebhookNotification extends Notification {\n toWebhook(ctx: ChannelContext): WebhookMessage | Record<string, unknown>;\n}\n\n/** Resolves per-tenant {@link WebhookChannelOptions} from a tenant id. */\nexport type WebhookOptionsResolver = (tenant: string) => WebhookChannelOptions;\n\n/**\n * Delivers a notification by sending an HTTP request (JSON body) to a webhook endpoint.\n * The target URL comes from the {@link WebhookMessage}, else from\n * `routeNotificationFor('webhook')` (a URL string), else from the configured default.\n */\n@Injectable()\nexport class WebhookChannel implements ChannelDriver {\n readonly channel = 'webhook';\n\n constructor(\n @Inject(WEBHOOK_OPTIONS)\n private readonly options: WebhookChannelOptions,\n @Optional()\n @Inject(WEBHOOK_OPTIONS_RESOLVER)\n private readonly resolveOptions?: WebhookOptionsResolver,\n ) {}\n\n async send(\n notifiable: Notifiable,\n notification: Notification,\n context?: DeliveryContext,\n ): Promise<void> {\n const options =\n context?.tenant && this.resolveOptions ? this.resolveOptions(context.tenant) : this.options;\n\n const handler = getHandler(notification, 'webhook', 'toWebhook');\n if (!handler) {\n const name =\n (notification.constructor as { notificationName?: string }).notificationName ??\n notification.constructor.name;\n throw new MissingChannelMethodError('webhook', 'toWebhook()', name);\n }\n\n const result = handler({\n notifiable,\n localization: context?.localization,\n tenant: context?.tenant,\n }) as WebhookMessage | Record<string, unknown>;\n const message =\n result instanceof WebhookMessage ? result : new WebhookMessage().payload(result);\n const request = message.toRequest();\n\n const route = routeFor(notifiable, 'webhook', notification);\n const url = request.url ?? (typeof route === 'string' ? route : undefined) ?? options.url;\n\n if (!url) {\n throw new Error(\n 'The webhook channel needs a target URL. Set one on the WebhookMessage via .url(), ' +\n 'return one from routeNotificationFor(\"webhook\"), or set url in forRoot().',\n );\n }\n\n await this.post(options, url, request.method, request.body, request.headers);\n }\n\n private async post(\n options: WebhookChannelOptions,\n url: string,\n method: WebhookMethod,\n body: Record<string, unknown>,\n messageHeaders: Record<string, string>,\n ): Promise<void> {\n const payload = JSON.stringify(body);\n const headers: Record<string, string> = {\n ...options.headers,\n ...messageHeaders,\n 'Content-Type': 'application/json',\n };\n\n if (options.secret) {\n const signature = createHmac('sha256', options.secret).update(payload).digest('hex');\n headers[options.signatureHeader ?? DEFAULT_SIGNATURE_HEADER] = `sha256=${signature}`;\n }\n\n const response = await fetch(url, {\n method,\n headers,\n body: payload,\n });\n\n if (!response.ok) {\n throw new Error(`Webhook request to ${url} failed with status ${response.status}.`);\n }\n }\n}\n","/** DI token for the resolved {@link WebhookChannelOptions} (default url, headers). */\nexport const WEBHOOK_OPTIONS = Symbol('WEBHOOK_OPTIONS');\n\n/** DI token for the optional per-tenant {@link WebhookChannelOptions} resolver. */\nexport const WEBHOOK_OPTIONS_RESOLVER = Symbol('WEBHOOK_OPTIONS_RESOLVER');\n","import { type DynamicModule, Module, type Provider } from '@nestjs/common';\nimport { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER } from './tokens';\nimport {\n WebhookChannel,\n type WebhookChannelOptions,\n type WebhookOptionsResolver,\n} from './webhook.channel';\n\nexport interface WebhookChannelModuleOptions {\n /** Default URL used when neither the message nor the route supplies one. */\n url?: string;\n /** Default headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * Optional per-tenant options resolver. When a notification is delivered with a\n * `context.tenant`, the returned options are used instead of the defaults.\n */\n resolveOptions?: WebhookOptionsResolver;\n /** Register globally so the channel is discoverable app-wide. Default true. */\n global?: boolean;\n}\n\n/**\n * Registers the webhook channel.\n *\n * ```ts\n * WebhookChannelModule.forRoot({ url: 'https://example.com/hooks/notifications' });\n * ```\n */\n@Module({})\nexport class WebhookChannelModule {\n static forRoot(options: WebhookChannelModuleOptions = {}): DynamicModule {\n const webhookOptions: WebhookChannelOptions = {\n // Set each field only when provided (exactOptionalPropertyTypes); the channel resolves a\n // per-notifiable URL and default headers when these are absent.\n ...(options.url !== undefined ? { url: options.url } : {}),\n ...(options.headers !== undefined ? { headers: options.headers } : {}),\n };\n\n const providers: Provider[] = [\n { provide: WEBHOOK_OPTIONS, useValue: webhookOptions },\n { provide: WEBHOOK_OPTIONS_RESOLVER, useValue: options.resolveOptions ?? null },\n WebhookChannel,\n ];\n\n return {\n module: WebhookChannelModule,\n global: options.global ?? true,\n providers,\n exports: [WebhookChannel],\n };\n }\n}\n"],"mappings":"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","names":["WebhookMessage","_url","_method","_headers","_payload","url","u","payload","obj","header","key","value","headers","method","m","urlValue","methodValue","headerValues","payloadValue","toRequest","body","createHmac","MissingChannelMethodError","createChannel","getHandler","routeFor","Inject","Injectable","Optional","WEBHOOK_OPTIONS","Symbol","WEBHOOK_OPTIONS_RESOLVER","DEFAULT_SIGNATURE_HEADER","Webhook","createChannel","WebhookChannel","channel","options","resolveOptions","send","notifiable","notification","context","tenant","handler","getHandler","name","notificationName","MissingChannelMethodError","result","localization","message","WebhookMessage","payload","request","toRequest","route","routeFor","url","undefined","Error","post","method","body","headers","messageHeaders","JSON","stringify","secret","signature","createHmac","update","digest","signatureHeader","response","fetch","ok","status","Module","WebhookChannelModule","forRoot","options","webhookOptions","url","undefined","headers","providers","provide","WEBHOOK_OPTIONS","useValue","WEBHOOK_OPTIONS_RESOLVER","resolveOptions","WebhookChannel","module","global","exports"]}
1
+ {"version":3,"sources":["../src/webhook-message.ts","../src/webhook.channel.ts","../src/tokens.ts","../src/webhook.module.ts"],"sourcesContent":["/** The HTTP method used for a webhook request. */\nexport type WebhookMethod = 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'GET';\n\n/** The resolved request description produced by {@link WebhookMessage.toRequest}. */\nexport interface WebhookRequest {\n /** Target URL, when set on the message; otherwise resolved by the channel. */\n url?: string | undefined;\n method: WebhookMethod;\n headers: Record<string, string>;\n /** The JSON body to send (a plain object). */\n body: Record<string, unknown>;\n}\n\n/**\n * A fluent builder for a webhook request.\n *\n * ```ts\n * new WebhookMessage()\n * .url('https://example.com/hooks/orders')\n * .header('X-Signature', sign(payload))\n * .payload({ event: 'order.paid', id: 42 });\n * ```\n */\nexport class WebhookMessage {\n private _url?: string;\n private _method: WebhookMethod = 'POST';\n private _headers: Record<string, string> = {};\n private _payload: Record<string, unknown> = {};\n\n /** Set the target URL (overrides the route and configured default). */\n url(u: string): this {\n this._url = u;\n return this;\n }\n\n /** Set the JSON body to send. */\n payload(obj: Record<string, unknown>): this {\n this._payload = obj;\n return this;\n }\n\n /** Set a single request header. */\n header(key: string, value: string): this {\n this._headers[key] = value;\n return this;\n }\n\n /** Merge multiple request headers. */\n headers(obj: Record<string, string>): this {\n this._headers = { ...this._headers, ...obj };\n return this;\n }\n\n /** Set the HTTP method (default `POST`). */\n method(m: WebhookMethod): this {\n this._method = m;\n return this;\n }\n\n get urlValue(): string | undefined {\n return this._url;\n }\n\n get methodValue(): WebhookMethod {\n return this._method;\n }\n\n get headerValues(): Record<string, string> {\n return this._headers;\n }\n\n get payloadValue(): Record<string, unknown> {\n return this._payload;\n }\n\n /** Serialize to a {@link WebhookRequest}. */\n toRequest(): WebhookRequest {\n return {\n url: this._url,\n method: this._method,\n headers: { ...this._headers },\n body: this._payload,\n };\n }\n}\n","import { createHmac } from 'node:crypto';\nimport {\n BaseChannel,\n type ChannelContext,\n type DeliveryContext,\n type Notifiable,\n type Notification,\n createChannel,\n postJson,\n routeFor,\n} from '@dudousxd/nestjs-notifications-core';\nimport { Inject, Injectable, Optional } from '@nestjs/common';\nimport { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER } from './tokens';\nimport { WebhookMessage } from './webhook-message';\n\nconst DEFAULT_SIGNATURE_HEADER = 'X-Signature-256';\n\n/** Channel handle: use as `@Webhook()` on a payload method, or as a token in `via()`. */\nexport const Webhook = createChannel('webhook');\n\n/** Resolved runtime options for the webhook channel. */\nexport interface WebhookChannelOptions {\n /** Default URL used when neither the message nor the route supplies one. */\n url?: string;\n /** Default headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * HMAC-SHA256 secret. When set, the request is signed: the header (default\n * `X-Signature-256`) is set to `sha256=<hex digest of the raw JSON body>`, so the receiver\n * can verify authenticity. Per-tenant secrets work via `resolveOptions`.\n */\n secret?: string;\n /** Header name for the signature. Default `X-Signature-256`. */\n signatureHeader?: string;\n}\n\n/**\n * Implement this on a notification to define its webhook payload. Returning a plain\n * object is treated as the JSON body to POST; return a {@link WebhookMessage} for full\n * control over the url, method and headers.\n */\nexport interface WebhookNotification extends Notification {\n toWebhook(ctx: ChannelContext): WebhookMessage | Record<string, unknown>;\n}\n\n/** Resolves per-tenant {@link WebhookChannelOptions} from a tenant id. */\nexport type WebhookOptionsResolver = (tenant: string) => WebhookChannelOptions;\n\n/**\n * Delivers a notification by sending an HTTP request (JSON body) to a webhook endpoint.\n * The target URL comes from the {@link WebhookMessage}, else from\n * `routeNotificationFor('webhook')` (a URL string), else from the configured default.\n */\n@Injectable()\nexport class WebhookChannel extends BaseChannel {\n readonly channel = 'webhook';\n\n constructor(\n @Inject(WEBHOOK_OPTIONS)\n private readonly options: WebhookChannelOptions,\n @Optional()\n @Inject(WEBHOOK_OPTIONS_RESOLVER)\n private readonly resolveOptions?: WebhookOptionsResolver,\n ) {\n super();\n }\n\n async send(\n notifiable: Notifiable,\n notification: Notification,\n context?: DeliveryContext,\n ): Promise<void> {\n const options = this.forTenant(this.options, context, this.resolveOptions);\n const result = this.buildPayload<WebhookMessage | Record<string, unknown>>(\n notification,\n notifiable,\n 'toWebhook',\n context,\n );\n const message =\n result instanceof WebhookMessage ? result : new WebhookMessage().payload(result);\n const request = message.toRequest();\n\n const route = routeFor(notifiable, 'webhook', notification);\n const url = request.url ?? (typeof route === 'string' ? route : undefined) ?? options.url;\n\n if (!url) {\n throw new Error(\n 'The webhook channel needs a target URL. Set one on the WebhookMessage via .url(), ' +\n 'return one from routeNotificationFor(\"webhook\"), or set url in forRoot().',\n );\n }\n\n const headers: Record<string, string> = { ...options.headers, ...request.headers };\n if (options.secret) {\n const signature = createHmac('sha256', options.secret)\n .update(JSON.stringify(request.body))\n .digest('hex');\n headers[options.signatureHeader ?? DEFAULT_SIGNATURE_HEADER] = `sha256=${signature}`;\n }\n\n await postJson(url, request.body, { label: 'Webhook', method: request.method, headers });\n }\n}\n","/** DI token for the resolved {@link WebhookChannelOptions} (default url, headers). */\nexport const WEBHOOK_OPTIONS = Symbol('WEBHOOK_OPTIONS');\n\n/** DI token for the optional per-tenant {@link WebhookChannelOptions} resolver. */\nexport const WEBHOOK_OPTIONS_RESOLVER = Symbol('WEBHOOK_OPTIONS_RESOLVER');\n","import { defineChannelModule } from '@dudousxd/nestjs-notifications-core';\nimport { type DynamicModule, Module } from '@nestjs/common';\nimport { WEBHOOK_OPTIONS, WEBHOOK_OPTIONS_RESOLVER } from './tokens';\nimport {\n WebhookChannel,\n type WebhookChannelOptions,\n type WebhookOptionsResolver,\n} from './webhook.channel';\n\nexport interface WebhookChannelModuleOptions {\n /** Default URL used when neither the message nor the route supplies one. */\n url?: string;\n /** Default headers merged into every request. */\n headers?: Record<string, string>;\n /**\n * Optional per-tenant options resolver. When a notification is delivered with a\n * `context.tenant`, the returned options are used instead of the defaults.\n */\n resolveOptions?: WebhookOptionsResolver;\n /** Register globally so the channel is discoverable app-wide. Default true. */\n global?: boolean;\n}\n\n/**\n * Registers the webhook channel.\n *\n * ```ts\n * WebhookChannelModule.forRoot({ url: 'https://example.com/hooks/notifications' });\n * ```\n */\n@Module({})\nexport class WebhookChannelModule {\n static forRoot(options: WebhookChannelModuleOptions = {}): DynamicModule {\n const webhookOptions: WebhookChannelOptions = {\n // Set each field only when provided (exactOptionalPropertyTypes); the channel resolves a\n // per-notifiable URL and default headers when these are absent.\n ...(options.url !== undefined ? { url: options.url } : {}),\n ...(options.headers !== undefined ? { headers: options.headers } : {}),\n };\n\n return defineChannelModule({\n module: WebhookChannelModule,\n channel: WebhookChannel,\n optionsToken: WEBHOOK_OPTIONS,\n options: webhookOptions,\n resolver: { token: WEBHOOK_OPTIONS_RESOLVER, value: options.resolveOptions },\n ...(options.global !== undefined ? { global: options.global } : {}),\n });\n }\n}\n"],"mappings":"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","names":["WebhookMessage","_url","_method","_headers","_payload","url","u","payload","obj","header","key","value","headers","method","m","urlValue","methodValue","headerValues","payloadValue","toRequest","body","createHmac","BaseChannel","createChannel","postJson","routeFor","Inject","Injectable","Optional","WEBHOOK_OPTIONS","Symbol","WEBHOOK_OPTIONS_RESOLVER","DEFAULT_SIGNATURE_HEADER","Webhook","createChannel","WebhookChannel","BaseChannel","channel","options","resolveOptions","send","notifiable","notification","context","forTenant","result","buildPayload","message","WebhookMessage","payload","request","toRequest","route","routeFor","url","undefined","Error","headers","secret","signature","createHmac","update","JSON","stringify","body","digest","signatureHeader","postJson","label","method","defineChannelModule","Module","WebhookChannelModule","forRoot","options","webhookOptions","url","undefined","headers","defineChannelModule","module","channel","WebhookChannel","optionsToken","WEBHOOK_OPTIONS","resolver","token","WEBHOOK_OPTIONS_RESOLVER","value","resolveOptions","global"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-notifications-webhook",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Webhook channel for nestjs-notifications — deliver notifications by POSTing JSON to an HTTP endpoint",
5
5
  "license": "MIT",
6
6
  "author": "Davide Carvalho",
@@ -23,7 +23,7 @@
23
23
  "@nestjs/common": "11.1.26",
24
24
  "reflect-metadata": "0.2.2",
25
25
  "typescript": "5.9.3",
26
- "@dudousxd/nestjs-notifications-core": "^0.7.0"
26
+ "@dudousxd/nestjs-notifications-core": "^0.8.1"
27
27
  },
28
28
  "module": "./dist/index.js",
29
29
  "exports": {