@boostengine/payments 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,150 +1,5 @@
1
- type GatewayName = 'razorpay' | 'cashfree' | 'phonepe' | 'paytm' | 'stripe' | 'cod';
2
- interface UnifiedCustomer {
3
- id?: string;
4
- name: string;
5
- email: string;
6
- phone: string;
7
- }
8
- interface UnifiedOrderItem {
9
- name: string;
10
- quantity: number;
11
- price: number;
12
- sku?: string;
13
- }
14
- interface UnifiedCreateOrderOptions {
15
- /** Amount in standard currency units (e.g. 1499.00 for INR, 25.00 for USD) */
16
- amount: number;
17
- /** 3-letter ISO currency code (e.g. 'INR', 'USD', 'EUR') */
18
- currency: string;
19
- /** Merchant order or receipt reference ID */
20
- receipt: string;
21
- /** Customer details */
22
- customer: UnifiedCustomer;
23
- /** Line items */
24
- items?: UnifiedOrderItem[];
25
- /** Merchant notes/metadata */
26
- notes?: Record<string, any>;
27
- /** Customer return/redirect URL after payment */
28
- redirectUrl?: string;
29
- /** Server-to-server webhook callback URL */
30
- callbackUrl?: string;
31
- /** Explicitly override gateway for this transaction */
32
- gateway?: GatewayName;
33
- }
34
- interface UnifiedOrderResult {
35
- gateway: GatewayName;
36
- orderId: string;
37
- gatewayOrderId: string;
38
- amount: number;
39
- currency: string;
40
- status: 'CREATED' | 'PENDING' | 'PAID' | 'FAILED';
41
- /** Cashfree payment_session_id for Drop-in UI or SDK */
42
- paymentSessionId?: string;
43
- /** Redirect or hosted pay URL (PhonePe, Stripe, Cashfree) */
44
- redirectUrl?: string;
45
- /** Paytm checkout txnToken */
46
- txnToken?: string;
47
- /** Raw response object from gateway */
48
- rawResponse: any;
49
- }
50
- interface UnifiedPaymentVerificationOptions {
51
- gateway: GatewayName;
52
- orderId: string;
53
- paymentId?: string;
54
- signature?: string;
55
- rawPayload?: any;
56
- }
57
- interface UnifiedPaymentVerificationResult {
58
- gateway: GatewayName;
59
- isSuccessful: boolean;
60
- paymentId: string;
61
- orderId: string;
62
- amount: number;
63
- currency: string;
64
- paymentMethod?: string;
65
- rawResponse: any;
66
- }
67
- interface UnifiedRefundOptions {
68
- gateway: GatewayName;
69
- paymentId: string;
70
- orderId?: string;
71
- /** Partial or full refund amount in currency units */
72
- amount?: number;
73
- reason?: string;
74
- }
75
- interface UnifiedRefundResult {
76
- gateway: GatewayName;
77
- refundId: string;
78
- paymentId: string;
79
- amount: number;
80
- status: 'SUCCESS' | 'PENDING' | 'FAILED';
81
- rawResponse: any;
82
- }
83
- interface WebhookVerificationOptions {
84
- gateway: GatewayName;
85
- rawBody: string | Buffer;
86
- headers: Record<string, string | string[] | undefined>;
87
- webhookSecret?: string;
88
- }
89
- interface WebhookVerificationResult {
90
- isValid: boolean;
91
- event?: string;
92
- gateway: GatewayName;
93
- data?: any;
94
- error?: string;
95
- }
96
- interface RazorpayConfig {
97
- keyId: string;
98
- keySecret: string;
99
- webhookSecret?: string;
100
- }
101
- interface CashfreeConfig {
102
- appId: string;
103
- secretKey: string;
104
- env?: 'SANDBOX' | 'PRODUCTION';
105
- apiVersion?: string;
106
- }
107
- interface PhonePeConfig {
108
- merchantId: string;
109
- saltKey: string;
110
- saltIndex?: string;
111
- env?: 'UAT' | 'PRODUCTION';
112
- }
113
- interface PaytmConfig {
114
- mid: string;
115
- merchantKey: string;
116
- website?: string;
117
- env?: 'STAGE' | 'PRODUCTION';
118
- }
119
- interface StripeConfig {
120
- secretKey: string;
121
- webhookSecret?: string;
122
- }
123
- interface CODConfig {
124
- minOrderValue?: number;
125
- maxOrderValue?: number;
126
- extraFee?: number;
127
- allowedPincodes?: string[];
128
- }
129
- interface GatewayConfigs {
130
- razorpay?: RazorpayConfig;
131
- cashfree?: CashfreeConfig;
132
- phonepe?: PhonePeConfig;
133
- paytm?: PaytmConfig;
134
- stripe?: StripeConfig;
135
- cod?: CODConfig;
136
- }
137
- interface SmartRoutingConfig {
138
- /** Map currency to default gateway, e.g. { 'USD': 'stripe', 'INR': 'cashfree' } */
139
- currencyMap?: Record<string, GatewayName>;
140
- /** Automatic fallback order if primary gateway fails, e.g. ['razorpay', 'cashfree', 'phonepe'] */
141
- fallbackChain?: GatewayName[];
142
- }
143
- interface PaymentManagerOptions {
144
- defaultGateway?: GatewayName;
145
- gateways: GatewayConfigs;
146
- smartRouting?: SmartRoutingConfig;
147
- }
1
+ import { G as GatewayName, U as UnifiedCreateOrderOptions, a as UnifiedOrderResult, b as UnifiedPaymentVerificationOptions, c as UnifiedPaymentVerificationResult, d as UnifiedRefundOptions, e as UnifiedRefundResult, W as WebhookVerificationOptions, f as WebhookVerificationResult, P as PaymentManagerOptions, R as RazorpayConfig, C as CashfreeConfig, g as PhonePeConfig, h as PaytmConfig, S as StripeConfig, i as CODConfig } from './types-D3bPaYhQ.js';
2
+ export { B as BoostPaymentOpenOptions, j as CreateOrderOptions, k as GatewayConfigs, N as NormalizedWebhookEvent, l as PaymentOrderResult, m as RefundResult, n as SmartRoutingConfig, o as SupportedGateway, p as UnifiedCustomer, q as UnifiedOrderItem, V as VerificationResult, r as WebhookResult } from './types-D3bPaYhQ.js';
148
3
 
149
4
  declare abstract class BasePaymentAdapter {
150
5
  abstract readonly name: GatewayName;
@@ -221,6 +76,23 @@ declare class PaymentManager {
221
76
  * Verifies incoming webhook authenticity and decodes payload.
222
77
  */
223
78
  verifyWebhook(options: WebhookVerificationOptions): Promise<WebhookVerificationResult>;
79
+ /**
80
+ * Ready-made Next.js 13/14/15 App Router Route Handler Webhook Authenticator.
81
+ * Directly consumes the standard web Request object with raw stream body handling:
82
+ *
83
+ * ```typescript
84
+ * export async function POST(req: Request) {
85
+ * const result = await payments.verifyNextJsWebhook(req, { gateway: 'razorpay' });
86
+ * if (!result.isValid) return new Response('Invalid Signature', { status: 400 });
87
+ * console.log('Event:', result.normalizedEvent, result.orderId);
88
+ * return new Response('OK');
89
+ * }
90
+ * ```
91
+ */
92
+ verifyNextJsWebhook(request: Request | any, options: {
93
+ gateway: GatewayName;
94
+ webhookSecret?: string;
95
+ }): Promise<WebhookVerificationResult>;
224
96
  }
225
97
  /**
226
98
  * Factory function to instantiate a PaymentManager.
@@ -336,4 +208,4 @@ declare class CODAdapter extends BasePaymentAdapter {
336
208
  verifyWebhook(_options: WebhookVerificationOptions): Promise<WebhookVerificationResult>;
337
209
  }
338
210
 
339
- export { BasePaymentAdapter, CODAdapter, type CODConfig, CashfreeAdapter, type CashfreeConfig, type GatewayConfigs, type GatewayName, GatewayNotConfiguredError, PaymentError, PaymentManager, type PaymentManagerOptions, PaytmAdapter, type PaytmConfig, PhonePeAdapter, type PhonePeConfig, RazorpayAdapter, type RazorpayConfig, SignatureVerificationError, type SmartRoutingConfig, StripeAdapter, type StripeConfig, type UnifiedCreateOrderOptions, type UnifiedCustomer, type UnifiedOrderItem, type UnifiedOrderResult, type UnifiedPaymentVerificationOptions, type UnifiedPaymentVerificationResult, type UnifiedRefundOptions, type UnifiedRefundResult, type WebhookVerificationOptions, type WebhookVerificationResult, base64Decode, base64Encode, createPaymentManager, hmacSha256, safeCompare, sha256 };
211
+ export { BasePaymentAdapter, CODAdapter, CODConfig, CashfreeAdapter, CashfreeConfig, GatewayName, GatewayNotConfiguredError, PaymentError, PaymentManager, PaymentManagerOptions, PaytmAdapter, PaytmConfig, PhonePeAdapter, PhonePeConfig, RazorpayAdapter, RazorpayConfig, SignatureVerificationError, StripeAdapter, StripeConfig, UnifiedCreateOrderOptions, UnifiedOrderResult, UnifiedPaymentVerificationOptions, UnifiedPaymentVerificationResult, UnifiedRefundOptions, UnifiedRefundResult, WebhookVerificationOptions, WebhookVerificationResult, base64Decode, base64Encode, createPaymentManager, hmacSha256, safeCompare, sha256 };
package/dist/index.mjs CHANGED
@@ -172,6 +172,7 @@ var RazorpayAdapter = class extends BasePaymentAdapter {
172
172
  paymentId: payment.id,
173
173
  orderId: options.orderId,
174
174
  amount: payment.amount / 100,
175
+ // Normalized back to standard currency units
175
176
  currency: payment.currency,
176
177
  paymentMethod: payment.method,
177
178
  rawResponse: payment
@@ -196,6 +197,7 @@ var RazorpayAdapter = class extends BasePaymentAdapter {
196
197
  refundId: res.id,
197
198
  paymentId: options.paymentId,
198
199
  amount: res.amount / 100,
200
+ // Normalized to standard currency units
199
201
  status: res.status === "processed" ? "SUCCESS" : "PENDING",
200
202
  rawResponse: res
201
203
  };
@@ -205,32 +207,58 @@ var RazorpayAdapter = class extends BasePaymentAdapter {
205
207
  if (!secret) {
206
208
  return {
207
209
  isValid: false,
210
+ normalizedEvent: "UNKNOWN",
208
211
  gateway: "razorpay",
209
212
  error: "Razorpay webhookSecret is not configured."
210
213
  };
211
214
  }
212
215
  const signature = this.getHeader(options.headers, "x-razorpay-signature");
213
- if (!signature || typeof signature !== "string") {
216
+ if (!signature) {
214
217
  return {
215
218
  isValid: false,
219
+ normalizedEvent: "UNKNOWN",
216
220
  gateway: "razorpay",
217
- error: "Missing X-Razorpay-Signature header."
221
+ error: "Missing x-razorpay-signature header."
218
222
  };
219
223
  }
220
224
  const rawString = typeof options.rawBody === "string" ? options.rawBody : options.rawBody.toString("utf8");
221
225
  const expectedSignature = hmacSha256(rawString, secret);
222
226
  const isValid = safeCompare(expectedSignature, signature);
223
- let parsedData;
227
+ let parsed;
224
228
  try {
225
- parsedData = JSON.parse(rawString);
229
+ parsed = JSON.parse(rawString);
226
230
  } catch {
227
- parsedData = null;
231
+ parsed = null;
228
232
  }
233
+ const rawEvent = parsed?.event || "";
234
+ let normalizedEvent = "UNKNOWN";
235
+ if (rawEvent === "order.paid" || rawEvent === "payment.captured" || rawEvent === "payment.authorized") {
236
+ normalizedEvent = "PAYMENT_SUCCESS";
237
+ } else if (rawEvent === "payment.failed") {
238
+ normalizedEvent = "PAYMENT_FAILED";
239
+ } else if (rawEvent === "refund.processed" || rawEvent === "refund.created") {
240
+ normalizedEvent = "REFUND_PROCESSED";
241
+ } else if (rawEvent === "refund.failed") {
242
+ normalizedEvent = "REFUND_FAILED";
243
+ } else if (rawEvent?.includes("dispute")) {
244
+ normalizedEvent = "DISPUTE_CREATED";
245
+ }
246
+ const paymentEntity = parsed?.payload?.payment?.entity;
247
+ const orderEntity = parsed?.payload?.order?.entity;
248
+ const orderId = orderEntity?.receipt || paymentEntity?.order_id || orderEntity?.id;
249
+ const paymentId = paymentEntity?.id;
250
+ const amount = paymentEntity?.amount ? paymentEntity.amount / 100 : orderEntity?.amount ? orderEntity.amount / 100 : void 0;
251
+ const currency = paymentEntity?.currency || orderEntity?.currency;
229
252
  return {
230
253
  isValid,
254
+ normalizedEvent,
255
+ rawEvent,
231
256
  gateway: "razorpay",
232
- event: parsedData?.event,
233
- data: parsedData?.payload
257
+ orderId,
258
+ paymentId,
259
+ amount,
260
+ currency,
261
+ data: parsed?.payload
234
262
  };
235
263
  }
236
264
  };
@@ -363,17 +391,41 @@ var CashfreeAdapter = class extends BasePaymentAdapter {
363
391
  ).toString("base64");
364
392
  isValid = safeCompare(expectedSignature, signature);
365
393
  }
366
- let parsedData;
394
+ let parsed;
367
395
  try {
368
- parsedData = JSON.parse(rawString);
396
+ parsed = JSON.parse(rawString);
369
397
  } catch {
370
- parsedData = null;
398
+ parsed = null;
399
+ }
400
+ const rawEvent = parsed?.type || "";
401
+ let normalizedEvent = "UNKNOWN";
402
+ if (rawEvent === "PAYMENT_SUCCESS_WEBHOOK") {
403
+ normalizedEvent = "PAYMENT_SUCCESS";
404
+ } else if (rawEvent === "PAYMENT_FAILED_WEBHOOK" || rawEvent === "USER_DROPPED_WEBHOOK") {
405
+ normalizedEvent = "PAYMENT_FAILED";
406
+ } else if (rawEvent === "REFUND_STATUS_WEBHOOK") {
407
+ const refundStatus = parsed?.data?.refund?.refund_status;
408
+ normalizedEvent = refundStatus === "SUCCESS" ? "REFUND_PROCESSED" : "REFUND_FAILED";
409
+ } else if (rawEvent?.includes("DISPUTE")) {
410
+ normalizedEvent = "DISPUTE_CREATED";
371
411
  }
412
+ const orderData = parsed?.data?.order;
413
+ const paymentData = parsed?.data?.payment;
414
+ const refundData = parsed?.data?.refund;
415
+ const orderId = orderData?.order_id || refundData?.order_id;
416
+ const paymentId = paymentData ? String(paymentData.cf_payment_id) : refundData ? String(refundData.cf_payment_id) : void 0;
417
+ const amount = paymentData?.payment_amount ?? orderData?.order_amount ?? refundData?.refund_amount;
418
+ const currency = paymentData?.payment_currency || orderData?.order_currency;
372
419
  return {
373
420
  isValid,
421
+ normalizedEvent,
422
+ rawEvent,
374
423
  gateway: "cashfree",
375
- event: parsedData?.type,
376
- data: parsedData?.data
424
+ orderId,
425
+ paymentId,
426
+ amount,
427
+ currency,
428
+ data: parsed?.data
377
429
  };
378
430
  }
379
431
  };
@@ -499,17 +551,36 @@ var PhonePeAdapter = class extends BasePaymentAdapter {
499
551
  try {
500
552
  parsed = JSON.parse(rawString);
501
553
  } catch {
502
- return { isValid: false, gateway: "phonepe", error: "Invalid JSON payload" };
554
+ return { isValid: false, normalizedEvent: "UNKNOWN", gateway: "phonepe", error: "Invalid JSON payload" };
503
555
  }
504
556
  if (!parsed.response) {
505
- return { isValid: false, gateway: "phonepe", error: "Missing response field in PhonePe callback" };
557
+ return { isValid: false, normalizedEvent: "UNKNOWN", gateway: "phonepe", error: "Missing response field in PhonePe callback" };
558
+ }
559
+ let decoded = {};
560
+ try {
561
+ decoded = JSON.parse(base64Decode(parsed.response));
562
+ } catch {
563
+ return { isValid: false, normalizedEvent: "UNKNOWN", gateway: "phonepe", error: "Failed to decode base64 PhonePe response" };
506
564
  }
507
- const decoded = JSON.parse(base64Decode(parsed.response));
508
- decoded.code === "PAYMENT_SUCCESS";
565
+ const rawEvent = decoded.code || "";
566
+ let normalizedEvent = "UNKNOWN";
567
+ if (rawEvent === "PAYMENT_SUCCESS") {
568
+ normalizedEvent = "PAYMENT_SUCCESS";
569
+ } else if (rawEvent === "PAYMENT_ERROR" || rawEvent === "PAYMENT_DECLINED") {
570
+ normalizedEvent = "PAYMENT_FAILED";
571
+ }
572
+ const orderId = decoded.data?.merchantTransactionId;
573
+ const paymentId = decoded.data?.transactionId;
574
+ const amount = decoded.data?.amount ? decoded.data.amount / 100 : void 0;
509
575
  return {
510
576
  isValid: true,
577
+ normalizedEvent,
578
+ rawEvent,
511
579
  gateway: "phonepe",
512
- event: decoded.code,
580
+ orderId,
581
+ paymentId,
582
+ amount,
583
+ currency: "INR",
513
584
  data: decoded.data
514
585
  };
515
586
  }
@@ -624,11 +695,21 @@ var PaytmAdapter = class extends BasePaymentAdapter {
624
695
  const params = new URLSearchParams(rawString);
625
696
  parsed = Object.fromEntries(params.entries());
626
697
  }
627
- const isSuccess = parsed?.STATUS === "TXN_SUCCESS" || parsed?.resultInfo?.resultStatus === "TXN_SUCCESS";
698
+ const rawStatus = parsed?.STATUS || parsed?.resultInfo?.resultStatus;
699
+ const isSuccess = rawStatus === "TXN_SUCCESS";
700
+ const normalizedEvent = isSuccess ? "PAYMENT_SUCCESS" : "PAYMENT_FAILED";
701
+ const orderId = parsed?.ORDERID || parsed?.orderId;
702
+ const paymentId = parsed?.TXNID || parsed?.txnId;
703
+ const amount = parsed?.TXNAMOUNT ? parseFloat(parsed.TXNAMOUNT) : void 0;
628
704
  return {
629
705
  isValid: true,
706
+ normalizedEvent,
707
+ rawEvent: rawStatus,
630
708
  gateway: "paytm",
631
- event: isSuccess ? "TXN_SUCCESS" : "TXN_FAILURE",
709
+ orderId,
710
+ paymentId,
711
+ amount,
712
+ currency: "INR",
632
713
  data: parsed
633
714
  };
634
715
  }
@@ -720,6 +801,7 @@ var StripeAdapter = class extends BasePaymentAdapter {
720
801
  refundId: res.id,
721
802
  paymentId: options.paymentId,
722
803
  amount: res.amount / 100,
804
+ // Normalized to standard currency units
723
805
  status: res.status === "succeeded" ? "SUCCESS" : "PENDING",
724
806
  rawResponse: res
725
807
  };
@@ -727,11 +809,11 @@ var StripeAdapter = class extends BasePaymentAdapter {
727
809
  async verifyWebhook(options) {
728
810
  const secret = options.webhookSecret || this.config.webhookSecret;
729
811
  if (!secret) {
730
- return { isValid: false, gateway: "stripe", error: "Stripe webhookSecret is not configured." };
812
+ return { isValid: false, normalizedEvent: "UNKNOWN", gateway: "stripe", error: "Stripe webhookSecret is not configured." };
731
813
  }
732
814
  const sigHeader = this.getHeader(options.headers, "stripe-signature");
733
815
  if (!sigHeader || typeof sigHeader !== "string") {
734
- return { isValid: false, gateway: "stripe", error: "Missing stripe-signature header." };
816
+ return { isValid: false, normalizedEvent: "UNKNOWN", gateway: "stripe", error: "Missing stripe-signature header." };
735
817
  }
736
818
  const parts = sigHeader.split(",");
737
819
  let timestamp = "";
@@ -751,11 +833,32 @@ var StripeAdapter = class extends BasePaymentAdapter {
751
833
  } catch {
752
834
  parsed = null;
753
835
  }
836
+ const rawEvent = parsed?.type || "";
837
+ let normalizedEvent = "UNKNOWN";
838
+ if (rawEvent === "checkout.session.completed" || rawEvent === "payment_intent.succeeded") {
839
+ normalizedEvent = "PAYMENT_SUCCESS";
840
+ } else if (rawEvent === "payment_intent.payment_failed") {
841
+ normalizedEvent = "PAYMENT_FAILED";
842
+ } else if (rawEvent === "charge.refunded") {
843
+ normalizedEvent = "REFUND_PROCESSED";
844
+ } else if (rawEvent?.includes("dispute")) {
845
+ normalizedEvent = "DISPUTE_CREATED";
846
+ }
847
+ const obj = parsed?.data?.object;
848
+ const orderId = obj?.client_reference_id || obj?.metadata?.order_id || obj?.id;
849
+ const paymentId = obj?.payment_intent || obj?.id;
850
+ const amount = obj?.amount_total ? obj.amount_total / 100 : obj?.amount ? obj.amount / 100 : void 0;
851
+ const currency = obj?.currency ? obj.currency.toUpperCase() : void 0;
754
852
  return {
755
853
  isValid,
854
+ normalizedEvent,
855
+ rawEvent,
756
856
  gateway: "stripe",
757
- event: parsed?.type,
758
- data: parsed?.data?.object
857
+ orderId,
858
+ paymentId,
859
+ amount,
860
+ currency,
861
+ data: obj
759
862
  };
760
863
  }
761
864
  };
@@ -824,8 +927,9 @@ var CODAdapter = class extends BasePaymentAdapter {
824
927
  async verifyWebhook(_options) {
825
928
  return {
826
929
  isValid: true,
930
+ normalizedEvent: "PAYMENT_SUCCESS",
931
+ rawEvent: "COD_ORDER",
827
932
  gateway: "cod",
828
- event: "COD_ORDER",
829
933
  data: {}
830
934
  };
831
935
  }
@@ -956,6 +1060,60 @@ var PaymentManager = class {
956
1060
  const adapter = this.getAdapter(options.gateway);
957
1061
  return adapter.verifyWebhook(options);
958
1062
  }
1063
+ /**
1064
+ * Ready-made Next.js 13/14/15 App Router Route Handler Webhook Authenticator.
1065
+ * Directly consumes the standard web Request object with raw stream body handling:
1066
+ *
1067
+ * ```typescript
1068
+ * export async function POST(req: Request) {
1069
+ * const result = await payments.verifyNextJsWebhook(req, { gateway: 'razorpay' });
1070
+ * if (!result.isValid) return new Response('Invalid Signature', { status: 400 });
1071
+ * console.log('Event:', result.normalizedEvent, result.orderId);
1072
+ * return new Response('OK');
1073
+ * }
1074
+ * ```
1075
+ */
1076
+ async verifyNextJsWebhook(request, options) {
1077
+ try {
1078
+ let rawBody = "";
1079
+ if (typeof request.text === "function") {
1080
+ rawBody = await request.text();
1081
+ } else if (typeof request.body === "string") {
1082
+ rawBody = request.body;
1083
+ } else if (Buffer.isBuffer(request.body)) {
1084
+ rawBody = request.body.toString("utf8");
1085
+ }
1086
+ const headers = {};
1087
+ if (request.headers) {
1088
+ if (typeof request.headers.forEach === "function") {
1089
+ request.headers.forEach((val, key) => {
1090
+ headers[key.toLowerCase()] = val;
1091
+ });
1092
+ } else if (typeof request.headers.entries === "function") {
1093
+ for (const [key, val] of request.headers.entries()) {
1094
+ headers[key.toLowerCase()] = val;
1095
+ }
1096
+ } else if (typeof request.headers === "object") {
1097
+ Object.entries(request.headers).forEach(([k, v]) => {
1098
+ headers[k.toLowerCase()] = Array.isArray(v) ? v[0] : v;
1099
+ });
1100
+ }
1101
+ }
1102
+ return this.verifyWebhook({
1103
+ gateway: options.gateway,
1104
+ rawBody,
1105
+ headers,
1106
+ webhookSecret: options.webhookSecret
1107
+ });
1108
+ } catch (err) {
1109
+ return {
1110
+ isValid: false,
1111
+ normalizedEvent: "UNKNOWN",
1112
+ gateway: options.gateway,
1113
+ error: `Failed to process Next.js webhook: ${err.message}`
1114
+ };
1115
+ }
1116
+ }
959
1117
  };
960
1118
  function createPaymentManager(options) {
961
1119
  return new PaymentManager(options);