@crediblemark/buayar 0.1.6 → 0.1.8

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.js CHANGED
@@ -32,6 +32,8 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  BasePaymentProvider: () => BasePaymentProvider,
34
34
  DuitkuProvider: () => DuitkuProvider,
35
+ MidtransClient: () => MidtransClient,
36
+ MidtransProvider: () => MidtransProvider,
35
37
  PaymentManager: () => PaymentManager,
36
38
  getPaymentMethodCategory: () => getPaymentMethodCategory,
37
39
  paymentManager: () => paymentManager
@@ -304,6 +306,701 @@ var DuitkuProvider = class extends BasePaymentProvider {
304
306
  };
305
307
  }
306
308
  }
309
+ async probePaymentMethods(config) {
310
+ const res = await this.getPaymentMethods({ amount: 1e4 }, config);
311
+ if (res.success) {
312
+ return { success: true, enabled: res.methods.map((m) => m.paymentMethod) };
313
+ }
314
+ return { success: false, enabled: [], error: res.error };
315
+ }
316
+ };
317
+
318
+ // src/providers/midtrans.ts
319
+ var import_crypto2 = __toESM(require("crypto"));
320
+
321
+ // src/clients/midtrans.ts
322
+ var MidtransClient = class {
323
+ apiKey;
324
+ sandbox;
325
+ constructor(config) {
326
+ this.apiKey = config.apiKey;
327
+ this.sandbox = config.sandbox;
328
+ }
329
+ getApiBaseUrl() {
330
+ return this.sandbox ? "https://api.sandbox.midtrans.com/v2" : "https://api.midtrans.com/v2";
331
+ }
332
+ async request(method, path, body) {
333
+ let url = path.startsWith("http") ? path : `${this.getApiBaseUrl()}${path}`;
334
+ if (!path.startsWith("http") && (path.startsWith("/v1/") || path.startsWith("/v2/"))) {
335
+ url = `${this.sandbox ? "https://api.sandbox.midtrans.com" : "https://api.midtrans.com"}${path}`;
336
+ }
337
+ const authHeader = `Basic ${Buffer.from(this.apiKey + ":").toString("base64")}`;
338
+ const headers = {
339
+ "Content-Type": "application/json",
340
+ "Accept": "application/json",
341
+ "Authorization": authHeader
342
+ };
343
+ const fetchOptions = {
344
+ method,
345
+ headers
346
+ };
347
+ if (body) {
348
+ fetchOptions.body = JSON.stringify(body);
349
+ }
350
+ const response = await fetch(url, fetchOptions);
351
+ const text = await response.text();
352
+ let data = null;
353
+ try {
354
+ data = JSON.parse(text);
355
+ } catch (e) {
356
+ }
357
+ if (!response.ok) {
358
+ throw new Error(data?.message || data?.status_message || `HTTP error! Status: ${response.status} - ${text}`);
359
+ }
360
+ return data || text;
361
+ }
362
+ // ─── TRANSACTION ACTIONS ─────────────────────────────────────────────────────
363
+ async cancelTransaction(orderId) {
364
+ return this.request("POST", `/${orderId}/cancel`, null);
365
+ }
366
+ async refundTransaction(orderId, payload) {
367
+ return this.request("POST", `/${orderId}/refund`, payload);
368
+ }
369
+ async expireTransaction(orderId) {
370
+ return this.request("POST", `/${orderId}/expire`, null);
371
+ }
372
+ async approveTransaction(orderId) {
373
+ return this.request("POST", `/${orderId}/approve`, null);
374
+ }
375
+ async denyTransaction(orderId) {
376
+ return this.request("POST", `/${orderId}/deny`, null);
377
+ }
378
+ async captureTransaction(transactionId, amount) {
379
+ const payload = amount ? { transaction_id: transactionId, gross_amount: Math.round(amount) } : { transaction_id: transactionId };
380
+ return this.request("POST", "/capture", payload);
381
+ }
382
+ // ─── GOPAY TOKENIZATION API ──────────────────────────────────────────────────
383
+ async linkPayAccount(payload) {
384
+ return this.request("POST", "/v2/pay/account", payload);
385
+ }
386
+ async getPayAccount(accountId) {
387
+ return this.request("GET", `/v2/pay/account/${accountId}`, null);
388
+ }
389
+ async unbindPayAccount(accountId) {
390
+ return this.request("POST", `/v2/pay/account/${accountId}/unbind`, null);
391
+ }
392
+ async getGoPayPromo(accountId, grossAmount, currency = "IDR") {
393
+ return this.request("GET", `/v2/gopay/promo/${accountId}?gross_amount=${grossAmount}&currency=${currency}`, null);
394
+ }
395
+ // ─── SUBSCRIPTION API ────────────────────────────────────────────────────────
396
+ async createSubscription(payload) {
397
+ return this.request("POST", "/v1/subscriptions", payload);
398
+ }
399
+ async getSubscription(subscriptionId) {
400
+ return this.request("GET", `/v1/subscriptions/${subscriptionId}`, null);
401
+ }
402
+ async updateSubscription(subscriptionId, payload) {
403
+ return this.request("PATCH", `/v1/subscriptions/${subscriptionId}`, payload);
404
+ }
405
+ async disableSubscription(subscriptionId) {
406
+ return this.request("POST", `/v1/subscriptions/${subscriptionId}/disable`, null);
407
+ }
408
+ async enableSubscription(subscriptionId) {
409
+ return this.request("POST", `/v1/subscriptions/${subscriptionId}/enable`, null);
410
+ }
411
+ // ─── PAYMENT LINK API ────────────────────────────────────────────────────────
412
+ async createPaymentLink(payload) {
413
+ return this.request("POST", "/v1/payment-links", payload);
414
+ }
415
+ async getPaymentLink(paymentLinkId) {
416
+ return this.request("GET", `/v1/payment-links/${paymentLinkId}`, null);
417
+ }
418
+ async deletePaymentLink(paymentLinkId) {
419
+ return this.request("DELETE", `/v1/payment-links/${paymentLinkId}`, null);
420
+ }
421
+ // ─── BALANCE API ─────────────────────────────────────────────────────────────
422
+ async getBalance() {
423
+ try {
424
+ return await this.request("GET", "/v1/balance", null);
425
+ } catch (e) {
426
+ try {
427
+ const irisUrl = `${this.sandbox ? "https://api.sandbox.midtrans.com" : "https://api.midtrans.com"}/iris/api/v1/balance`;
428
+ const authHeader = `Basic ${Buffer.from(this.apiKey + ":").toString("base64")}`;
429
+ const response = await fetch(irisUrl, {
430
+ method: "GET",
431
+ headers: {
432
+ "Accept": "application/json",
433
+ "Authorization": authHeader
434
+ }
435
+ });
436
+ const text = await response.text();
437
+ let data = null;
438
+ try {
439
+ data = JSON.parse(text);
440
+ } catch (err) {
441
+ }
442
+ if (response.ok) return data || text;
443
+ } catch (irisErr) {
444
+ }
445
+ throw e;
446
+ }
447
+ }
448
+ // ─── INVOICING API ───────────────────────────────────────────────────────────
449
+ async createBillingInvoice(payload) {
450
+ return this.request("POST", "/v1/invoices", payload);
451
+ }
452
+ async getBillingInvoice(invoiceId) {
453
+ return this.request("GET", `/v1/invoices/${invoiceId}`, null);
454
+ }
455
+ async voidBillingInvoice(invoiceId) {
456
+ return this.request("PATCH", `/v1/invoices/${invoiceId}/void`, null);
457
+ }
458
+ async convertBillingInvoice(invoiceId) {
459
+ return this.request("PATCH", `/v1/invoices/${invoiceId}/convert`, null);
460
+ }
461
+ };
462
+
463
+ // src/providers/midtrans.ts
464
+ var MidtransProvider = class extends BasePaymentProvider {
465
+ name = "midtrans";
466
+ getSnapBaseUrl(sandbox) {
467
+ return sandbox ? "https://app.sandbox.midtrans.com/snap/v1/transactions" : "https://app.midtrans.com/snap/v1/transactions";
468
+ }
469
+ getApiBaseUrl(sandbox) {
470
+ return sandbox ? "https://api.sandbox.midtrans.com/v2" : "https://api.midtrans.com/v2";
471
+ }
472
+ async createInvoice(params, config) {
473
+ const { orderId, amount, productDetails, customer, returnUrl } = params;
474
+ const { apiKey, sandbox } = config;
475
+ const integerAmount = Math.round(amount);
476
+ const method = params.paymentMethod?.toLowerCase() || "";
477
+ const coreApiMethods = [
478
+ "bca_va",
479
+ "bni_va",
480
+ "bri_va",
481
+ "permata_va",
482
+ "cimb_va",
483
+ "danamon_va",
484
+ "bsi_va",
485
+ "seabank_va",
486
+ "mandiri_va",
487
+ "qris",
488
+ "gopay",
489
+ "shopeepay",
490
+ "ovo",
491
+ "dana",
492
+ "linkaja",
493
+ "alfamart",
494
+ "indomaret",
495
+ "credit_card",
496
+ "googlepay",
497
+ "kredivo",
498
+ "akulaku"
499
+ ];
500
+ if (method && coreApiMethods.includes(method)) {
501
+ const url2 = `${this.getApiBaseUrl(sandbox)}/charge`;
502
+ let payload2 = {
503
+ transaction_details: {
504
+ order_id: orderId,
505
+ gross_amount: integerAmount
506
+ },
507
+ customer_details: {
508
+ first_name: customer.name,
509
+ email: customer.email,
510
+ phone: customer.phone || ""
511
+ },
512
+ item_details: [
513
+ {
514
+ id: orderId,
515
+ price: integerAmount,
516
+ quantity: 1,
517
+ name: productDetails.length > 50 ? productDetails.substring(0, 47) + "..." : productDetails
518
+ }
519
+ ],
520
+ ...params.providerParams
521
+ };
522
+ if (["bca_va", "bni_va", "bri_va", "cimb_va", "permata_va", "danamon_va", "bsi_va", "seabank_va"].includes(method)) {
523
+ const bankName = method.split("_")[0];
524
+ payload2.payment_type = "bank_transfer";
525
+ payload2.bank_transfer = {
526
+ bank: bankName
527
+ };
528
+ } else if (method === "mandiri_va") {
529
+ payload2.payment_type = "echannel";
530
+ payload2.echannel = {
531
+ bill_info1: "Payment for",
532
+ bill_info2: productDetails.length > 30 ? productDetails.substring(0, 27) + "..." : productDetails
533
+ };
534
+ } else if (method === "qris") {
535
+ payload2.payment_type = "qris";
536
+ } else if (method === "gopay") {
537
+ payload2.payment_type = "gopay";
538
+ payload2.gopay = {
539
+ enable_callback: true,
540
+ callback_url: returnUrl
541
+ };
542
+ } else if (method === "shopeepay") {
543
+ payload2.payment_type = "shopeepay";
544
+ payload2.shopeepay = {
545
+ callback_url: returnUrl
546
+ };
547
+ } else if (method === "ovo") {
548
+ if (!customer.phone) {
549
+ return {
550
+ success: false,
551
+ rawResponse: null,
552
+ error: "OVO payment method requires a customer phone number in customer.phone"
553
+ };
554
+ }
555
+ payload2.payment_type = "ovo";
556
+ payload2.ovo = {
557
+ phone: customer.phone
558
+ };
559
+ } else if (method === "dana") {
560
+ payload2.payment_type = "dana";
561
+ } else if (method === "linkaja") {
562
+ payload2.payment_type = "linkaja";
563
+ } else if (method === "credit_card") {
564
+ const token = params.providerParams?.credit_card?.token_id || params.providerParams?.tokenId;
565
+ if (!token) {
566
+ return {
567
+ success: false,
568
+ rawResponse: null,
569
+ error: "Credit Card payment method requires token_id (passed via providerParams.credit_card.token_id or providerParams.tokenId)"
570
+ };
571
+ }
572
+ payload2.payment_type = "credit_card";
573
+ payload2.credit_card = {
574
+ token_id: token,
575
+ authentication: params.providerParams?.credit_card?.authentication ?? true,
576
+ save_card: params.providerParams?.credit_card?.save_card,
577
+ bank: params.providerParams?.credit_card?.bank,
578
+ installment_term: params.providerParams?.credit_card?.installment_term,
579
+ bins: params.providerParams?.credit_card?.bins,
580
+ type: params.providerParams?.credit_card?.type
581
+ };
582
+ } else if (method === "googlepay") {
583
+ const token = params.providerParams?.googlepay?.token_id || params.providerParams?.tokenId;
584
+ if (!token) {
585
+ return {
586
+ success: false,
587
+ rawResponse: null,
588
+ error: "Google Pay payment method requires token_id (passed via providerParams.googlepay.token_id or providerParams.tokenId)"
589
+ };
590
+ }
591
+ payload2.payment_type = "googlepay";
592
+ payload2.googlepay = {
593
+ token_id: token
594
+ };
595
+ } else if (method === "kredivo") {
596
+ payload2.payment_type = "kredivo";
597
+ payload2.kredivo = {
598
+ address: params.providerParams?.kredivo?.address,
599
+ first_name: params.providerParams?.kredivo?.first_name || customer.name.split(" ")[0],
600
+ last_name: params.providerParams?.kredivo?.last_name || customer.name.split(" ").slice(1).join(" "),
601
+ email: params.providerParams?.kredivo?.email || customer.email,
602
+ phone: params.providerParams?.kredivo?.phone || customer.phone || ""
603
+ };
604
+ } else if (method === "akulaku") {
605
+ payload2.payment_type = "akulaku";
606
+ } else if (["alfamart", "indomaret"].includes(method)) {
607
+ payload2.payment_type = "cstore";
608
+ payload2.cstore = {
609
+ store: method,
610
+ message: productDetails.length > 30 ? productDetails.substring(0, 27) + "..." : productDetails
611
+ };
612
+ }
613
+ try {
614
+ const client = new MidtransClient(config);
615
+ const data = await client.request("POST", "/charge", payload2);
616
+ if (data.status_code === "201" || data.status_code === "200") {
617
+ const res = {
618
+ success: true,
619
+ reference: data.transaction_id || data.order_id,
620
+ rawResponse: data
621
+ };
622
+ if (["bca_va", "bni_va", "bri_va", "cimb_va", "danamon_va", "bsi_va", "seabank_va"].includes(method)) {
623
+ res.vaNumber = data.va_numbers?.[0]?.va_number;
624
+ } else if (method === "permata_va") {
625
+ res.vaNumber = data.permata_va_number;
626
+ } else if (method === "mandiri_va") {
627
+ res.vaNumber = `${data.biller_code}-${data.bill_key}`;
628
+ } else if (method === "qris") {
629
+ res.qrString = data.qr_string;
630
+ res.qrCodeUrl = data.actions?.find((a) => a.name === "generate-qr-code")?.url;
631
+ } else if (["gopay", "shopeepay", "dana", "linkaja", "kredivo", "akulaku", "googlepay"].includes(method)) {
632
+ res.paymentUrl = data.actions?.find((a) => a.name === "deeplink-redirect")?.url || data.actions?.find((a) => a.name === "web-redirect")?.url || data.actions?.find((a) => a.name === "generate-qr-code")?.url || data.redirect_url;
633
+ res.qrCodeUrl = data.actions?.find((a) => a.name === "generate-qr-code")?.url;
634
+ } else if (method === "credit_card") {
635
+ res.paymentUrl = data.redirect_url || data.actions?.find((a) => a.name === "redirect")?.url;
636
+ } else if (method === "ovo") {
637
+ res.paymentUrl = "";
638
+ } else if (["alfamart", "indomaret"].includes(method)) {
639
+ res.paymentCode = data.payment_code;
640
+ }
641
+ return res;
642
+ } else {
643
+ return {
644
+ success: false,
645
+ rawResponse: data,
646
+ error: data.status_message || `Midtrans Core Error: ${data.status_code}`
647
+ };
648
+ }
649
+ } catch (e) {
650
+ return {
651
+ success: false,
652
+ rawResponse: null,
653
+ error: e.message || "Failed to make request to Midtrans Core API"
654
+ };
655
+ }
656
+ }
657
+ const url = this.getSnapBaseUrl(sandbox);
658
+ const payload = {
659
+ transaction_details: {
660
+ order_id: orderId,
661
+ gross_amount: integerAmount
662
+ },
663
+ customer_details: {
664
+ first_name: customer.name,
665
+ email: customer.email,
666
+ phone: customer.phone || ""
667
+ },
668
+ item_details: [
669
+ {
670
+ id: orderId,
671
+ price: integerAmount,
672
+ quantity: 1,
673
+ name: productDetails.length > 50 ? productDetails.substring(0, 47) + "..." : productDetails
674
+ }
675
+ ],
676
+ callbacks: {
677
+ finish: returnUrl
678
+ },
679
+ ...params.paymentMethod ? { enabled_payments: [params.paymentMethod] } : {},
680
+ ...params.providerParams
681
+ };
682
+ try {
683
+ const client = new MidtransClient(config);
684
+ const data = await client.request("POST", url, payload);
685
+ if (data.token) {
686
+ return {
687
+ success: true,
688
+ paymentUrl: data.redirect_url,
689
+ reference: data.token,
690
+ rawResponse: data
691
+ };
692
+ } else {
693
+ return {
694
+ success: false,
695
+ rawResponse: data,
696
+ error: data.error_messages?.[0] || "Failed to create Midtrans Snap transaction"
697
+ };
698
+ }
699
+ } catch (e) {
700
+ return {
701
+ success: false,
702
+ rawResponse: null,
703
+ error: e.message || "Failed to make request to Midtrans Snap API"
704
+ };
705
+ }
706
+ }
707
+ async verifyCallback(body, config) {
708
+ const { apiKey } = config;
709
+ const orderId = body.order_id || "";
710
+ const statusCode = body.status_code || "";
711
+ const grossAmount = body.gross_amount || "";
712
+ const signatureKey = body.signature_key || "";
713
+ const rawSignature = orderId + statusCode + grossAmount + apiKey;
714
+ const computedSignature = import_crypto2.default.createHash("sha512").update(rawSignature).digest("hex");
715
+ const isValid = signatureKey.toLowerCase() === computedSignature.toLowerCase();
716
+ const transactionStatus = body.transaction_status || "";
717
+ const fraudStatus = body.fraud_status || "";
718
+ let status = "pending";
719
+ if (transactionStatus === "capture" || transactionStatus === "settlement") {
720
+ if (fraudStatus === "accept" || !fraudStatus) {
721
+ status = "paid";
722
+ } else if (fraudStatus === "challenge") {
723
+ status = "pending";
724
+ } else {
725
+ status = "failed";
726
+ }
727
+ } else if (transactionStatus === "pending") {
728
+ status = "pending";
729
+ } else if (["deny", "cancel", "expire"].includes(transactionStatus)) {
730
+ status = "failed";
731
+ }
732
+ return {
733
+ isValid,
734
+ orderId,
735
+ amount: grossAmount ? Number(grossAmount) : 0,
736
+ status: isValid ? status : "failed",
737
+ rawPayload: body
738
+ };
739
+ }
740
+ async getPaymentMethods(params, config) {
741
+ const staticMethods = [
742
+ {
743
+ paymentMethod: "credit_card",
744
+ paymentName: "Credit / Debit Card",
745
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/credit_card.png",
746
+ totalFee: "2.9% + IDR 2,000",
747
+ category: "Kartu Kredit"
748
+ },
749
+ {
750
+ paymentMethod: "googlepay",
751
+ paymentName: "Google Pay\u2122",
752
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/googlepay.png",
753
+ totalFee: "2.9% + IDR 2,000",
754
+ category: "Kartu Kredit"
755
+ },
756
+ {
757
+ paymentMethod: "bca_va",
758
+ paymentName: "BCA Virtual Account",
759
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/bca_va.png",
760
+ totalFee: "IDR 4,000",
761
+ category: "Virtual Account"
762
+ },
763
+ {
764
+ paymentMethod: "bni_va",
765
+ paymentName: "BNI Virtual Account",
766
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/bni_va.png",
767
+ totalFee: "IDR 4,000",
768
+ category: "Virtual Account"
769
+ },
770
+ {
771
+ paymentMethod: "bri_va",
772
+ paymentName: "BRI Virtual Account",
773
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/bri_va.png",
774
+ totalFee: "IDR 4,000",
775
+ category: "Virtual Account"
776
+ },
777
+ {
778
+ paymentMethod: "mandiri_va",
779
+ paymentName: "Mandiri Bill Payment / VA",
780
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/mandiri_va.png",
781
+ totalFee: "IDR 4,000",
782
+ category: "Virtual Account"
783
+ },
784
+ {
785
+ paymentMethod: "permata_va",
786
+ paymentName: "Permata Virtual Account",
787
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/permata_va.png",
788
+ totalFee: "IDR 4,000",
789
+ category: "Virtual Account"
790
+ },
791
+ {
792
+ paymentMethod: "cimb_va",
793
+ paymentName: "CIMB Virtual Account",
794
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/cimb_va.png",
795
+ totalFee: "IDR 4,000",
796
+ category: "Virtual Account"
797
+ },
798
+ {
799
+ paymentMethod: "danamon_va",
800
+ paymentName: "Danamon Virtual Account",
801
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/danamon_va.png",
802
+ totalFee: "IDR 4,000",
803
+ category: "Virtual Account"
804
+ },
805
+ {
806
+ paymentMethod: "bsi_va",
807
+ paymentName: "BSI Virtual Account",
808
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/bsi_va.png",
809
+ totalFee: "IDR 4,000",
810
+ category: "Virtual Account"
811
+ },
812
+ {
813
+ paymentMethod: "seabank_va",
814
+ paymentName: "SeaBank Virtual Account",
815
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/seabank_va.png",
816
+ totalFee: "IDR 4,000",
817
+ category: "Virtual Account"
818
+ },
819
+ {
820
+ paymentMethod: "other_va",
821
+ paymentName: "Other Banks (ATM Bersama, Prima, Alto)",
822
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/other_va.png",
823
+ totalFee: "IDR 4,000",
824
+ category: "Virtual Account"
825
+ },
826
+ {
827
+ paymentMethod: "qris",
828
+ paymentName: "QRIS (GoPay, ShopeePay, Dana, LinkAja)",
829
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/qris.png",
830
+ totalFee: "0.7%",
831
+ category: "QRIS"
832
+ },
833
+ {
834
+ paymentMethod: "other_qris",
835
+ paymentName: "Other QRIS",
836
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/other_qris.png",
837
+ totalFee: "0.7%",
838
+ category: "QRIS"
839
+ },
840
+ {
841
+ paymentMethod: "gopay",
842
+ paymentName: "GoPay E-Wallet",
843
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/gopay.png",
844
+ totalFee: "2.0%",
845
+ category: "E-Wallet"
846
+ },
847
+ {
848
+ paymentMethod: "shopeepay",
849
+ paymentName: "ShopeePay E-Wallet",
850
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/shopeepay.png",
851
+ totalFee: "2.0%",
852
+ category: "E-Wallet"
853
+ },
854
+ {
855
+ paymentMethod: "ovo",
856
+ paymentName: "OVO E-Wallet",
857
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/ovo.png",
858
+ totalFee: "1.5%",
859
+ category: "E-Wallet"
860
+ },
861
+ {
862
+ paymentMethod: "dana",
863
+ paymentName: "DANA E-Wallet",
864
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/dana.png",
865
+ totalFee: "1.7%",
866
+ category: "E-Wallet"
867
+ },
868
+ {
869
+ paymentMethod: "linkaja",
870
+ paymentName: "LinkAja E-Wallet",
871
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/linkaja.png",
872
+ totalFee: "1.7%",
873
+ category: "E-Wallet"
874
+ },
875
+ {
876
+ paymentMethod: "indomaret",
877
+ paymentName: "Indomaret",
878
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/indomaret.png",
879
+ totalFee: "IDR 5,000",
880
+ category: "Retail / Gerai"
881
+ },
882
+ {
883
+ paymentMethod: "alfamart",
884
+ paymentName: "Alfamart / Alfamidi",
885
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/alfamart.png",
886
+ totalFee: "IDR 5,000",
887
+ category: "Retail / Gerai"
888
+ },
889
+ {
890
+ paymentMethod: "kredivo",
891
+ paymentName: "Kredivo Paylater",
892
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/kredivo.png",
893
+ totalFee: "2.3%",
894
+ category: "Paylater / Cicilan"
895
+ },
896
+ {
897
+ paymentMethod: "akulaku",
898
+ paymentName: "Akulaku Paylater",
899
+ paymentImage: "https://docs.midtrans.com/asset/payment_methods/akulaku.png",
900
+ totalFee: "1.7%",
901
+ category: "Paylater / Cicilan"
902
+ }
903
+ ];
904
+ return {
905
+ success: true,
906
+ methods: staticMethods,
907
+ rawResponse: staticMethods
908
+ };
909
+ }
910
+ async checkTransaction(params, config) {
911
+ const { merchantOrderId } = params;
912
+ try {
913
+ const client = new MidtransClient(config);
914
+ const data = await client.request("GET", `/${merchantOrderId}/status`, null);
915
+ const transactionStatus = data.transaction_status || "";
916
+ const fraudStatus = data.fraud_status || "";
917
+ let status = "pending";
918
+ if (transactionStatus === "capture" || transactionStatus === "settlement") {
919
+ if (fraudStatus === "accept" || !fraudStatus) {
920
+ status = "paid";
921
+ } else if (fraudStatus === "challenge") {
922
+ status = "pending";
923
+ } else {
924
+ status = "failed";
925
+ }
926
+ } else if (transactionStatus === "pending") {
927
+ status = "pending";
928
+ } else if (["deny", "cancel", "expire"].includes(transactionStatus)) {
929
+ status = "failed";
930
+ }
931
+ return {
932
+ success: true,
933
+ orderId: data.order_id || merchantOrderId,
934
+ reference: data.transaction_id || "",
935
+ amount: data.gross_amount ? Number(data.gross_amount) : 0,
936
+ statusCode: data.status_code || "",
937
+ status,
938
+ statusMessage: data.status_message || "",
939
+ rawResponse: data
940
+ };
941
+ } catch (e) {
942
+ return {
943
+ success: false,
944
+ orderId: merchantOrderId,
945
+ reference: "",
946
+ amount: 0,
947
+ statusCode: "",
948
+ status: "failed",
949
+ statusMessage: "Network error",
950
+ error: e.message || "Failed to check transaction status with Midtrans",
951
+ rawResponse: null
952
+ };
953
+ }
954
+ }
955
+ /**
956
+ * Get an instance of MidtransClient to perform transaction actions, subscriptions, invoicing, etc.
957
+ */
958
+ getClient(config) {
959
+ return new MidtransClient(config);
960
+ }
961
+ async probePaymentMethods(config) {
962
+ const probePayloads = {
963
+ qris: { payment_type: "qris", qris: { acquirer: "gopay" } },
964
+ gopay: { payment_type: "gopay", gopay: { enable_callback: true, callback_url: "https://example.com" } },
965
+ shopeepay: { payment_type: "shopeepay", shopeepay: { callback_url: "https://example.com" } },
966
+ bca: { payment_type: "bank_transfer", bank_transfer: { bank: "bca" } },
967
+ bni: { payment_type: "bank_transfer", bank_transfer: { bank: "bni" } },
968
+ bri: { payment_type: "bank_transfer", bank_transfer: { bank: "bri" } },
969
+ cimb: { payment_type: "bank_transfer", bank_transfer: { bank: "cimb" } },
970
+ mandiri: { payment_type: "echannel", echannel: { bill_info1: "Payment", bill_info2: "Probe" } },
971
+ permata: { payment_type: "permata" },
972
+ alfamart: { payment_type: "cstore", cstore: { store: "alfamart", message: "Probe" } },
973
+ indomaret: { payment_type: "cstore", cstore: { store: "indomaret", message: "Probe" } },
974
+ akulaku: { payment_type: "akulaku" },
975
+ kredivo: {
976
+ payment_type: "kredivo",
977
+ seller_details: { address: { city: "Jakarta" } }
978
+ }
979
+ };
980
+ const enabled = [];
981
+ const client = new MidtransClient(config);
982
+ for (const [methodId, specificPayload] of Object.entries(probePayloads)) {
983
+ try {
984
+ const probeOrderId = `PROBE-${methodId}-${Date.now()}`;
985
+ const probeBody = {
986
+ ...specificPayload,
987
+ transaction_details: { order_id: probeOrderId, gross_amount: 15e3 },
988
+ item_details: [{ id: probeOrderId, name: "Probe", price: 15e3, quantity: 1 }],
989
+ customer_details: { first_name: "Probe", email: "probe@test.com" }
990
+ };
991
+ const result = await client.request("POST", "/charge", probeBody);
992
+ if (result && ["200", "201", "202"].includes(result.status_code)) {
993
+ enabled.push(methodId);
994
+ try {
995
+ await client.cancelTransaction(probeOrderId);
996
+ } catch (e) {
997
+ }
998
+ }
999
+ } catch (e) {
1000
+ }
1001
+ }
1002
+ return { success: true, enabled };
1003
+ }
307
1004
  };
308
1005
 
309
1006
  // src/index.ts
@@ -311,6 +1008,7 @@ var PaymentManager = class {
311
1008
  providers = /* @__PURE__ */ new Map();
312
1009
  constructor() {
313
1010
  this.registerProvider(new DuitkuProvider());
1011
+ this.registerProvider(new MidtransProvider());
314
1012
  }
315
1013
  registerProvider(provider) {
316
1014
  this.providers.set(provider.name.toLowerCase(), provider);
@@ -322,6 +1020,12 @@ var PaymentManager = class {
322
1020
  }
323
1021
  return provider;
324
1022
  }
1023
+ getMidtransProvider() {
1024
+ return this.getProvider("midtrans");
1025
+ }
1026
+ getMidtransClient(config) {
1027
+ return new MidtransClient(config);
1028
+ }
325
1029
  async createInvoice(providerName, params, config) {
326
1030
  const provider = this.getProvider(providerName);
327
1031
  return provider.createInvoice(params, config);
@@ -338,12 +1042,21 @@ var PaymentManager = class {
338
1042
  const provider = this.getProvider(providerName);
339
1043
  return provider.checkTransaction(params, config);
340
1044
  }
1045
+ async probePaymentMethods(providerName, config) {
1046
+ const provider = this.getProvider(providerName);
1047
+ if (provider.probePaymentMethods) {
1048
+ return provider.probePaymentMethods(config);
1049
+ }
1050
+ return { success: false, enabled: [], error: `Provider '${providerName}' does not support payment methods probing` };
1051
+ }
341
1052
  };
342
1053
  var paymentManager = new PaymentManager();
343
1054
  // Annotate the CommonJS export names for ESM import in node:
344
1055
  0 && (module.exports = {
345
1056
  BasePaymentProvider,
346
1057
  DuitkuProvider,
1058
+ MidtransClient,
1059
+ MidtransProvider,
347
1060
  PaymentManager,
348
1061
  getPaymentMethodCategory,
349
1062
  paymentManager