@zendfi/sdk 0.1.2 → 0.3.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/index.d.ts CHANGED
@@ -1,328 +1,9 @@
1
- /**
2
- * ZendFi SDK Types
3
- * Complete type definitions for the ZendFi API
4
- */
5
- type Environment = 'development' | 'staging' | 'production';
6
- type Currency = 'USD' | 'EUR' | 'GBP';
7
- type PaymentToken = 'SOL' | 'USDC' | 'USDT';
8
- type PaymentStatus = 'pending' | 'confirmed' | 'failed' | 'expired';
9
- type SubscriptionStatus = 'active' | 'canceled' | 'past_due' | 'paused';
10
- type InstallmentPlanStatus = 'active' | 'completed' | 'defaulted' | 'cancelled';
11
- type EscrowStatus = 'pending' | 'funded' | 'released' | 'refunded' | 'disputed' | 'cancelled';
12
- type InvoiceStatus = 'draft' | 'sent' | 'paid';
13
- type SplitStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'refunded';
14
- type WebhookEvent = 'payment.created' | 'payment.confirmed' | 'payment.failed' | 'payment.expired' | 'subscription.created' | 'subscription.activated' | 'subscription.canceled' | 'subscription.payment_failed' | 'split.completed' | 'split.failed' | 'installment.due' | 'installment.paid' | 'installment.late' | 'escrow.funded' | 'escrow.released' | 'escrow.refunded' | 'escrow.disputed' | 'invoice.sent' | 'invoice.paid';
15
- interface ZendFiConfig {
16
- apiKey?: string;
17
- baseURL?: string;
18
- environment?: Environment;
19
- timeout?: number;
20
- retries?: number;
21
- idempotencyEnabled?: boolean;
22
- }
23
- interface SplitRecipient {
24
- recipient_wallet: string;
25
- recipient_name?: string;
26
- percentage?: number;
27
- fixed_amount_usd?: number;
28
- split_order?: number;
29
- }
30
- interface CreatePaymentRequest {
31
- amount: number;
32
- currency?: Currency;
33
- token?: PaymentToken;
34
- description?: string;
35
- customer_email?: string;
36
- redirect_url?: string;
37
- metadata?: Record<string, any>;
38
- split_recipients?: SplitRecipient[];
39
- }
40
- /**
41
- * Payment Link - Shareable checkout links
42
- */
43
- interface CreatePaymentLinkRequest {
44
- amount: number;
45
- currency?: string;
46
- token?: string;
47
- description?: string;
48
- max_uses?: number;
49
- expires_at?: string;
50
- metadata?: Record<string, any>;
51
- }
52
- interface PaymentLink {
53
- id: string;
54
- link_code: string;
55
- payment_url: string;
56
- hosted_page_url: string;
57
- amount: number;
58
- currency: string;
59
- token: string;
60
- max_uses?: number;
61
- uses_count: number;
62
- expires_at?: string;
63
- is_active: boolean;
64
- created_at: string;
65
- url: string;
66
- }
67
- interface Payment {
68
- id: string;
69
- merchant_id: string;
70
- amount_usd?: number;
71
- amount?: number;
72
- currency?: string;
73
- payment_token?: PaymentToken;
74
- status: PaymentStatus;
75
- customer_wallet?: string;
76
- customer_email?: string;
77
- description?: string;
78
- checkout_url?: string;
79
- payment_url?: string;
80
- qr_code?: string;
81
- expires_at: string;
82
- confirmed_at?: string;
83
- transaction_signature?: string;
84
- metadata?: Record<string, any>;
85
- split_ids?: string[];
86
- created_at?: string;
87
- updated_at?: string;
88
- }
89
- interface ListPaymentsRequest {
90
- page?: number;
91
- limit?: number;
92
- status?: PaymentStatus;
93
- from_date?: string;
94
- to_date?: string;
95
- }
96
- interface PaginatedResponse<T> {
97
- data: T[];
98
- pagination: {
99
- page: number;
100
- limit: number;
101
- total: number;
102
- total_pages: number;
103
- };
104
- }
105
- interface CreateSubscriptionPlanRequest {
106
- name: string;
107
- description?: string;
108
- amount: number;
109
- currency?: Currency;
110
- interval: 'daily' | 'weekly' | 'monthly' | 'yearly';
111
- interval_count?: number;
112
- trial_days?: number;
113
- metadata?: Record<string, any>;
114
- }
115
- interface SubscriptionPlan {
116
- id: string;
117
- merchant_id: string;
118
- name: string;
119
- description?: string;
120
- amount: number;
121
- currency: Currency;
122
- interval: string;
123
- interval_count: number;
124
- trial_days: number;
125
- is_active: boolean;
126
- metadata?: Record<string, any>;
127
- created_at: string;
128
- updated_at: string;
129
- }
130
- interface CreateSubscriptionRequest {
131
- plan_id: string;
132
- customer_email: string;
133
- customer_wallet?: string;
134
- metadata?: Record<string, any>;
135
- }
136
- interface Subscription {
137
- id: string;
138
- plan_id: string;
139
- merchant_id: string;
140
- customer_email: string;
141
- customer_wallet?: string;
142
- status: SubscriptionStatus;
143
- current_period_start: string;
144
- current_period_end: string;
145
- trial_end?: string;
146
- canceled_at?: string;
147
- metadata?: Record<string, any>;
148
- created_at: string;
149
- updated_at: string;
150
- }
151
- interface WebhookPayload {
152
- event: WebhookEvent;
153
- timestamp: string;
154
- merchant_id: string;
155
- data: Payment | Subscription;
156
- }
157
- interface VerifyWebhookRequest {
158
- payload: string | object;
159
- signature: string;
160
- secret: string;
161
- }
162
- declare class ZendFiError extends Error {
163
- statusCode?: number | undefined;
164
- code?: string | undefined;
165
- details?: any | undefined;
166
- constructor(message: string, statusCode?: number | undefined, code?: string | undefined, details?: any | undefined);
167
- }
168
- declare class AuthenticationError extends ZendFiError {
169
- constructor(message?: string);
170
- }
171
- declare class ValidationError extends ZendFiError {
172
- constructor(message: string, details?: any);
173
- }
174
- declare class NetworkError extends ZendFiError {
175
- constructor(message: string);
176
- }
177
- declare class RateLimitError extends ZendFiError {
178
- constructor(message?: string);
179
- }
180
- /**
181
- * Installment Plans - Pay over time
182
- */
183
- interface InstallmentScheduleItem {
184
- installment_number: number;
185
- due_date: string;
186
- amount: string;
187
- status: string;
188
- payment_id?: string;
189
- paid_at?: string;
190
- }
191
- interface CreateInstallmentPlanRequest {
192
- customer_wallet: string;
193
- customer_email?: string;
194
- total_amount: number;
195
- installment_count: number;
196
- first_payment_date?: string;
197
- payment_frequency_days: number;
198
- description?: string;
199
- late_fee_amount?: number;
200
- grace_period_days?: number;
201
- metadata?: Record<string, any>;
202
- }
203
- interface CreateInstallmentPlanResponse {
204
- plan_id: string;
205
- status: string;
206
- }
207
- interface InstallmentPlan {
208
- id?: string;
209
- plan_id?: string;
210
- merchant_id?: string;
211
- customer_wallet?: string;
212
- customer_email?: string;
213
- total_amount?: string;
214
- installment_count?: number;
215
- amount_per_installment?: string;
216
- payment_schedule?: InstallmentScheduleItem[];
217
- paid_count?: number;
218
- status: InstallmentPlanStatus | string;
219
- description?: string;
220
- late_fee_amount?: string;
221
- grace_period_days?: number;
222
- metadata?: Record<string, any>;
223
- created_at?: string;
224
- updated_at?: string;
225
- completed_at?: string;
226
- defaulted_at?: string;
227
- }
228
- /**
229
- * Escrow - Secure fund holding
230
- */
231
- interface ReleaseCondition {
232
- type: 'manual_approval' | 'time_based' | 'confirmation_required' | 'milestone';
233
- approver?: string;
234
- approved?: boolean;
235
- release_after?: string;
236
- confirmations_needed?: number;
237
- confirmed_by?: string[];
238
- description?: string;
239
- approved_by?: string;
240
- }
241
- interface CreateEscrowRequest {
242
- buyer_wallet: string;
243
- seller_wallet: string;
244
- amount: number;
245
- currency?: Currency;
246
- token?: PaymentToken;
247
- description?: string;
248
- release_conditions: ReleaseCondition;
249
- metadata?: Record<string, any>;
250
- }
251
- interface Escrow {
252
- id: string;
253
- payment_id: string;
254
- merchant_id: string;
255
- buyer_wallet: string;
256
- seller_wallet: string;
257
- escrow_wallet: string;
258
- amount: number;
259
- currency: Currency;
260
- token: PaymentToken;
261
- release_conditions: ReleaseCondition;
262
- status: EscrowStatus;
263
- payment_url?: string;
264
- qr_code?: string;
265
- funded_at?: string;
266
- released_at?: string;
267
- refunded_at?: string;
268
- disputed_at?: string;
269
- dispute_reason?: string;
270
- release_transaction_signature?: string;
271
- refund_transaction_signature?: string;
272
- metadata?: Record<string, any>;
273
- created_at: string;
274
- updated_at: string;
275
- }
276
- interface ApproveEscrowRequest {
277
- approver_wallet: string;
278
- }
279
- interface RefundEscrowRequest {
280
- reason: string;
281
- }
282
- interface DisputeEscrowRequest {
283
- reason: string;
284
- }
285
- /**
286
- * Invoices - Professional billing
287
- */
288
- interface InvoiceLineItem {
289
- description: string;
290
- quantity: number;
291
- unit_price: number;
292
- }
293
- interface CreateInvoiceRequest {
294
- customer_email: string;
295
- customer_name?: string;
296
- amount: number;
297
- token?: PaymentToken;
298
- description: string;
299
- line_items?: InvoiceLineItem[];
300
- due_date?: string;
301
- metadata?: Record<string, any>;
302
- }
303
- interface Invoice {
304
- id: string;
305
- invoice_number: string;
306
- merchant_id: string;
307
- customer_email: string;
308
- customer_name?: string;
309
- amount_usd: number;
310
- token: PaymentToken;
311
- description: string;
312
- line_items?: InvoiceLineItem[];
313
- status: InvoiceStatus;
314
- payment_url?: string;
315
- due_date?: string;
316
- sent_at?: string;
317
- paid_at?: string;
318
- metadata?: Record<string, any>;
319
- created_at: string;
320
- updated_at: string;
321
- }
1
+ import { Z as ZendFiConfig, C as CreatePaymentRequest, P as Payment, L as ListPaymentsRequest, b as PaginatedResponse, c as CreateSubscriptionPlanRequest, S as SubscriptionPlan, d as CreateSubscriptionRequest, e as Subscription, f as CreatePaymentLinkRequest, g as PaymentLink, h as CreateInstallmentPlanRequest, I as InstallmentPlan, i as CreateEscrowRequest, E as Escrow, A as ApproveEscrowRequest, R as RefundEscrowRequest, D as DisputeEscrowRequest, j as CreateInvoiceRequest, k as Invoice, V as VerifyWebhookRequest, l as WebhookPayload } from './webhook-handler-DG-zic8m.js';
2
+ export { q as ApiKeyMode, G as AuthenticationError, M as CreateInstallmentPlanResponse, r as Currency, o as Environment, w as EscrowStatus, v as InstallmentPlanStatus, K as InstallmentScheduleItem, Q as InvoiceLineItem, x as InvoiceStatus, N as NetworkError, t as PaymentStatus, s as PaymentToken, J as RateLimitError, O as ReleaseCondition, B as SplitRecipient, y as SplitStatus, u as SubscriptionStatus, H as ValidationError, z as WebhookEvent, n as WebhookEventHandler, W as WebhookHandlerConfig, a as WebhookHandlers, m as WebhookResult, F as ZendFiError, p as processWebhook } from './webhook-handler-DG-zic8m.js';
322
3
 
323
4
  /**
324
- * ZendFi SDK Client
325
- * Zero-config TypeScript SDK for crypto payments
5
+ * ZendFi SDK Client.
6
+ * AZero-config TypeScript SDK for crypto payments
326
7
  */
327
8
  declare class ZendFiClient {
328
9
  private config;
@@ -368,7 +49,7 @@ declare class ZendFiClient {
368
49
  */
369
50
  getPaymentLink(linkCode: string): Promise<PaymentLink>;
370
51
  /**
371
- * List all payment links
52
+ * List all payment links for the authenticated merchant
372
53
  */
373
54
  listPaymentLinks(): Promise<PaymentLink[]>;
374
55
  /**
@@ -515,6 +196,10 @@ declare class ConfigLoader {
515
196
  * Load configuration from various sources
516
197
  */
517
198
  static load(options?: Partial<ZendFiConfig>): Required<ZendFiConfig>;
199
+ /**
200
+ * Detect mode (test/live) from API key prefix
201
+ */
202
+ private static detectMode;
518
203
  /**
519
204
  * Detect environment based on various signals
520
205
  */
@@ -525,6 +210,8 @@ declare class ConfigLoader {
525
210
  private static loadApiKey;
526
211
  /**
527
212
  * Get base URL for API
213
+ * Note: Both test and live modes use the same API endpoint.
214
+ * The backend routes requests to devnet or mainnet based on API key prefix.
528
215
  */
529
216
  private static getBaseURL;
530
217
  /**
@@ -608,64 +295,4 @@ declare function verifyExpressWebhook(request: any, secret?: string): Promise<We
608
295
  */
609
296
  declare function verifyWebhookSignature(payload: string, signature: string, secret: string): boolean;
610
297
 
611
- /**
612
- * ZendFi Webhook Handlers
613
- * Type-safe webhook handlers with automatic verification and deduplication
614
- */
615
-
616
- /**
617
- * Webhook handler configuration
618
- */
619
- interface WebhookHandlerConfig {
620
- /** Your webhook secret from ZendFi dashboard */
621
- secret: string;
622
- /** Optional: Path to store processed webhook IDs (for deduplication) */
623
- onProcessed?: (webhookId: string) => Promise<void>;
624
- /** Optional: Check if webhook was already processed */
625
- isProcessed?: (webhookId: string) => Promise<boolean>;
626
- /** Optional: Custom error handler */
627
- onError?: (error: Error, event?: WebhookEvent) => void | Promise<void>;
628
- }
629
- /**
630
- * Event handler function type
631
- */
632
- type WebhookEventHandler<T = any> = (data: T, event: WebhookPayload) => void | Promise<void>;
633
- /**
634
- * Webhook handlers map - type-safe event handlers
635
- */
636
- type WebhookHandlers = Partial<{
637
- 'payment.created': WebhookEventHandler;
638
- 'payment.confirmed': WebhookEventHandler;
639
- 'payment.failed': WebhookEventHandler;
640
- 'payment.expired': WebhookEventHandler;
641
- 'subscription.created': WebhookEventHandler;
642
- 'subscription.activated': WebhookEventHandler;
643
- 'subscription.canceled': WebhookEventHandler;
644
- 'subscription.payment_failed': WebhookEventHandler;
645
- 'split.completed': WebhookEventHandler;
646
- 'split.failed': WebhookEventHandler;
647
- 'installment.due': WebhookEventHandler;
648
- 'installment.paid': WebhookEventHandler;
649
- 'installment.late': WebhookEventHandler;
650
- 'escrow.funded': WebhookEventHandler;
651
- 'escrow.released': WebhookEventHandler;
652
- 'escrow.refunded': WebhookEventHandler;
653
- 'escrow.disputed': WebhookEventHandler;
654
- 'invoice.sent': WebhookEventHandler;
655
- 'invoice.paid': WebhookEventHandler;
656
- }>;
657
- /**
658
- * Webhook processing result
659
- */
660
- interface WebhookResult {
661
- success: boolean;
662
- processed: boolean;
663
- error?: string;
664
- event?: WebhookEvent;
665
- }
666
- /**
667
- * Process webhook with handlers
668
- */
669
- declare function processWebhook(payload: WebhookPayload, handlers: WebhookHandlers, config: WebhookHandlerConfig): Promise<WebhookResult>;
670
-
671
- export { type ApproveEscrowRequest, AuthenticationError, ConfigLoader, type CreateEscrowRequest, type CreateInstallmentPlanRequest, type CreateInstallmentPlanResponse, type CreateInvoiceRequest, type CreatePaymentLinkRequest, type CreatePaymentRequest, type CreateSubscriptionPlanRequest, type CreateSubscriptionRequest, type Currency, type DisputeEscrowRequest, type Environment, type Escrow, type EscrowStatus, type InstallmentPlan, type InstallmentPlanStatus, type InstallmentScheduleItem, type Invoice, type InvoiceLineItem, type InvoiceStatus, type ListPaymentsRequest, NetworkError, type PaginatedResponse, type Payment, type PaymentLink, type PaymentStatus, type PaymentToken, RateLimitError, type RefundEscrowRequest, type ReleaseCondition, type SplitRecipient, type SplitStatus, type Subscription, type SubscriptionPlan, type SubscriptionStatus, ValidationError, type VerifyWebhookRequest, type WebhookEvent, type WebhookEventHandler, type WebhookHandlerConfig, type WebhookHandlers, type WebhookPayload, type WebhookResult, ZendFiClient, type ZendFiConfig, ZendFiError, processWebhook, verifyExpressWebhook, verifyNextWebhook, verifyWebhookSignature, zendfi };
298
+ export { ApproveEscrowRequest, ConfigLoader, CreateEscrowRequest, CreateInstallmentPlanRequest, CreateInvoiceRequest, CreatePaymentLinkRequest, CreatePaymentRequest, CreateSubscriptionPlanRequest, CreateSubscriptionRequest, DisputeEscrowRequest, Escrow, InstallmentPlan, Invoice, ListPaymentsRequest, PaginatedResponse, Payment, PaymentLink, RefundEscrowRequest, Subscription, SubscriptionPlan, VerifyWebhookRequest, WebhookPayload, ZendFiClient, ZendFiConfig, verifyExpressWebhook, verifyNextWebhook, verifyWebhookSignature, zendfi };
package/dist/index.js CHANGED
@@ -92,16 +92,30 @@ var ConfigLoader = class {
92
92
  static load(options) {
93
93
  const environment = this.detectEnvironment();
94
94
  const apiKey = this.loadApiKey(options?.apiKey);
95
- const baseURL = this.getBaseURL(environment, options?.baseURL);
95
+ const mode = this.detectMode(apiKey);
96
+ const baseURL = this.getBaseURL(environment, mode, options?.baseURL);
96
97
  return {
97
98
  apiKey,
98
99
  baseURL,
99
100
  environment,
101
+ mode,
100
102
  timeout: options?.timeout ?? 3e4,
101
103
  retries: options?.retries ?? 3,
102
104
  idempotencyEnabled: options?.idempotencyEnabled ?? true
103
105
  };
104
106
  }
107
+ /**
108
+ * Detect mode (test/live) from API key prefix
109
+ */
110
+ static detectMode(apiKey) {
111
+ if (apiKey.startsWith("zfi_test_")) {
112
+ return "test";
113
+ }
114
+ if (apiKey.startsWith("zfi_live_")) {
115
+ return "live";
116
+ }
117
+ return "live";
118
+ }
105
119
  /**
106
120
  * Detect environment based on various signals
107
121
  */
@@ -150,8 +164,10 @@ var ConfigLoader = class {
150
164
  }
151
165
  /**
152
166
  * Get base URL for API
167
+ * Note: Both test and live modes use the same API endpoint.
168
+ * The backend routes requests to devnet or mainnet based on API key prefix.
153
169
  */
154
- static getBaseURL(_environment, explicitURL) {
170
+ static getBaseURL(_environment, _mode, explicitURL) {
155
171
  if (explicitURL) return explicitURL;
156
172
  return process.env.ZENDFI_API_URL || "https://api.zendfi.tech";
157
173
  }
@@ -183,13 +199,17 @@ var ConfigLoader = class {
183
199
  'Invalid API key format. ZendFi API keys should start with "zfi_test_" or "zfi_live_"'
184
200
  );
185
201
  }
186
- if (apiKey.startsWith("zfi_live_")) {
187
- const env = this.detectEnvironment();
188
- if (env === "development") {
189
- console.warn(
190
- "\u26A0\uFE0F Warning: Using a live API key (zfi_live_) in development environment. This will create real transactions. Use a test key (zfi_test_) for development."
191
- );
192
- }
202
+ const mode = this.detectMode(apiKey);
203
+ const env = this.detectEnvironment();
204
+ if (mode === "live" && env === "development") {
205
+ console.warn(
206
+ "\u26A0\uFE0F Warning: Using a live API key (zfi_live_) in development environment. This will create real mainnet transactions. Use a test key (zfi_test_) for devnet testing."
207
+ );
208
+ }
209
+ if (mode === "test" && env === "production") {
210
+ console.warn(
211
+ "\u26A0\uFE0F Warning: Using a test API key (zfi_test_) in production environment. This will create devnet transactions only. Use a live key (zfi_live_) for mainnet."
212
+ );
193
213
  }
194
214
  }
195
215
  };
@@ -230,6 +250,11 @@ var ZendFiClient = class {
230
250
  constructor(options) {
231
251
  this.config = ConfigLoader.load(options);
232
252
  ConfigLoader.validateApiKey(this.config.apiKey);
253
+ if (this.config.environment === "development") {
254
+ console.log(
255
+ `\u2713 ZendFi SDK initialized in ${this.config.mode} mode (${this.config.mode === "test" ? "devnet" : "mainnet"})`
256
+ );
257
+ }
233
258
  }
234
259
  /**
235
260
  * Create a new payment
@@ -323,10 +348,14 @@ var ZendFiClient = class {
323
348
  };
324
349
  }
325
350
  /**
326
- * List all payment links
351
+ * List all payment links for the authenticated merchant
327
352
  */
328
353
  async listPaymentLinks() {
329
- return [];
354
+ const response = await this.request("GET", "/api/v1/payment-links");
355
+ return response.map((link) => ({
356
+ ...link,
357
+ url: link.hosted_page_url
358
+ }));
330
359
  }
331
360
  /**
332
361
  * Create an installment plan
@@ -677,6 +706,7 @@ function verifyWebhookSignature(payload, signature, secret) {
677
706
  }
678
707
 
679
708
  // src/webhook-handler.ts
709
+ var import_crypto2 = require("crypto");
680
710
  var processedWebhooks = /* @__PURE__ */ new Set();
681
711
  var defaultIsProcessed = async (webhookId) => {
682
712
  return processedWebhooks.has(webhookId);
@@ -694,16 +724,19 @@ var defaultOnProcessed = async (webhookId) => {
694
724
  function generateWebhookId(payload) {
695
725
  return `${payload.merchant_id}:${payload.event}:${payload.timestamp}`;
696
726
  }
697
- async function processWebhook(payload, handlers, config) {
727
+ async function processPayload(payload, handlers, config) {
698
728
  try {
699
729
  const webhookId = generateWebhookId(payload);
700
- const isProcessed = config.isProcessed || defaultIsProcessed;
701
- const onProcessed = config.onProcessed || defaultOnProcessed;
702
- if (await isProcessed(webhookId)) {
730
+ const isProcessed = config.isProcessed || config.checkDuplicate || defaultIsProcessed;
731
+ const onProcessed = config.onProcessed || config.markProcessed || defaultOnProcessed;
732
+ const dedupEnabled = !!(config.enableDeduplication || config.isProcessed || config.checkDuplicate);
733
+ if (dedupEnabled && await isProcessed(webhookId)) {
703
734
  return {
704
- success: true,
735
+ success: false,
705
736
  processed: false,
706
- event: payload.event
737
+ event: payload.event,
738
+ error: "Duplicate webhook",
739
+ statusCode: 409
707
740
  };
708
741
  }
709
742
  const handler = handlers[payload.event];
@@ -711,7 +744,8 @@ async function processWebhook(payload, handlers, config) {
711
744
  return {
712
745
  success: true,
713
746
  processed: false,
714
- event: payload.event
747
+ event: payload.event,
748
+ statusCode: 200
715
749
  };
716
750
  }
717
751
  await handler(payload.data, payload);
@@ -723,14 +757,91 @@ async function processWebhook(payload, handlers, config) {
723
757
  };
724
758
  } catch (error) {
725
759
  const err = error;
726
- if (config.onError) {
727
- await config.onError(err, payload?.event);
760
+ if (config?.onError) {
761
+ await config.onError(err, error?.event);
762
+ }
763
+ return {
764
+ success: false,
765
+ processed: false,
766
+ error: err.message,
767
+ event: error?.event,
768
+ statusCode: 500
769
+ };
770
+ }
771
+ }
772
+ async function processWebhook(a, b, c) {
773
+ if (a && typeof a === "object" && a.event && b && c) {
774
+ return processPayload(a, b, c);
775
+ }
776
+ const opts = a;
777
+ if (!opts || !opts.signature && !opts.body && !opts.handlers) {
778
+ return {
779
+ success: false,
780
+ processed: false,
781
+ error: "Invalid arguments to processWebhook",
782
+ statusCode: 400
783
+ };
784
+ }
785
+ const signature = opts.signature;
786
+ const body = opts.body;
787
+ const handlers = opts.handlers || {};
788
+ const cfg = opts.config || {};
789
+ const secret = cfg.webhookSecret || cfg.secret;
790
+ if (!secret) {
791
+ return {
792
+ success: false,
793
+ processed: false,
794
+ error: "Webhook secret not provided",
795
+ statusCode: 400
796
+ };
797
+ }
798
+ if (!signature || !body) {
799
+ return {
800
+ success: false,
801
+ processed: false,
802
+ error: "Missing signature or body",
803
+ statusCode: 400
804
+ };
805
+ }
806
+ try {
807
+ const sig = typeof signature === "string" && signature.startsWith("sha256=") ? signature.slice("sha256=".length) : String(signature);
808
+ const hmac = (0, import_crypto2.createHmac)("sha256", secret).update(body, "utf8").digest("hex");
809
+ let ok = false;
810
+ try {
811
+ const sigBuf = Buffer.from(sig, "hex");
812
+ const hmacBuf = Buffer.from(hmac, "hex");
813
+ if (sigBuf.length === hmacBuf.length) {
814
+ ok = (0, import_crypto2.timingSafeEqual)(sigBuf, hmacBuf);
815
+ }
816
+ } catch (e) {
817
+ ok = (0, import_crypto2.timingSafeEqual)(Buffer.from(String(sig), "utf8"), Buffer.from(hmac, "utf8"));
728
818
  }
819
+ if (!ok) {
820
+ return {
821
+ success: false,
822
+ processed: false,
823
+ error: "Invalid signature",
824
+ statusCode: 401
825
+ };
826
+ }
827
+ const payload = JSON.parse(body);
828
+ const fullConfig = {
829
+ secret,
830
+ isProcessed: cfg.isProcessed,
831
+ onProcessed: cfg.onProcessed,
832
+ onError: cfg.onError,
833
+ // Forward compatibility for alternate names and flags
834
+ enableDeduplication: cfg.enableDeduplication,
835
+ checkDuplicate: cfg.checkDuplicate,
836
+ markProcessed: cfg.markProcessed
837
+ };
838
+ return await processPayload(payload, handlers, fullConfig);
839
+ } catch (err) {
729
840
  return {
730
841
  success: false,
731
842
  processed: false,
732
843
  error: err.message,
733
- event: payload?.event
844
+ statusCode: 500
734
845
  };
735
846
  }
736
847
  }