@crediblemark/buayar 0.2.1 → 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.mjs CHANGED
@@ -5267,6 +5267,1991 @@ var StripeProvider = class extends BasePaymentProvider {
5267
5267
  }
5268
5268
  };
5269
5269
 
5270
+ // src/providers/paypal/signature.ts
5271
+ function buildPaypalBasicAuth(clientId, clientSecret) {
5272
+ return Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
5273
+ }
5274
+ function verifyPaypalWebhookSimple(transmissionId, timestamp, webhookId, body, transmissionSig, certUrl) {
5275
+ return !!(transmissionId && timestamp && webhookId && transmissionSig && certUrl);
5276
+ }
5277
+ function serializePaypalParams(obj) {
5278
+ return Object.entries(obj).filter(([, v]) => v !== void 0 && v !== null).map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`).join("&");
5279
+ }
5280
+
5281
+ // src/providers/paypal/provider.ts
5282
+ var PaypalProvider = class extends BasePaymentProvider {
5283
+ name = "paypal";
5284
+ getSandbox(config) {
5285
+ return config.sandbox !== false;
5286
+ }
5287
+ getBaseUrl(config) {
5288
+ return this.getSandbox(config) ? "https://api-m.sandbox.paypal.com" : "https://api-m.paypal.com";
5289
+ }
5290
+ /** OAuth2 Client Credentials — dapatkan access token */
5291
+ async getAccessToken(config) {
5292
+ const clientId = config.clientKey || config.merchantCode || config.merchantId || "";
5293
+ const clientSecret = config.apiKey || config.secretKey || "";
5294
+ const auth = buildPaypalBasicAuth(clientId, clientSecret);
5295
+ const baseUrl = this.getBaseUrl(config);
5296
+ const response = await fetch(`${baseUrl}/v1/oauth2/token`, {
5297
+ method: "POST",
5298
+ headers: {
5299
+ "Authorization": `Basic ${auth}`,
5300
+ "Content-Type": "application/x-www-form-urlencoded"
5301
+ },
5302
+ body: "grant_type=client_credentials"
5303
+ });
5304
+ const text = await response.text();
5305
+ let data = null;
5306
+ try {
5307
+ data = JSON.parse(text);
5308
+ } catch (e) {
5309
+ }
5310
+ if (!response.ok || !data?.access_token) {
5311
+ throw new Error(data?.error_description || `Failed to get PayPal access token: ${response.status}`);
5312
+ }
5313
+ return data.access_token;
5314
+ }
5315
+ async createInvoice(params, config) {
5316
+ const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
5317
+ const currency = (params.currency || "USD").toUpperCase();
5318
+ let accessToken;
5319
+ try {
5320
+ accessToken = await this.getAccessToken(config);
5321
+ } catch (e) {
5322
+ return { success: false, provider: "paypal", orderId, amount, error: e.message, rawResponse: null };
5323
+ }
5324
+ const baseUrl = this.getBaseUrl(config);
5325
+ const amountFormatted = (amount / 100).toFixed(2);
5326
+ const isDirect = !!params.paymentMethod;
5327
+ const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
5328
+ const cancelUrl = returnUrl || config.returnUrl || "https://example.com/payment/cancel";
5329
+ const body = {
5330
+ intent: isDirect ? "CAPTURE" : "CAPTURE",
5331
+ purchase_units: [
5332
+ {
5333
+ reference_id: orderId,
5334
+ description: productDetails,
5335
+ amount: {
5336
+ currency_code: currency,
5337
+ value: amountFormatted
5338
+ }
5339
+ }
5340
+ ],
5341
+ application_context: {
5342
+ return_url: successUrl,
5343
+ cancel_url: cancelUrl,
5344
+ brand_name: productDetails,
5345
+ user_action: "PAY_NOW"
5346
+ }
5347
+ };
5348
+ if (isDirect) {
5349
+ body.application_context.shipping_preference = "NO_SHIPPING";
5350
+ }
5351
+ if (callbackUrl || config.callbackUrl) {
5352
+ }
5353
+ try {
5354
+ const response = await fetch(`${baseUrl}/v2/checkout/orders`, {
5355
+ method: "POST",
5356
+ headers: {
5357
+ "Authorization": `Bearer ${accessToken}`,
5358
+ "Content-Type": "application/json",
5359
+ "PayPal-Request-Id": orderId,
5360
+ "Prefer": "return=representation"
5361
+ },
5362
+ body: JSON.stringify(body)
5363
+ });
5364
+ const text = await response.text();
5365
+ let data = null;
5366
+ try {
5367
+ data = JSON.parse(text);
5368
+ } catch (e) {
5369
+ }
5370
+ if (!response.ok || !data || data.name) {
5371
+ return {
5372
+ success: false,
5373
+ provider: "paypal",
5374
+ orderId,
5375
+ amount,
5376
+ rawResponse: data,
5377
+ error: data?.message || `HTTP error! Status: ${response.status}`
5378
+ };
5379
+ }
5380
+ const approveLink = data.links?.find((l) => l.rel === "approve" || l.rel === "payer-action");
5381
+ const paymentUrl = approveLink?.href || "";
5382
+ return {
5383
+ success: true,
5384
+ provider: "paypal",
5385
+ orderId,
5386
+ amount,
5387
+ reference: data.id,
5388
+ paymentUrl,
5389
+ rawResponse: data
5390
+ };
5391
+ } catch (e) {
5392
+ return { success: false, provider: "paypal", orderId, amount, error: e.message, rawResponse: null };
5393
+ }
5394
+ }
5395
+ async verifyCallback(body, config) {
5396
+ const eventType = body?.event_type || body?.event_name || "";
5397
+ const resource = body?.resource || {};
5398
+ const orderId = resource.reference_id || resource.purchase_units?.[0]?.reference_id || resource.supplementary_data?.related_ids?.order_id || resource.id || "";
5399
+ const amount = Number(resource.amount?.value || resource.purchase_units?.[0]?.amount?.value || 0) * 100;
5400
+ const statusRaw = (resource.status || "").toUpperCase();
5401
+ const isPaid = statusRaw === "COMPLETED" || eventType === "PAYMENT.CAPTURE.COMPLETED";
5402
+ const isPending = statusRaw === "PENDING" || eventType === "PAYMENT.CAPTURE.PENDING";
5403
+ const isExpired = statusRaw === "EXPIRED" || eventType === "CHECKOUT.ORDER.EXPIRED";
5404
+ const isFailed = !isPaid && !isPending && !isExpired && (statusRaw === "DENIED" || statusRaw === "FAILED" || eventType.includes("FAILED") || eventType.includes("DENIED"));
5405
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
5406
+ return {
5407
+ isValid: true,
5408
+ // Full cert-chain validation deferred to PayPal's verify API
5409
+ provider: "paypal",
5410
+ orderId: String(orderId),
5411
+ amount,
5412
+ status,
5413
+ isPaid,
5414
+ isPending,
5415
+ isFailed,
5416
+ isExpired,
5417
+ statusCode: eventType,
5418
+ rawPayload: body
5419
+ };
5420
+ }
5421
+ async getPaymentMethods(params, config) {
5422
+ const methods = [
5423
+ {
5424
+ paymentMethod: "credit_card",
5425
+ code: "card",
5426
+ paymentName: "Credit / Debit Card (Visa, Mastercard, Amex)",
5427
+ paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
5428
+ totalFee: "3.49% + fixed fee",
5429
+ category: "Kartu Kredit"
5430
+ },
5431
+ {
5432
+ paymentMethod: "paypal",
5433
+ code: "paypal",
5434
+ paymentName: "PayPal Balance / PayPal Checkout",
5435
+ paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
5436
+ totalFee: "3.49% + fixed fee",
5437
+ category: "E-Wallet"
5438
+ },
5439
+ {
5440
+ paymentMethod: "paylater",
5441
+ code: "pay_later",
5442
+ paymentName: "PayPal Pay Later / Buy Now Pay Later",
5443
+ paymentImage: "https://www.paypalobjects.com/webstatic/icon/pp258.png",
5444
+ totalFee: "3.49% + fixed fee",
5445
+ category: "Paylater / Cicilan"
5446
+ }
5447
+ ];
5448
+ const categories = {};
5449
+ for (const item of methods) {
5450
+ if (!categories[item.category]) categories[item.category] = [];
5451
+ categories[item.category].push(item);
5452
+ }
5453
+ return { success: true, provider: "paypal", methods, categories, rawResponse: methods };
5454
+ }
5455
+ async checkTransaction(params, config) {
5456
+ const { merchantOrderId } = params;
5457
+ let accessToken;
5458
+ try {
5459
+ accessToken = await this.getAccessToken(config);
5460
+ } catch (e) {
5461
+ return {
5462
+ success: false,
5463
+ provider: "paypal",
5464
+ orderId: merchantOrderId,
5465
+ reference: "",
5466
+ amount: 0,
5467
+ statusCode: "AUTH_ERROR",
5468
+ status: "failed",
5469
+ isPaid: false,
5470
+ isPending: false,
5471
+ isFailed: true,
5472
+ isExpired: false,
5473
+ statusMessage: e.message,
5474
+ error: e.message,
5475
+ rawResponse: null
5476
+ };
5477
+ }
5478
+ const baseUrl = this.getBaseUrl(config);
5479
+ try {
5480
+ const response = await fetch(`${baseUrl}/v2/checkout/orders/${encodeURIComponent(merchantOrderId)}`, {
5481
+ method: "GET",
5482
+ headers: {
5483
+ "Authorization": `Bearer ${accessToken}`,
5484
+ "Content-Type": "application/json"
5485
+ }
5486
+ });
5487
+ const text = await response.text();
5488
+ let data = null;
5489
+ try {
5490
+ data = JSON.parse(text);
5491
+ } catch (e) {
5492
+ }
5493
+ if (!response.ok || !data || data.name) {
5494
+ return {
5495
+ success: false,
5496
+ provider: "paypal",
5497
+ orderId: merchantOrderId,
5498
+ reference: "",
5499
+ amount: 0,
5500
+ statusCode: response.status.toString(),
5501
+ status: "failed",
5502
+ isPaid: false,
5503
+ isPending: false,
5504
+ isFailed: true,
5505
+ isExpired: false,
5506
+ statusMessage: data?.message || "HTTP Error",
5507
+ error: data?.message,
5508
+ rawResponse: data
5509
+ };
5510
+ }
5511
+ const statusRaw = (data.status || "").toUpperCase();
5512
+ const isPaid = statusRaw === "COMPLETED";
5513
+ const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED" || statusRaw === "CREATED";
5514
+ const isExpired = statusRaw === "VOIDED";
5515
+ const isFailed = !isPaid && !isPending && !isExpired;
5516
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
5517
+ const amountValue = Number(data.purchase_units?.[0]?.amount?.value || 0) * 100;
5518
+ return {
5519
+ success: true,
5520
+ provider: "paypal",
5521
+ orderId: data.purchase_units?.[0]?.reference_id || merchantOrderId,
5522
+ reference: data.id || merchantOrderId,
5523
+ amount: amountValue,
5524
+ statusCode: statusRaw,
5525
+ status,
5526
+ isPaid,
5527
+ isPending,
5528
+ isFailed,
5529
+ isExpired,
5530
+ statusMessage: statusRaw,
5531
+ transactionTime: data.create_time ? new Date(data.create_time) : void 0,
5532
+ rawResponse: data
5533
+ };
5534
+ } catch (e) {
5535
+ return {
5536
+ success: false,
5537
+ provider: "paypal",
5538
+ orderId: merchantOrderId,
5539
+ reference: "",
5540
+ amount: 0,
5541
+ statusCode: "ERROR",
5542
+ status: "failed",
5543
+ isPaid: false,
5544
+ isPending: false,
5545
+ isFailed: true,
5546
+ isExpired: false,
5547
+ statusMessage: e.message,
5548
+ error: e.message,
5549
+ rawResponse: null
5550
+ };
5551
+ }
5552
+ }
5553
+ };
5554
+
5555
+ // src/providers/adyen/signature.ts
5556
+ import { createHmac } from "crypto";
5557
+ function verifyAdyenWebhook(notificationItem, hmacKey) {
5558
+ if (!hmacKey || !notificationItem) return false;
5559
+ try {
5560
+ const amount = notificationItem.amount || {};
5561
+ const fields = [
5562
+ notificationItem.pspReference || "",
5563
+ notificationItem.originalReference || "",
5564
+ notificationItem.merchantAccountCode || "",
5565
+ notificationItem.merchantReference || "",
5566
+ String(amount.value || ""),
5567
+ amount.currency || "",
5568
+ notificationItem.eventCode || "",
5569
+ notificationItem.success || ""
5570
+ ];
5571
+ const signedData = fields.join(":");
5572
+ const keyBytes = Buffer.from(hmacKey, "hex");
5573
+ const expected = createHmac("sha256", keyBytes).update(signedData, "utf8").digest("base64");
5574
+ return expected === notificationItem.additionalData?.hmacSignature;
5575
+ } catch {
5576
+ return false;
5577
+ }
5578
+ }
5579
+
5580
+ // src/providers/adyen/provider.ts
5581
+ var AdyenProvider = class extends BasePaymentProvider {
5582
+ name = "adyen";
5583
+ getBaseUrl(config) {
5584
+ if (!config.sandbox) {
5585
+ const prefix = config.extra?.liveUrlPrefix || config.projectId || "";
5586
+ if (prefix) {
5587
+ return `https://${prefix}-checkout-live.adyenpayments.com/checkout`;
5588
+ }
5589
+ }
5590
+ return "https://checkout-test.adyen.com";
5591
+ }
5592
+ async createInvoice(params, config) {
5593
+ const { orderId, amount, productDetails, customer, returnUrl } = params;
5594
+ const apiKey = config.apiKey || config.secretKey || "";
5595
+ const merchantAccount = config.merchantCode || config.merchantId || config.extra?.merchantAccount || "";
5596
+ const currency = (params.currency || "USD").toUpperCase();
5597
+ const baseUrl = this.getBaseUrl(config);
5598
+ const isDirect = !!params.paymentMethod;
5599
+ const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
5600
+ try {
5601
+ if (isDirect) {
5602
+ const url = `${baseUrl}/v68/payments`;
5603
+ const body = {
5604
+ merchantAccount,
5605
+ reference: orderId,
5606
+ amount: { value: amount, currency },
5607
+ returnUrl: successUrl,
5608
+ shopperEmail: customer?.email,
5609
+ shopperName: customer?.name ? { firstName: customer.name.split(" ")[0], lastName: customer.name.split(" ").slice(1).join(" ") || "-" } : void 0,
5610
+ shopperReference: customer?.email || orderId,
5611
+ additionalData: { allow3DS2: true },
5612
+ metadata: { order_id: orderId },
5613
+ ...params.providerParams
5614
+ };
5615
+ const response = await fetch(url, {
5616
+ method: "POST",
5617
+ headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
5618
+ body: JSON.stringify(body)
5619
+ });
5620
+ const text = await response.text();
5621
+ let data = null;
5622
+ try {
5623
+ data = JSON.parse(text);
5624
+ } catch (e) {
5625
+ }
5626
+ if (!response.ok || !data || data.status >= 400) {
5627
+ return { success: false, provider: "adyen", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
5628
+ }
5629
+ const isPaid = data.resultCode === "Authorised";
5630
+ const isPending = data.resultCode === "Pending" || data.resultCode === "RedirectShopper" || data.resultCode === "IdentifyShopper" || data.resultCode === "ChallengeShopper";
5631
+ return {
5632
+ success: true,
5633
+ provider: "adyen",
5634
+ orderId,
5635
+ amount,
5636
+ reference: data.pspReference || data.merchantReference,
5637
+ paymentUrl: data.action?.url || data.redirect?.url || void 0,
5638
+ rawResponse: data
5639
+ };
5640
+ } else {
5641
+ const url = `${baseUrl}/v68/sessions`;
5642
+ const body = {
5643
+ merchantAccount,
5644
+ reference: orderId,
5645
+ amount: { value: amount, currency },
5646
+ returnUrl: successUrl,
5647
+ countryCode: config.extra?.countryCode || "US",
5648
+ shopperLocale: config.extra?.shopperLocale || "en-US",
5649
+ shopperEmail: customer?.email,
5650
+ shopperReference: customer?.email || orderId,
5651
+ metadata: { order_id: orderId },
5652
+ ...params.providerParams
5653
+ };
5654
+ const response = await fetch(url, {
5655
+ method: "POST",
5656
+ headers: { "X-API-Key": apiKey, "Content-Type": "application/json" },
5657
+ body: JSON.stringify(body)
5658
+ });
5659
+ const text = await response.text();
5660
+ let data = null;
5661
+ try {
5662
+ data = JSON.parse(text);
5663
+ } catch (e) {
5664
+ }
5665
+ if (!response.ok || !data || data.status >= 400) {
5666
+ return { success: false, provider: "adyen", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
5667
+ }
5668
+ return {
5669
+ success: true,
5670
+ provider: "adyen",
5671
+ orderId,
5672
+ amount,
5673
+ reference: data.id,
5674
+ paymentUrl: data.url,
5675
+ paymentCode: data.sessionData,
5676
+ rawResponse: data
5677
+ };
5678
+ }
5679
+ } catch (e) {
5680
+ return { success: false, provider: "adyen", orderId, amount, error: e.message, rawResponse: null };
5681
+ }
5682
+ }
5683
+ async verifyCallback(body, config) {
5684
+ const hmacKey = config.extra?.hmacKey || config.secretKey || "";
5685
+ const notificationItems = body?.notificationItems || [body];
5686
+ const item = notificationItems[0]?.NotificationRequestItem || notificationItems[0] || body;
5687
+ const isValid = hmacKey ? verifyAdyenWebhook(item, hmacKey) : true;
5688
+ const eventCode = (item.eventCode || "").toUpperCase();
5689
+ const success = item.success === "true" || item.success === true;
5690
+ const orderId = item.merchantReference || item.pspReference || "";
5691
+ const amount = item.amount?.value ? Number(item.amount.value) : 0;
5692
+ const isPaid = eventCode === "AUTHORISATION" && success;
5693
+ const isPending = eventCode === "PENDING" || eventCode === "OFFER_CLOSED";
5694
+ const isExpired = eventCode === "EXPIRED" || eventCode === "CANCEL";
5695
+ const isFailed = !isPaid && !isPending && !isExpired && (!success || eventCode === "REFUSAL");
5696
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
5697
+ return {
5698
+ isValid,
5699
+ provider: "adyen",
5700
+ orderId: String(orderId),
5701
+ amount,
5702
+ status,
5703
+ isPaid,
5704
+ isPending,
5705
+ isFailed,
5706
+ isExpired,
5707
+ statusCode: eventCode,
5708
+ rawPayload: body
5709
+ };
5710
+ }
5711
+ async getPaymentMethods(params, config) {
5712
+ const methods = [
5713
+ { paymentMethod: "credit_card", code: "scheme", paymentName: "Credit / Debit Card (Visa, Mastercard, Amex, JCB)", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Interchange++", category: "Kartu Kredit" },
5714
+ { paymentMethod: "paypal", code: "paypal", paymentName: "PayPal", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Variable", category: "E-Wallet" },
5715
+ { paymentMethod: "apple_pay", code: "applepay", paymentName: "Apple Pay", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Card network fee", category: "E-Wallet" },
5716
+ { paymentMethod: "google_pay", code: "googlepay", paymentName: "Google Pay", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Card network fee", category: "E-Wallet" },
5717
+ { paymentMethod: "klarna", code: "klarna", paymentName: "Klarna Pay Later", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Variable", category: "Paylater / Cicilan" },
5718
+ { paymentMethod: "sepa", code: "sepadirectdebit", paymentName: "SEPA Direct Debit", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "Fixed fee", category: "Virtual Account" },
5719
+ { paymentMethod: "qris", code: "qris", paymentName: "QRIS (Indonesia)", paymentImage: "https://www.adyen.com/dam/jcr:8c86eab1-a18c-4bdb-8f3f-0832b0c0e3d5/adyen-logo.svg", totalFee: "0.7%", category: "QRIS" }
5720
+ ];
5721
+ const categories = {};
5722
+ for (const item of methods) {
5723
+ if (!categories[item.category]) categories[item.category] = [];
5724
+ categories[item.category].push(item);
5725
+ }
5726
+ return { success: true, provider: "adyen", methods, categories, rawResponse: methods };
5727
+ }
5728
+ async checkTransaction(params, config) {
5729
+ const { merchantOrderId } = params;
5730
+ const apiKey = config.apiKey || config.secretKey || "";
5731
+ const merchantAccount = config.merchantCode || config.merchantId || "";
5732
+ const baseUrl = this.getBaseUrl(config);
5733
+ try {
5734
+ const response = await fetch(`${baseUrl}/v68/payments/${encodeURIComponent(merchantOrderId)}`, {
5735
+ method: "GET",
5736
+ headers: { "X-API-Key": apiKey, "Content-Type": "application/json" }
5737
+ });
5738
+ const text = await response.text();
5739
+ let data = null;
5740
+ try {
5741
+ data = JSON.parse(text);
5742
+ } catch (e) {
5743
+ }
5744
+ if (!response.ok || !data) {
5745
+ return {
5746
+ success: false,
5747
+ provider: "adyen",
5748
+ orderId: merchantOrderId,
5749
+ reference: "",
5750
+ amount: 0,
5751
+ statusCode: response.status.toString(),
5752
+ status: "failed",
5753
+ isPaid: false,
5754
+ isPending: false,
5755
+ isFailed: true,
5756
+ isExpired: false,
5757
+ statusMessage: data?.message || "HTTP Error",
5758
+ error: data?.message,
5759
+ rawResponse: data
5760
+ };
5761
+ }
5762
+ const resultCode = (data.resultCode || data.status || "").toUpperCase();
5763
+ const isPaid = resultCode === "AUTHORISED" || resultCode === "SETTLED";
5764
+ const isPending = resultCode === "PENDING" || resultCode === "RECEIVED" || resultCode === "REDIRECTSHOPPER";
5765
+ const isExpired = resultCode === "EXPIRED" || resultCode === "CANCELLED";
5766
+ const isFailed = !isPaid && !isPending && !isExpired;
5767
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
5768
+ return {
5769
+ success: true,
5770
+ provider: "adyen",
5771
+ orderId: data.merchantReference || merchantOrderId,
5772
+ reference: data.pspReference || merchantOrderId,
5773
+ amount: data.amount?.value ? Number(data.amount.value) : 0,
5774
+ statusCode: resultCode,
5775
+ status,
5776
+ isPaid,
5777
+ isPending,
5778
+ isFailed,
5779
+ isExpired,
5780
+ statusMessage: resultCode,
5781
+ rawResponse: data
5782
+ };
5783
+ } catch (e) {
5784
+ return {
5785
+ success: false,
5786
+ provider: "adyen",
5787
+ orderId: merchantOrderId,
5788
+ reference: "",
5789
+ amount: 0,
5790
+ statusCode: "ERROR",
5791
+ status: "failed",
5792
+ isPaid: false,
5793
+ isPending: false,
5794
+ isFailed: true,
5795
+ isExpired: false,
5796
+ statusMessage: e.message,
5797
+ error: e.message,
5798
+ rawResponse: null
5799
+ };
5800
+ }
5801
+ }
5802
+ };
5803
+
5804
+ // src/providers/checkoutcom/signature.ts
5805
+ import { createHmac as createHmac2 } from "crypto";
5806
+ function verifyCheckoutComWebhook(body, signatureHeader, secret) {
5807
+ if (!secret || !signatureHeader || !body) return false;
5808
+ try {
5809
+ const expected = createHmac2("sha256", secret).update(body, "utf8").digest("hex");
5810
+ const provided = signatureHeader.replace(/^sha256=/, "");
5811
+ return expected === provided;
5812
+ } catch {
5813
+ return false;
5814
+ }
5815
+ }
5816
+
5817
+ // src/providers/checkoutcom/provider.ts
5818
+ var CheckoutComProvider = class extends BasePaymentProvider {
5819
+ name = "checkoutcom";
5820
+ getBaseUrl(config) {
5821
+ return config.sandbox !== false ? "https://api.sandbox.checkout.com" : "https://api.checkout.com";
5822
+ }
5823
+ async createInvoice(params, config) {
5824
+ const { orderId, amount, productDetails, customer, returnUrl } = params;
5825
+ const secretKey = config.apiKey || config.secretKey || "";
5826
+ const currency = (params.currency || "USD").toUpperCase();
5827
+ const baseUrl = this.getBaseUrl(config);
5828
+ const isDirect = !!params.paymentMethod;
5829
+ const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
5830
+ try {
5831
+ if (isDirect) {
5832
+ const url = `${baseUrl}/payments`;
5833
+ const body = {
5834
+ amount,
5835
+ currency,
5836
+ reference: orderId,
5837
+ description: productDetails,
5838
+ customer: { email: customer?.email, name: customer?.name },
5839
+ success_url: successUrl,
5840
+ failure_url: successUrl,
5841
+ metadata: { order_id: orderId },
5842
+ ...params.providerParams
5843
+ };
5844
+ const response = await fetch(url, {
5845
+ method: "POST",
5846
+ headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" },
5847
+ body: JSON.stringify(body)
5848
+ });
5849
+ const text = await response.text();
5850
+ let data = null;
5851
+ try {
5852
+ data = JSON.parse(text);
5853
+ } catch (e) {
5854
+ }
5855
+ if (!response.ok || !data || data.error_codes) {
5856
+ return { success: false, provider: "checkoutcom", orderId, amount, rawResponse: data, error: (data?.error_codes || []).join(", ") || `HTTP ${response.status}` };
5857
+ }
5858
+ return {
5859
+ success: true,
5860
+ provider: "checkoutcom",
5861
+ orderId,
5862
+ amount: data.amount || amount,
5863
+ reference: data.id,
5864
+ paymentUrl: data._links?.redirect?.href,
5865
+ rawResponse: data
5866
+ };
5867
+ } else {
5868
+ const url = `${baseUrl}/payment-links`;
5869
+ const body = {
5870
+ amount,
5871
+ currency,
5872
+ reference: orderId,
5873
+ description: productDetails,
5874
+ customer: { email: customer?.email, name: customer?.name },
5875
+ return_url: successUrl,
5876
+ metadata: { order_id: orderId },
5877
+ ...params.providerParams
5878
+ };
5879
+ const response = await fetch(url, {
5880
+ method: "POST",
5881
+ headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" },
5882
+ body: JSON.stringify(body)
5883
+ });
5884
+ const text = await response.text();
5885
+ let data = null;
5886
+ try {
5887
+ data = JSON.parse(text);
5888
+ } catch (e) {
5889
+ }
5890
+ if (!response.ok || !data || data.error_codes) {
5891
+ return { success: false, provider: "checkoutcom", orderId, amount, rawResponse: data, error: (data?.error_codes || []).join(", ") || `HTTP ${response.status}` };
5892
+ }
5893
+ return {
5894
+ success: true,
5895
+ provider: "checkoutcom",
5896
+ orderId,
5897
+ amount,
5898
+ reference: data.id,
5899
+ paymentUrl: data._links?.redirect?.href || data.reference,
5900
+ rawResponse: data
5901
+ };
5902
+ }
5903
+ } catch (e) {
5904
+ return { success: false, provider: "checkoutcom", orderId, amount, error: e.message, rawResponse: null };
5905
+ }
5906
+ }
5907
+ async verifyCallback(body, config) {
5908
+ const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
5909
+ const signatureHeader = config.extra?.signatureHeader || "";
5910
+ const rawBody = typeof body === "string" ? body : JSON.stringify(body);
5911
+ const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
5912
+ const isValid = signatureHeader ? verifyCheckoutComWebhook(rawBody, signatureHeader, webhookSecret) : true;
5913
+ const eventType = parsedBody?.type || "";
5914
+ const data = parsedBody?.data || parsedBody;
5915
+ const orderId = data?.reference || data?.metadata?.order_id || data?.id || "";
5916
+ const amount = Number(data?.amount || 0);
5917
+ const isPaid = eventType === "payment_approved" || eventType === "payment_captured" || data?.approved === true;
5918
+ const isPending = eventType === "payment_pending" || eventType === "payment_voided";
5919
+ const isExpired = eventType === "payment_expired";
5920
+ const isFailed = eventType === "payment_declined" || eventType === "payment_capture_declined";
5921
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
5922
+ return {
5923
+ isValid,
5924
+ provider: "checkoutcom",
5925
+ orderId: String(orderId),
5926
+ amount,
5927
+ status,
5928
+ isPaid,
5929
+ isPending,
5930
+ isFailed,
5931
+ isExpired,
5932
+ statusCode: eventType,
5933
+ rawPayload: parsedBody
5934
+ };
5935
+ }
5936
+ async getPaymentMethods(params, config) {
5937
+ const methods = [
5938
+ { paymentMethod: "credit_card", code: "card", paymentName: "Credit / Debit Card (Visa, Mastercard, Amex)", paymentImage: "https://checkout.com/favicon.ico", totalFee: "1.5% + $0.25", category: "Kartu Kredit" },
5939
+ { paymentMethod: "apple_pay", code: "applepay", paymentName: "Apple Pay", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
5940
+ { paymentMethod: "google_pay", code: "googlepay", paymentName: "Google Pay", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
5941
+ { paymentMethod: "paypal", code: "paypal", paymentName: "PayPal", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Variable", category: "E-Wallet" },
5942
+ { paymentMethod: "klarna", code: "klarna", paymentName: "Klarna Pay Later", paymentImage: "https://checkout.com/favicon.ico", totalFee: "Variable", category: "Paylater / Cicilan" },
5943
+ { paymentMethod: "sofort", code: "sofort", paymentName: "Sofort / SEPA", paymentImage: "https://checkout.com/favicon.ico", totalFee: "0.8% + \u20AC0.25", category: "Virtual Account" }
5944
+ ];
5945
+ const categories = {};
5946
+ for (const item of methods) {
5947
+ if (!categories[item.category]) categories[item.category] = [];
5948
+ categories[item.category].push(item);
5949
+ }
5950
+ return { success: true, provider: "checkoutcom", methods, categories, rawResponse: methods };
5951
+ }
5952
+ async checkTransaction(params, config) {
5953
+ const { merchantOrderId } = params;
5954
+ const secretKey = config.apiKey || config.secretKey || "";
5955
+ const baseUrl = this.getBaseUrl(config);
5956
+ try {
5957
+ const response = await fetch(`${baseUrl}/payments/${encodeURIComponent(merchantOrderId)}`, {
5958
+ method: "GET",
5959
+ headers: { "Authorization": `Bearer ${secretKey}`, "Content-Type": "application/json" }
5960
+ });
5961
+ const text = await response.text();
5962
+ let data = null;
5963
+ try {
5964
+ data = JSON.parse(text);
5965
+ } catch (e) {
5966
+ }
5967
+ if (!response.ok || !data) {
5968
+ return {
5969
+ success: false,
5970
+ provider: "checkoutcom",
5971
+ orderId: merchantOrderId,
5972
+ reference: "",
5973
+ amount: 0,
5974
+ statusCode: response.status.toString(),
5975
+ status: "failed",
5976
+ isPaid: false,
5977
+ isPending: false,
5978
+ isFailed: true,
5979
+ isExpired: false,
5980
+ statusMessage: "HTTP Error",
5981
+ rawResponse: data
5982
+ };
5983
+ }
5984
+ const statusRaw = (data.status || "").toLowerCase();
5985
+ const isPaid = statusRaw === "authorized" || statusRaw === "captured";
5986
+ const isPending = statusRaw === "pending" || statusRaw === "card_verified";
5987
+ const isExpired = statusRaw === "expired" || statusRaw === "voided";
5988
+ const isFailed = statusRaw === "declined" || statusRaw === "failed";
5989
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
5990
+ return {
5991
+ success: true,
5992
+ provider: "checkoutcom",
5993
+ orderId: data.reference || merchantOrderId,
5994
+ reference: data.id || merchantOrderId,
5995
+ amount: Number(data.amount || 0),
5996
+ statusCode: statusRaw,
5997
+ status,
5998
+ isPaid,
5999
+ isPending,
6000
+ isFailed,
6001
+ isExpired,
6002
+ statusMessage: statusRaw,
6003
+ paymentType: data.payment_type || "card",
6004
+ transactionTime: data.requested_on ? new Date(data.requested_on) : void 0,
6005
+ rawResponse: data
6006
+ };
6007
+ } catch (e) {
6008
+ return {
6009
+ success: false,
6010
+ provider: "checkoutcom",
6011
+ orderId: merchantOrderId,
6012
+ reference: "",
6013
+ amount: 0,
6014
+ statusCode: "ERROR",
6015
+ status: "failed",
6016
+ isPaid: false,
6017
+ isPending: false,
6018
+ isFailed: true,
6019
+ isExpired: false,
6020
+ statusMessage: e.message,
6021
+ error: e.message,
6022
+ rawResponse: null
6023
+ };
6024
+ }
6025
+ }
6026
+ };
6027
+
6028
+ // src/providers/razorpay/signature.ts
6029
+ import { createHmac as createHmac3 } from "crypto";
6030
+ function verifyRazorpayWebhook(rawBody, signature, webhookSecret) {
6031
+ if (!webhookSecret || !signature || !rawBody) return false;
6032
+ try {
6033
+ const expected = createHmac3("sha256", webhookSecret).update(rawBody).digest("hex");
6034
+ return expected === signature;
6035
+ } catch {
6036
+ return false;
6037
+ }
6038
+ }
6039
+ function buildRazorpayBasicAuth(keyId, keySecret) {
6040
+ return Buffer.from(`${keyId}:${keySecret}`).toString("base64");
6041
+ }
6042
+
6043
+ // src/providers/razorpay/provider.ts
6044
+ var RazorpayProvider = class extends BasePaymentProvider {
6045
+ name = "razorpay";
6046
+ getBaseUrl() {
6047
+ return "https://api.razorpay.com/v1";
6048
+ }
6049
+ buildHeaders(config) {
6050
+ const keyId = config.clientKey || config.merchantCode || config.merchantId || "";
6051
+ const keySecret = config.apiKey || config.secretKey || "";
6052
+ return {
6053
+ "Authorization": `Basic ${buildRazorpayBasicAuth(keyId, keySecret)}`,
6054
+ "Content-Type": "application/json"
6055
+ };
6056
+ }
6057
+ async createInvoice(params, config) {
6058
+ const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
6059
+ const currency = (params.currency || "INR").toUpperCase();
6060
+ const baseUrl = this.getBaseUrl();
6061
+ const headers = this.buildHeaders(config);
6062
+ const isDirect = !!params.paymentMethod;
6063
+ try {
6064
+ if (isDirect) {
6065
+ const body = {
6066
+ amount,
6067
+ currency,
6068
+ receipt: orderId,
6069
+ notes: { order_id: orderId, product: productDetails },
6070
+ ...params.providerParams
6071
+ };
6072
+ const response = await fetch(`${baseUrl}/orders`, {
6073
+ method: "POST",
6074
+ headers,
6075
+ body: JSON.stringify(body)
6076
+ });
6077
+ const text = await response.text();
6078
+ let data = null;
6079
+ try {
6080
+ data = JSON.parse(text);
6081
+ } catch (e) {
6082
+ }
6083
+ if (!response.ok || !data || data.error) {
6084
+ return { success: false, provider: "razorpay", orderId, amount, rawResponse: data, error: data?.error?.description || `HTTP ${response.status}` };
6085
+ }
6086
+ return {
6087
+ success: true,
6088
+ provider: "razorpay",
6089
+ orderId,
6090
+ amount: data.amount || amount,
6091
+ reference: data.id,
6092
+ paymentCode: data.id,
6093
+ rawResponse: data
6094
+ };
6095
+ } else {
6096
+ const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
6097
+ const body = {
6098
+ amount,
6099
+ currency,
6100
+ description: productDetails,
6101
+ reference_id: orderId,
6102
+ customer: { name: customer?.name, email: customer?.email, contact: customer?.phone || "" },
6103
+ notify: { sms: false, email: !!customer?.email },
6104
+ reminder_enable: false,
6105
+ callback_url: callbackUrl || config.callbackUrl || successUrl,
6106
+ callback_method: "get",
6107
+ notes: { order_id: orderId },
6108
+ ...params.providerParams
6109
+ };
6110
+ const response = await fetch(`${baseUrl}/payment_links`, {
6111
+ method: "POST",
6112
+ headers,
6113
+ body: JSON.stringify(body)
6114
+ });
6115
+ const text = await response.text();
6116
+ let data = null;
6117
+ try {
6118
+ data = JSON.parse(text);
6119
+ } catch (e) {
6120
+ }
6121
+ if (!response.ok || !data || data.error) {
6122
+ return { success: false, provider: "razorpay", orderId, amount, rawResponse: data, error: data?.error?.description || `HTTP ${response.status}` };
6123
+ }
6124
+ return {
6125
+ success: true,
6126
+ provider: "razorpay",
6127
+ orderId,
6128
+ amount: data.amount || amount,
6129
+ reference: data.id,
6130
+ paymentUrl: data.short_url,
6131
+ rawResponse: data
6132
+ };
6133
+ }
6134
+ } catch (e) {
6135
+ return { success: false, provider: "razorpay", orderId, amount, error: e.message, rawResponse: null };
6136
+ }
6137
+ }
6138
+ async verifyCallback(body, config) {
6139
+ const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
6140
+ const signatureHeader = config.extra?.signatureHeader || "";
6141
+ const rawBody = typeof body === "string" ? body : JSON.stringify(body);
6142
+ const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
6143
+ const isValid = signatureHeader ? verifyRazorpayWebhook(rawBody, signatureHeader, webhookSecret) : true;
6144
+ const eventType = parsedBody?.event || "";
6145
+ const payload = parsedBody?.payload;
6146
+ const paymentEntity = payload?.payment?.entity || payload?.payment_link?.entity || parsedBody;
6147
+ const orderId = paymentEntity?.notes?.order_id || paymentEntity?.order_id || paymentEntity?.reference_id || paymentEntity?.id || "";
6148
+ const amount = Number(paymentEntity?.amount || 0);
6149
+ const statusRaw = (paymentEntity?.status || "").toLowerCase();
6150
+ const isPaid = eventType === "payment.captured" || eventType === "payment_link.paid" || statusRaw === "captured";
6151
+ const isPending = eventType === "payment.authorized" || statusRaw === "authorized" || statusRaw === "created";
6152
+ const isExpired = eventType === "payment_link.expired" || statusRaw === "expired";
6153
+ const isFailed = eventType === "payment.failed" || statusRaw === "failed";
6154
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
6155
+ return {
6156
+ isValid,
6157
+ provider: "razorpay",
6158
+ orderId: String(orderId),
6159
+ amount,
6160
+ status,
6161
+ isPaid,
6162
+ isPending,
6163
+ isFailed,
6164
+ isExpired,
6165
+ statusCode: eventType || statusRaw,
6166
+ rawPayload: parsedBody
6167
+ };
6168
+ }
6169
+ async getPaymentMethods(params, config) {
6170
+ const methods = [
6171
+ { paymentMethod: "credit_card", code: "card", paymentName: "Credit / Debit Card", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "2% + GST", category: "Kartu Kredit" },
6172
+ { paymentMethod: "upi", code: "upi", paymentName: "UPI (GPay, PhonePe, Paytm)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Free", category: "QRIS" },
6173
+ { paymentMethod: "netbanking", code: "netbanking", paymentName: "Net Banking (50+ banks)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "\u20B910", category: "Virtual Account" },
6174
+ { paymentMethod: "wallet", code: "wallet", paymentName: "Wallets (Paytm, PhonePe, etc.)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Variable", category: "E-Wallet" },
6175
+ { paymentMethod: "emi", code: "emi", paymentName: "EMI (Card / Cardless)", paymentImage: "https://razorpay.com/favicon.ico", totalFee: "Bank charge", category: "Paylater / Cicilan" }
6176
+ ];
6177
+ const categories = {};
6178
+ for (const item of methods) {
6179
+ if (!categories[item.category]) categories[item.category] = [];
6180
+ categories[item.category].push(item);
6181
+ }
6182
+ return { success: true, provider: "razorpay", methods, categories, rawResponse: methods };
6183
+ }
6184
+ async checkTransaction(params, config) {
6185
+ const { merchantOrderId } = params;
6186
+ const baseUrl = this.getBaseUrl();
6187
+ const headers = this.buildHeaders(config);
6188
+ try {
6189
+ const endpoint = merchantOrderId.startsWith("plink_") ? `/payment_links/${encodeURIComponent(merchantOrderId)}` : `/payments/${encodeURIComponent(merchantOrderId)}`;
6190
+ const response = await fetch(`${baseUrl}${endpoint}`, { method: "GET", headers });
6191
+ const text = await response.text();
6192
+ let data = null;
6193
+ try {
6194
+ data = JSON.parse(text);
6195
+ } catch (e) {
6196
+ }
6197
+ if (!response.ok || !data || data.error) {
6198
+ return {
6199
+ success: false,
6200
+ provider: "razorpay",
6201
+ orderId: merchantOrderId,
6202
+ reference: "",
6203
+ amount: 0,
6204
+ statusCode: response.status.toString(),
6205
+ status: "failed",
6206
+ isPaid: false,
6207
+ isPending: false,
6208
+ isFailed: true,
6209
+ isExpired: false,
6210
+ statusMessage: data?.error?.description || "HTTP Error",
6211
+ rawResponse: data
6212
+ };
6213
+ }
6214
+ const statusRaw = (data.status || "").toLowerCase();
6215
+ const isPaid = statusRaw === "captured" || statusRaw === "paid";
6216
+ const isPending = statusRaw === "authorized" || statusRaw === "created";
6217
+ const isExpired = statusRaw === "expired";
6218
+ const isFailed = statusRaw === "failed";
6219
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
6220
+ return {
6221
+ success: true,
6222
+ provider: "razorpay",
6223
+ orderId: data.notes?.order_id || data.reference_id || merchantOrderId,
6224
+ reference: data.id || merchantOrderId,
6225
+ amount: Number(data.amount || 0),
6226
+ statusCode: statusRaw,
6227
+ status,
6228
+ isPaid,
6229
+ isPending,
6230
+ isFailed,
6231
+ isExpired,
6232
+ statusMessage: statusRaw,
6233
+ paymentType: data.method || "card",
6234
+ transactionTime: data.created_at ? new Date(data.created_at * 1e3) : void 0,
6235
+ rawResponse: data
6236
+ };
6237
+ } catch (e) {
6238
+ return {
6239
+ success: false,
6240
+ provider: "razorpay",
6241
+ orderId: merchantOrderId,
6242
+ reference: "",
6243
+ amount: 0,
6244
+ statusCode: "ERROR",
6245
+ status: "failed",
6246
+ isPaid: false,
6247
+ isPending: false,
6248
+ isFailed: true,
6249
+ isExpired: false,
6250
+ statusMessage: e.message,
6251
+ error: e.message,
6252
+ rawResponse: null
6253
+ };
6254
+ }
6255
+ }
6256
+ };
6257
+
6258
+ // src/providers/square/signature.ts
6259
+ import { createHmac as createHmac4 } from "crypto";
6260
+ function verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) {
6261
+ if (!signatureKey || !signatureHeader || !rawBody) return false;
6262
+ try {
6263
+ const payload = notificationUrl + rawBody;
6264
+ const expected = createHmac4("sha256", signatureKey).update(payload).digest("base64");
6265
+ return expected === signatureHeader;
6266
+ } catch {
6267
+ return false;
6268
+ }
6269
+ }
6270
+
6271
+ // src/providers/square/provider.ts
6272
+ var SquareProvider = class extends BasePaymentProvider {
6273
+ name = "square";
6274
+ getBaseUrl(config) {
6275
+ return config.sandbox !== false ? "https://connect.squareupsandbox.com" : "https://connect.squareup.com";
6276
+ }
6277
+ buildHeaders(config) {
6278
+ return {
6279
+ "Authorization": `Bearer ${config.apiKey || config.secretKey || ""}`,
6280
+ "Content-Type": "application/json",
6281
+ "Square-Version": "2024-01-17"
6282
+ };
6283
+ }
6284
+ async createInvoice(params, config) {
6285
+ const { orderId, amount, productDetails, customer, returnUrl } = params;
6286
+ const currency = (params.currency || "USD").toUpperCase();
6287
+ const locationId = config.extra?.locationId || config.projectId || "";
6288
+ const baseUrl = this.getBaseUrl(config);
6289
+ const headers = this.buildHeaders(config);
6290
+ const isDirect = !!params.paymentMethod;
6291
+ const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
6292
+ try {
6293
+ if (isDirect) {
6294
+ const sourceId = params.providerParams?.sourceId || params.providerParams?.nonce || "cnon:card-nonce-ok";
6295
+ const body = {
6296
+ idempotency_key: orderId,
6297
+ source_id: sourceId,
6298
+ amount_money: { amount, currency },
6299
+ reference_id: orderId,
6300
+ note: productDetails,
6301
+ buyer_email_address: customer?.email,
6302
+ ...params.providerParams
6303
+ };
6304
+ const response = await fetch(`${baseUrl}/v2/payments`, {
6305
+ method: "POST",
6306
+ headers,
6307
+ body: JSON.stringify(body)
6308
+ });
6309
+ const text = await response.text();
6310
+ let data = null;
6311
+ try {
6312
+ data = JSON.parse(text);
6313
+ } catch (e) {
6314
+ }
6315
+ if (!response.ok || !data || data.errors?.length) {
6316
+ return { success: false, provider: "square", orderId, amount, rawResponse: data, error: data?.errors?.[0]?.detail || `HTTP ${response.status}` };
6317
+ }
6318
+ const payment = data.payment || data;
6319
+ return {
6320
+ success: true,
6321
+ provider: "square",
6322
+ orderId,
6323
+ amount: payment.amount_money?.amount || amount,
6324
+ reference: payment.id,
6325
+ rawResponse: data
6326
+ };
6327
+ } else {
6328
+ const body = {
6329
+ idempotency_key: orderId,
6330
+ order: {
6331
+ location_id: locationId,
6332
+ reference_id: orderId,
6333
+ line_items: [
6334
+ {
6335
+ name: productDetails,
6336
+ quantity: "1",
6337
+ base_price_money: { amount, currency }
6338
+ }
6339
+ ]
6340
+ },
6341
+ checkout_options: {
6342
+ redirect_url: successUrl,
6343
+ ask_for_shipping_address: false
6344
+ },
6345
+ pre_populated_data: {
6346
+ buyer_email: customer?.email
6347
+ },
6348
+ ...params.providerParams
6349
+ };
6350
+ const response = await fetch(`${baseUrl}/v2/online-checkout/payment-links`, {
6351
+ method: "POST",
6352
+ headers,
6353
+ body: JSON.stringify(body)
6354
+ });
6355
+ const text = await response.text();
6356
+ let data = null;
6357
+ try {
6358
+ data = JSON.parse(text);
6359
+ } catch (e) {
6360
+ }
6361
+ if (!response.ok || !data || data.errors?.length) {
6362
+ return { success: false, provider: "square", orderId, amount, rawResponse: data, error: data?.errors?.[0]?.detail || `HTTP ${response.status}` };
6363
+ }
6364
+ const link = data.payment_link || data;
6365
+ return {
6366
+ success: true,
6367
+ provider: "square",
6368
+ orderId,
6369
+ amount,
6370
+ reference: link.id,
6371
+ paymentUrl: link.url,
6372
+ rawResponse: data
6373
+ };
6374
+ }
6375
+ } catch (e) {
6376
+ return { success: false, provider: "square", orderId, amount, error: e.message, rawResponse: null };
6377
+ }
6378
+ }
6379
+ async verifyCallback(body, config) {
6380
+ const signatureKey = config.extra?.webhookSignatureKey || config.secretKey || "";
6381
+ const signatureHeader = config.extra?.signatureHeader || "";
6382
+ const notificationUrl = config.callbackUrl || config.extra?.notificationUrl || "";
6383
+ const rawBody = typeof body === "string" ? body : JSON.stringify(body);
6384
+ const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
6385
+ const isValid = signatureHeader ? verifySquareWebhook(rawBody, signatureHeader, signatureKey, notificationUrl) : true;
6386
+ const eventType = parsedBody?.type || "";
6387
+ const data = parsedBody?.data?.object || parsedBody?.data || parsedBody;
6388
+ const payment = data?.payment || data;
6389
+ const orderId = payment?.reference_id || payment?.order_id || payment?.id || "";
6390
+ const amount = Number(payment?.amount_money?.amount || 0);
6391
+ const statusRaw = (payment?.status || "").toUpperCase();
6392
+ const isPaid = statusRaw === "COMPLETED" || eventType === "payment.completed";
6393
+ const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED";
6394
+ const isFailed = statusRaw === "FAILED" || statusRaw === "CANCELED";
6395
+ const isExpired = eventType === "payment.expired";
6396
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
6397
+ return {
6398
+ isValid,
6399
+ provider: "square",
6400
+ orderId: String(orderId),
6401
+ amount,
6402
+ status,
6403
+ isPaid,
6404
+ isPending,
6405
+ isFailed,
6406
+ isExpired,
6407
+ statusCode: eventType || statusRaw,
6408
+ rawPayload: parsedBody
6409
+ };
6410
+ }
6411
+ async getPaymentMethods(params, config) {
6412
+ const methods = [
6413
+ { paymentMethod: "credit_card", code: "card", paymentName: "Credit / Debit Card (Visa, Mastercard, Amex, JCB)", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "Kartu Kredit" },
6414
+ { paymentMethod: "apple_pay", code: "applepay", paymentName: "Apple Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
6415
+ { paymentMethod: "google_pay", code: "googlepay", paymentName: "Google Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
6416
+ { paymentMethod: "cash_app", code: "cashapp", paymentName: "Cash App Pay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "2.9% + $0.30", category: "E-Wallet" },
6417
+ { paymentMethod: "afterpay", code: "afterpay", paymentName: "Afterpay / Clearpay", paymentImage: "https://squareup.com/favicon.ico", totalFee: "6% + $0.30", category: "Paylater / Cicilan" }
6418
+ ];
6419
+ const categories = {};
6420
+ for (const item of methods) {
6421
+ if (!categories[item.category]) categories[item.category] = [];
6422
+ categories[item.category].push(item);
6423
+ }
6424
+ return { success: true, provider: "square", methods, categories, rawResponse: methods };
6425
+ }
6426
+ async checkTransaction(params, config) {
6427
+ const { merchantOrderId } = params;
6428
+ const baseUrl = this.getBaseUrl(config);
6429
+ const headers = this.buildHeaders(config);
6430
+ try {
6431
+ const response = await fetch(`${baseUrl}/v2/payments/${encodeURIComponent(merchantOrderId)}`, {
6432
+ method: "GET",
6433
+ headers
6434
+ });
6435
+ const text = await response.text();
6436
+ let data = null;
6437
+ try {
6438
+ data = JSON.parse(text);
6439
+ } catch (e) {
6440
+ }
6441
+ if (!response.ok || !data || data.errors?.length) {
6442
+ return {
6443
+ success: false,
6444
+ provider: "square",
6445
+ orderId: merchantOrderId,
6446
+ reference: "",
6447
+ amount: 0,
6448
+ statusCode: response.status.toString(),
6449
+ status: "failed",
6450
+ isPaid: false,
6451
+ isPending: false,
6452
+ isFailed: true,
6453
+ isExpired: false,
6454
+ statusMessage: data?.errors?.[0]?.detail || "HTTP Error",
6455
+ rawResponse: data
6456
+ };
6457
+ }
6458
+ const payment = data.payment || data;
6459
+ const statusRaw = (payment.status || "").toUpperCase();
6460
+ const isPaid = statusRaw === "COMPLETED";
6461
+ const isPending = statusRaw === "PENDING" || statusRaw === "APPROVED";
6462
+ const isExpired = statusRaw === "CANCELED";
6463
+ const isFailed = statusRaw === "FAILED";
6464
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
6465
+ return {
6466
+ success: true,
6467
+ provider: "square",
6468
+ orderId: payment.reference_id || merchantOrderId,
6469
+ reference: payment.id || merchantOrderId,
6470
+ amount: Number(payment.amount_money?.amount || 0),
6471
+ statusCode: statusRaw,
6472
+ status,
6473
+ isPaid,
6474
+ isPending,
6475
+ isFailed,
6476
+ isExpired,
6477
+ statusMessage: statusRaw,
6478
+ paymentType: payment.source_type || "card",
6479
+ transactionTime: payment.created_at ? new Date(payment.created_at) : void 0,
6480
+ rawResponse: data
6481
+ };
6482
+ } catch (e) {
6483
+ return {
6484
+ success: false,
6485
+ provider: "square",
6486
+ orderId: merchantOrderId,
6487
+ reference: "",
6488
+ amount: 0,
6489
+ statusCode: "ERROR",
6490
+ status: "failed",
6491
+ isPaid: false,
6492
+ isPending: false,
6493
+ isFailed: true,
6494
+ isExpired: false,
6495
+ statusMessage: e.message,
6496
+ error: e.message,
6497
+ rawResponse: null
6498
+ };
6499
+ }
6500
+ }
6501
+ };
6502
+
6503
+ // src/providers/payu/signature.ts
6504
+ import { createHash } from "crypto";
6505
+ function verifyPayuWebhook(rawBody, signatureHeader, md5Key) {
6506
+ if (!md5Key || !signatureHeader || !rawBody) return false;
6507
+ try {
6508
+ const parts = {};
6509
+ for (const part of signatureHeader.split(";")) {
6510
+ const [k, v] = part.split("=");
6511
+ if (k && v) parts[k.trim()] = v.trim();
6512
+ }
6513
+ const providedSig = parts["signature"];
6514
+ const algorithm = (parts["algorithm"] || "MD5").toUpperCase();
6515
+ if (algorithm === "MD5") {
6516
+ const expected = createHash("md5").update(rawBody + md5Key).digest("hex");
6517
+ return expected === providedSig;
6518
+ } else if (algorithm === "SHA-256") {
6519
+ const expected = createHash("sha256").update(rawBody + md5Key).digest("hex");
6520
+ return expected === providedSig;
6521
+ }
6522
+ return false;
6523
+ } catch {
6524
+ return false;
6525
+ }
6526
+ }
6527
+ function buildPayuBasicAuth(clientId, clientSecret) {
6528
+ return Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
6529
+ }
6530
+
6531
+ // src/providers/payu/provider.ts
6532
+ var PayuProvider = class extends BasePaymentProvider {
6533
+ name = "payu";
6534
+ getBaseUrl(config) {
6535
+ return config.sandbox !== false ? "https://secure.snd.payu.com" : "https://secure.payu.com";
6536
+ }
6537
+ /** OAuth2 Bearer Token untuk PayU */
6538
+ async getAccessToken(config) {
6539
+ const clientId = config.extra?.oauthClientId || config.clientKey || "";
6540
+ const clientSecret = config.extra?.oauthClientSecret || config.apiKey || config.secretKey || "";
6541
+ if (!clientId || !clientSecret) {
6542
+ return "";
6543
+ }
6544
+ const baseUrl = this.getBaseUrl(config);
6545
+ const response = await fetch(`${baseUrl}/pl/standard/user/oauth/authorize`, {
6546
+ method: "POST",
6547
+ headers: {
6548
+ "Authorization": `Basic ${buildPayuBasicAuth(clientId, clientSecret)}`,
6549
+ "Content-Type": "application/x-www-form-urlencoded"
6550
+ },
6551
+ body: "grant_type=client_credentials"
6552
+ });
6553
+ const text = await response.text();
6554
+ let data = null;
6555
+ try {
6556
+ data = JSON.parse(text);
6557
+ } catch (e) {
6558
+ }
6559
+ if (!response.ok || !data?.access_token) {
6560
+ throw new Error(data?.error_description || `Failed to get PayU access token: ${response.status}`);
6561
+ }
6562
+ return data.access_token;
6563
+ }
6564
+ async createInvoice(params, config) {
6565
+ const { orderId, amount, productDetails, customer, returnUrl, callbackUrl } = params;
6566
+ const currency = (params.currency || "PLN").toUpperCase();
6567
+ const posId = config.merchantCode || config.merchantId || config.extra?.posId || "";
6568
+ const baseUrl = this.getBaseUrl(config);
6569
+ let accessToken;
6570
+ try {
6571
+ accessToken = await this.getAccessToken(config);
6572
+ } catch (e) {
6573
+ return { success: false, provider: "payu", orderId, amount, error: e.message, rawResponse: null };
6574
+ }
6575
+ const isDirect = !!params.paymentMethod;
6576
+ const continueUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
6577
+ const notifyUrl = callbackUrl || config.callbackUrl || "";
6578
+ const body = {
6579
+ notifyUrl,
6580
+ customerIp: params.providerParams?.customerIp || "127.0.0.1",
6581
+ merchantPosId: posId,
6582
+ description: productDetails,
6583
+ currencyCode: currency,
6584
+ totalAmount: amount.toString(),
6585
+ extOrderId: orderId,
6586
+ continueUrl,
6587
+ buyer: {
6588
+ email: customer?.email,
6589
+ firstName: customer?.name?.split(" ")[0],
6590
+ lastName: customer?.name?.split(" ").slice(1).join(" ") || "-",
6591
+ phone: customer?.phone,
6592
+ language: "en"
6593
+ },
6594
+ products: [
6595
+ { name: productDetails, unitPrice: amount.toString(), quantity: "1" }
6596
+ ],
6597
+ ...params.providerParams
6598
+ };
6599
+ if (isDirect && params.paymentMethod) {
6600
+ body.payMethods = {
6601
+ payMethod: {
6602
+ type: "PBL",
6603
+ value: params.paymentMethod
6604
+ // e.g. "blik", "c" (card), "ap" (Apple Pay)
6605
+ }
6606
+ };
6607
+ }
6608
+ try {
6609
+ const response = await fetch(`${baseUrl}/api/v2_1/orders`, {
6610
+ method: "POST",
6611
+ headers: {
6612
+ "Authorization": `Bearer ${accessToken}`,
6613
+ "Content-Type": "application/json"
6614
+ },
6615
+ body: JSON.stringify(body),
6616
+ redirect: "manual"
6617
+ // PayU responds with 302
6618
+ });
6619
+ const text = await response.text();
6620
+ let data = null;
6621
+ try {
6622
+ data = JSON.parse(text);
6623
+ } catch (e) {
6624
+ }
6625
+ if (response.status === 302 || response.headers.get("location")) {
6626
+ const location = response.headers.get("location") || "";
6627
+ return {
6628
+ success: true,
6629
+ provider: "payu",
6630
+ orderId,
6631
+ amount,
6632
+ reference: data?.orderId || orderId,
6633
+ paymentUrl: location,
6634
+ rawResponse: data
6635
+ };
6636
+ }
6637
+ if (!response.ok || !data || data.status?.statusCode === "ERROR") {
6638
+ return { success: false, provider: "payu", orderId, amount, rawResponse: data, error: data?.status?.statusDesc || `HTTP ${response.status}` };
6639
+ }
6640
+ return {
6641
+ success: true,
6642
+ provider: "payu",
6643
+ orderId,
6644
+ amount,
6645
+ reference: data.orderId || orderId,
6646
+ paymentUrl: data.redirectUri,
6647
+ rawResponse: data
6648
+ };
6649
+ } catch (e) {
6650
+ return { success: false, provider: "payu", orderId, amount, error: e.message, rawResponse: null };
6651
+ }
6652
+ }
6653
+ async verifyCallback(body, config) {
6654
+ const md5Key = config.extra?.md5Key || config.apiKey || config.secretKey || "";
6655
+ const signatureHeader = config.extra?.signatureHeader || "";
6656
+ const rawBody = typeof body === "string" ? body : JSON.stringify(body);
6657
+ const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
6658
+ const isValid = signatureHeader ? verifyPayuWebhook(rawBody, signatureHeader, md5Key) : true;
6659
+ const order = parsedBody?.order || parsedBody;
6660
+ const orderId = order.extOrderId || order.orderId || "";
6661
+ const amount = Number(order.totalAmount || 0);
6662
+ const statusRaw = (order.status || "").toUpperCase();
6663
+ const isPaid = statusRaw === "COMPLETED";
6664
+ const isPending = statusRaw === "PENDING" || statusRaw === "WAITING_FOR_CONFIRMATION";
6665
+ const isFailed = statusRaw === "CANCELED" || statusRaw === "REJECTED";
6666
+ const isExpired = false;
6667
+ const status = isPaid ? "paid" : isPending ? "pending" : "failed";
6668
+ return {
6669
+ isValid,
6670
+ provider: "payu",
6671
+ orderId: String(orderId),
6672
+ amount,
6673
+ status,
6674
+ isPaid,
6675
+ isPending,
6676
+ isFailed,
6677
+ isExpired,
6678
+ statusCode: statusRaw,
6679
+ rawPayload: parsedBody
6680
+ };
6681
+ }
6682
+ async getPaymentMethods(params, config) {
6683
+ const methods = [
6684
+ { paymentMethod: "credit_card", code: "c", paymentName: "Credit / Debit Card", paymentImage: "https://payu.com/favicon.ico", totalFee: "1.5%+", category: "Kartu Kredit" },
6685
+ { paymentMethod: "blik", code: "blik", paymentName: "BLIK (Poland)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Fixed fee", category: "E-Wallet" },
6686
+ { paymentMethod: "apple_pay", code: "ap", paymentName: "Apple Pay", paymentImage: "https://payu.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
6687
+ { paymentMethod: "google_pay", code: "gp", paymentName: "Google Pay", paymentImage: "https://payu.com/favicon.ico", totalFee: "Card fee", category: "E-Wallet" },
6688
+ { paymentMethod: "bank_transfer", code: "t", paymentName: "Online Bank Transfer (50+ banks)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Fixed fee", category: "Virtual Account" },
6689
+ { paymentMethod: "installment", code: "ai", paymentName: "Installments (PayU)", paymentImage: "https://payu.com/favicon.ico", totalFee: "Bank rate", category: "Paylater / Cicilan" }
6690
+ ];
6691
+ const categories = {};
6692
+ for (const item of methods) {
6693
+ if (!categories[item.category]) categories[item.category] = [];
6694
+ categories[item.category].push(item);
6695
+ }
6696
+ return { success: true, provider: "payu", methods, categories, rawResponse: methods };
6697
+ }
6698
+ async checkTransaction(params, config) {
6699
+ const { merchantOrderId } = params;
6700
+ const baseUrl = this.getBaseUrl(config);
6701
+ let accessToken;
6702
+ try {
6703
+ accessToken = await this.getAccessToken(config);
6704
+ } catch (e) {
6705
+ return {
6706
+ success: false,
6707
+ provider: "payu",
6708
+ orderId: merchantOrderId,
6709
+ reference: "",
6710
+ amount: 0,
6711
+ statusCode: "AUTH_ERROR",
6712
+ status: "failed",
6713
+ isPaid: false,
6714
+ isPending: false,
6715
+ isFailed: true,
6716
+ isExpired: false,
6717
+ statusMessage: e.message,
6718
+ error: e.message,
6719
+ rawResponse: null
6720
+ };
6721
+ }
6722
+ try {
6723
+ const response = await fetch(`${baseUrl}/api/v2_1/orders/${encodeURIComponent(merchantOrderId)}`, {
6724
+ method: "GET",
6725
+ headers: { "Authorization": `Bearer ${accessToken}`, "Content-Type": "application/json" }
6726
+ });
6727
+ const text = await response.text();
6728
+ let data = null;
6729
+ try {
6730
+ data = JSON.parse(text);
6731
+ } catch (e) {
6732
+ }
6733
+ if (!response.ok || !data) {
6734
+ return {
6735
+ success: false,
6736
+ provider: "payu",
6737
+ orderId: merchantOrderId,
6738
+ reference: "",
6739
+ amount: 0,
6740
+ statusCode: response.status.toString(),
6741
+ status: "failed",
6742
+ isPaid: false,
6743
+ isPending: false,
6744
+ isFailed: true,
6745
+ isExpired: false,
6746
+ statusMessage: "HTTP Error",
6747
+ rawResponse: data
6748
+ };
6749
+ }
6750
+ const order = data.orders?.[0] || data;
6751
+ const statusRaw = (order.status || "").toUpperCase();
6752
+ const isPaid = statusRaw === "COMPLETED";
6753
+ const isPending = statusRaw === "PENDING" || statusRaw === "WAITING_FOR_CONFIRMATION";
6754
+ const isFailed = statusRaw === "CANCELED" || statusRaw === "REJECTED";
6755
+ const isExpired = false;
6756
+ const status = isPaid ? "paid" : isPending ? "pending" : "failed";
6757
+ return {
6758
+ success: true,
6759
+ provider: "payu",
6760
+ orderId: order.extOrderId || merchantOrderId,
6761
+ reference: order.orderId || merchantOrderId,
6762
+ amount: Number(order.totalAmount || 0),
6763
+ statusCode: statusRaw,
6764
+ status,
6765
+ isPaid,
6766
+ isPending,
6767
+ isFailed,
6768
+ isExpired,
6769
+ statusMessage: statusRaw,
6770
+ transactionTime: order.orderCreateDate ? new Date(order.orderCreateDate) : void 0,
6771
+ rawResponse: data
6772
+ };
6773
+ } catch (e) {
6774
+ return {
6775
+ success: false,
6776
+ provider: "payu",
6777
+ orderId: merchantOrderId,
6778
+ reference: "",
6779
+ amount: 0,
6780
+ statusCode: "ERROR",
6781
+ status: "failed",
6782
+ isPaid: false,
6783
+ isPending: false,
6784
+ isFailed: true,
6785
+ isExpired: false,
6786
+ statusMessage: e.message,
6787
+ error: e.message,
6788
+ rawResponse: null
6789
+ };
6790
+ }
6791
+ }
6792
+ };
6793
+
6794
+ // src/providers/braintree/signature.ts
6795
+ import { createHash as createHash2, createHmac as createHmac6 } from "crypto";
6796
+ function verifyBraintreeWebhook(btSignature, btPayload, privateKey) {
6797
+ if (!privateKey || !btSignature || !btPayload) return false;
6798
+ try {
6799
+ const parts = btSignature.split("|");
6800
+ if (parts.length < 2) return false;
6801
+ const providedHmac = parts[1];
6802
+ const payload = Buffer.from(btPayload, "base64").toString("utf8");
6803
+ const secretHash = createHash2("sha1").update(privateKey).digest("hex");
6804
+ const expected = createHmac6("sha1", secretHash).update(payload).digest("hex");
6805
+ return expected === providedHmac;
6806
+ } catch {
6807
+ return false;
6808
+ }
6809
+ }
6810
+ function buildBraintreeBasicAuth(publicKey, privateKey) {
6811
+ return Buffer.from(`${publicKey}:${privateKey}`).toString("base64");
6812
+ }
6813
+
6814
+ // src/providers/braintree/provider.ts
6815
+ var BraintreeProvider = class extends BasePaymentProvider {
6816
+ name = "braintree";
6817
+ getBaseUrl(config) {
6818
+ const merchantId = config.merchantCode || config.merchantId || "";
6819
+ const base = config.sandbox !== false ? "https://api.sandbox.braintreegateway.com" : "https://api.braintreegateway.com";
6820
+ return `${base}/merchants/${merchantId}`;
6821
+ }
6822
+ buildHeaders(config) {
6823
+ const publicKey = config.clientKey || config.extra?.publicKey || "";
6824
+ const privateKey = config.apiKey || config.secretKey || "";
6825
+ return {
6826
+ "Authorization": `Basic ${buildBraintreeBasicAuth(publicKey, privateKey)}`,
6827
+ "Content-Type": "application/json",
6828
+ "Braintree-Version": "2019-01-01"
6829
+ };
6830
+ }
6831
+ async createInvoice(params, config) {
6832
+ const { orderId, amount, productDetails, customer } = params;
6833
+ const currency = (params.currency || "USD").toUpperCase();
6834
+ const baseUrl = this.getBaseUrl(config);
6835
+ const headers = this.buildHeaders(config);
6836
+ const isDirect = !!params.paymentMethod;
6837
+ try {
6838
+ if (isDirect) {
6839
+ const paymentMethodNonce = params.providerParams?.nonce || params.providerParams?.paymentMethodNonce || "fake-valid-nonce";
6840
+ const body = {
6841
+ transaction: {
6842
+ amount: (amount / 100).toFixed(2),
6843
+ payment_method_nonce: paymentMethodNonce,
6844
+ order_id: orderId,
6845
+ currency_iso_code: currency,
6846
+ options: { submit_for_settlement: true },
6847
+ customer: { first_name: customer?.name, email: customer?.email },
6848
+ custom_fields: { order_id: orderId },
6849
+ ...params.providerParams
6850
+ }
6851
+ };
6852
+ const response = await fetch(`${baseUrl}/transactions`, {
6853
+ method: "POST",
6854
+ headers,
6855
+ body: JSON.stringify(body)
6856
+ });
6857
+ const text = await response.text();
6858
+ let data = null;
6859
+ try {
6860
+ data = JSON.parse(text);
6861
+ } catch (e) {
6862
+ }
6863
+ if (!response.ok || data?.apiErrorResponse) {
6864
+ return { success: false, provider: "braintree", orderId, amount, rawResponse: data, error: data?.apiErrorResponse?.message || `HTTP ${response.status}` };
6865
+ }
6866
+ const tx = data?.transaction || data;
6867
+ const statusRaw = (tx.status || "").toLowerCase();
6868
+ return {
6869
+ success: statusRaw === "submitted_for_settlement" || statusRaw === "settling" || statusRaw === "settled",
6870
+ provider: "braintree",
6871
+ orderId,
6872
+ amount: Math.round(Number(tx.amount || amount / 100) * 100),
6873
+ reference: tx.id,
6874
+ rawResponse: data
6875
+ };
6876
+ } else {
6877
+ const body = { client_token: { customer_id: customer?.email || orderId } };
6878
+ const response = await fetch(`${baseUrl}/client_token`, {
6879
+ method: "POST",
6880
+ headers,
6881
+ body: JSON.stringify(body)
6882
+ });
6883
+ const text = await response.text();
6884
+ let data = null;
6885
+ try {
6886
+ data = JSON.parse(text);
6887
+ } catch (e) {
6888
+ }
6889
+ if (!response.ok || !data?.clientToken) {
6890
+ return { success: false, provider: "braintree", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
6891
+ }
6892
+ return {
6893
+ success: true,
6894
+ provider: "braintree",
6895
+ orderId,
6896
+ amount,
6897
+ reference: orderId,
6898
+ paymentCode: data.clientToken,
6899
+ // Frontend uses this token for Drop-in UI
6900
+ rawResponse: data
6901
+ };
6902
+ }
6903
+ } catch (e) {
6904
+ return { success: false, provider: "braintree", orderId, amount, error: e.message, rawResponse: null };
6905
+ }
6906
+ }
6907
+ async verifyCallback(body, config) {
6908
+ const privateKey = config.apiKey || config.secretKey || "";
6909
+ const btSignature = config.extra?.btSignature || "";
6910
+ const btPayload = config.extra?.btPayload || "";
6911
+ const isValid = btSignature && btPayload ? verifyBraintreeWebhook(btSignature, btPayload, privateKey) : true;
6912
+ const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
6913
+ const subject = parsedBody?.subject || parsedBody;
6914
+ const transaction = subject?.transaction || subject?.disbursement || parsedBody;
6915
+ const kind = parsedBody?.kind || parsedBody?.event || "";
6916
+ const orderId = transaction?.orderId || transaction?.order_id || transaction?.id || "";
6917
+ const amount = Math.round(Number(transaction?.amount || 0) * 100);
6918
+ const statusRaw = (transaction?.status || "").toLowerCase();
6919
+ const isPaid = kind === "transaction_settled" || kind === "transaction_disbursed" || statusRaw === "settled";
6920
+ const isPending = kind === "transaction_settlement_declined" || statusRaw === "submitted_for_settlement" || statusRaw === "settling";
6921
+ const isFailed = kind === "transaction_failed" || statusRaw === "failed" || statusRaw === "voided";
6922
+ const isExpired = statusRaw === "expired";
6923
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
6924
+ return {
6925
+ isValid,
6926
+ provider: "braintree",
6927
+ orderId: String(orderId),
6928
+ amount,
6929
+ status,
6930
+ isPaid,
6931
+ isPending,
6932
+ isFailed,
6933
+ isExpired,
6934
+ statusCode: kind || statusRaw,
6935
+ rawPayload: parsedBody
6936
+ };
6937
+ }
6938
+ async getPaymentMethods(params, config) {
6939
+ const methods = [
6940
+ { paymentMethod: "credit_card", code: "CreditCard", paymentName: "Credit / Debit Card (Drop-in UI)", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "2.59% + $0.49", category: "Kartu Kredit" },
6941
+ { paymentMethod: "paypal", code: "PayPalAccount", paymentName: "PayPal (via Drop-in UI)", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "3.49% + fixed", category: "E-Wallet" },
6942
+ { paymentMethod: "apple_pay", code: "ApplePayCard", paymentName: "Apple Pay", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "Card network fee", category: "E-Wallet" },
6943
+ { paymentMethod: "google_pay", code: "AndroidPayCard", paymentName: "Google Pay", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "Card network fee", category: "E-Wallet" },
6944
+ { paymentMethod: "venmo", code: "VenmoAccount", paymentName: "Venmo (US only)", paymentImage: "https://www.braintreepayments.com/favicon.ico", totalFee: "1.9% + $0.10", category: "E-Wallet" }
6945
+ ];
6946
+ const categories = {};
6947
+ for (const item of methods) {
6948
+ if (!categories[item.category]) categories[item.category] = [];
6949
+ categories[item.category].push(item);
6950
+ }
6951
+ return { success: true, provider: "braintree", methods, categories, rawResponse: methods };
6952
+ }
6953
+ async checkTransaction(params, config) {
6954
+ const { merchantOrderId } = params;
6955
+ const baseUrl = this.getBaseUrl(config);
6956
+ const headers = this.buildHeaders(config);
6957
+ try {
6958
+ const response = await fetch(`${baseUrl}/transactions/${encodeURIComponent(merchantOrderId)}`, {
6959
+ method: "GET",
6960
+ headers
6961
+ });
6962
+ const text = await response.text();
6963
+ let data = null;
6964
+ try {
6965
+ data = JSON.parse(text);
6966
+ } catch (e) {
6967
+ }
6968
+ if (!response.ok || !data) {
6969
+ return {
6970
+ success: false,
6971
+ provider: "braintree",
6972
+ orderId: merchantOrderId,
6973
+ reference: "",
6974
+ amount: 0,
6975
+ statusCode: response.status.toString(),
6976
+ status: "failed",
6977
+ isPaid: false,
6978
+ isPending: false,
6979
+ isFailed: true,
6980
+ isExpired: false,
6981
+ statusMessage: "HTTP Error",
6982
+ rawResponse: data
6983
+ };
6984
+ }
6985
+ const tx = data.transaction || data;
6986
+ const statusRaw = (tx.status || "").toLowerCase();
6987
+ const isPaid = statusRaw === "settled" || statusRaw === "settling";
6988
+ const isPending = statusRaw === "submitted_for_settlement" || statusRaw === "authorized";
6989
+ const isExpired = statusRaw === "expired";
6990
+ const isFailed = statusRaw === "failed" || statusRaw === "voided";
6991
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
6992
+ return {
6993
+ success: true,
6994
+ provider: "braintree",
6995
+ orderId: tx.orderId || merchantOrderId,
6996
+ reference: tx.id || merchantOrderId,
6997
+ amount: Math.round(Number(tx.amount || 0) * 100),
6998
+ statusCode: statusRaw,
6999
+ status,
7000
+ isPaid,
7001
+ isPending,
7002
+ isFailed,
7003
+ isExpired,
7004
+ statusMessage: statusRaw,
7005
+ paymentType: tx.paymentInstrumentType || "card",
7006
+ transactionTime: tx.createdAt ? new Date(tx.createdAt) : void 0,
7007
+ rawResponse: data
7008
+ };
7009
+ } catch (e) {
7010
+ return {
7011
+ success: false,
7012
+ provider: "braintree",
7013
+ orderId: merchantOrderId,
7014
+ reference: "",
7015
+ amount: 0,
7016
+ statusCode: "ERROR",
7017
+ status: "failed",
7018
+ isPaid: false,
7019
+ isPending: false,
7020
+ isFailed: true,
7021
+ isExpired: false,
7022
+ statusMessage: e.message,
7023
+ error: e.message,
7024
+ rawResponse: null
7025
+ };
7026
+ }
7027
+ }
7028
+ };
7029
+
7030
+ // src/providers/twocheckout/signature.ts
7031
+ import { createHash as createHash3, createHmac as createHmac7 } from "crypto";
7032
+ function buildTwoCheckoutAuth(merchantCode, secretKey) {
7033
+ const date = Math.floor(Date.now() / 1e3).toString();
7034
+ const raw = merchantCode + date;
7035
+ const hmac = createHmac7("sha256", secretKey).update(raw).digest("hex");
7036
+ const header = `code="${merchantCode}" date="${date}" hash="${hmac}"`;
7037
+ return { header, date };
7038
+ }
7039
+ function verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, providedHash) {
7040
+ if (!secretWord || !providedHash) return false;
7041
+ try {
7042
+ const raw = secretWord + saleId + productId + invoiceId;
7043
+ const expected = createHash3("md5").update(raw).digest("hex").toUpperCase();
7044
+ return expected === (providedHash || "").toUpperCase();
7045
+ } catch {
7046
+ return false;
7047
+ }
7048
+ }
7049
+
7050
+ // src/providers/twocheckout/provider.ts
7051
+ var TwoCheckoutProvider = class extends BasePaymentProvider {
7052
+ name = "twocheckout";
7053
+ getBaseUrl(config) {
7054
+ return config.sandbox !== false ? "https://api.sandbox.2checkout.com/rest" : "https://api.2checkout.com/rest";
7055
+ }
7056
+ buildHeaders(config) {
7057
+ const merchantCode = config.merchantCode || config.merchantId || "";
7058
+ const secretKey = config.apiKey || config.secretKey || "";
7059
+ const { header } = buildTwoCheckoutAuth(merchantCode, secretKey);
7060
+ return {
7061
+ "X-Avangate-Authentication": header,
7062
+ "Content-Type": "application/json",
7063
+ "Accept": "application/json"
7064
+ };
7065
+ }
7066
+ async createInvoice(params, config) {
7067
+ const { orderId, amount, productDetails, customer, returnUrl } = params;
7068
+ const currency = (params.currency || "USD").toUpperCase();
7069
+ const baseUrl = this.getBaseUrl(config);
7070
+ const headers = this.buildHeaders(config);
7071
+ const isDirect = !!params.paymentMethod;
7072
+ const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
7073
+ const body = {
7074
+ Currency: currency,
7075
+ Language: "en",
7076
+ Country: config.extra?.country || "US",
7077
+ CustomerIP: params.providerParams?.customerIp || "127.0.0.1",
7078
+ Source: "API",
7079
+ MerchantReference: orderId,
7080
+ Items: [
7081
+ {
7082
+ Name: productDetails,
7083
+ Quantity: 1,
7084
+ Price: { Amount: (amount / 100).toFixed(2), Type: "CUSTOM" },
7085
+ Type: "PRODUCT",
7086
+ IsDynamic: true,
7087
+ Tangible: false
7088
+ }
7089
+ ],
7090
+ BillingDetails: {
7091
+ FirstName: customer?.name?.split(" ")[0] || "Customer",
7092
+ LastName: customer?.name?.split(" ").slice(1).join(" ") || "Name",
7093
+ Email: customer?.email,
7094
+ Country: config.extra?.country || "US",
7095
+ Address1: config.extra?.address || "N/A",
7096
+ City: config.extra?.city || "N/A",
7097
+ State: config.extra?.state || "",
7098
+ Zip: config.extra?.zip || "00000"
7099
+ },
7100
+ ...params.providerParams
7101
+ };
7102
+ if (!isDirect) {
7103
+ body.PaymentDetails = { Type: "EES_TOKEN_PAYMENT", Currency: currency };
7104
+ } else {
7105
+ body.PaymentDetails = { Type: params.paymentMethod === "paypal" ? "PAYPAL" : "EES_TOKEN_PAYMENT", Currency: currency };
7106
+ }
7107
+ try {
7108
+ const response = await fetch(`${baseUrl}/6.0/orders`, {
7109
+ method: "POST",
7110
+ headers,
7111
+ body: JSON.stringify(body)
7112
+ });
7113
+ const text = await response.text();
7114
+ let data = null;
7115
+ try {
7116
+ data = JSON.parse(text);
7117
+ } catch (e) {
7118
+ }
7119
+ if (!response.ok || !data || data.error_code) {
7120
+ return { success: false, provider: "twocheckout", orderId, amount, rawResponse: data, error: data?.message || `HTTP ${response.status}` };
7121
+ }
7122
+ const paymentUrl = data.PaymentDetails?.PaymentMethod?.RedirectURL || data.PaymentDetails?.PaymentMethod?.Href || `${successUrl}?ref=${data.RefNo}`;
7123
+ return {
7124
+ success: true,
7125
+ provider: "twocheckout",
7126
+ orderId,
7127
+ amount,
7128
+ reference: data.RefNo || data.OrderNo?.toString(),
7129
+ paymentUrl,
7130
+ rawResponse: data
7131
+ };
7132
+ } catch (e) {
7133
+ return { success: false, provider: "twocheckout", orderId, amount, error: e.message, rawResponse: null };
7134
+ }
7135
+ }
7136
+ async verifyCallback(body, config) {
7137
+ const secretWord = config.extra?.secretWord || config.apiKey || "";
7138
+ const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
7139
+ const saleId = parsedBody?.SALE_ID || parsedBody?.sale_id || "";
7140
+ const productId = parsedBody?.IPN_PID?.[0] || parsedBody?.product_id || "";
7141
+ const invoiceId = parsedBody?.IPN_PNAME?.[0] || parsedBody?.invoice_id || "";
7142
+ const providedHash = parsedBody?.HASH || parsedBody?.hash || "";
7143
+ const isValid = secretWord ? verifyTwoCheckoutWebhook(secretWord, saleId, productId, invoiceId, providedHash) : true;
7144
+ const orderId = parsedBody?.REFNOEXT || parsedBody?.ext_ref_no || parsedBody?.SALE_ID || "";
7145
+ const amount = Math.round(Number(parsedBody?.IPN_TOTAL_GENERAL || parsedBody?.total || 0) * 100);
7146
+ const statusRaw = (parsedBody?.ORDERSTATUS || parsedBody?.order_status || "").toUpperCase();
7147
+ const isPaid = statusRaw === "COMPLETE" || statusRaw === "COMPLETE_MANUAL";
7148
+ const isPending = statusRaw === "PENDING" || statusRaw === "PURCHASE_PENDING";
7149
+ const isFailed = statusRaw === "CANCELED" || statusRaw === "REFUND" || statusRaw === "FRAUD";
7150
+ const isExpired = statusRaw === "EXPIRED";
7151
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
7152
+ return {
7153
+ isValid,
7154
+ provider: "twocheckout",
7155
+ orderId: String(orderId),
7156
+ amount,
7157
+ status,
7158
+ isPaid,
7159
+ isPending,
7160
+ isFailed,
7161
+ isExpired,
7162
+ statusCode: statusRaw,
7163
+ rawPayload: parsedBody
7164
+ };
7165
+ }
7166
+ async getPaymentMethods(params, config) {
7167
+ const methods = [
7168
+ { paymentMethod: "credit_card", code: "EES_TOKEN_PAYMENT", paymentName: "Credit / Debit Card (Visa, Mastercard, Amex)", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "3.5% + $0.35", category: "Kartu Kredit" },
7169
+ { paymentMethod: "paypal", code: "PAYPAL", paymentName: "PayPal", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "3.5% + $0.35", category: "E-Wallet" },
7170
+ { paymentMethod: "wire_transfer", code: "WIRE", paymentName: "Wire Transfer / Bank Transfer", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "Fixed fee", category: "Virtual Account" },
7171
+ { paymentMethod: "paylater", code: "PAY_LATER", paymentName: "Buy Now Pay Later (Klarna)", paymentImage: "https://www.2checkout.com/favicon.ico", totalFee: "Variable", category: "Paylater / Cicilan" }
7172
+ ];
7173
+ const categories = {};
7174
+ for (const item of methods) {
7175
+ if (!categories[item.category]) categories[item.category] = [];
7176
+ categories[item.category].push(item);
7177
+ }
7178
+ return { success: true, provider: "twocheckout", methods, categories, rawResponse: methods };
7179
+ }
7180
+ async checkTransaction(params, config) {
7181
+ const { merchantOrderId } = params;
7182
+ const baseUrl = this.getBaseUrl(config);
7183
+ const headers = this.buildHeaders(config);
7184
+ try {
7185
+ const response = await fetch(`${baseUrl}/6.0/orders/${encodeURIComponent(merchantOrderId)}`, {
7186
+ method: "GET",
7187
+ headers
7188
+ });
7189
+ const text = await response.text();
7190
+ let data = null;
7191
+ try {
7192
+ data = JSON.parse(text);
7193
+ } catch (e) {
7194
+ }
7195
+ if (!response.ok || !data || data.error_code) {
7196
+ return {
7197
+ success: false,
7198
+ provider: "twocheckout",
7199
+ orderId: merchantOrderId,
7200
+ reference: "",
7201
+ amount: 0,
7202
+ statusCode: response.status.toString(),
7203
+ status: "failed",
7204
+ isPaid: false,
7205
+ isPending: false,
7206
+ isFailed: true,
7207
+ isExpired: false,
7208
+ statusMessage: data?.message || "HTTP Error",
7209
+ rawResponse: data
7210
+ };
7211
+ }
7212
+ const statusRaw = (data.Status || "").toUpperCase();
7213
+ const isPaid = statusRaw === "COMPLETE";
7214
+ const isPending = statusRaw === "PENDING" || statusRaw === "PURCHASE_PENDING";
7215
+ const isExpired = statusRaw === "EXPIRED";
7216
+ const isFailed = statusRaw === "CANCELED" || statusRaw === "REFUND";
7217
+ const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
7218
+ return {
7219
+ success: true,
7220
+ provider: "twocheckout",
7221
+ orderId: data.ExternalReference || merchantOrderId,
7222
+ reference: data.RefNo?.toString() || merchantOrderId,
7223
+ amount: Math.round(Number(data.GrossAmount || 0) * 100),
7224
+ statusCode: statusRaw,
7225
+ status,
7226
+ isPaid,
7227
+ isPending,
7228
+ isFailed,
7229
+ isExpired,
7230
+ statusMessage: statusRaw,
7231
+ transactionTime: data.OrderDate ? new Date(data.OrderDate) : void 0,
7232
+ rawResponse: data
7233
+ };
7234
+ } catch (e) {
7235
+ return {
7236
+ success: false,
7237
+ provider: "twocheckout",
7238
+ orderId: merchantOrderId,
7239
+ reference: "",
7240
+ amount: 0,
7241
+ statusCode: "ERROR",
7242
+ status: "failed",
7243
+ isPaid: false,
7244
+ isPending: false,
7245
+ isFailed: true,
7246
+ isExpired: false,
7247
+ statusMessage: e.message,
7248
+ error: e.message,
7249
+ rawResponse: null
7250
+ };
7251
+ }
7252
+ }
7253
+ };
7254
+
5270
7255
  // src/clients/duitku.ts
5271
7256
  var DuitkuClient = class {
5272
7257
  merchantCode;
@@ -6032,6 +8017,533 @@ var StripeClient = class {
6032
8017
  }
6033
8018
  };
6034
8019
 
8020
+ // src/clients/paypal.ts
8021
+ var PaypalClient = class {
8022
+ config;
8023
+ constructor(config) {
8024
+ this.config = config;
8025
+ }
8026
+ getBaseUrl() {
8027
+ return this.config.sandbox !== false ? "https://api-m.sandbox.paypal.com" : "https://api-m.paypal.com";
8028
+ }
8029
+ async getAccessToken() {
8030
+ const clientId = this.config.clientKey || this.config.merchantCode || this.config.merchantId || "";
8031
+ const clientSecret = this.config.apiKey || this.config.secretKey || "";
8032
+ const auth = buildPaypalBasicAuth(clientId, clientSecret);
8033
+ const response = await fetch(`${this.getBaseUrl()}/v1/oauth2/token`, {
8034
+ method: "POST",
8035
+ headers: { "Authorization": `Basic ${auth}`, "Content-Type": "application/x-www-form-urlencoded" },
8036
+ body: "grant_type=client_credentials"
8037
+ });
8038
+ const data = await response.json();
8039
+ if (!data?.access_token) throw new Error(data?.error_description || "Failed to get PayPal access token");
8040
+ return data.access_token;
8041
+ }
8042
+ /** Ambil detail order PayPal berdasarkan Order ID */
8043
+ async getOrder(orderId) {
8044
+ const token = await this.getAccessToken();
8045
+ const response = await fetch(`${this.getBaseUrl()}/v2/checkout/orders/${orderId}`, {
8046
+ headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
8047
+ });
8048
+ return response.json();
8049
+ }
8050
+ /** Capture order PayPal (mengeksekusi pembayaran yang sudah diapprove buyer) */
8051
+ async captureOrder(orderId) {
8052
+ const token = await this.getAccessToken();
8053
+ const response = await fetch(`${this.getBaseUrl()}/v2/checkout/orders/${orderId}/capture`, {
8054
+ method: "POST",
8055
+ headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
8056
+ body: "{}"
8057
+ });
8058
+ return response.json();
8059
+ }
8060
+ /** Refund capture PayPal */
8061
+ async refundCapture(captureId, amount, currency) {
8062
+ const token = await this.getAccessToken();
8063
+ const body = {};
8064
+ if (amount && currency) {
8065
+ body.amount = { value: (amount / 100).toFixed(2), currency_code: currency };
8066
+ body.note_to_payer = "Refund";
8067
+ }
8068
+ const response = await fetch(`${this.getBaseUrl()}/v2/payments/captures/${captureId}/refund`, {
8069
+ method: "POST",
8070
+ headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
8071
+ body: JSON.stringify(body)
8072
+ });
8073
+ return response.json();
8074
+ }
8075
+ /** Cek saldo akun PayPal merchant (hanya tersedia di account via Seller REST API) */
8076
+ async checkBalance() {
8077
+ const token = await this.getAccessToken();
8078
+ const response = await fetch(`${this.getBaseUrl()}/v1/reporting/balances`, {
8079
+ headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
8080
+ });
8081
+ return response.json();
8082
+ }
8083
+ /** Verifikasi webhook via PayPal Webhook Verification API */
8084
+ async verifyWebhookSignature(webhookId, body, headers) {
8085
+ const token = await this.getAccessToken();
8086
+ const verifyBody = {
8087
+ auth_algo: headers["paypal-auth-algo"],
8088
+ cert_url: headers["paypal-cert-url"],
8089
+ transmission_id: headers["paypal-transmission-id"],
8090
+ transmission_sig: headers["paypal-transmission-sig"],
8091
+ transmission_time: headers["paypal-transmission-time"],
8092
+ webhook_id: webhookId,
8093
+ webhook_event: typeof body === "string" ? JSON.parse(body) : body
8094
+ };
8095
+ const response = await fetch(`${this.getBaseUrl()}/v1/notifications/verify-webhook-signature`, {
8096
+ method: "POST",
8097
+ headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
8098
+ body: JSON.stringify(verifyBody)
8099
+ });
8100
+ const data = await response.json();
8101
+ return data?.verification_status === "SUCCESS";
8102
+ }
8103
+ };
8104
+
8105
+ // src/clients/adyen.ts
8106
+ var AdyenClient = class {
8107
+ config;
8108
+ constructor(config) {
8109
+ this.config = config;
8110
+ }
8111
+ getBaseUrl() {
8112
+ if (this.config.sandbox === false) {
8113
+ const prefix = this.config.extra?.liveUrlPrefix || this.config.projectId || "";
8114
+ if (prefix) return `https://${prefix}-checkout-live.adyenpayments.com/checkout`;
8115
+ }
8116
+ return "https://checkout-test.adyen.com";
8117
+ }
8118
+ buildHeaders() {
8119
+ return {
8120
+ "X-API-Key": this.config.apiKey || this.config.secretKey || "",
8121
+ "Content-Type": "application/json"
8122
+ };
8123
+ }
8124
+ /** Ambil detail payment berdasarkan PSP Reference */
8125
+ async getPaymentDetails(pspReference) {
8126
+ const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}`, {
8127
+ method: "GET",
8128
+ headers: this.buildHeaders()
8129
+ });
8130
+ return response.json();
8131
+ }
8132
+ /** Batalkan payment (sebelum capture) */
8133
+ async cancelPayment(pspReference, merchantAccount) {
8134
+ const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
8135
+ const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/cancels`, {
8136
+ method: "POST",
8137
+ headers: this.buildHeaders(),
8138
+ body: JSON.stringify({ merchantAccount: account })
8139
+ });
8140
+ return response.json();
8141
+ }
8142
+ /** Refund payment yang sudah di-capture */
8143
+ async refundPayment(pspReference, amount, currency, merchantAccount) {
8144
+ const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
8145
+ const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/refunds`, {
8146
+ method: "POST",
8147
+ headers: this.buildHeaders(),
8148
+ body: JSON.stringify({
8149
+ merchantAccount: account,
8150
+ amount: { value: amount, currency }
8151
+ })
8152
+ });
8153
+ return response.json();
8154
+ }
8155
+ /** Capture authorized payment */
8156
+ async capturePayment(pspReference, amount, currency, merchantAccount) {
8157
+ const account = merchantAccount || this.config.merchantCode || this.config.merchantId || "";
8158
+ const response = await fetch(`${this.getBaseUrl()}/v68/payments/${pspReference}/captures`, {
8159
+ method: "POST",
8160
+ headers: this.buildHeaders(),
8161
+ body: JSON.stringify({
8162
+ merchantAccount: account,
8163
+ amount: { value: amount, currency }
8164
+ })
8165
+ });
8166
+ return response.json();
8167
+ }
8168
+ /** Ambil daftar payment methods yang tersedia */
8169
+ async getAvailablePaymentMethods(merchantAccount, countryCode, currency, amount) {
8170
+ const response = await fetch(`${this.getBaseUrl()}/v68/paymentMethods`, {
8171
+ method: "POST",
8172
+ headers: this.buildHeaders(),
8173
+ body: JSON.stringify({ merchantAccount, countryCode, channel: "Web", amount: { value: amount, currency } })
8174
+ });
8175
+ return response.json();
8176
+ }
8177
+ };
8178
+
8179
+ // src/clients/checkoutcom.ts
8180
+ var CheckoutComClient = class {
8181
+ config;
8182
+ constructor(config) {
8183
+ this.config = config;
8184
+ }
8185
+ getBaseUrl() {
8186
+ return this.config.sandbox !== false ? "https://api.sandbox.checkout.com" : "https://api.checkout.com";
8187
+ }
8188
+ buildHeaders() {
8189
+ return {
8190
+ "Authorization": `Bearer ${this.config.apiKey || this.config.secretKey || ""}`,
8191
+ "Content-Type": "application/json"
8192
+ };
8193
+ }
8194
+ /** Ambil detail payment berdasarkan Payment ID */
8195
+ async getPaymentDetails(paymentId) {
8196
+ const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}`, {
8197
+ method: "GET",
8198
+ headers: this.buildHeaders()
8199
+ });
8200
+ return response.json();
8201
+ }
8202
+ /** Void (batalkan) payment yang belum di-capture */
8203
+ async voidPayment(paymentId, reference) {
8204
+ const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/voids`, {
8205
+ method: "POST",
8206
+ headers: this.buildHeaders(),
8207
+ body: JSON.stringify({ reference })
8208
+ });
8209
+ return response.json();
8210
+ }
8211
+ /** Refund payment yang sudah di-capture */
8212
+ async refundPayment(paymentId, amount, reference) {
8213
+ const body = { reference };
8214
+ if (amount) body.amount = amount;
8215
+ const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/refunds`, {
8216
+ method: "POST",
8217
+ headers: this.buildHeaders(),
8218
+ body: JSON.stringify(body)
8219
+ });
8220
+ return response.json();
8221
+ }
8222
+ /** Cek saldo merchant di Checkout.com */
8223
+ async checkBalance() {
8224
+ const response = await fetch(`${this.getBaseUrl()}/balances`, {
8225
+ method: "GET",
8226
+ headers: this.buildHeaders()
8227
+ });
8228
+ return response.json();
8229
+ }
8230
+ /** Ambil daftar payment links */
8231
+ async listPaymentLinks() {
8232
+ const response = await fetch(`${this.getBaseUrl()}/payment-links`, {
8233
+ method: "GET",
8234
+ headers: this.buildHeaders()
8235
+ });
8236
+ return response.json();
8237
+ }
8238
+ };
8239
+
8240
+ // src/clients/razorpay.ts
8241
+ var RazorpayClient = class {
8242
+ config;
8243
+ constructor(config) {
8244
+ this.config = config;
8245
+ }
8246
+ getBaseUrl() {
8247
+ return "https://api.razorpay.com/v1";
8248
+ }
8249
+ buildHeaders() {
8250
+ const keyId = this.config.clientKey || this.config.merchantCode || this.config.merchantId || "";
8251
+ const keySecret = this.config.apiKey || this.config.secretKey || "";
8252
+ return {
8253
+ "Authorization": `Basic ${buildRazorpayBasicAuth(keyId, keySecret)}`,
8254
+ "Content-Type": "application/json"
8255
+ };
8256
+ }
8257
+ /** Ambil detail payment */
8258
+ async fetchPayment(paymentId) {
8259
+ const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}`, {
8260
+ method: "GET",
8261
+ headers: this.buildHeaders()
8262
+ });
8263
+ return response.json();
8264
+ }
8265
+ /** Capture authorized payment */
8266
+ async capturePayment(paymentId, amount, currency) {
8267
+ const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/capture`, {
8268
+ method: "POST",
8269
+ headers: this.buildHeaders(),
8270
+ body: JSON.stringify({ amount, currency: currency || "INR" })
8271
+ });
8272
+ return response.json();
8273
+ }
8274
+ /** Buat refund untuk payment */
8275
+ async createRefund(paymentId, amount, notes) {
8276
+ const body = { notes };
8277
+ if (amount) body.amount = amount;
8278
+ const response = await fetch(`${this.getBaseUrl()}/payments/${paymentId}/refund`, {
8279
+ method: "POST",
8280
+ headers: this.buildHeaders(),
8281
+ body: JSON.stringify(body)
8282
+ });
8283
+ return response.json();
8284
+ }
8285
+ /** Cek saldo akun Razorpay */
8286
+ async checkBalance() {
8287
+ const response = await fetch(`${this.getBaseUrl()}/balance`, {
8288
+ method: "GET",
8289
+ headers: this.buildHeaders()
8290
+ });
8291
+ return response.json();
8292
+ }
8293
+ /** Ambil daftar semua payment */
8294
+ async listPayments(from, to, count) {
8295
+ const params = new URLSearchParams();
8296
+ if (from) params.set("from", from.toString());
8297
+ if (to) params.set("to", to.toString());
8298
+ if (count) params.set("count", count.toString());
8299
+ const response = await fetch(`${this.getBaseUrl()}/payments?${params}`, {
8300
+ method: "GET",
8301
+ headers: this.buildHeaders()
8302
+ });
8303
+ return response.json();
8304
+ }
8305
+ };
8306
+
8307
+ // src/clients/square.ts
8308
+ var SquareClient = class {
8309
+ config;
8310
+ constructor(config) {
8311
+ this.config = config;
8312
+ }
8313
+ getBaseUrl() {
8314
+ return this.config.sandbox !== false ? "https://connect.squareupsandbox.com" : "https://connect.squareup.com";
8315
+ }
8316
+ buildHeaders() {
8317
+ return {
8318
+ "Authorization": `Bearer ${this.config.apiKey || this.config.secretKey || ""}`,
8319
+ "Content-Type": "application/json",
8320
+ "Square-Version": "2024-01-17"
8321
+ };
8322
+ }
8323
+ /** Ambil detail payment Square */
8324
+ async getPayment(paymentId) {
8325
+ const response = await fetch(`${this.getBaseUrl()}/v2/payments/${paymentId}`, {
8326
+ method: "GET",
8327
+ headers: this.buildHeaders()
8328
+ });
8329
+ return response.json();
8330
+ }
8331
+ /** Batalkan payment Square */
8332
+ async cancelPayment(paymentId) {
8333
+ const response = await fetch(`${this.getBaseUrl()}/v2/payments/${paymentId}/cancel`, {
8334
+ method: "POST",
8335
+ headers: this.buildHeaders(),
8336
+ body: "{}"
8337
+ });
8338
+ return response.json();
8339
+ }
8340
+ /** Refund payment Square */
8341
+ async refundPayment(paymentId, amount, currency, idempotencyKey, reason) {
8342
+ const response = await fetch(`${this.getBaseUrl()}/v2/refunds`, {
8343
+ method: "POST",
8344
+ headers: this.buildHeaders(),
8345
+ body: JSON.stringify({
8346
+ idempotency_key: idempotencyKey,
8347
+ payment_id: paymentId,
8348
+ amount_money: { amount, currency },
8349
+ reason
8350
+ })
8351
+ });
8352
+ return response.json();
8353
+ }
8354
+ /** Ambil saldo location Square */
8355
+ async retrieveBalance(locationId) {
8356
+ const id = locationId || this.config.extra?.locationId || this.config.projectId || "";
8357
+ const response = await fetch(`${this.getBaseUrl()}/v2/locations/${id}`, {
8358
+ method: "GET",
8359
+ headers: this.buildHeaders()
8360
+ });
8361
+ return response.json();
8362
+ }
8363
+ /** List semua locations merchant */
8364
+ async listLocations() {
8365
+ const response = await fetch(`${this.getBaseUrl()}/v2/locations`, {
8366
+ method: "GET",
8367
+ headers: this.buildHeaders()
8368
+ });
8369
+ return response.json();
8370
+ }
8371
+ };
8372
+
8373
+ // src/clients/payu.ts
8374
+ var PayuClient = class {
8375
+ config;
8376
+ accessToken = null;
8377
+ constructor(config) {
8378
+ this.config = config;
8379
+ }
8380
+ getBaseUrl() {
8381
+ return this.config.sandbox !== false ? "https://secure.snd.payu.com" : "https://secure.payu.com";
8382
+ }
8383
+ async getToken() {
8384
+ if (this.accessToken) return this.accessToken;
8385
+ const clientId = this.config.extra?.oauthClientId || this.config.clientKey || "";
8386
+ const clientSecret = this.config.extra?.oauthClientSecret || this.config.apiKey || this.config.secretKey || "";
8387
+ const response = await fetch(`${this.getBaseUrl()}/pl/standard/user/oauth/authorize`, {
8388
+ method: "POST",
8389
+ headers: { "Authorization": `Basic ${buildPayuBasicAuth(clientId, clientSecret)}`, "Content-Type": "application/x-www-form-urlencoded" },
8390
+ body: "grant_type=client_credentials"
8391
+ });
8392
+ const data = await response.json();
8393
+ if (!data?.access_token) throw new Error("Failed to get PayU access token");
8394
+ this.accessToken = data.access_token;
8395
+ return this.accessToken;
8396
+ }
8397
+ /** Ambil detail order PayU */
8398
+ async getOrder(orderId) {
8399
+ const token = await this.getToken();
8400
+ const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}`, {
8401
+ headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
8402
+ });
8403
+ return response.json();
8404
+ }
8405
+ /** Batalkan order PayU */
8406
+ async cancelOrder(orderId) {
8407
+ const token = await this.getToken();
8408
+ const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}`, {
8409
+ method: "DELETE",
8410
+ headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" }
8411
+ });
8412
+ return response.json();
8413
+ }
8414
+ /** Refund order PayU */
8415
+ async refundOrder(orderId, amount, description) {
8416
+ const token = await this.getToken();
8417
+ const body = { refund: { description: description || "Refund" } };
8418
+ if (amount) body.refund.amount = amount;
8419
+ const response = await fetch(`${this.getBaseUrl()}/api/v2_1/orders/${orderId}/refunds`, {
8420
+ method: "POST",
8421
+ headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
8422
+ body: JSON.stringify(body)
8423
+ });
8424
+ return response.json();
8425
+ }
8426
+ };
8427
+
8428
+ // src/clients/braintree.ts
8429
+ var BraintreeClient = class {
8430
+ config;
8431
+ constructor(config) {
8432
+ this.config = config;
8433
+ }
8434
+ getBaseUrl() {
8435
+ const merchantId = this.config.merchantCode || this.config.merchantId || "";
8436
+ const base = this.config.sandbox !== false ? "https://api.sandbox.braintreegateway.com" : "https://api.braintreegateway.com";
8437
+ return `${base}/merchants/${merchantId}`;
8438
+ }
8439
+ buildHeaders() {
8440
+ const publicKey = this.config.clientKey || this.config.extra?.publicKey || "";
8441
+ const privateKey = this.config.apiKey || this.config.secretKey || "";
8442
+ return {
8443
+ "Authorization": `Basic ${buildBraintreeBasicAuth(publicKey, privateKey)}`,
8444
+ "Content-Type": "application/json",
8445
+ "Braintree-Version": "2019-01-01"
8446
+ };
8447
+ }
8448
+ /** Generate Client Token untuk frontend Drop-in UI */
8449
+ async getClientToken(customerId) {
8450
+ const body = {};
8451
+ if (customerId) body.client_token = { customer_id: customerId };
8452
+ const response = await fetch(`${this.getBaseUrl()}/client_token`, {
8453
+ method: "POST",
8454
+ headers: this.buildHeaders(),
8455
+ body: JSON.stringify(body)
8456
+ });
8457
+ const data = await response.json();
8458
+ return data.clientToken || "";
8459
+ }
8460
+ /** Ambil detail transaction */
8461
+ async findTransaction(transactionId) {
8462
+ const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}`, {
8463
+ method: "GET",
8464
+ headers: this.buildHeaders()
8465
+ });
8466
+ return response.json();
8467
+ }
8468
+ /** Refund transaction Braintree */
8469
+ async refundTransaction(transactionId, amount) {
8470
+ const body = {};
8471
+ if (amount) body.transaction = { amount: (amount / 100).toFixed(2) };
8472
+ const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}/refund`, {
8473
+ method: "POST",
8474
+ headers: this.buildHeaders(),
8475
+ body: JSON.stringify(body)
8476
+ });
8477
+ return response.json();
8478
+ }
8479
+ /** Void (batalkan) transaction sebelum settlement */
8480
+ async voidTransaction(transactionId) {
8481
+ const response = await fetch(`${this.getBaseUrl()}/transactions/${transactionId}/void`, {
8482
+ method: "PUT",
8483
+ headers: this.buildHeaders(),
8484
+ body: "{}"
8485
+ });
8486
+ return response.json();
8487
+ }
8488
+ };
8489
+
8490
+ // src/clients/twocheckout.ts
8491
+ var TwoCheckoutClient = class {
8492
+ config;
8493
+ constructor(config) {
8494
+ this.config = config;
8495
+ }
8496
+ getBaseUrl() {
8497
+ return this.config.sandbox !== false ? "https://api.sandbox.2checkout.com/rest" : "https://api.2checkout.com/rest";
8498
+ }
8499
+ buildHeaders() {
8500
+ const merchantCode = this.config.merchantCode || this.config.merchantId || "";
8501
+ const secretKey = this.config.apiKey || this.config.secretKey || "";
8502
+ const { header } = buildTwoCheckoutAuth(merchantCode, secretKey);
8503
+ return {
8504
+ "X-Avangate-Authentication": header,
8505
+ "Content-Type": "application/json",
8506
+ "Accept": "application/json"
8507
+ };
8508
+ }
8509
+ /** Ambil detail order 2Checkout berdasarkan Reference Number */
8510
+ async getOrder(refNo) {
8511
+ const response = await fetch(`${this.getBaseUrl()}/6.0/orders/${refNo}`, {
8512
+ method: "GET",
8513
+ headers: this.buildHeaders()
8514
+ });
8515
+ return response.json();
8516
+ }
8517
+ /** Refund order 2Checkout */
8518
+ async refundOrder(refNo, amount, comment) {
8519
+ const response = await fetch(`${this.getBaseUrl()}/6.0/orders/${refNo}/refund`, {
8520
+ method: "POST",
8521
+ headers: this.buildHeaders(),
8522
+ body: JSON.stringify({ amount, comment: comment || "Refund", reason: "NOT_SATISFIED" })
8523
+ });
8524
+ return response.json();
8525
+ }
8526
+ /** Ambil detail subscription */
8527
+ async getSubscription(subscriptionRef) {
8528
+ const response = await fetch(`${this.getBaseUrl()}/6.0/subscriptions/${subscriptionRef}`, {
8529
+ method: "GET",
8530
+ headers: this.buildHeaders()
8531
+ });
8532
+ return response.json();
8533
+ }
8534
+ /** List semua orders merchant */
8535
+ async listOrders(page, limit) {
8536
+ const params = new URLSearchParams({
8537
+ Pagination: JSON.stringify({ Page: page || 1, Limit: limit || 10 })
8538
+ });
8539
+ const response = await fetch(`${this.getBaseUrl()}/6.0/orders?${params}`, {
8540
+ method: "GET",
8541
+ headers: this.buildHeaders()
8542
+ });
8543
+ return response.json();
8544
+ }
8545
+ };
8546
+
6035
8547
  // src/core/manager.ts
6036
8548
  var PaymentManager = class {
6037
8549
  providers = /* @__PURE__ */ new Map();
@@ -6047,6 +8559,14 @@ var PaymentManager = class {
6047
8559
  this.registerProvider(new NicepayProvider());
6048
8560
  this.registerProvider(new OyProvider());
6049
8561
  this.registerProvider(new StripeProvider());
8562
+ this.registerProvider(new PaypalProvider());
8563
+ this.registerProvider(new AdyenProvider());
8564
+ this.registerProvider(new CheckoutComProvider());
8565
+ this.registerProvider(new RazorpayProvider());
8566
+ this.registerProvider(new SquareProvider());
8567
+ this.registerProvider(new PayuProvider());
8568
+ this.registerProvider(new BraintreeProvider());
8569
+ this.registerProvider(new TwoCheckoutProvider());
6050
8570
  }
6051
8571
  registerProvider(provider) {
6052
8572
  this.providers.set(provider.name.toLowerCase(), provider);
@@ -6058,6 +8578,7 @@ var PaymentManager = class {
6058
8578
  }
6059
8579
  return provider;
6060
8580
  }
8581
+ // ─── Indonesian Provider Getters ──────────────────────────────────────────
6061
8582
  getMidtransProvider() {
6062
8583
  return this.getProvider("midtrans");
6063
8584
  }
@@ -6118,12 +8639,62 @@ var PaymentManager = class {
6118
8639
  getOyClient(config) {
6119
8640
  return new OyClient(config);
6120
8641
  }
8642
+ // ─── International Provider Getters ─────────────────────────────────────
6121
8643
  getStripeProvider() {
6122
8644
  return this.getProvider("stripe");
6123
8645
  }
6124
8646
  getStripeClient(config) {
6125
8647
  return new StripeClient(config);
6126
8648
  }
8649
+ getPaypalProvider() {
8650
+ return this.getProvider("paypal");
8651
+ }
8652
+ getPaypalClient(config) {
8653
+ return new PaypalClient(config);
8654
+ }
8655
+ getAdyenProvider() {
8656
+ return this.getProvider("adyen");
8657
+ }
8658
+ getAdyenClient(config) {
8659
+ return new AdyenClient(config);
8660
+ }
8661
+ getCheckoutComProvider() {
8662
+ return this.getProvider("checkoutcom");
8663
+ }
8664
+ getCheckoutComClient(config) {
8665
+ return new CheckoutComClient(config);
8666
+ }
8667
+ getRazorpayProvider() {
8668
+ return this.getProvider("razorpay");
8669
+ }
8670
+ getRazorpayClient(config) {
8671
+ return new RazorpayClient(config);
8672
+ }
8673
+ getSquareProvider() {
8674
+ return this.getProvider("square");
8675
+ }
8676
+ getSquareClient(config) {
8677
+ return new SquareClient(config);
8678
+ }
8679
+ getPayuProvider() {
8680
+ return this.getProvider("payu");
8681
+ }
8682
+ getPayuClient(config) {
8683
+ return new PayuClient(config);
8684
+ }
8685
+ getBraintreeProvider() {
8686
+ return this.getProvider("braintree");
8687
+ }
8688
+ getBraintreeClient(config) {
8689
+ return new BraintreeClient(config);
8690
+ }
8691
+ getTwoCheckoutProvider() {
8692
+ return this.getProvider("twocheckout");
8693
+ }
8694
+ getTwoCheckoutClient(config) {
8695
+ return new TwoCheckoutClient(config);
8696
+ }
8697
+ // ─── Unified Operations ──────────────────────────────────────────────────
6127
8698
  async createInvoice(providerName, params, config) {
6128
8699
  const provider = this.getProvider(providerName);
6129
8700
  return provider.createInvoice(params, config);
@@ -6183,6 +8754,22 @@ function resolveConfigFromEnv(customConfig) {
6183
8754
  sandbox = env.OY_SANDBOX === "true" || env.OY_SANDBOX === "1";
6184
8755
  } else if (env.STRIPE_SANDBOX !== void 0) {
6185
8756
  sandbox = env.STRIPE_SANDBOX === "true" || env.STRIPE_SANDBOX === "1";
8757
+ } else if (env.PAYPAL_SANDBOX !== void 0) {
8758
+ sandbox = env.PAYPAL_SANDBOX === "true" || env.PAYPAL_SANDBOX === "1";
8759
+ } else if (env.ADYEN_SANDBOX !== void 0) {
8760
+ sandbox = env.ADYEN_SANDBOX === "true" || env.ADYEN_SANDBOX === "1";
8761
+ } else if (env.CHECKOUTCOM_SANDBOX !== void 0) {
8762
+ sandbox = env.CHECKOUTCOM_SANDBOX === "true" || env.CHECKOUTCOM_SANDBOX === "1";
8763
+ } else if (env.RAZORPAY_SANDBOX !== void 0) {
8764
+ sandbox = env.RAZORPAY_SANDBOX === "true" || env.RAZORPAY_SANDBOX === "1";
8765
+ } else if (env.SQUARE_SANDBOX !== void 0) {
8766
+ sandbox = env.SQUARE_SANDBOX === "true" || env.SQUARE_SANDBOX === "1";
8767
+ } else if (env.PAYU_SANDBOX !== void 0) {
8768
+ sandbox = env.PAYU_SANDBOX === "true" || env.PAYU_SANDBOX === "1";
8769
+ } else if (env.BRAINTREE_SANDBOX !== void 0) {
8770
+ sandbox = env.BRAINTREE_SANDBOX === "true" || env.BRAINTREE_SANDBOX === "1";
8771
+ } else if (env.TWOCHECKOUT_SANDBOX !== void 0) {
8772
+ sandbox = env.TWOCHECKOUT_SANDBOX === "true" || env.TWOCHECKOUT_SANDBOX === "1";
6186
8773
  } else {
6187
8774
  sandbox = env.NODE_ENV !== "production";
6188
8775
  }
@@ -6210,6 +8797,22 @@ function resolveConfigFromEnv(customConfig) {
6210
8797
  apiKey = env.OY_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
6211
8798
  } else if (provider === "stripe") {
6212
8799
  apiKey = env.STRIPE_SECRET_KEY || env.STRIPE_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
8800
+ } else if (provider === "paypal") {
8801
+ apiKey = env.PAYPAL_CLIENT_SECRET || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
8802
+ } else if (provider === "adyen") {
8803
+ apiKey = env.ADYEN_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
8804
+ } else if (provider === "checkoutcom") {
8805
+ apiKey = env.CHECKOUTCOM_SECRET_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
8806
+ } else if (provider === "razorpay") {
8807
+ apiKey = env.RAZORPAY_KEY_SECRET || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
8808
+ } else if (provider === "square") {
8809
+ apiKey = env.SQUARE_ACCESS_TOKEN || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
8810
+ } else if (provider === "payu") {
8811
+ apiKey = env.PAYU_MD5_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
8812
+ } else if (provider === "braintree") {
8813
+ apiKey = env.BRAINTREE_PRIVATE_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
8814
+ } else if (provider === "twocheckout" || provider === "2checkout") {
8815
+ apiKey = env.TWOCHECKOUT_SECRET_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
6213
8816
  } else {
6214
8817
  apiKey = env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY || env.PG_SECRET_KEY || env.BUAYAR_SECRET_KEY;
6215
8818
  }
@@ -6247,26 +8850,63 @@ function resolveConfigFromEnv(customConfig) {
6247
8850
  } else if (provider === "stripe") {
6248
8851
  clientKey = clientKey || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY || env.BUAYAR_CLIENT_KEY || env.BUAYAR_PUBLIC_KEY;
6249
8852
  merchantCode = merchantCode || clientKey || "stripe";
8853
+ } else if (provider === "paypal") {
8854
+ clientKey = clientKey || env.PAYPAL_CLIENT_ID || env.BUAYAR_CLIENT_KEY;
8855
+ merchantCode = merchantCode || env.PAYPAL_CLIENT_ID || env.BUAYAR_MERCHANT_CODE;
8856
+ } else if (provider === "adyen") {
8857
+ clientKey = clientKey || env.ADYEN_CLIENT_KEY || env.BUAYAR_CLIENT_KEY;
8858
+ merchantCode = merchantCode || env.ADYEN_MERCHANT_ACCOUNT || env.BUAYAR_MERCHANT_CODE;
8859
+ merchantId = merchantId || env.ADYEN_MERCHANT_ACCOUNT || env.BUAYAR_MERCHANT_ID;
8860
+ } else if (provider === "checkoutcom") {
8861
+ clientKey = clientKey || env.CHECKOUTCOM_PUBLIC_KEY || env.BUAYAR_CLIENT_KEY;
8862
+ merchantCode = merchantCode || env.BUAYAR_MERCHANT_CODE;
8863
+ } else if (provider === "razorpay") {
8864
+ clientKey = clientKey || env.RAZORPAY_KEY_ID || env.BUAYAR_CLIENT_KEY;
8865
+ merchantCode = merchantCode || env.RAZORPAY_KEY_ID || env.BUAYAR_MERCHANT_CODE;
8866
+ } else if (provider === "square") {
8867
+ clientKey = clientKey || env.SQUARE_APPLICATION_ID || env.BUAYAR_CLIENT_KEY;
8868
+ merchantCode = merchantCode || env.SQUARE_APPLICATION_ID || env.BUAYAR_MERCHANT_CODE;
8869
+ } else if (provider === "payu") {
8870
+ merchantCode = merchantCode || env.PAYU_POS_ID || env.BUAYAR_MERCHANT_CODE;
8871
+ merchantId = merchantId || env.PAYU_POS_ID;
8872
+ } else if (provider === "braintree") {
8873
+ clientKey = clientKey || env.BRAINTREE_PUBLIC_KEY || env.BUAYAR_CLIENT_KEY;
8874
+ merchantCode = merchantCode || env.BRAINTREE_MERCHANT_ID || env.BUAYAR_MERCHANT_CODE;
8875
+ merchantId = merchantId || env.BRAINTREE_MERCHANT_ID;
8876
+ } else if (provider === "twocheckout" || provider === "2checkout") {
8877
+ merchantCode = merchantCode || env.TWOCHECKOUT_MERCHANT_CODE || env.BUAYAR_MERCHANT_CODE;
8878
+ merchantId = merchantId || env.TWOCHECKOUT_MERCHANT_CODE;
6250
8879
  } else {
6251
8880
  merchantCode = merchantCode || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
6252
8881
  }
6253
- const projectId = customConfig?.projectId || env.BUAYAR_PROJECT_ID || env.PG_PROJECT_ID || env.PROJECT_ID;
6254
- const publicKey = customConfig?.publicKey || env.BUAYAR_PUBLIC_KEY || env.PG_PUBLIC_KEY || env.PUBLIC_KEY || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY;
6255
- const privateKey = customConfig?.privateKey || env.BUAYAR_PRIVATE_KEY || env.PG_PRIVATE_KEY || env.PRIVATE_KEY;
6256
- const secretKey = customConfig?.secretKey || env.BUAYAR_SECRET_KEY || env.PG_SECRET_KEY || env.SECRET_KEY || env.XENDIT_SECRET_KEY || env.DOKU_SECRET_KEY || env.PRISMALINK_SECRET_KEY || env.FASPAY_PASSWORD || env.FINPAY_MERCHANT_KEY || env.NICEPAY_KEY || env.OY_API_KEY || env.STRIPE_SECRET_KEY;
8882
+ const projectId = customConfig?.projectId || env.BUAYAR_PROJECT_ID || env.PG_PROJECT_ID || env.PROJECT_ID || env.SQUARE_LOCATION_ID;
8883
+ const publicKey = customConfig?.publicKey || env.BUAYAR_PUBLIC_KEY || env.PG_PUBLIC_KEY || env.PUBLIC_KEY || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY || env.CHECKOUTCOM_PUBLIC_KEY;
8884
+ const privateKey = customConfig?.privateKey || env.BUAYAR_PRIVATE_KEY || env.PG_PRIVATE_KEY || env.PRIVATE_KEY || env.BRAINTREE_PRIVATE_KEY;
8885
+ const secretKey = customConfig?.secretKey || env.BUAYAR_SECRET_KEY || env.PG_SECRET_KEY || env.SECRET_KEY || env.XENDIT_SECRET_KEY || env.DOKU_SECRET_KEY || env.PRISMALINK_SECRET_KEY || env.FASPAY_PASSWORD || env.FINPAY_MERCHANT_KEY || env.NICEPAY_KEY || env.OY_API_KEY || env.STRIPE_SECRET_KEY || env.PAYPAL_CLIENT_SECRET || env.CHECKOUTCOM_SECRET_KEY || env.RAZORPAY_KEY_SECRET || env.SQUARE_ACCESS_TOKEN || env.BRAINTREE_PRIVATE_KEY || env.TWOCHECKOUT_SECRET_KEY;
6257
8886
  const callbackUrl = customConfig?.callbackUrl || env.BUAYAR_CALLBACK_URL || env.PG_CALLBACK_URL || env.PAYMENT_CALLBACK_URL;
6258
8887
  const returnUrl = customConfig?.returnUrl || env.BUAYAR_RETURN_URL || env.PG_RETURN_URL || env.PAYMENT_RETURN_URL;
6259
8888
  const extra = {
6260
8889
  webhookToken: env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
6261
- webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
8890
+ webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.CHECKOUTCOM_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
6262
8891
  merchantName: env.FASPAY_MERCHANT_NAME || env.BUAYAR_MERCHANT_NAME,
6263
8892
  userId: env.FASPAY_USER_ID,
6264
8893
  iMid: env.NICEPAY_IMID,
6265
8894
  username: env.OY_USERNAME,
8895
+ hmacKey: env.ADYEN_HMAC_KEY,
8896
+ liveUrlPrefix: env.ADYEN_LIVE_URL_PREFIX,
8897
+ webhookId: env.PAYPAL_WEBHOOK_ID,
8898
+ merchantAccount: env.ADYEN_MERCHANT_ACCOUNT,
8899
+ md5Key: env.PAYU_MD5_KEY,
8900
+ oauthClientId: env.PAYU_OAUTH_CLIENT_ID,
8901
+ oauthClientSecret: env.PAYU_OAUTH_CLIENT_SECRET,
8902
+ locationId: env.SQUARE_LOCATION_ID,
8903
+ webhookSignatureKey: env.SQUARE_WEBHOOK_SIGNATURE_KEY,
8904
+ publicKey: env.BRAINTREE_PUBLIC_KEY || env.ADYEN_CLIENT_KEY,
8905
+ secretWord: env.TWOCHECKOUT_SECRET_WORD,
6266
8906
  ...customConfig?.extra
6267
8907
  };
6268
8908
  return {
6269
- provider: provider === "oyindonesia" ? "oy" : provider,
8909
+ provider: provider === "oyindonesia" ? "oy" : provider === "2checkout" ? "twocheckout" : provider,
6270
8910
  apiKey: apiKey || "",
6271
8911
  serverKey: apiKey || "",
6272
8912
  secretKey: secretKey || apiKey || "",
@@ -6304,7 +8944,7 @@ var Buayar = class {
6304
8944
  this.config = resolveConfigFromEnv({ ...this.config, ...config });
6305
8945
  }
6306
8946
  /**
6307
- * Dapatkan nama provider aktif ('midtrans' | 'duitku' | 'ipaymu' | 'xendit' | 'doku' | 'prismalink' | 'faspay' | 'finpay' | 'nicepay' | 'oy' | 'stripe' | ...)
8947
+ * Dapatkan nama provider aktif
6308
8948
  */
6309
8949
  get provider() {
6310
8950
  return this.config.provider || "midtrans";
@@ -6353,10 +8993,37 @@ var Buayar = class {
6353
8993
  async verifyWebhook(payload, headers, configOverride) {
6354
8994
  const mergedConfig = { ...this.config, ...configOverride };
6355
8995
  if (headers) {
6356
- const sigHeader = headers["stripe-signature"] || headers["Stripe-Signature"];
6357
- if (sigHeader) {
8996
+ const stripeSig = headers["stripe-signature"] || headers["Stripe-Signature"];
8997
+ if (stripeSig) {
8998
+ if (!mergedConfig.extra) mergedConfig.extra = {};
8999
+ mergedConfig.extra.signatureHeader = Array.isArray(stripeSig) ? stripeSig[0] : stripeSig;
9000
+ }
9001
+ const ckoSig = headers["cko-signature"] || headers["Cko-Signature"];
9002
+ if (ckoSig) {
9003
+ if (!mergedConfig.extra) mergedConfig.extra = {};
9004
+ mergedConfig.extra.signatureHeader = Array.isArray(ckoSig) ? ckoSig[0] : ckoSig;
9005
+ }
9006
+ const rzpSig = headers["x-razorpay-signature"] || headers["X-Razorpay-Signature"];
9007
+ if (rzpSig) {
9008
+ if (!mergedConfig.extra) mergedConfig.extra = {};
9009
+ mergedConfig.extra.signatureHeader = Array.isArray(rzpSig) ? rzpSig[0] : rzpSig;
9010
+ }
9011
+ const squareSig = headers["x-square-hmacsha256-signature"] || headers["x-square-signature"];
9012
+ if (squareSig) {
9013
+ if (!mergedConfig.extra) mergedConfig.extra = {};
9014
+ mergedConfig.extra.signatureHeader = Array.isArray(squareSig) ? squareSig[0] : squareSig;
9015
+ }
9016
+ const payuSig = headers["openpayu-signature"] || headers["OpenPayU-Signature"];
9017
+ if (payuSig) {
9018
+ if (!mergedConfig.extra) mergedConfig.extra = {};
9019
+ mergedConfig.extra.signatureHeader = Array.isArray(payuSig) ? payuSig[0] : payuSig;
9020
+ }
9021
+ const btSig = headers["bt_signature"];
9022
+ const btPayload = headers["bt_payload"];
9023
+ if (btSig && btPayload) {
6358
9024
  if (!mergedConfig.extra) mergedConfig.extra = {};
6359
- mergedConfig.extra.signatureHeader = Array.isArray(sigHeader) ? sigHeader[0] : sigHeader;
9025
+ mergedConfig.extra.btSignature = Array.isArray(btSig) ? btSig[0] : btSig;
9026
+ mergedConfig.extra.btPayload = Array.isArray(btPayload) ? btPayload[0] : btPayload;
6360
9027
  }
6361
9028
  }
6362
9029
  let providerName = configOverride?.provider || this.provider;
@@ -6381,8 +9048,26 @@ var Buayar = class {
6381
9048
  providerName = "prismalink";
6382
9049
  } else if (payload.object === "event" || payload.type && payload.data?.object && payload.api_version) {
6383
9050
  providerName = "stripe";
9051
+ } else if (payload.event && payload.payload?.payment?.entity) {
9052
+ providerName = "razorpay";
6384
9053
  } else if (payload.external_id || payload.event?.startsWith("payment.") || payload.event?.startsWith("qr.") || payload.data?.reference_id) {
6385
9054
  providerName = "xendit";
9055
+ } else if (payload.event_type && payload.resource && (payload.event_type.startsWith("PAYMENT.") || payload.event_type.startsWith("CHECKOUT.ORDER."))) {
9056
+ providerName = "paypal";
9057
+ } else if (payload.notificationItems || payload.merchantAccountCode && payload.pspReference && payload.eventCode) {
9058
+ providerName = "adyen";
9059
+ } else if (payload.type && payload.data?._links && (payload.type.startsWith("payment_") || payload.type.startsWith("refund_"))) {
9060
+ providerName = "checkoutcom";
9061
+ } else if (payload.event && payload.payload?.payment?.entity) {
9062
+ providerName = "razorpay";
9063
+ } else if (payload.type && payload.data?.object?.status && payload.merchant_id) {
9064
+ providerName = "square";
9065
+ } else if (payload.order && payload.order?.status && payload.order?.extOrderId) {
9066
+ providerName = "payu";
9067
+ } else if (payload.kind && payload.subject?.transaction) {
9068
+ providerName = "braintree";
9069
+ } else if (payload.HASH && payload.REFNOEXT && payload.IPN_PID) {
9070
+ providerName = "twocheckout";
6386
9071
  }
6387
9072
  }
6388
9073
  return this.manager.verifyCallback(providerName, payload, mergedConfig);
@@ -6390,76 +9075,73 @@ var Buayar = class {
6390
9075
  async handleWebhook(payload, headers, configOverride) {
6391
9076
  return this.verifyWebhook(payload, headers, configOverride);
6392
9077
  }
9078
+ // ─── Indonesian Provider Client Getters ───────────────────────────────────
6393
9079
  getMidtransClient(configOverride) {
6394
- return new MidtransClient({
6395
- ...this.config,
6396
- ...configOverride
6397
- });
9080
+ return new MidtransClient({ ...this.config, ...configOverride });
6398
9081
  }
6399
9082
  getDuitkuClient(configOverride) {
6400
- return new DuitkuClient({
6401
- ...this.config,
6402
- ...configOverride
6403
- });
9083
+ return new DuitkuClient({ ...this.config, ...configOverride });
6404
9084
  }
6405
9085
  getIpaymuClient(configOverride) {
6406
- return new IpaymuClient({
6407
- ...this.config,
6408
- ...configOverride
6409
- });
9086
+ return new IpaymuClient({ ...this.config, ...configOverride });
6410
9087
  }
6411
9088
  getXenditClient(configOverride) {
6412
- return new XenditClient({
6413
- ...this.config,
6414
- ...configOverride
6415
- });
9089
+ return new XenditClient({ ...this.config, ...configOverride });
6416
9090
  }
6417
9091
  getDokuClient(configOverride) {
6418
- return new DokuClient({
6419
- ...this.config,
6420
- ...configOverride
6421
- });
9092
+ return new DokuClient({ ...this.config, ...configOverride });
6422
9093
  }
6423
9094
  getPrismalinkClient(configOverride) {
6424
- return new PrismalinkClient({
6425
- ...this.config,
6426
- ...configOverride
6427
- });
9095
+ return new PrismalinkClient({ ...this.config, ...configOverride });
6428
9096
  }
6429
9097
  getFaspayClient(configOverride) {
6430
- return new FaspayClient({
6431
- ...this.config,
6432
- ...configOverride
6433
- });
9098
+ return new FaspayClient({ ...this.config, ...configOverride });
6434
9099
  }
6435
9100
  getFinpayClient(configOverride) {
6436
- return new FinpayClient({
6437
- ...this.config,
6438
- ...configOverride
6439
- });
9101
+ return new FinpayClient({ ...this.config, ...configOverride });
6440
9102
  }
6441
9103
  getNicepayClient(configOverride) {
6442
- return new NicepayClient({
6443
- ...this.config,
6444
- ...configOverride
6445
- });
9104
+ return new NicepayClient({ ...this.config, ...configOverride });
6446
9105
  }
6447
9106
  getOyClient(configOverride) {
6448
- return new OyClient({
6449
- ...this.config,
6450
- ...configOverride
6451
- });
9107
+ return new OyClient({ ...this.config, ...configOverride });
6452
9108
  }
9109
+ // ─── International Provider Client Getters ────────────────────────────────
6453
9110
  getStripeClient(configOverride) {
6454
- return new StripeClient({
6455
- ...this.config,
6456
- ...configOverride
6457
- });
9111
+ return new StripeClient({ ...this.config, ...configOverride });
9112
+ }
9113
+ getPaypalClient(configOverride) {
9114
+ return new PaypalClient({ ...this.config, ...configOverride });
9115
+ }
9116
+ getAdyenClient(configOverride) {
9117
+ return new AdyenClient({ ...this.config, ...configOverride });
9118
+ }
9119
+ getCheckoutComClient(configOverride) {
9120
+ return new CheckoutComClient({ ...this.config, ...configOverride });
9121
+ }
9122
+ getRazorpayClient(configOverride) {
9123
+ return new RazorpayClient({ ...this.config, ...configOverride });
9124
+ }
9125
+ getSquareClient(configOverride) {
9126
+ return new SquareClient({ ...this.config, ...configOverride });
9127
+ }
9128
+ getPayuClient(configOverride) {
9129
+ return new PayuClient({ ...this.config, ...configOverride });
9130
+ }
9131
+ getBraintreeClient(configOverride) {
9132
+ return new BraintreeClient({ ...this.config, ...configOverride });
9133
+ }
9134
+ getTwoCheckoutClient(configOverride) {
9135
+ return new TwoCheckoutClient({ ...this.config, ...configOverride });
6458
9136
  }
6459
9137
  };
6460
9138
  var buayar = new Buayar();
6461
9139
  export {
9140
+ AdyenClient,
9141
+ AdyenProvider,
6462
9142
  BasePaymentProvider,
9143
+ BraintreeClient,
9144
+ BraintreeProvider,
6463
9145
  Buayar,
6464
9146
  CANONICAL_TO_DOKU,
6465
9147
  CANONICAL_TO_DUITKU,
@@ -6473,6 +9155,8 @@ export {
6473
9155
  CANONICAL_TO_STRIPE,
6474
9156
  CANONICAL_TO_XENDIT,
6475
9157
  CORE_API_METHODS,
9158
+ CheckoutComClient,
9159
+ CheckoutComProvider,
6476
9160
  DUITKU_TO_CANONICAL,
6477
9161
  DokuClient,
6478
9162
  DokuProvider,
@@ -6493,14 +9177,29 @@ export {
6493
9177
  OyClient,
6494
9178
  OyProvider,
6495
9179
  PaymentManager,
9180
+ PaypalClient,
9181
+ PaypalProvider,
9182
+ PayuClient,
9183
+ PayuProvider,
6496
9184
  PrismalinkClient,
6497
9185
  PrismalinkProvider,
9186
+ RazorpayClient,
9187
+ RazorpayProvider,
9188
+ SquareClient,
9189
+ SquareProvider,
6498
9190
  StripeClient,
6499
9191
  StripeProvider,
9192
+ TwoCheckoutClient,
9193
+ TwoCheckoutProvider,
6500
9194
  XenditClient,
6501
9195
  XenditProvider,
6502
9196
  buayar,
9197
+ buildBraintreeBasicAuth,
6503
9198
  buildCoreChargePayload,
9199
+ buildPaypalBasicAuth,
9200
+ buildPayuBasicAuth,
9201
+ buildRazorpayBasicAuth,
9202
+ buildTwoCheckoutAuth,
6504
9203
  formatNicepayTimestamp,
6505
9204
  generateDokuHeaders,
6506
9205
  generateFaspaySignature,
@@ -6520,6 +9219,7 @@ export {
6520
9219
  paymentManager,
6521
9220
  resolveConfigFromEnv,
6522
9221
  safeCompare,
9222
+ serializePaypalParams,
6523
9223
  serializeStripeParams,
6524
9224
  sha256,
6525
9225
  sha512,
@@ -6534,6 +9234,9 @@ export {
6534
9234
  toPrismalinkPaymentMethod,
6535
9235
  toStripePaymentMethod,
6536
9236
  toXenditPaymentMethod,
9237
+ verifyAdyenWebhook,
9238
+ verifyBraintreeWebhook,
9239
+ verifyCheckoutComWebhook,
6537
9240
  verifyDokuWebhookSignature,
6538
9241
  verifyDuitkuCallbackSignature,
6539
9242
  verifyFaspaySignature,
@@ -6541,7 +9244,12 @@ export {
6541
9244
  verifyIpaymuCallback,
6542
9245
  verifyNicepayWebhook,
6543
9246
  verifyOyWebhook,
9247
+ verifyPaypalWebhookSimple,
9248
+ verifyPayuWebhook,
6544
9249
  verifyPrismalinkSignature,
9250
+ verifyRazorpayWebhook,
9251
+ verifySquareWebhook,
6545
9252
  verifyStripeWebhook,
9253
+ verifyTwoCheckoutWebhook,
6546
9254
  verifyXenditWebhookToken
6547
9255
  };