@hookflo/tern 1.0.1 → 1.0.2

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/examples.js CHANGED
@@ -1,160 +1,302 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.exampleBasicUsage = exampleBasicUsage;
4
- exports.exampleTokenBased = exampleTokenBased;
3
+ exports.examplePlatformSpecific = examplePlatformSpecific;
5
4
  exports.exampleCustomSignature = exampleCustomSignature;
6
- exports.examplePlatformDetection = examplePlatformDetection;
5
+ exports.exampleSimplifiedPlatform = exampleSimplifiedPlatform;
6
+ exports.exampleTokenBased = exampleTokenBased;
7
7
  exports.exampleErrorHandling = exampleErrorHandling;
8
- exports.exampleBatchVerification = exampleBatchVerification;
9
- exports.exampleExpressIntegration = exampleExpressIntegration;
10
- exports.exampleNextJsApiRoute = exampleNextJsApiRoute;
11
- exports.exampleCustomPlatform = exampleCustomPlatform;
12
- exports.exampleHelperMethods = exampleHelperMethods;
8
+ exports.examplePlatformInfo = examplePlatformInfo;
9
+ exports.exampleRealWorldUsage = exampleRealWorldUsage;
10
+ exports.runAllExamples = runAllExamples;
13
11
  const index_1 = require("./index");
14
- // Example 1: Basic usage with platform config
15
- async function exampleBasicUsage(request) {
16
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'github', 'your-github-secret', 300);
17
- return result;
18
- }
19
- // Example 2: Token-based authentication (Supabase style)
20
- async function exampleTokenBased(request) {
21
- const result = await index_1.WebhookVerificationService.verifyTokenBased(request, 'your-webhook-id', 'your-webhook-token');
22
- return result;
12
+ // Example 1: Using platform-specific configurations (Recommended)
13
+ async function examplePlatformSpecific() {
14
+ console.log('šŸ”§ Example 1: Platform-Specific Configurations\n');
15
+ // Stripe webhook verification
16
+ const stripeConfig = {
17
+ platform: 'stripe',
18
+ secret: 'whsec_your_stripe_webhook_secret',
19
+ toleranceInSeconds: 300,
20
+ };
21
+ // GitHub webhook verification
22
+ const githubConfig = {
23
+ platform: 'github',
24
+ secret: 'your_github_webhook_secret',
25
+ toleranceInSeconds: 300,
26
+ };
27
+ // Clerk webhook verification
28
+ const clerkConfig = {
29
+ platform: 'clerk',
30
+ secret: 'whsec_your_clerk_webhook_secret',
31
+ toleranceInSeconds: 300,
32
+ };
33
+ // Usage with Request object
34
+ const request = new Request('https://your-app.com/webhook', {
35
+ method: 'POST',
36
+ headers: {
37
+ 'stripe-signature': 't=1234567890,v1=abc123...',
38
+ 'content-type': 'application/json',
39
+ },
40
+ body: JSON.stringify({ event: 'payment_intent.succeeded' }),
41
+ });
42
+ try {
43
+ const result = await index_1.WebhookVerificationService.verify(request, stripeConfig);
44
+ if (result.isValid) {
45
+ console.log('āœ… Webhook verified successfully!');
46
+ console.log('Platform:', result.platform);
47
+ console.log('Payload:', result.payload);
48
+ console.log('Metadata:', result.metadata);
49
+ }
50
+ else {
51
+ console.log('āŒ Webhook verification failed:', result.error);
52
+ }
53
+ }
54
+ catch (error) {
55
+ console.error('Error verifying webhook:', error);
56
+ }
23
57
  }
24
- // Example 3: Custom signature configuration
25
- async function exampleCustomSignature(request) {
26
- const signatureConfig = {
27
- algorithm: 'hmac-sha256',
28
- headerName: 'x-custom-signature',
29
- headerFormat: 'prefixed',
30
- prefix: 'sha256=',
31
- payloadFormat: 'raw',
58
+ // Example 2: Using custom signature configurations
59
+ async function exampleCustomSignature() {
60
+ console.log('\nšŸ”§ Example 2: Custom Signature Configurations\n');
61
+ // Custom HMAC-SHA256 configuration
62
+ const customConfig = {
63
+ platform: 'custom',
64
+ secret: 'your_custom_secret',
65
+ signatureConfig: {
66
+ algorithm: 'hmac-sha256',
67
+ headerName: 'x-custom-signature',
68
+ headerFormat: 'prefixed',
69
+ prefix: 'sha256=',
70
+ payloadFormat: 'raw',
71
+ },
32
72
  };
33
- const config = {
73
+ // Custom timestamped configuration
74
+ const timestampedConfig = {
34
75
  platform: 'custom',
35
- secret: 'your-custom-secret',
36
- signatureConfig,
76
+ secret: 'your_custom_secret',
77
+ signatureConfig: {
78
+ algorithm: 'hmac-sha256',
79
+ headerName: 'x-webhook-signature',
80
+ headerFormat: 'raw',
81
+ timestampHeader: 'x-webhook-timestamp',
82
+ timestampFormat: 'unix',
83
+ payloadFormat: 'timestamped',
84
+ },
37
85
  };
38
- const result = await index_1.WebhookVerificationService.verify(request, config);
39
- return result;
86
+ console.log('Custom configurations created for different signature formats');
40
87
  }
41
- // Example 4: Platform detection
42
- async function examplePlatformDetection(request) {
43
- const { detectPlatformFromHeaders } = require('./utils');
44
- const platform = detectPlatformFromHeaders(request.headers);
45
- if (platform) {
46
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, platform, 'your-secret', 300);
47
- return result;
48
- }
49
- throw new Error('Unknown platform');
50
- }
51
- // Example 5: Error handling
52
- async function exampleErrorHandling(request) {
88
+ // Example 3: Using the simplified platform config method
89
+ async function exampleSimplifiedPlatform() {
90
+ console.log('\nšŸ”§ Example 3: Simplified Platform Configuration\n');
91
+ const request = new Request('https://your-app.com/webhook', {
92
+ method: 'POST',
93
+ headers: {
94
+ 'x-hub-signature-256': 'sha256=abc123...',
95
+ 'x-github-event': 'push',
96
+ 'content-type': 'application/json',
97
+ },
98
+ body: JSON.stringify({ ref: 'refs/heads/main' }),
99
+ });
53
100
  try {
54
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'github', 'your-secret', 300);
55
- if (!result.isValid) {
56
- console.error('Verification failed:', result.error);
57
- return { success: false, error: result.error };
101
+ // Simple one-liner for platform-specific verification
102
+ const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'github', 'your_github_webhook_secret');
103
+ if (result.isValid) {
104
+ console.log('āœ… GitHub webhook verified!');
105
+ console.log('Event:', result.metadata?.event);
106
+ console.log('Payload:', result.payload);
107
+ }
108
+ else {
109
+ console.log('āŒ GitHub webhook verification failed:', result.error);
58
110
  }
59
- return { success: true, payload: result.payload };
60
111
  }
61
112
  catch (error) {
62
- console.error('Verification error:', error);
63
- return { success: false, error: error.message };
113
+ console.error('Error:', error);
64
114
  }
65
115
  }
66
- // Example 6: Batch verification
67
- async function exampleBatchVerification(request) {
68
- const platforms = ['github', 'stripe', 'clerk'];
69
- const results = [];
70
- for (const platform of platforms) {
71
- try {
72
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, platform, 'your-secret', 300);
73
- results.push({ platform, success: true, result });
116
+ // Example 4: Token-based authentication (Supabase style)
117
+ async function exampleTokenBased() {
118
+ console.log('\nšŸ”§ Example 4: Token-Based Authentication\n');
119
+ const request = new Request('https://your-app.com/webhook', {
120
+ method: 'POST',
121
+ headers: {
122
+ 'x-webhook-id': 'webhook_123',
123
+ 'x-webhook-token': 'token_456',
124
+ 'content-type': 'application/json',
125
+ },
126
+ body: JSON.stringify({ event: 'database.insert' }),
127
+ });
128
+ try {
129
+ const result = await index_1.WebhookVerificationService.verifyTokenBased(request, 'webhook_123', 'token_456');
130
+ if (result.isValid) {
131
+ console.log('āœ… Token-based webhook verified!');
132
+ console.log('Webhook ID:', result.metadata?.id);
133
+ console.log('Payload:', result.payload);
74
134
  }
75
- catch (error) {
76
- results.push({ platform, success: false, error: error.message });
135
+ else {
136
+ console.log('āŒ Token-based webhook verification failed:', result.error);
77
137
  }
78
138
  }
79
- return results;
139
+ catch (error) {
140
+ console.error('Error:', error);
141
+ }
80
142
  }
81
- // Example 7: Express.js integration
82
- function exampleExpressIntegration() {
83
- const express = require('express');
84
- const app = express();
85
- app.post('/webhook', async (req, res) => {
86
- try {
87
- const fetchRequest = new Request('http://localhost/webhook', {
88
- method: req.method,
89
- headers: req.headers, // headers need to be a plain object
90
- body: JSON.stringify(req.body),
91
- });
92
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(fetchRequest, 'github', process.env.GITHUB_WEBHOOK_SECRET || '', 300);
93
- if (result.isValid) {
94
- console.log('Webhook received:', result.payload);
95
- res.status(200).json({ success: true });
96
- }
97
- else {
98
- res.status(401).json({ error: result.error });
99
- }
143
+ // Example 5: Error handling and validation
144
+ async function exampleErrorHandling() {
145
+ console.log('\nšŸ”§ Example 5: Error Handling and Validation\n');
146
+ // Test with invalid signature
147
+ const invalidRequest = new Request('https://your-app.com/webhook', {
148
+ method: 'POST',
149
+ headers: {
150
+ 'stripe-signature': 't=1234567890,v1=invalid_signature',
151
+ 'content-type': 'application/json',
152
+ },
153
+ body: JSON.stringify({ event: 'test' }),
154
+ });
155
+ try {
156
+ const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(invalidRequest, 'stripe', 'whsec_your_stripe_webhook_secret');
157
+ if (!result.isValid) {
158
+ console.log('āŒ Expected failure:', result.error);
159
+ console.log('Platform:', result.platform);
100
160
  }
101
- catch (error) {
102
- res.status(500).json({ error: 'Internal server error' });
161
+ else {
162
+ console.log('āš ļø Unexpected success - this should have failed');
103
163
  }
164
+ }
165
+ catch (error) {
166
+ console.error('Error during verification:', error);
167
+ }
168
+ // Test with missing headers
169
+ const missingHeadersRequest = new Request('https://your-app.com/webhook', {
170
+ method: 'POST',
171
+ headers: {
172
+ 'content-type': 'application/json',
173
+ },
174
+ body: JSON.stringify({ event: 'test' }),
104
175
  });
105
- return app;
106
- }
107
- // Example 8: Next.js API route
108
- function exampleNextJsApiRoute() {
109
- return async function handler(req, res) {
110
- if (req.method !== 'POST') {
111
- return res.status(405).json({ error: 'Method not allowed' });
112
- }
113
- try {
114
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(req, 'stripe', process.env.STRIPE_WEBHOOK_SECRET || '', 300);
115
- if (result.isValid) {
116
- console.log('Stripe webhook:', result.payload);
117
- res.status(200).json({ received: true });
118
- }
119
- else {
120
- res.status(401).json({ error: result.error });
121
- }
176
+ try {
177
+ const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(missingHeadersRequest, 'stripe', 'whsec_your_stripe_webhook_secret');
178
+ if (!result.isValid) {
179
+ console.log('āŒ Missing headers detected:', result.error);
122
180
  }
123
- catch (error) {
124
- res.status(500).json({ error: 'Internal server error' });
181
+ else {
182
+ console.log('āš ļø Unexpected success - should have detected missing headers');
125
183
  }
126
- };
127
- }
128
- // Example 9: Custom platform integration
129
- async function exampleCustomPlatform(request) {
130
- const customConfig = {
131
- platform: 'custom',
132
- secret: 'your-custom-secret',
133
- signatureConfig: {
134
- algorithm: 'hmac-sha256',
135
- headerName: 'x-custom-signature',
136
- headerFormat: 'raw',
137
- payloadFormat: 'raw',
138
- },
139
- };
140
- const result = await index_1.WebhookVerificationService.verify(request, customConfig);
141
- return result;
184
+ }
185
+ catch (error) {
186
+ console.error('Error during verification:', error);
187
+ }
142
188
  }
143
- // Example 10: Helper methods usage
144
- function exampleHelperMethods() {
145
- const { WebhookVerificationService } = require('./index');
189
+ // Example 6: Platform algorithm information
190
+ function examplePlatformInfo() {
191
+ console.log('\nšŸ”§ Example 6: Platform Algorithm Information\n');
146
192
  // Get all platforms using HMAC-SHA256
147
- const hmacPlatforms = WebhookVerificationService.getPlatformsUsingAlgorithm('hmac-sha256');
148
- console.log('Platforms using HMAC-SHA256:', hmacPlatforms);
193
+ const hmacSha256Platforms = index_1.WebhookVerificationService.getPlatformsUsingAlgorithm('hmac-sha256');
194
+ console.log('Platforms using HMAC-SHA256:', hmacSha256Platforms);
149
195
  // Check if a platform uses a specific algorithm
150
- const githubUsesHmac = WebhookVerificationService.platformUsesAlgorithm('github', 'hmac-sha256');
151
- console.log('GitHub uses HMAC-SHA256:', githubUsesHmac);
152
- // Validate a signature config
153
- const config = {
196
+ const stripeUsesHmac = index_1.WebhookVerificationService.platformUsesAlgorithm('stripe', 'hmac-sha256');
197
+ console.log('Stripe uses HMAC-SHA256:', stripeUsesHmac);
198
+ const clerkUsesCustom = index_1.WebhookVerificationService.platformUsesAlgorithm('clerk', 'custom');
199
+ console.log('Clerk uses custom algorithm:', clerkUsesCustom);
200
+ // Validate signature config
201
+ const validConfig = {
154
202
  algorithm: 'hmac-sha256',
155
- headerName: 'x-signature',
203
+ headerName: 'x-webhook-signature',
204
+ headerFormat: 'raw',
156
205
  payloadFormat: 'raw',
157
206
  };
158
- const isValid = WebhookVerificationService.validateSignatureConfig(config);
159
- console.log('Config is valid:', isValid);
207
+ const isValid = index_1.WebhookVerificationService.validateSignatureConfig(validConfig);
208
+ console.log('Signature config is valid:', isValid);
209
+ }
210
+ // Example 7: Real-world usage patterns
211
+ async function exampleRealWorldUsage() {
212
+ console.log('\nšŸ”§ Example 7: Real-World Usage Patterns\n');
213
+ // Pattern 1: Express.js middleware
214
+ console.log('Pattern 1: Express.js Middleware');
215
+ console.log(`
216
+ app.post('/webhooks/stripe', async (req, res) => {
217
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
218
+ req,
219
+ 'stripe',
220
+ process.env.STRIPE_WEBHOOK_SECRET
221
+ );
222
+
223
+ if (!result.isValid) {
224
+ return res.status(400).json({ error: result.error });
225
+ }
226
+
227
+ // Process the webhook
228
+ console.log('Stripe event:', result.payload.type);
229
+ res.json({ received: true });
230
+ });
231
+ `);
232
+ // Pattern 2: Next.js API route
233
+ console.log('\nPattern 2: Next.js API Route');
234
+ console.log(`
235
+ // pages/api/webhooks/github.js
236
+ export default async function handler(req, res) {
237
+ if (req.method !== 'POST') {
238
+ return res.status(405).json({ error: 'Method not allowed' });
239
+ }
240
+
241
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
242
+ req,
243
+ 'github',
244
+ process.env.GITHUB_WEBHOOK_SECRET
245
+ );
246
+
247
+ if (!result.isValid) {
248
+ return res.status(400).json({ error: result.error });
249
+ }
250
+
251
+ // Handle GitHub webhook
252
+ const event = req.headers['x-github-event'];
253
+ console.log('GitHub event:', event);
254
+
255
+ res.json({ received: true });
256
+ }
257
+ `);
258
+ // Pattern 3: Cloudflare Workers
259
+ console.log('\nPattern 3: Cloudflare Workers');
260
+ console.log(`
261
+ addEventListener('fetch', event => {
262
+ event.respondWith(handleRequest(event.request));
263
+ });
264
+
265
+ async function handleRequest(request) {
266
+ if (request.url.includes('/webhooks/clerk')) {
267
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
268
+ request,
269
+ 'clerk',
270
+ CLERK_WEBHOOK_SECRET
271
+ );
272
+
273
+ if (!result.isValid) {
274
+ return new Response(JSON.stringify({ error: result.error }), {
275
+ status: 400,
276
+ headers: { 'Content-Type': 'application/json' }
277
+ });
278
+ }
279
+
280
+ // Process Clerk webhook
281
+ console.log('Clerk event:', result.payload.type);
282
+ return new Response(JSON.stringify({ received: true }));
283
+ }
284
+ }
285
+ `);
286
+ }
287
+ // Run all examples
288
+ async function runAllExamples() {
289
+ console.log('šŸš€ Running Webhook Verification Examples\n');
290
+ await examplePlatformSpecific();
291
+ await exampleCustomSignature();
292
+ await exampleSimplifiedPlatform();
293
+ await exampleTokenBased();
294
+ await exampleErrorHandling();
295
+ examplePlatformInfo();
296
+ await exampleRealWorldUsage();
297
+ console.log('\nāœ… All examples completed!');
298
+ }
299
+ // Run examples if this file is executed directly
300
+ if (require.main === module) {
301
+ runAllExamples().catch(console.error);
160
302
  }
package/dist/index.js CHANGED
@@ -21,7 +21,12 @@ const algorithms_2 = require("./platforms/algorithms");
21
21
  class WebhookVerificationService {
22
22
  static async verify(request, config) {
23
23
  const verifier = this.getVerifier(config);
24
- return await verifier.verify(request);
24
+ const result = await verifier.verify(request);
25
+ // Ensure the platform is set correctly in the result
26
+ if (result.isValid) {
27
+ result.platform = config.platform;
28
+ }
29
+ return result;
25
30
  }
26
31
  static getVerifier(config) {
27
32
  const platform = config.platform.toLowerCase();
@@ -37,12 +42,12 @@ class WebhookVerificationService {
37
42
  if (!signatureConfig) {
38
43
  throw new Error('Signature config is required for algorithm-based verification');
39
44
  }
40
- // Use custom verifiers for special cases
45
+ // Use custom verifiers for special cases (token-based, etc.)
41
46
  if (signatureConfig.algorithm === 'custom') {
42
47
  return (0, custom_algorithms_1.createCustomVerifier)(secret, signatureConfig, toleranceInSeconds);
43
48
  }
44
49
  // Use algorithm-based verifiers for standard algorithms
45
- return (0, algorithms_1.createAlgorithmVerifier)(secret, signatureConfig, toleranceInSeconds);
50
+ return (0, algorithms_1.createAlgorithmVerifier)(secret, signatureConfig, config.platform, toleranceInSeconds);
46
51
  }
47
52
  static getLegacyVerifier(config) {
48
53
  const platform = config.platform.toLowerCase();
@@ -39,17 +39,17 @@ exports.platformAlgorithmConfigs = {
39
39
  clerk: {
40
40
  platform: "clerk",
41
41
  signatureConfig: {
42
- algorithm: "custom",
42
+ algorithm: "hmac-sha256",
43
43
  headerName: "svix-signature",
44
44
  headerFormat: "raw",
45
45
  timestampHeader: "svix-timestamp",
46
46
  timestampFormat: "unix",
47
47
  payloadFormat: "custom",
48
48
  customConfig: {
49
- type: "clerk-custom",
50
49
  signatureFormat: "v1={signature}",
51
50
  payloadFormat: "{id}.{timestamp}.{body}",
52
51
  encoding: "base64",
52
+ idHeader: "svix-id",
53
53
  },
54
54
  },
55
55
  description: "Clerk webhooks use HMAC-SHA256 with base64 encoding",
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const test_1 = require("./test");
4
- (0, test_1.runAllTests)().catch(console.error);
4
+ (0, test_1.runTests)();
package/dist/test.d.ts CHANGED
@@ -1,6 +1,2 @@
1
- declare function testGitHubWebhook(): Promise<import("./types").WebhookVerificationResult>;
2
- declare function testTokenBasedWebhook(): Promise<import("./types").WebhookVerificationResult>;
3
- declare function testPlatformDetection(): void;
4
- declare function testCustomSignature(): Promise<import("./types").WebhookVerificationResult>;
5
- export declare function runAllTests(): Promise<void>;
6
- export { testGitHubWebhook, testTokenBasedWebhook, testPlatformDetection, testCustomSignature, };
1
+ declare function runTests(): Promise<void>;
2
+ export { runTests };