@hostwebhook/node 1.0.4 → 1.0.6

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.mts CHANGED
@@ -140,6 +140,18 @@ declare function createNestGuard(secret: string, options?: VerifyOptions): {
140
140
  */
141
141
  declare function fastifyHook(secret: string, options?: VerifyOptions): (req: ExpressRequest, reply: ExpressResponse, done: NextFn) => void;
142
142
 
143
+ /** Static secret signature — sends the secret as-is in a header (no HMAC). */
144
+ interface StaticSignature {
145
+ type: 'static';
146
+ /** The secret/token value to send. */
147
+ secret: string;
148
+ /**
149
+ * Header name to send the secret in.
150
+ * Default: `Authorization` with `Bearer <secret>` format.
151
+ * @example 'X-My-Custom-Key'
152
+ */
153
+ header?: string;
154
+ }
143
155
  /** Configuration for the HostWebhook client. */
144
156
  interface HostWebhookConfig {
145
157
  /** Ingress token from your endpoint settings. */
@@ -147,12 +159,26 @@ interface HostWebhookConfig {
147
159
  /** Base URL of the HostWebhook API. Default: `https://api.hostwebhook.com` */
148
160
  baseUrl?: string;
149
161
  /**
150
- * Signing secret for incoming signature verification.
151
- * When provided, every request is signed with HMAC-SHA256 using the `custom`
152
- * format (`X-Webhook-Signature: sha256=<hex>`), which HostWebhook verifies
153
- * if the endpoint has `incomingSignatureType: 'custom'` configured.
162
+ * HMAC-SHA256 signing secret. When set, every request is signed with the
163
+ * HostWebhook signature format (`X-HostWebhook-Signature: t=<ts>,v1=<hmac>`).
164
+ * Pair with `incomingSignatureType: 'hostwebhook'` on the endpoint.
165
+ * @deprecated Prefer `signature` for new integrations.
154
166
  */
155
167
  signingSecret?: string;
168
+ /**
169
+ * Signature configuration for incoming webhook verification.
170
+ * Cannot be used together with `signingSecret`.
171
+ *
172
+ * @example Static with default header (Authorization: Bearer)
173
+ * ```ts
174
+ * { type: 'static', secret: 'my-secret' }
175
+ * ```
176
+ * @example Static with custom header
177
+ * ```ts
178
+ * { type: 'static', secret: 'my-secret', header: 'X-My-Custom-Key' }
179
+ * ```
180
+ */
181
+ signature?: StaticSignature;
156
182
  /** Custom headers to include in every request. */
157
183
  defaultHeaders?: Record<string, string>;
158
184
  /** Request timeout in milliseconds. Default: 10000 (10s). */
@@ -192,11 +218,7 @@ declare class SendError extends Error {
192
218
  * ```
193
219
  */
194
220
  declare class HostWebhook {
195
- private readonly token;
196
- private readonly baseUrl;
197
- private readonly signingSecret?;
198
- private readonly defaultHeaders;
199
- private readonly timeoutMs;
221
+ #private;
200
222
  constructor(config: HostWebhookConfig);
201
223
  /**
202
224
  * Send a webhook payload through HostWebhook.
@@ -231,4 +253,4 @@ declare class HostWebhook {
231
253
  */
232
254
  declare function send(config: HostWebhookConfig, payload: Record<string, unknown>, options?: SendOptions): Promise<SendResult>;
233
255
 
234
- export { HostWebhook, type HostWebhookConfig, SendError, type SendOptions, type SendResult, VerificationError, type VerifyOptions, type WebhookHeaders, createNestGuard, expressMiddleware, fastifyHook, parseHeaders, send, verify };
256
+ export { HostWebhook, type HostWebhookConfig, SendError, type SendOptions, type SendResult, type StaticSignature, VerificationError, type VerifyOptions, type WebhookHeaders, createNestGuard, expressMiddleware, fastifyHook, parseHeaders, send, verify };
package/dist/index.d.ts CHANGED
@@ -140,6 +140,18 @@ declare function createNestGuard(secret: string, options?: VerifyOptions): {
140
140
  */
141
141
  declare function fastifyHook(secret: string, options?: VerifyOptions): (req: ExpressRequest, reply: ExpressResponse, done: NextFn) => void;
142
142
 
143
+ /** Static secret signature — sends the secret as-is in a header (no HMAC). */
144
+ interface StaticSignature {
145
+ type: 'static';
146
+ /** The secret/token value to send. */
147
+ secret: string;
148
+ /**
149
+ * Header name to send the secret in.
150
+ * Default: `Authorization` with `Bearer <secret>` format.
151
+ * @example 'X-My-Custom-Key'
152
+ */
153
+ header?: string;
154
+ }
143
155
  /** Configuration for the HostWebhook client. */
144
156
  interface HostWebhookConfig {
145
157
  /** Ingress token from your endpoint settings. */
@@ -147,12 +159,26 @@ interface HostWebhookConfig {
147
159
  /** Base URL of the HostWebhook API. Default: `https://api.hostwebhook.com` */
148
160
  baseUrl?: string;
149
161
  /**
150
- * Signing secret for incoming signature verification.
151
- * When provided, every request is signed with HMAC-SHA256 using the `custom`
152
- * format (`X-Webhook-Signature: sha256=<hex>`), which HostWebhook verifies
153
- * if the endpoint has `incomingSignatureType: 'custom'` configured.
162
+ * HMAC-SHA256 signing secret. When set, every request is signed with the
163
+ * HostWebhook signature format (`X-HostWebhook-Signature: t=<ts>,v1=<hmac>`).
164
+ * Pair with `incomingSignatureType: 'hostwebhook'` on the endpoint.
165
+ * @deprecated Prefer `signature` for new integrations.
154
166
  */
155
167
  signingSecret?: string;
168
+ /**
169
+ * Signature configuration for incoming webhook verification.
170
+ * Cannot be used together with `signingSecret`.
171
+ *
172
+ * @example Static with default header (Authorization: Bearer)
173
+ * ```ts
174
+ * { type: 'static', secret: 'my-secret' }
175
+ * ```
176
+ * @example Static with custom header
177
+ * ```ts
178
+ * { type: 'static', secret: 'my-secret', header: 'X-My-Custom-Key' }
179
+ * ```
180
+ */
181
+ signature?: StaticSignature;
156
182
  /** Custom headers to include in every request. */
157
183
  defaultHeaders?: Record<string, string>;
158
184
  /** Request timeout in milliseconds. Default: 10000 (10s). */
@@ -192,11 +218,7 @@ declare class SendError extends Error {
192
218
  * ```
193
219
  */
194
220
  declare class HostWebhook {
195
- private readonly token;
196
- private readonly baseUrl;
197
- private readonly signingSecret?;
198
- private readonly defaultHeaders;
199
- private readonly timeoutMs;
221
+ #private;
200
222
  constructor(config: HostWebhookConfig);
201
223
  /**
202
224
  * Send a webhook payload through HostWebhook.
@@ -231,4 +253,4 @@ declare class HostWebhook {
231
253
  */
232
254
  declare function send(config: HostWebhookConfig, payload: Record<string, unknown>, options?: SendOptions): Promise<SendResult>;
233
255
 
234
- export { HostWebhook, type HostWebhookConfig, SendError, type SendOptions, type SendResult, VerificationError, type VerifyOptions, type WebhookHeaders, createNestGuard, expressMiddleware, fastifyHook, parseHeaders, send, verify };
256
+ export { HostWebhook, type HostWebhookConfig, SendError, type SendOptions, type SendResult, type StaticSignature, VerificationError, type VerifyOptions, type WebhookHeaders, createNestGuard, expressMiddleware, fastifyHook, parseHeaders, send, verify };
package/dist/index.js CHANGED
@@ -3,6 +3,9 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __typeError = (msg) => {
7
+ throw TypeError(msg);
8
+ };
6
9
  var __export = (target, all) => {
7
10
  for (var name in all)
8
11
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -16,6 +19,10 @@ var __copyProps = (to, from, except, desc) => {
16
19
  return to;
17
20
  };
18
21
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
23
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
24
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
25
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
19
26
 
20
27
  // src/index.ts
21
28
  var index_exports = {};
@@ -199,16 +206,29 @@ var SendError = class extends Error {
199
206
  // src/client.ts
200
207
  var DEFAULT_BASE_URL = "https://api.hostwebhook.com";
201
208
  var DEFAULT_TIMEOUT = 1e4;
209
+ var _token, _baseUrl, _signingSecret, _signature, _defaultHeaders, _timeoutMs;
202
210
  var HostWebhook = class {
203
211
  constructor(config) {
212
+ __privateAdd(this, _token);
213
+ __privateAdd(this, _baseUrl);
214
+ __privateAdd(this, _signingSecret);
215
+ __privateAdd(this, _signature);
216
+ __privateAdd(this, _defaultHeaders);
217
+ __privateAdd(this, _timeoutMs);
204
218
  if (!config.token) {
205
219
  throw new Error("HostWebhook: token is required");
206
220
  }
207
- this.token = config.token;
208
- this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
209
- this.signingSecret = config.signingSecret;
210
- this.defaultHeaders = config.defaultHeaders ?? {};
211
- this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT;
221
+ if (config.signingSecret && config.signature) {
222
+ throw new Error(
223
+ "HostWebhook: use either signingSecret or signature, not both"
224
+ );
225
+ }
226
+ __privateSet(this, _token, config.token);
227
+ __privateSet(this, _baseUrl, (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""));
228
+ __privateSet(this, _signingSecret, config.signingSecret);
229
+ __privateSet(this, _signature, config.signature);
230
+ __privateSet(this, _defaultHeaders, config.defaultHeaders ?? {});
231
+ __privateSet(this, _timeoutMs, config.timeoutMs ?? DEFAULT_TIMEOUT);
212
232
  }
213
233
  /**
214
234
  * Send a webhook payload through HostWebhook.
@@ -224,20 +244,34 @@ var HostWebhook = class {
224
244
  */
225
245
  async send(payload, options) {
226
246
  const body = options?.rawBody !== void 0 ? typeof options.rawBody === "string" ? options.rawBody : options.rawBody.toString("utf8") : JSON.stringify(payload);
247
+ let tz = "";
248
+ try {
249
+ tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
250
+ } catch {
251
+ }
227
252
  const headers = {
228
253
  "Content-Type": options?.contentType ?? "application/json",
229
- "User-Agent": "HostWebhook-SDK/1.0",
230
- ...this.defaultHeaders,
254
+ "User-Agent": `HostWebhook-SDK/${"1.0.5"}`,
255
+ "X-HostWebhook-Sent-At": (/* @__PURE__ */ new Date()).toISOString(),
256
+ ...tz ? { "X-HostWebhook-Timezone": tz } : {},
257
+ ...__privateGet(this, _defaultHeaders),
231
258
  ...options?.headers
232
259
  };
233
- if (this.signingSecret) {
260
+ if (__privateGet(this, _signature)?.type === "static") {
261
+ const { secret, header } = __privateGet(this, _signature);
262
+ if (header) {
263
+ headers[header] = secret;
264
+ } else {
265
+ headers["Authorization"] = `Bearer ${secret}`;
266
+ }
267
+ } else if (__privateGet(this, _signingSecret)) {
234
268
  const timestamp = Math.floor(Date.now() / 1e3);
235
- const sig = (0, import_crypto2.createHmac)("sha256", this.signingSecret).update(`${timestamp}.${body}`).digest("hex");
269
+ const sig = (0, import_crypto2.createHmac)("sha256", __privateGet(this, _signingSecret)).update(`${timestamp}.${body}`).digest("hex");
236
270
  headers["X-HostWebhook-Signature"] = `t=${timestamp},v1=${sig}`;
237
271
  }
238
- const url = `${this.baseUrl}/api/in/${this.token}`;
272
+ const url = `${__privateGet(this, _baseUrl)}/api/in/${__privateGet(this, _token)}`;
239
273
  const controller = new AbortController();
240
- const timer = setTimeout(() => controller.abort(), this.timeoutMs);
274
+ const timer = setTimeout(() => controller.abort(), __privateGet(this, _timeoutMs));
241
275
  try {
242
276
  const res = await fetch(url, {
243
277
  method: "POST",
@@ -262,7 +296,7 @@ var HostWebhook = class {
262
296
  if (err instanceof SendError) throw err;
263
297
  if (err instanceof DOMException && err.name === "AbortError") {
264
298
  throw new SendError(
265
- `HostWebhook request timed out after ${this.timeoutMs}ms`,
299
+ `HostWebhook request timed out after ${__privateGet(this, _timeoutMs)}ms`,
266
300
  0,
267
301
  ""
268
302
  );
@@ -283,6 +317,12 @@ var HostWebhook = class {
283
317
  return Promise.all(payloads.map((p) => this.send(p, options)));
284
318
  }
285
319
  };
320
+ _token = new WeakMap();
321
+ _baseUrl = new WeakMap();
322
+ _signingSecret = new WeakMap();
323
+ _signature = new WeakMap();
324
+ _defaultHeaders = new WeakMap();
325
+ _timeoutMs = new WeakMap();
286
326
  async function send(config, payload, options) {
287
327
  const client = new HostWebhook(config);
288
328
  return client.send(payload, options);
package/dist/index.mjs CHANGED
@@ -1,3 +1,11 @@
1
+ var __typeError = (msg) => {
2
+ throw TypeError(msg);
3
+ };
4
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
+
1
9
  // src/verify.ts
2
10
  import { createHmac, timingSafeEqual } from "crypto";
3
11
  var VerificationError = class extends Error {
@@ -165,16 +173,29 @@ var SendError = class extends Error {
165
173
  // src/client.ts
166
174
  var DEFAULT_BASE_URL = "https://api.hostwebhook.com";
167
175
  var DEFAULT_TIMEOUT = 1e4;
176
+ var _token, _baseUrl, _signingSecret, _signature, _defaultHeaders, _timeoutMs;
168
177
  var HostWebhook = class {
169
178
  constructor(config) {
179
+ __privateAdd(this, _token);
180
+ __privateAdd(this, _baseUrl);
181
+ __privateAdd(this, _signingSecret);
182
+ __privateAdd(this, _signature);
183
+ __privateAdd(this, _defaultHeaders);
184
+ __privateAdd(this, _timeoutMs);
170
185
  if (!config.token) {
171
186
  throw new Error("HostWebhook: token is required");
172
187
  }
173
- this.token = config.token;
174
- this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
175
- this.signingSecret = config.signingSecret;
176
- this.defaultHeaders = config.defaultHeaders ?? {};
177
- this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT;
188
+ if (config.signingSecret && config.signature) {
189
+ throw new Error(
190
+ "HostWebhook: use either signingSecret or signature, not both"
191
+ );
192
+ }
193
+ __privateSet(this, _token, config.token);
194
+ __privateSet(this, _baseUrl, (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""));
195
+ __privateSet(this, _signingSecret, config.signingSecret);
196
+ __privateSet(this, _signature, config.signature);
197
+ __privateSet(this, _defaultHeaders, config.defaultHeaders ?? {});
198
+ __privateSet(this, _timeoutMs, config.timeoutMs ?? DEFAULT_TIMEOUT);
178
199
  }
179
200
  /**
180
201
  * Send a webhook payload through HostWebhook.
@@ -190,20 +211,34 @@ var HostWebhook = class {
190
211
  */
191
212
  async send(payload, options) {
192
213
  const body = options?.rawBody !== void 0 ? typeof options.rawBody === "string" ? options.rawBody : options.rawBody.toString("utf8") : JSON.stringify(payload);
214
+ let tz = "";
215
+ try {
216
+ tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
217
+ } catch {
218
+ }
193
219
  const headers = {
194
220
  "Content-Type": options?.contentType ?? "application/json",
195
- "User-Agent": "HostWebhook-SDK/1.0",
196
- ...this.defaultHeaders,
221
+ "User-Agent": `HostWebhook-SDK/${"1.0.5"}`,
222
+ "X-HostWebhook-Sent-At": (/* @__PURE__ */ new Date()).toISOString(),
223
+ ...tz ? { "X-HostWebhook-Timezone": tz } : {},
224
+ ...__privateGet(this, _defaultHeaders),
197
225
  ...options?.headers
198
226
  };
199
- if (this.signingSecret) {
227
+ if (__privateGet(this, _signature)?.type === "static") {
228
+ const { secret, header } = __privateGet(this, _signature);
229
+ if (header) {
230
+ headers[header] = secret;
231
+ } else {
232
+ headers["Authorization"] = `Bearer ${secret}`;
233
+ }
234
+ } else if (__privateGet(this, _signingSecret)) {
200
235
  const timestamp = Math.floor(Date.now() / 1e3);
201
- const sig = createHmac2("sha256", this.signingSecret).update(`${timestamp}.${body}`).digest("hex");
236
+ const sig = createHmac2("sha256", __privateGet(this, _signingSecret)).update(`${timestamp}.${body}`).digest("hex");
202
237
  headers["X-HostWebhook-Signature"] = `t=${timestamp},v1=${sig}`;
203
238
  }
204
- const url = `${this.baseUrl}/api/in/${this.token}`;
239
+ const url = `${__privateGet(this, _baseUrl)}/api/in/${__privateGet(this, _token)}`;
205
240
  const controller = new AbortController();
206
- const timer = setTimeout(() => controller.abort(), this.timeoutMs);
241
+ const timer = setTimeout(() => controller.abort(), __privateGet(this, _timeoutMs));
207
242
  try {
208
243
  const res = await fetch(url, {
209
244
  method: "POST",
@@ -228,7 +263,7 @@ var HostWebhook = class {
228
263
  if (err instanceof SendError) throw err;
229
264
  if (err instanceof DOMException && err.name === "AbortError") {
230
265
  throw new SendError(
231
- `HostWebhook request timed out after ${this.timeoutMs}ms`,
266
+ `HostWebhook request timed out after ${__privateGet(this, _timeoutMs)}ms`,
232
267
  0,
233
268
  ""
234
269
  );
@@ -249,6 +284,12 @@ var HostWebhook = class {
249
284
  return Promise.all(payloads.map((p) => this.send(p, options)));
250
285
  }
251
286
  };
287
+ _token = new WeakMap();
288
+ _baseUrl = new WeakMap();
289
+ _signingSecret = new WeakMap();
290
+ _signature = new WeakMap();
291
+ _defaultHeaders = new WeakMap();
292
+ _timeoutMs = new WeakMap();
252
293
  async function send(config, payload, options) {
253
294
  const client = new HostWebhook(config);
254
295
  return client.send(payload, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostwebhook/node",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Official HostWebhook SDK — verify signatures, parse headers, and send webhooks",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -18,7 +18,7 @@
18
18
  "llms.txt"
19
19
  ],
20
20
  "scripts": {
21
- "build": "tsup src/index.ts --format cjs,esm --dts --clean",
21
+ "build": "tsup",
22
22
  "test": "node --test __tests__/sdk.test.mjs",
23
23
  "prepublishOnly": "npm run build"
24
24
  },