@hookflo/tern 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 tern
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,396 @@
1
+ # Tern
2
+
3
+ A robust, scalable webhook verification framework supporting multiple platforms and signature algorithms. Built with TypeScript for maximum type safety and developer experience.
4
+
5
+ ## Features
6
+
7
+ - **Algorithm-based verification**: Instead of platform-specific verifiers, use algorithm-based verifiers
8
+ - **Platform configuration**: Each platform specifies which algorithm to use
9
+ - **Extensible framework**: Easy to add new algorithms and platforms
10
+ - **Most common algorithms**: HMAC-SHA256, HMAC-SHA1, HMAC-SHA512, and custom algorithms
11
+ - **TypeScript support**: Full type safety and IntelliSense
12
+ - **Zero dependencies**: Only uses Node.js built-in modules
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install tern
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### Basic Usage
23
+
24
+ ```typescript
25
+ import { WebhookVerificationService } from 'tern';
26
+
27
+ // Verify a GitHub webhook
28
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
29
+ request,
30
+ 'github',
31
+ 'your-github-secret',
32
+ 300
33
+ );
34
+
35
+ if (result.isValid) {
36
+ console.log('Webhook verified successfully:', result.payload);
37
+ } else {
38
+ console.error('Verification failed:', result.error);
39
+ }
40
+ ```
41
+
42
+ ### Token-based Authentication (Supabase, Custom)
43
+
44
+ ```typescript
45
+ // For platforms that use simple token-based auth
46
+ const result = await WebhookVerificationService.verifyTokenBased(
47
+ request,
48
+ 'your-webhook-id',
49
+ 'your-webhook-token'
50
+ );
51
+ ```
52
+
53
+ ### Custom Signature Configuration
54
+
55
+ ```typescript
56
+ import { WebhookVerificationService } from 'tern';
57
+
58
+ const config = {
59
+ platform: 'custom',
60
+ secret: 'your-secret',
61
+ signatureConfig: {
62
+ algorithm: 'hmac-sha256',
63
+ headerName: 'x-signature',
64
+ headerFormat: 'prefixed',
65
+ prefix: 'sha256=',
66
+ payloadFormat: 'raw'
67
+ }
68
+ };
69
+
70
+ const result = await WebhookVerificationService.verify(request, config);
71
+ ```
72
+
73
+ ## 🏗️ Supported Platforms
74
+
75
+ ### HMAC-SHA256 (Most Common)
76
+ - **GitHub**: `x-hub-signature-256` with `sha256=` prefix
77
+ - **Stripe**: `stripe-signature` with comma-separated format
78
+ - **Clerk**: `svix-signature` with base64 encoding
79
+ - **Dodo Payments**: `webhook-signature` with raw format
80
+ - **Shopify**: `x-shopify-hmac-sha256`
81
+ - **Vercel**: `x-vercel-signature`
82
+ - **Polar**: `x-polar-signature`
83
+
84
+ ### Custom Algorithms
85
+ - **Supabase**: Token-based authentication
86
+ - **Clerk**: Custom base64 encoding
87
+ - **Stripe**: Custom comma-separated format
88
+
89
+ ## 🔧 API Reference
90
+
91
+ ### WebhookVerificationService
92
+
93
+ #### `verify(request: Request, config: WebhookConfig): Promise<WebhookVerificationResult>`
94
+
95
+ Verify a webhook using a configuration object.
96
+
97
+ ```typescript
98
+ const config = {
99
+ platform: 'github',
100
+ secret: 'your-secret',
101
+ toleranceInSeconds: 300
102
+ };
103
+
104
+ const result = await WebhookVerificationService.verify(request, config);
105
+ ```
106
+
107
+ #### `verifyWithPlatformConfig(request: Request, platform: WebhookPlatform, secret: string, toleranceInSeconds?: number): Promise<WebhookVerificationResult>`
108
+
109
+ Verify a webhook using platform-specific configuration.
110
+
111
+ ```typescript
112
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
113
+ request,
114
+ 'stripe',
115
+ 'your-stripe-secret',
116
+ 300
117
+ );
118
+ ```
119
+
120
+ #### `verifyTokenBased(request: Request, webhookId: string, webhookToken: string): Promise<WebhookVerificationResult>`
121
+
122
+ Verify a webhook using simple token-based authentication.
123
+
124
+ ```typescript
125
+ const result = await WebhookVerificationService.verifyTokenBased(
126
+ request,
127
+ 'your-webhook-id',
128
+ 'your-webhook-token'
129
+ );
130
+ ```
131
+
132
+ ### Utility Functions
133
+
134
+ #### `detectPlatformFromHeaders(headers: Headers): WebhookPlatform | null`
135
+
136
+ Automatically detect the platform from request headers.
137
+
138
+ ```typescript
139
+ import { detectPlatformFromHeaders } from 'tern';
140
+
141
+ const platform = detectPlatformFromHeaders(request.headers);
142
+ if (platform) {
143
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
144
+ request, platform, 'your-secret', 300
145
+ );
146
+ }
147
+ ```
148
+
149
+ #### `getPlatformsUsingAlgorithm(algorithm: string): WebhookPlatform[]`
150
+
151
+ Get all platforms that use a specific algorithm.
152
+
153
+ ```typescript
154
+ import { WebhookVerificationService } from 'tern';
155
+
156
+ const hmacPlatforms = WebhookVerificationService.getPlatformsUsingAlgorithm('hmac-sha256');
157
+ // Returns: ['github', 'stripe', 'clerk', 'dodopayments', ...]
158
+ ```
159
+
160
+ ## 🎯 Usage Examples
161
+
162
+ ### Express.js Integration
163
+
164
+ ```typescript
165
+ import express from 'express';
166
+ import { WebhookVerificationService } from 'tern';
167
+
168
+ const app = express();
169
+
170
+ app.post('/webhook', async (req, res) => {
171
+ try {
172
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
173
+ req,
174
+ 'github',
175
+ process.env.GITHUB_WEBHOOK_SECRET,
176
+ 300
177
+ );
178
+
179
+ if (result.isValid) {
180
+ // Process the webhook
181
+ console.log('Webhook received:', result.payload);
182
+ res.status(200).json({ success: true });
183
+ } else {
184
+ res.status(401).json({ error: result.error });
185
+ }
186
+ } catch (error) {
187
+ res.status(500).json({ error: 'Internal server error' });
188
+ }
189
+ });
190
+ ```
191
+
192
+ ### Next.js API Route
193
+
194
+ ```typescript
195
+ // pages/api/webhook.ts
196
+ import { NextApiRequest, NextApiResponse } from 'next';
197
+ import { WebhookVerificationService } from 'tern';
198
+
199
+ export default async function handler(req: NextApiRequest, res: NextApiResponse) {
200
+ if (req.method !== 'POST') {
201
+ return res.status(405).json({ error: 'Method not allowed' });
202
+ }
203
+
204
+ try {
205
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
206
+ req as any,
207
+ 'stripe',
208
+ process.env.STRIPE_WEBHOOK_SECRET,
209
+ 300
210
+ );
211
+
212
+ if (result.isValid) {
213
+ // Handle the webhook
214
+ console.log('Stripe webhook:', result.payload);
215
+ res.status(200).json({ received: true });
216
+ } else {
217
+ res.status(401).json({ error: result.error });
218
+ }
219
+ } catch (error) {
220
+ res.status(500).json({ error: 'Internal server error' });
221
+ }
222
+ }
223
+ ```
224
+
225
+ ### Platform Detection
226
+
227
+ ```typescript
228
+ import { detectPlatformFromHeaders, WebhookVerificationService } from 'tern';
229
+
230
+ async function handleWebhook(request: Request) {
231
+ const platform = detectPlatformFromHeaders(request.headers);
232
+
233
+ if (!platform) {
234
+ throw new Error('Unknown webhook platform');
235
+ }
236
+
237
+ const secret = getSecretForPlatform(platform); // Your secret management
238
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
239
+ request,
240
+ platform,
241
+ secret,
242
+ 300
243
+ );
244
+
245
+ return result;
246
+ }
247
+ ```
248
+
249
+ ### Custom Platform Integration
250
+
251
+ ```typescript
252
+ import { WebhookVerificationService } from 'tern';
253
+
254
+ const customConfig = {
255
+ platform: 'custom',
256
+ secret: 'your-custom-secret',
257
+ signatureConfig: {
258
+ algorithm: 'hmac-sha256',
259
+ headerName: 'x-custom-signature',
260
+ headerFormat: 'raw',
261
+ payloadFormat: 'raw'
262
+ }
263
+ };
264
+
265
+ const result = await WebhookVerificationService.verify(request, customConfig);
266
+ ```
267
+
268
+ ## 🔧 Adding New Platforms
269
+
270
+ ### Step 1: Add Platform Type
271
+
272
+ ```typescript
273
+ // In your project, extend the types
274
+ declare module 'tern' {
275
+ interface WebhookPlatform {
276
+ 'your-platform': 'your-platform';
277
+ }
278
+ }
279
+ ```
280
+
281
+ ### Step 2: Use Custom Configuration
282
+
283
+ ```typescript
284
+ const config = {
285
+ platform: 'custom',
286
+ secret: 'your-secret',
287
+ signatureConfig: {
288
+ algorithm: 'hmac-sha256', // or 'custom'
289
+ headerName: 'x-your-signature',
290
+ headerFormat: 'raw',
291
+ payloadFormat: 'raw'
292
+ }
293
+ };
294
+ ```
295
+
296
+ ## 📊 Platform Support Matrix
297
+
298
+ | Platform | Algorithm | Header | Format |
299
+ |----------|-----------|--------|--------|
300
+ | GitHub | HMAC-SHA256 | `x-hub-signature-256` | `sha256=...` |
301
+ | Stripe | HMAC-SHA256 | `stripe-signature` | `t=...,v1=...` |
302
+ | Clerk | Custom | `svix-signature` | Base64 |
303
+ | Supabase | Token-based | `x-webhook-token` | Simple |
304
+ | Shopify | HMAC-SHA256 | `x-shopify-hmac-sha256` | Raw |
305
+ | Vercel | HMAC-SHA256 | `x-vercel-signature` | Raw |
306
+ | Polar | HMAC-SHA256 | `x-polar-signature` | Raw |
307
+
308
+ ## 🔍 Error Handling
309
+
310
+ ```typescript
311
+ try {
312
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
313
+ request,
314
+ 'github',
315
+ 'your-secret',
316
+ 300
317
+ );
318
+
319
+ if (!result.isValid) {
320
+ console.error('Verification failed:', result.error);
321
+ return res.status(401).json({ error: result.error });
322
+ }
323
+
324
+ // Process webhook
325
+ console.log('Webhook verified:', result.payload);
326
+ } catch (error) {
327
+ console.error('Verification error:', error);
328
+ return res.status(500).json({ error: 'Internal server error' });
329
+ }
330
+ ```
331
+
332
+ ## 🧪 Testing
333
+
334
+ ```typescript
335
+ import { WebhookVerificationService } from 'tern';
336
+
337
+ // Create a mock request
338
+ const mockRequest = new Request('http://localhost/webhook', {
339
+ method: 'POST',
340
+ headers: {
341
+ 'x-hub-signature-256': 'sha256=abc123',
342
+ 'content-type': 'application/json'
343
+ },
344
+ body: JSON.stringify({ test: 'data' })
345
+ });
346
+
347
+ const result = await WebhookVerificationService.verifyWithPlatformConfig(
348
+ mockRequest,
349
+ 'github',
350
+ 'test-secret',
351
+ 300
352
+ );
353
+
354
+ console.log('Test result:', result);
355
+ ```
356
+
357
+ ## 📈 Performance
358
+
359
+ - **Zero dependencies**: Only uses Node.js built-in modules
360
+ - **Optimized algorithms**: Efficient HMAC verification
361
+ - **Timing-safe comparisons**: Prevents timing attacks
362
+ - **Minimal overhead**: Lightweight and fast
363
+
364
+ ## 🔒 Security Features
365
+
366
+ - **Timing-safe comparisons**: Prevents timing attacks
367
+ - **Proper validation**: Comprehensive input validation
368
+ - **Secure defaults**: Secure by default configuration
369
+ - **Algorithm flexibility**: Support for multiple signature algorithms
370
+
371
+ ## 🤝 Contributing
372
+
373
+ 1. Fork the repository
374
+ 2. Create a feature branch
375
+ 3. Make your changes
376
+ 4. Add tests
377
+ 5. Submit a pull request
378
+
379
+ ## 📄 License
380
+
381
+ MIT License - see LICENSE file for details.
382
+
383
+ ## 🆘 Support
384
+
385
+ - **Issues**: [GitHub Issues](https://github.com/yourusername/tern/issues)
386
+ - **Documentation**: [GitHub Wiki](https://github.com/yourusername/tern/wiki)
387
+ - **Discussions**: [GitHub Discussions](https://github.com/yourusername/tern/discussions)
388
+
389
+ ## 🚀 Roadmap
390
+
391
+ - [ ] RSA-SHA256 support
392
+ - [ ] Ed25519 support
393
+ - [ ] Performance optimizations
394
+ - [ ] More platform integrations
395
+ - [ ] Built-in rate limiting
396
+ - [ ] Monitoring and metrics
@@ -0,0 +1,28 @@
1
+ export declare function exampleBasicUsage(request: Request): Promise<import("./types").WebhookVerificationResult>;
2
+ export declare function exampleTokenBased(request: Request): Promise<import("./types").WebhookVerificationResult>;
3
+ export declare function exampleCustomSignature(request: Request): Promise<import("./types").WebhookVerificationResult>;
4
+ export declare function examplePlatformDetection(request: Request): Promise<import("./types").WebhookVerificationResult>;
5
+ export declare function exampleErrorHandling(request: Request): Promise<{
6
+ success: boolean;
7
+ error: string | undefined;
8
+ payload?: undefined;
9
+ } | {
10
+ success: boolean;
11
+ payload: any;
12
+ error?: undefined;
13
+ }>;
14
+ export declare function exampleBatchVerification(request: Request): Promise<({
15
+ platform: string;
16
+ success: boolean;
17
+ result: import("./types").WebhookVerificationResult;
18
+ error?: undefined;
19
+ } | {
20
+ platform: string;
21
+ success: boolean;
22
+ error: string;
23
+ result?: undefined;
24
+ })[]>;
25
+ export declare function exampleExpressIntegration(): any;
26
+ export declare function exampleNextJsApiRoute(): (req: any, res: any) => Promise<any>;
27
+ export declare function exampleCustomPlatform(request: Request): Promise<import("./types").WebhookVerificationResult>;
28
+ export declare function exampleHelperMethods(): void;
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exampleBasicUsage = exampleBasicUsage;
4
+ exports.exampleTokenBased = exampleTokenBased;
5
+ exports.exampleCustomSignature = exampleCustomSignature;
6
+ exports.examplePlatformDetection = examplePlatformDetection;
7
+ exports.exampleErrorHandling = exampleErrorHandling;
8
+ exports.exampleBatchVerification = exampleBatchVerification;
9
+ exports.exampleExpressIntegration = exampleExpressIntegration;
10
+ exports.exampleNextJsApiRoute = exampleNextJsApiRoute;
11
+ exports.exampleCustomPlatform = exampleCustomPlatform;
12
+ exports.exampleHelperMethods = exampleHelperMethods;
13
+ 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;
23
+ }
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',
32
+ };
33
+ const config = {
34
+ platform: 'custom',
35
+ secret: 'your-custom-secret',
36
+ signatureConfig,
37
+ };
38
+ const result = await index_1.WebhookVerificationService.verify(request, config);
39
+ return result;
40
+ }
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) {
53
+ 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 };
58
+ }
59
+ return { success: true, payload: result.payload };
60
+ }
61
+ catch (error) {
62
+ console.error('Verification error:', error);
63
+ return { success: false, error: error.message };
64
+ }
65
+ }
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 });
74
+ }
75
+ catch (error) {
76
+ results.push({ platform, success: false, error: error.message });
77
+ }
78
+ }
79
+ return results;
80
+ }
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
+ }
100
+ }
101
+ catch (error) {
102
+ res.status(500).json({ error: 'Internal server error' });
103
+ }
104
+ });
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
+ }
122
+ }
123
+ catch (error) {
124
+ res.status(500).json({ error: 'Internal server error' });
125
+ }
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;
142
+ }
143
+ // Example 10: Helper methods usage
144
+ function exampleHelperMethods() {
145
+ const { WebhookVerificationService } = require('./index');
146
+ // Get all platforms using HMAC-SHA256
147
+ const hmacPlatforms = WebhookVerificationService.getPlatformsUsingAlgorithm('hmac-sha256');
148
+ console.log('Platforms using HMAC-SHA256:', hmacPlatforms);
149
+ // 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 = {
154
+ algorithm: 'hmac-sha256',
155
+ headerName: 'x-signature',
156
+ payloadFormat: 'raw',
157
+ };
158
+ const isValid = WebhookVerificationService.validateSignatureConfig(config);
159
+ console.log('Config is valid:', isValid);
160
+ }
@@ -0,0 +1,17 @@
1
+ import { WebhookConfig, WebhookVerificationResult, WebhookPlatform, SignatureConfig } from './types';
2
+ export declare class WebhookVerificationService {
3
+ static verify(request: Request, config: WebhookConfig): Promise<WebhookVerificationResult>;
4
+ private static getVerifier;
5
+ private static createAlgorithmBasedVerifier;
6
+ private static getLegacyVerifier;
7
+ static verifyWithPlatformConfig(request: Request, platform: WebhookPlatform, secret: string, toleranceInSeconds?: number): Promise<WebhookVerificationResult>;
8
+ static getPlatformsUsingAlgorithm(algorithm: string): WebhookPlatform[];
9
+ static platformUsesAlgorithm(platform: WebhookPlatform, algorithm: string): boolean;
10
+ static validateSignatureConfig(config: SignatureConfig): boolean;
11
+ static verifyTokenBased(request: Request, webhookId: string, webhookToken: string): Promise<WebhookVerificationResult>;
12
+ }
13
+ export * from './types';
14
+ export { getPlatformAlgorithmConfig, platformUsesAlgorithm, getPlatformsUsingAlgorithm, validateSignatureConfig, } from './platforms/algorithms';
15
+ export { createAlgorithmVerifier } from './verifiers/algorithms';
16
+ export { createCustomVerifier } from './verifiers/custom-algorithms';
17
+ export default WebhookVerificationService;