@hookflo/tern 4.0.2 โ†’ 4.1.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/dist/test.js DELETED
@@ -1,668 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runTests = runTests;
4
- const crypto_1 = require("crypto");
5
- const index_1 = require("./index");
6
- const testSecret = 'whsec_test_secret_key_12345';
7
- const testBody = JSON.stringify({ event: 'test', data: { id: '123' } });
8
- function createMockRequest(headers, body = testBody) {
9
- return new Request('https://example.com/webhook', {
10
- method: 'POST',
11
- headers,
12
- body,
13
- });
14
- }
15
- function createStripeSignature(body, secret, timestamp) {
16
- const signedPayload = `${timestamp}.${body}`;
17
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
18
- hmac.update(signedPayload);
19
- const signature = hmac.digest('hex');
20
- return `t=${timestamp},v1=${signature}`;
21
- }
22
- function createGitHubSignature(body, secret) {
23
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
24
- hmac.update(body);
25
- return `sha256=${hmac.digest('hex')}`;
26
- }
27
- function createGitLabSignature(body, secret) {
28
- // GitLab just compares the token in X-Gitlab-Token header
29
- return secret;
30
- }
31
- function createClerkSignature(body, secret, id, timestamp) {
32
- const signedContent = `${id}.${timestamp}.${body}`;
33
- const secretBytes = new Uint8Array(Buffer.from(secret.split('_')[1], 'base64'));
34
- const hmac = (0, crypto_1.createHmac)('sha256', secretBytes);
35
- hmac.update(signedContent);
36
- return `v1,${hmac.digest('base64')}`;
37
- }
38
- function createStandardWebhooksSignature(body, secret, id, timestamp) {
39
- const signedContent = `${id}.${timestamp}.${body}`;
40
- const base64Secret = secret.includes('_') ? secret.split('_')[1] : secret;
41
- const secretBytes = new Uint8Array(Buffer.from(base64Secret, 'base64'));
42
- const hmac = (0, crypto_1.createHmac)('sha256', secretBytes);
43
- hmac.update(signedContent);
44
- return `v1,${hmac.digest('base64')}`;
45
- }
46
- function createPaddleSignature(body, secret, timestamp) {
47
- const signedPayload = `${timestamp}:${body}`;
48
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
49
- hmac.update(signedPayload);
50
- return `ts=${timestamp};h1=${hmac.digest('hex')}`;
51
- }
52
- function createShopifySignature(body, secret) {
53
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
54
- hmac.update(body);
55
- return hmac.digest('base64');
56
- }
57
- function createWooCommerceSignature(body, secret) {
58
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
59
- hmac.update(body);
60
- return hmac.digest('base64');
61
- }
62
- function createWorkOSSignature(body, secret, timestamp) {
63
- const signedPayload = `${timestamp}.${body}`;
64
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
65
- hmac.update(signedPayload);
66
- return `t=${timestamp},v1=${hmac.digest('hex')}`;
67
- }
68
- function createSentrySignature(body, secret) {
69
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
70
- hmac.update(JSON.stringify(JSON.parse(body)));
71
- return hmac.digest('hex');
72
- }
73
- function createSentryIssueAlertSignature(issueAlertObject, secret) {
74
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
75
- hmac.update(JSON.stringify(issueAlertObject));
76
- return hmac.digest('hex');
77
- }
78
- function createGrafanaSignature(body, secret, timestamp) {
79
- const payload = timestamp ? `${timestamp}.${body}` : body;
80
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
81
- hmac.update(payload);
82
- return hmac.digest('hex');
83
- }
84
- function createDopplerSignature(body, secret) {
85
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
86
- hmac.update(body);
87
- return `sha256=${hmac.digest('hex')}`;
88
- }
89
- function createSanitySignature(body, secret, timestamp) {
90
- const hmac = (0, crypto_1.createHmac)('sha256', secret);
91
- hmac.update(`${timestamp}.${body}`);
92
- return `t=${timestamp},v1=${hmac.digest('hex')}`;
93
- }
94
- function createFalPayloadToSign(body, requestId, userId, timestamp) {
95
- const bodyHash = (0, crypto_1.createHash)('sha256').update(body).digest('hex');
96
- return `${requestId}\n${userId}\n${timestamp}\n${bodyHash}`;
97
- }
98
- async function runTests() {
99
- console.log('๐Ÿงช Running Webhook Verification Tests...\n');
100
- // Test 1: Stripe Webhook
101
- console.log('1. Testing Stripe Webhook...');
102
- try {
103
- const timestamp = Math.floor(Date.now() / 1000);
104
- const stripeSignature = createStripeSignature(testBody, testSecret, timestamp);
105
- const stripeRequest = createMockRequest({
106
- 'stripe-signature': stripeSignature,
107
- 'content-type': 'application/json',
108
- });
109
- const stripeResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(stripeRequest, 'stripe', testSecret);
110
- const stripePassed = stripeResult.isValid && Boolean(stripeResult.eventId?.startsWith('stripe:'));
111
- console.log(' โœ… Stripe:', stripePassed ? 'PASSED' : 'FAILED');
112
- if (!stripeResult.isValid) {
113
- console.log(' โŒ Error:', stripeResult.error);
114
- }
115
- }
116
- catch (error) {
117
- console.log(' โŒ Stripe test failed:', error);
118
- }
119
- // Test 2: GitHub Webhook
120
- console.log('\n2. Testing GitHub Webhook...');
121
- try {
122
- const githubSignature = createGitHubSignature(testBody, testSecret);
123
- const githubRequest = createMockRequest({
124
- 'x-hub-signature-256': githubSignature,
125
- 'x-github-event': 'push',
126
- 'x-github-delivery': 'test-delivery-id',
127
- 'content-type': 'application/json',
128
- });
129
- const githubResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(githubRequest, 'github', testSecret);
130
- console.log(' โœ… GitHub:', githubResult.isValid ? 'PASSED' : 'FAILED');
131
- if (!githubResult.isValid) {
132
- console.log(' โŒ Error:', githubResult.error);
133
- }
134
- }
135
- catch (error) {
136
- console.log(' โŒ GitHub test failed:', error);
137
- }
138
- // Test 3: Clerk Webhook
139
- console.log('\n3. Testing Clerk Webhook...');
140
- try {
141
- // Create a proper Clerk-style secret (whsec_ + base64 encoded secret)
142
- const base64Secret = Buffer.from(testSecret).toString('base64');
143
- const clerkSecret = `whsec_${base64Secret}`;
144
- const id = 'test-id-123';
145
- const timestamp = Math.floor(Date.now() / 1000);
146
- const clerkSignature = createClerkSignature(testBody, clerkSecret, id, timestamp);
147
- const clerkRequest = createMockRequest({
148
- 'svix-signature': clerkSignature,
149
- 'svix-id': id,
150
- 'svix-timestamp': timestamp.toString(),
151
- 'content-type': 'application/json',
152
- });
153
- const clerkResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(clerkRequest, 'clerk', clerkSecret);
154
- console.log(' โœ… Clerk:', clerkResult.isValid ? 'PASSED' : 'FAILED');
155
- if (!clerkResult.isValid) {
156
- console.log(' โŒ Error:', clerkResult.error);
157
- }
158
- }
159
- catch (error) {
160
- console.log(' โŒ Clerk test failed:', error);
161
- }
162
- // Test 4: Standard HMAC-SHA256 (Generic)
163
- console.log('\n4. Testing Standard HMAC-SHA256...');
164
- try {
165
- const hmac = (0, crypto_1.createHmac)('sha256', testSecret);
166
- hmac.update(testBody);
167
- const signature = hmac.digest('hex');
168
- const genericRequest = createMockRequest({
169
- 'x-webhook-signature': signature,
170
- 'content-type': 'application/json',
171
- });
172
- const genericResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(genericRequest, 'unknown', testSecret);
173
- console.log(' โœ… Generic HMAC-SHA256:', genericResult.isValid ? 'PASSED' : 'FAILED');
174
- if (!genericResult.isValid) {
175
- console.log(' โŒ Error:', genericResult.error);
176
- }
177
- }
178
- catch (error) {
179
- console.log(' โŒ Generic test failed:', error);
180
- }
181
- // Test 4.5: Dodo Payments (Standard Webhooks / svix-style)
182
- console.log('\n4.5. Testing Dodo Payments...');
183
- try {
184
- const webhookId = 'test-webhook-id-123';
185
- const timestamp = Math.floor(Date.now() / 1000);
186
- // Create a proper secret format for Standard Webhooks (whsec_ + base64 encoded secret)
187
- const base64Secret = Buffer.from(testSecret).toString('base64');
188
- const dodoSecret = `whsec_${base64Secret}`;
189
- // Create svix-style signature: {webhook-id}.{webhook-timestamp}.{payload}
190
- const signedContent = `${webhookId}.${timestamp}.${testBody}`;
191
- // Use the base64-decoded secret for HMAC (like the Standard Webhooks library)
192
- const secretBytes = new Uint8Array(Buffer.from(base64Secret, 'base64'));
193
- const hmac = (0, crypto_1.createHmac)('sha256', secretBytes);
194
- hmac.update(signedContent);
195
- const signature = `v1,${hmac.digest('base64')}`;
196
- const dodoRequest = createMockRequest({
197
- 'webhook-signature': signature,
198
- 'webhook-id': webhookId,
199
- 'webhook-timestamp': timestamp.toString(),
200
- 'content-type': 'application/json',
201
- });
202
- const dodoResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(dodoRequest, 'dodopayments', dodoSecret);
203
- console.log(' โœ… Dodo Payments:', dodoResult.isValid ? 'PASSED' : 'FAILED');
204
- if (!dodoResult.isValid) {
205
- console.log(' โŒ Error:', dodoResult.error);
206
- }
207
- }
208
- catch (error) {
209
- console.log(' โŒ Dodo Payments test failed:', error);
210
- }
211
- // Test 5: Token-based authentication helper
212
- console.log('\n5. Testing Token-based Authentication...');
213
- try {
214
- const webhookId = 'test-webhook-id';
215
- const webhookToken = 'test-webhook-token';
216
- const tokenRequest = createMockRequest({
217
- 'x-webhook-id': webhookId,
218
- 'x-webhook-token': webhookToken,
219
- 'content-type': 'application/json',
220
- });
221
- const tokenResult = await index_1.WebhookVerificationService.verifyTokenAuth(tokenRequest.clone(), webhookId, webhookToken);
222
- const tokenAliasResult = await index_1.WebhookVerificationService.verifyTokenBased(tokenRequest.clone(), webhookId, webhookToken);
223
- const tokenPassed = tokenResult.isValid && tokenAliasResult.isValid;
224
- console.log(' โœ… Token-based:', tokenPassed ? 'PASSED' : 'FAILED');
225
- if (!tokenResult.isValid) {
226
- console.log(' โŒ Error:', tokenResult.error);
227
- }
228
- }
229
- catch (error) {
230
- console.log(' โŒ Token-based test failed:', error);
231
- }
232
- // Test 5.5: Sentry webhook verification (standard + issue alert fallback)
233
- console.log('\n5.5. Testing Sentry Webhook...');
234
- try {
235
- const timestamp = Math.floor(Date.now() / 1000);
236
- const requestId = 'sentry-request-id-123';
237
- const sentryBody = JSON.stringify({
238
- action: 'triggered',
239
- data: {
240
- issue_alert: {
241
- id: 'alert-1',
242
- title: 'CPU high',
243
- project: 'infra',
244
- },
245
- },
246
- });
247
- const sentryRequest = createMockRequest({
248
- 'sentry-hook-signature': createSentrySignature(sentryBody, testSecret),
249
- 'sentry-hook-timestamp': timestamp.toString(),
250
- 'request-id': requestId,
251
- 'content-type': 'application/json',
252
- }, sentryBody);
253
- const sentryResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(sentryRequest, 'sentry', testSecret);
254
- const sentryIssueAlertRequest = createMockRequest({
255
- 'sentry-hook-signature': createSentryIssueAlertSignature({ id: 'alert-1', title: 'CPU high', project: 'infra' }, testSecret),
256
- 'sentry-hook-timestamp': timestamp.toString(),
257
- 'request-id': `${requestId}-issue-alert`,
258
- 'content-type': 'application/json',
259
- }, sentryBody);
260
- const sentryIssueAlertResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(sentryIssueAlertRequest, 'sentry', testSecret);
261
- const sentryPassed = sentryResult.isValid && sentryIssueAlertResult.isValid && sentryResult.eventId?.startsWith('sentry:');
262
- console.log(' โœ… Sentry:', sentryPassed ? 'PASSED' : 'FAILED');
263
- }
264
- catch (error) {
265
- console.log(' โŒ Sentry test failed:', error);
266
- }
267
- // Test 5.6: Grafana webhook verification
268
- console.log('\n5.6. Testing Grafana Webhook...');
269
- try {
270
- const timestamp = Math.floor(Date.now() / 1000);
271
- const grafanaSignature = createGrafanaSignature(testBody, testSecret, timestamp);
272
- const grafanaRequest = createMockRequest({
273
- 'x-grafana-alerting-signature': grafanaSignature,
274
- 'x-grafana-alerting-timestamp': timestamp.toString(),
275
- 'content-type': 'application/json',
276
- });
277
- const grafanaResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(grafanaRequest, 'grafana', testSecret);
278
- console.log(' โœ… Grafana:', grafanaResult.isValid ? 'PASSED' : 'FAILED');
279
- }
280
- catch (error) {
281
- console.log(' โŒ Grafana test failed:', error);
282
- }
283
- // Test 5.7: Doppler webhook verification
284
- console.log('\n5.7. Testing Doppler Webhook...');
285
- try {
286
- const dopplerRequest = createMockRequest({
287
- 'x-doppler-signature': createDopplerSignature(testBody, testSecret),
288
- 'content-type': 'application/json',
289
- });
290
- const dopplerResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(dopplerRequest, 'doppler', testSecret);
291
- const dopplerPassed = dopplerResult.isValid && Boolean(dopplerResult.eventId?.startsWith('doppler:'));
292
- console.log(' โœ… Doppler:', dopplerPassed ? 'PASSED' : 'FAILED');
293
- }
294
- catch (error) {
295
- console.log(' โŒ Doppler test failed:', error);
296
- }
297
- // Test 5.8: Sanity webhook verification
298
- console.log('\n5.8. Testing Sanity Webhook...');
299
- try {
300
- const timestamp = Math.floor(Date.now() / 1000);
301
- const idempotencyKey = 'sanity-idem-123';
302
- const sanityRequest = createMockRequest({
303
- 'sanity-webhook-signature': createSanitySignature(testBody, testSecret, timestamp),
304
- 'idempotency-key': idempotencyKey,
305
- 'content-type': 'application/json',
306
- });
307
- const sanityResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(sanityRequest, 'sanity', testSecret);
308
- const sanityPassed = sanityResult.isValid && sanityResult.eventId === `sanity:${idempotencyKey}`;
309
- console.log(' โœ… Sanity:', sanityPassed ? 'PASSED' : 'FAILED');
310
- }
311
- catch (error) {
312
- console.log(' โŒ Sanity test failed:', error);
313
- }
314
- // Test 6: Invalid signatures
315
- console.log('\n6. Testing Invalid Signatures...');
316
- try {
317
- const invalidRequest = createMockRequest({
318
- 'stripe-signature': 't=1234567890,v1=invalid_signature',
319
- 'content-type': 'application/json',
320
- });
321
- const invalidResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(invalidRequest, 'stripe', testSecret);
322
- const invalidSigPassed = !invalidResult.isValid && (invalidResult.errorCode === 'INVALID_SIGNATURE'
323
- || invalidResult.errorCode === 'TIMESTAMP_EXPIRED');
324
- console.log(' โœ… Invalid signature correctly rejected:', invalidSigPassed ? 'PASSED' : 'FAILED');
325
- if (invalidResult.isValid) {
326
- console.log(' โŒ Should have been rejected');
327
- }
328
- }
329
- catch (error) {
330
- console.log(' โŒ Invalid signature test failed:', error);
331
- }
332
- // Test 7: Missing headers
333
- console.log('\n7. Testing Missing Headers...');
334
- try {
335
- const missingHeaderRequest = createMockRequest({
336
- 'content-type': 'application/json',
337
- });
338
- const missingHeaderResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(missingHeaderRequest, 'stripe', testSecret);
339
- const missingHeaderPassed = !missingHeaderResult.isValid && missingHeaderResult.errorCode === 'MISSING_SIGNATURE';
340
- console.log(' โœ… Missing headers correctly rejected:', missingHeaderPassed ? 'PASSED' : 'FAILED');
341
- if (missingHeaderResult.isValid) {
342
- console.log(' โŒ Should have been rejected');
343
- }
344
- }
345
- catch (error) {
346
- console.log(' โŒ Missing headers test failed:', error);
347
- }
348
- // Test 8: GitLab Webhook
349
- console.log('\n8. Testing GitLab Webhook...');
350
- try {
351
- const gitlabSecret = testSecret;
352
- const gitlabRequest = createMockRequest({
353
- 'X-Gitlab-Token': gitlabSecret,
354
- 'content-type': 'application/json',
355
- });
356
- const gitlabResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(gitlabRequest, 'gitlab', gitlabSecret);
357
- console.log(' โœ… GitLab:', gitlabResult.isValid ? 'PASSED' : 'FAILED');
358
- if (!gitlabResult.isValid) {
359
- console.log(' โŒ Error:', gitlabResult.error);
360
- }
361
- }
362
- catch (error) {
363
- console.log(' โŒ GitLab test failed:', error);
364
- }
365
- // Test 9: GitLab Invalid Token
366
- console.log('\n9. Testing GitLab Invalid Token...');
367
- try {
368
- const gitlabRequest = createMockRequest({
369
- 'X-Gitlab-Token': 'wrong_secret',
370
- 'content-type': 'application/json',
371
- });
372
- const gitlabResult = await index_1.WebhookVerificationService.verifyWithPlatformConfig(gitlabRequest, 'gitlab', testSecret);
373
- console.log(' โœ… Invalid token correctly rejected:', !gitlabResult.isValid ? 'PASSED' : 'FAILED');
374
- }
375
- catch (error) {
376
- console.log(' โŒ GitLab invalid token test failed:', error);
377
- }
378
- // Test 10: verifyAny should auto-detect Stripe
379
- console.log('\n10. Testing verifyAny auto-detection...');
380
- try {
381
- const timestamp = Math.floor(Date.now() / 1000);
382
- const stripeSignature = createStripeSignature(testBody, testSecret, timestamp);
383
- const request = createMockRequest({
384
- 'stripe-signature': stripeSignature,
385
- 'content-type': 'application/json',
386
- });
387
- const result = await index_1.WebhookVerificationService.verifyAny(request, {
388
- stripe: testSecret,
389
- github: 'wrong-secret',
390
- });
391
- console.log(' โœ… verifyAny:', result.isValid && result.platform === 'stripe' ? 'PASSED' : 'FAILED');
392
- }
393
- catch (error) {
394
- console.log(' โŒ verifyAny test failed:', error);
395
- }
396
- // Test 10.5: verifyAny error diagnostics
397
- console.log('\n10.5. Testing verifyAny error diagnostics...');
398
- try {
399
- const unknownRequest = createMockRequest({
400
- 'content-type': 'application/json',
401
- });
402
- const invalidVerifyAny = await index_1.WebhookVerificationService.verifyAny(unknownRequest, {
403
- stripe: testSecret,
404
- shopify: testSecret,
405
- });
406
- const hasDetailedErrors = Boolean(invalidVerifyAny.error
407
- && invalidVerifyAny.error.includes('Attempts ->')
408
- && invalidVerifyAny.metadata?.attempts?.length === 2);
409
- console.log(' โœ… verifyAny diagnostics:', hasDetailedErrors ? 'PASSED' : 'FAILED');
410
- }
411
- catch (error) {
412
- console.log(' โŒ verifyAny diagnostics test failed:', error);
413
- }
414
- // Test 11: Normalization for Stripe
415
- console.log('\n11. Testing payload normalization...');
416
- try {
417
- const normalizedStripeBody = JSON.stringify({
418
- type: 'payment_intent.succeeded',
419
- data: {
420
- object: {
421
- id: 'pi_123',
422
- amount: 5000,
423
- currency: 'usd',
424
- customer: 'cus_456',
425
- },
426
- },
427
- });
428
- const timestamp = Math.floor(Date.now() / 1000);
429
- const stripeSignature = createStripeSignature(normalizedStripeBody, testSecret, timestamp);
430
- const request = createMockRequest({
431
- 'stripe-signature': stripeSignature,
432
- 'content-type': 'application/json',
433
- }, normalizedStripeBody);
434
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'stripe', testSecret, 300, true);
435
- const payload = result.payload;
436
- const passed = result.isValid
437
- && payload.event === 'payment.succeeded'
438
- && payload.currency === 'USD'
439
- && payload.transaction_id === 'pi_123';
440
- console.log(' โœ… Normalization:', passed ? 'PASSED' : 'FAILED');
441
- }
442
- catch (error) {
443
- console.log(' โŒ Normalization test failed:', error);
444
- }
445
- // Test 12: Category-aware normalization registry
446
- console.log('\n12. Testing category-based platform registry...');
447
- try {
448
- const paymentPlatforms = (0, index_1.getPlatformsByCategory)('payment');
449
- const hasStripeAndPolar = paymentPlatforms.includes('stripe') && paymentPlatforms.includes('polar');
450
- console.log(' โœ… Category registry:', hasStripeAndPolar ? 'PASSED' : 'FAILED');
451
- }
452
- catch (error) {
453
- console.log(' โŒ Category registry test failed:', error);
454
- }
455
- // Test 13: Razorpay
456
- console.log('\n13. Testing Razorpay webhook...');
457
- try {
458
- const hmac = (0, crypto_1.createHmac)('sha256', testSecret);
459
- hmac.update(testBody);
460
- const signature = hmac.digest('hex');
461
- const request = createMockRequest({
462
- 'x-razorpay-signature': signature,
463
- 'content-type': 'application/json',
464
- });
465
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'razorpay', testSecret);
466
- console.log(' โœ… Razorpay:', result.isValid ? 'PASSED' : 'FAILED');
467
- }
468
- catch (error) {
469
- console.log(' โŒ Razorpay test failed:', error);
470
- }
471
- // Test 14: Lemon Squeezy
472
- console.log('\n14. Testing Lemon Squeezy webhook...');
473
- try {
474
- const hmac = (0, crypto_1.createHmac)('sha256', testSecret);
475
- hmac.update(testBody);
476
- const signature = hmac.digest('hex');
477
- const request = createMockRequest({
478
- 'x-signature': signature,
479
- 'content-type': 'application/json',
480
- });
481
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'lemonsqueezy', testSecret);
482
- console.log(' โœ… Lemon Squeezy:', result.isValid ? 'PASSED' : 'FAILED');
483
- }
484
- catch (error) {
485
- console.log(' โŒ Lemon Squeezy test failed:', error);
486
- }
487
- // Test 15: Paddle
488
- console.log('\n15. Testing Paddle webhook...');
489
- try {
490
- const timestamp = Math.floor(Date.now() / 1000);
491
- const signature = createPaddleSignature(testBody, testSecret, timestamp);
492
- const request = createMockRequest({
493
- 'paddle-signature': signature,
494
- 'content-type': 'application/json',
495
- });
496
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'paddle', testSecret);
497
- console.log(' โœ… Paddle:', result.isValid ? 'PASSED' : 'FAILED');
498
- }
499
- catch (error) {
500
- console.log(' โŒ Paddle test failed:', error);
501
- }
502
- // Test 16: WorkOS
503
- console.log('\n16. Testing WorkOS webhook...');
504
- try {
505
- const timestamp = Math.floor(Date.now() / 1000);
506
- const signature = createWorkOSSignature(testBody, testSecret, timestamp);
507
- const request = createMockRequest({
508
- 'workos-signature': signature,
509
- 'content-type': 'application/json',
510
- });
511
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'workos', testSecret);
512
- console.log(' โœ… WorkOS:', result.isValid ? 'PASSED' : 'FAILED');
513
- }
514
- catch (error) {
515
- console.log(' โŒ WorkOS test failed:', error);
516
- }
517
- // Test 17.5: Shopify
518
- console.log('\n17. Testing Shopify webhook...');
519
- try {
520
- const signature = createShopifySignature(testBody, testSecret);
521
- const request = createMockRequest({
522
- 'x-shopify-hmac-sha256': signature,
523
- 'content-type': 'application/json',
524
- });
525
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'shopify', testSecret);
526
- console.log(' โœ… Shopify:', result.isValid ? 'PASSED' : 'FAILED');
527
- if (!result.isValid) {
528
- console.log(' โŒ Error:', result.error);
529
- }
530
- }
531
- catch (error) {
532
- console.log(' โŒ Shopify test failed:', error);
533
- }
534
- // Test 18: WooCommerce
535
- console.log('\n18. Testing WooCommerce webhook...');
536
- try {
537
- const signature = createWooCommerceSignature(testBody, testSecret);
538
- const request = createMockRequest({
539
- 'x-wc-webhook-signature': signature,
540
- 'content-type': 'application/json',
541
- });
542
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'woocommerce', testSecret);
543
- console.log(' โœ… WooCommerce:', result.isValid ? 'PASSED' : 'FAILED');
544
- }
545
- catch (error) {
546
- console.log(' โŒ WooCommerce test failed:', error);
547
- }
548
- // Test 18.5: Polar (Standard Webhooks)
549
- console.log('\n18.5. Testing Polar webhook...');
550
- try {
551
- const secret = `whsec_${Buffer.from(testSecret).toString('base64')}`;
552
- const webhookId = 'polar-webhook-id-1';
553
- const timestamp = Math.floor(Date.now() / 1000);
554
- const signature = createStandardWebhooksSignature(testBody, secret, webhookId, timestamp);
555
- const request = createMockRequest({
556
- 'webhook-signature': signature,
557
- 'webhook-id': webhookId,
558
- 'webhook-timestamp': timestamp.toString(),
559
- 'user-agent': 'Polar.sh Webhooks',
560
- 'content-type': 'application/json',
561
- });
562
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'polar', secret);
563
- const detectedPlatform = index_1.WebhookVerificationService.detectPlatform(request);
564
- console.log(' โœ… Polar verification:', result.isValid ? 'PASSED' : 'FAILED');
565
- console.log(' โœ… Polar auto-detect:', detectedPlatform === 'polar' ? 'PASSED' : 'FAILED');
566
- }
567
- catch (error) {
568
- console.log(' โŒ Polar test failed:', error);
569
- }
570
- // Test 19: Replicate
571
- console.log('\n19. Testing Replicate webhook...');
572
- try {
573
- const secret = `whsec_${Buffer.from(testSecret).toString('base64')}`;
574
- const webhookId = 'replicate-webhook-id-1';
575
- const timestamp = Math.floor(Date.now() / 1000);
576
- const signature = createStandardWebhooksSignature(testBody, secret, webhookId, timestamp);
577
- const request = createMockRequest({
578
- 'webhook-signature': signature,
579
- 'webhook-id': webhookId,
580
- 'webhook-timestamp': timestamp.toString(),
581
- 'user-agent': 'Replicate-Webhooks/1.0',
582
- 'content-type': 'application/json',
583
- });
584
- const result = await index_1.WebhookVerificationService.verifyWithPlatformConfig(request, 'replicateai', secret);
585
- console.log(' โœ… Replicate:', result.isValid ? 'PASSED' : 'FAILED');
586
- }
587
- catch (error) {
588
- console.log(' โŒ Replicate test failed:', error);
589
- }
590
- // Test 20: fal.ai
591
- console.log('\n20. Testing fal.ai webhook...');
592
- try {
593
- const { privateKey, publicKey } = (0, crypto_1.generateKeyPairSync)('ed25519');
594
- const requestId = 'fal-request-id';
595
- const userId = 'fal-user-id';
596
- const timestamp = Math.floor(Date.now() / 1000).toString();
597
- const payloadToSign = createFalPayloadToSign(testBody, requestId, userId, timestamp);
598
- const payloadBytes = new Uint8Array(Buffer.from(payloadToSign));
599
- const signature = (0, crypto_1.sign)(null, payloadBytes, privateKey).toString('hex');
600
- const request = createMockRequest({
601
- 'x-fal-webhook-signature': signature,
602
- 'x-fal-webhook-request-id': requestId,
603
- 'x-fal-webhook-user-id': userId,
604
- 'x-fal-webhook-timestamp': timestamp,
605
- 'content-type': 'application/json',
606
- });
607
- const result = await index_1.WebhookVerificationService.verify(request, {
608
- platform: 'falai',
609
- secret: '',
610
- signatureConfig: {
611
- algorithm: 'ed25519',
612
- headerName: 'x-fal-webhook-signature',
613
- headerFormat: 'raw',
614
- payloadFormat: 'custom',
615
- customConfig: {
616
- publicKey: publicKey.export({ type: 'spki', format: 'pem' }).toString(),
617
- requestIdHeader: 'x-fal-webhook-request-id',
618
- userIdHeader: 'x-fal-webhook-user-id',
619
- timestampHeader: 'x-fal-webhook-timestamp',
620
- },
621
- },
622
- });
623
- console.log(' โœ… fal.ai:', result.isValid ? 'PASSED' : 'FAILED');
624
- }
625
- catch (error) {
626
- console.log(' โŒ fal.ai test failed:', error);
627
- }
628
- // Test 21: Core SDK queue entry point
629
- console.log('\n21. Testing core SDK handleWithQueue...');
630
- try {
631
- const request = createMockRequest({
632
- 'content-type': 'application/json',
633
- });
634
- const originalToken = process.env.QSTASH_TOKEN;
635
- const originalCurrent = process.env.QSTASH_CURRENT_SIGNING_KEY;
636
- const originalNext = process.env.QSTASH_NEXT_SIGNING_KEY;
637
- delete process.env.QSTASH_TOKEN;
638
- delete process.env.QSTASH_CURRENT_SIGNING_KEY;
639
- delete process.env.QSTASH_NEXT_SIGNING_KEY;
640
- let threw = false;
641
- try {
642
- await index_1.WebhookVerificationService.handleWithQueue(request, {
643
- platform: 'stripe',
644
- secret: testSecret,
645
- queue: true,
646
- handler: async () => undefined,
647
- });
648
- }
649
- catch (error) {
650
- threw = error.message.includes('queue: true requires QSTASH_TOKEN');
651
- }
652
- if (originalToken !== undefined)
653
- process.env.QSTASH_TOKEN = originalToken;
654
- if (originalCurrent !== undefined)
655
- process.env.QSTASH_CURRENT_SIGNING_KEY = originalCurrent;
656
- if (originalNext !== undefined)
657
- process.env.QSTASH_NEXT_SIGNING_KEY = originalNext;
658
- console.log(' โœ… handleWithQueue:', threw ? 'PASSED' : 'FAILED');
659
- }
660
- catch (error) {
661
- console.log(' โŒ handleWithQueue test failed:', error);
662
- }
663
- console.log('\n๐ŸŽ‰ All tests completed!');
664
- }
665
- // Run tests if this file is executed directly
666
- if (require.main === module) {
667
- runTests().catch(console.error);
668
- }