@hostwebhook/node 1.0.0 → 1.0.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.
Files changed (3) hide show
  1. package/README.md +167 -0
  2. package/llms.txt +167 -0
  3. package/package.json +4 -2
package/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # @hostwebhook/node
2
+
3
+ Official Node.js SDK for [HostWebhook](https://hostwebhook.com) — verify webhook signatures and send webhooks through the platform.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm install @hostwebhook/node
9
+ ```
10
+
11
+ Requires Node.js 18+.
12
+
13
+ ## Verify Webhook Signatures
14
+
15
+ HostWebhook signs every delivery with HMAC-SHA256. Use these helpers to verify authenticity and prevent replay attacks.
16
+
17
+ ### Express
18
+
19
+ ```ts
20
+ import express from 'express';
21
+ import { expressMiddleware } from '@hostwebhook/node';
22
+
23
+ const app = express();
24
+
25
+ app.post('/webhooks',
26
+ express.raw({ type: 'application/json' }),
27
+ expressMiddleware(process.env.SIGNING_SECRET!),
28
+ (req, res) => {
29
+ const payload = JSON.parse(req.body.toString());
30
+ // process payload...
31
+ res.json({ received: true });
32
+ },
33
+ );
34
+ ```
35
+
36
+ > **Important:** Use `express.raw()` so `req.body` is a Buffer, not parsed JSON.
37
+
38
+ ### NestJS
39
+
40
+ ```ts
41
+ import { Controller, Post, UseGuards, Req } from '@nestjs/common';
42
+ import { createNestGuard } from '@hostwebhook/node';
43
+
44
+ const WebhookGuard = createNestGuard(process.env.SIGNING_SECRET!);
45
+
46
+ @Controller('webhooks')
47
+ export class WebhooksController {
48
+ @Post()
49
+ @UseGuards(WebhookGuard)
50
+ handle(@Req() req: Request) {
51
+ return { received: true };
52
+ }
53
+ }
54
+ ```
55
+
56
+ ### Fastify
57
+
58
+ ```ts
59
+ import Fastify from 'fastify';
60
+ import { fastifyHook } from '@hostwebhook/node';
61
+
62
+ const app = Fastify();
63
+ app.addContentTypeParser('application/json', { parseAs: 'buffer' }, (req, body, done) => done(null, body));
64
+
65
+ app.post('/webhooks', {
66
+ preHandler: fastifyHook(process.env.SIGNING_SECRET!),
67
+ }, (req, reply) => {
68
+ reply.send({ received: true });
69
+ });
70
+ ```
71
+
72
+ ### Manual Verification
73
+
74
+ ```ts
75
+ import { verify, VerificationError } from '@hostwebhook/node';
76
+
77
+ try {
78
+ verify(rawBody, request.headers, secret);
79
+ // signature valid
80
+ } catch (err) {
81
+ if (err instanceof VerificationError) {
82
+ // invalid — reject the request
83
+ }
84
+ }
85
+ ```
86
+
87
+ Options: `verify(payload, headers, secret, { maxAgeSec: 300 })` — default 300s (5 min). Set `0` to disable replay protection.
88
+
89
+ ## Send Webhooks
90
+
91
+ Send webhook payloads through HostWebhook for reliable delivery with retries and monitoring.
92
+
93
+ ### Class-based
94
+
95
+ ```ts
96
+ import { HostWebhook } from '@hostwebhook/node';
97
+
98
+ const hw = new HostWebhook({ token: 'your_ingress_token' });
99
+
100
+ const { eventId } = await hw.send({ event: 'order.created', orderId: '123' });
101
+ ```
102
+
103
+ ### Batch
104
+
105
+ ```ts
106
+ const results = await hw.sendBatch([
107
+ { event: 'user.signup', userId: '1' },
108
+ { event: 'user.signup', userId: '2' },
109
+ ]);
110
+ ```
111
+
112
+ ### Standalone Function
113
+
114
+ ```ts
115
+ import { send } from '@hostwebhook/node';
116
+
117
+ const { eventId } = await send(
118
+ { token: 'your_ingress_token' },
119
+ { event: 'test', data: 'hello' },
120
+ );
121
+ ```
122
+
123
+ ## Configuration
124
+
125
+ | Option | Type | Default | Description |
126
+ |--------|------|---------|-------------|
127
+ | `token` | `string` | *required* | Endpoint ingress token |
128
+ | `baseUrl` | `string` | `https://api.hostwebhook.com` | API base URL |
129
+ | `signingSecret` | `string` | — | Signs outgoing requests with HMAC-SHA256 |
130
+ | `defaultHeaders` | `Record<string, string>` | — | Headers added to every request |
131
+ | `timeoutMs` | `number` | `10000` | Request timeout in ms |
132
+
133
+ ## Error Handling
134
+
135
+ ```ts
136
+ import { SendError, VerificationError } from '@hostwebhook/node';
137
+
138
+ // Send errors
139
+ try {
140
+ await hw.send(payload);
141
+ } catch (err) {
142
+ if (err instanceof SendError) {
143
+ console.log(err.statusCode, err.responseBody);
144
+ }
145
+ }
146
+
147
+ // Verification errors
148
+ try {
149
+ verify(body, headers, secret);
150
+ } catch (err) {
151
+ if (err instanceof VerificationError) {
152
+ console.log(err.message);
153
+ }
154
+ }
155
+ ```
156
+
157
+ ## Signature Format
158
+
159
+ ```
160
+ X-HostWebhook-Signature: t=<timestamp_ms>,v1=<hmac_hex>
161
+ ```
162
+
163
+ HMAC computed as: `HMAC-SHA256(secret, "${timestamp}.${rawBody}")`
164
+
165
+ ## License
166
+
167
+ MIT
package/llms.txt ADDED
@@ -0,0 +1,167 @@
1
+ # @hostwebhook/node
2
+
3
+ > Official HostWebhook Node.js SDK — verify webhook signatures and send webhooks through the platform.
4
+
5
+ ## Install
6
+
7
+ npm install @hostwebhook/node
8
+
9
+ ## Verify Signatures (receiving webhooks)
10
+
11
+ HostWebhook signs every delivery with HMAC-SHA256. Use these helpers to verify authenticity.
12
+
13
+ ### Express
14
+
15
+ ```ts
16
+ import express from 'express';
17
+ import { expressMiddleware } from '@hostwebhook/node';
18
+
19
+ const app = express();
20
+ app.post('/webhooks',
21
+ express.raw({ type: 'application/json' }),
22
+ expressMiddleware(process.env.SIGNING_SECRET!),
23
+ (req, res) => {
24
+ const payload = JSON.parse(req.body.toString());
25
+ // process payload...
26
+ res.json({ received: true });
27
+ },
28
+ );
29
+ ```
30
+
31
+ IMPORTANT: Use `express.raw()` so `req.body` is a Buffer, not parsed JSON.
32
+
33
+ ### NestJS
34
+
35
+ ```ts
36
+ import { Controller, Post, UseGuards, Req } from '@nestjs/common';
37
+ import { createNestGuard } from '@hostwebhook/node';
38
+
39
+ const WebhookGuard = createNestGuard(process.env.SIGNING_SECRET!);
40
+
41
+ @Controller('webhooks')
42
+ export class WebhooksController {
43
+ @Post()
44
+ @UseGuards(WebhookGuard)
45
+ handle(@Req() req: Request) {
46
+ return { received: true };
47
+ }
48
+ }
49
+ ```
50
+
51
+ ### Fastify
52
+
53
+ ```ts
54
+ import Fastify from 'fastify';
55
+ import { fastifyHook } from '@hostwebhook/node';
56
+
57
+ const app = Fastify();
58
+ app.addContentTypeParser('application/json', { parseAs: 'buffer' }, (req, body, done) => done(null, body));
59
+
60
+ app.post('/webhooks', {
61
+ preHandler: fastifyHook(process.env.SIGNING_SECRET!),
62
+ }, (req, reply) => {
63
+ reply.send({ received: true });
64
+ });
65
+ ```
66
+
67
+ ### Manual verification
68
+
69
+ ```ts
70
+ import { verify, VerificationError } from '@hostwebhook/node';
71
+
72
+ try {
73
+ verify(rawBody, request.headers, secret);
74
+ // signature is valid
75
+ } catch (err) {
76
+ if (err instanceof VerificationError) {
77
+ // invalid signature — reject
78
+ }
79
+ }
80
+ ```
81
+
82
+ verify(payload, headers, secret, options?) — throws VerificationError if invalid.
83
+ VerifyOptions: { maxAgeSec?: number } — default 300 (5 min). Set 0 to disable replay protection.
84
+
85
+ ## Send Webhooks (sending through HostWebhook)
86
+
87
+ ### Class-based client
88
+
89
+ ```ts
90
+ import { HostWebhook } from '@hostwebhook/node';
91
+
92
+ const hw = new HostWebhook({ token: 'your_ingress_token' });
93
+
94
+ // Send a single event
95
+ const { eventId } = await hw.send({ event: 'order.created', orderId: '123' });
96
+
97
+ // Send multiple events in parallel
98
+ const results = await hw.sendBatch([
99
+ { event: 'user.signup', userId: '1' },
100
+ { event: 'user.signup', userId: '2' },
101
+ ]);
102
+ ```
103
+
104
+ ### Standalone function (no class needed)
105
+
106
+ ```ts
107
+ import { send } from '@hostwebhook/node';
108
+
109
+ const { eventId } = await send(
110
+ { token: 'your_ingress_token' },
111
+ { event: 'test', data: 'hello' },
112
+ );
113
+ ```
114
+
115
+ ## Configuration
116
+
117
+ HostWebhookConfig: {
118
+ token: string (required — your endpoint's ingress token),
119
+ baseUrl?: string (default: https://api.hostwebhook.com),
120
+ signingSecret?: string (optional — signs outgoing requests with HMAC-SHA256),
121
+ defaultHeaders?: Record<string, string>,
122
+ timeoutMs?: number (default: 10000),
123
+ }
124
+
125
+ SendOptions: {
126
+ headers?: Record<string, string>,
127
+ contentType?: string (default: application/json),
128
+ rawBody?: string | Buffer (skip JSON.stringify, send raw),
129
+ }
130
+
131
+ SendResult: { eventId: string }
132
+
133
+ ## Signature Format
134
+
135
+ Header: `X-HostWebhook-Signature: t=<timestamp_ms>,v1=<hmac_hex>`
136
+ HMAC computed as: `HMAC-SHA256(secret, "${timestamp}.${rawBody}")`
137
+
138
+ ## Error Handling
139
+
140
+ ```ts
141
+ import { SendError, VerificationError } from '@hostwebhook/node';
142
+
143
+ // SendError — thrown when API returns non-2xx
144
+ try {
145
+ await hw.send(payload);
146
+ } catch (err) {
147
+ if (err instanceof SendError) {
148
+ console.log(err.statusCode, err.responseBody);
149
+ }
150
+ }
151
+
152
+ // VerificationError — thrown when signature is invalid
153
+ try {
154
+ verify(body, headers, secret);
155
+ } catch (err) {
156
+ if (err instanceof VerificationError) {
157
+ console.log(err.message); // e.g. "Signature mismatch"
158
+ }
159
+ }
160
+ ```
161
+
162
+ ## Exports
163
+
164
+ Functions: verify, expressMiddleware, createNestGuard, fastifyHook, send
165
+ Classes: HostWebhook, SendError, VerificationError
166
+ Types: VerifyOptions, HostWebhookConfig, SendOptions, SendResult, WebhookHeaders
167
+ Helpers: parseHeaders (extract webhook metadata from headers)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostwebhook/node",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
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",
@@ -13,7 +13,9 @@
13
13
  }
14
14
  },
15
15
  "files": [
16
- "dist"
16
+ "dist",
17
+ "README.md",
18
+ "llms.txt"
17
19
  ],
18
20
  "scripts": {
19
21
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",