@crediblemark/buayar 0.8.5 → 0.8.7
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/README.md +11 -7
- package/dist/cli/index.js +7 -3
- package/dist/index.d.mts +132 -8
- package/dist/index.d.ts +132 -8
- package/dist/index.js +593 -22
- package/dist/index.mjs +586 -22
- package/docs/AUDIT-BUG-DAN-PREMATURE.md +166 -0
- package/docs/guide.md +30 -4
- package/docs/ipaymu.md +22 -7
- package/docs/sumopod.md +359 -0
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
CANONICAL_TO_OY: () => CANONICAL_TO_OY,
|
|
47
47
|
CANONICAL_TO_PRISMALINK: () => CANONICAL_TO_PRISMALINK,
|
|
48
48
|
CANONICAL_TO_STRIPE: () => CANONICAL_TO_STRIPE,
|
|
49
|
+
CANONICAL_TO_SUMOPOD: () => CANONICAL_TO_SUMOPOD,
|
|
49
50
|
CANONICAL_TO_XENDIT: () => CANONICAL_TO_XENDIT,
|
|
50
51
|
CORE_API_METHODS: () => CORE_API_METHODS,
|
|
51
52
|
CheckoutComClient: () => CheckoutComClient,
|
|
@@ -79,12 +80,15 @@ __export(index_exports, {
|
|
|
79
80
|
ProviderRegistry: () => ProviderRegistry,
|
|
80
81
|
RazorpayClient: () => RazorpayClient,
|
|
81
82
|
RazorpayProvider: () => RazorpayProvider,
|
|
83
|
+
SUMOPOD_TO_CANONICAL: () => SUMOPOD_TO_CANONICAL,
|
|
82
84
|
SnapApiError: () => SnapApiError,
|
|
83
85
|
SnapClient: () => SnapClient,
|
|
84
86
|
SquareClient: () => SquareClient,
|
|
85
87
|
SquareProvider: () => SquareProvider,
|
|
86
88
|
StripeClient: () => StripeClient,
|
|
87
89
|
StripeProvider: () => StripeProvider,
|
|
90
|
+
SumopodClient: () => SumopodClient,
|
|
91
|
+
SumopodProvider: () => SumopodProvider,
|
|
88
92
|
TwoCheckoutClient: () => TwoCheckoutClient,
|
|
89
93
|
TwoCheckoutProvider: () => TwoCheckoutProvider,
|
|
90
94
|
XenditClient: () => XenditClient,
|
|
@@ -144,6 +148,7 @@ __export(index_exports, {
|
|
|
144
148
|
toOyPaymentMethod: () => toOyPaymentMethod,
|
|
145
149
|
toPrismalinkPaymentMethod: () => toPrismalinkPaymentMethod,
|
|
146
150
|
toStripePaymentMethod: () => toStripePaymentMethod,
|
|
151
|
+
toSumopodPaymentMethod: () => toSumopodPaymentMethod,
|
|
147
152
|
toXenditPaymentMethod: () => toXenditPaymentMethod,
|
|
148
153
|
verifyAdyenWebhook: () => verifyAdyenWebhook,
|
|
149
154
|
verifyBraintreeWebhook: () => verifyBraintreeWebhook,
|
|
@@ -163,6 +168,8 @@ __export(index_exports, {
|
|
|
163
168
|
verifySnapWebhookSignature: () => verifySnapWebhookSignature,
|
|
164
169
|
verifySquareWebhook: () => verifySquareWebhook,
|
|
165
170
|
verifyStripeWebhook: () => verifyStripeWebhook,
|
|
171
|
+
verifySumopodSvixSignature: () => verifySumopodSvixSignature,
|
|
172
|
+
verifySumopodToken: () => verifySumopodToken,
|
|
166
173
|
verifyTwoCheckoutWebhook: () => verifyTwoCheckoutWebhook,
|
|
167
174
|
verifyXenditWebhookToken: () => verifyXenditWebhookToken
|
|
168
175
|
});
|
|
@@ -461,6 +468,8 @@ var CANONICAL_TO_OY = {
|
|
|
461
468
|
var CANONICAL_TO_STRIPE = {
|
|
462
469
|
credit_card: "card",
|
|
463
470
|
qris: "qris",
|
|
471
|
+
QRIS_SUMOPOD: "qris",
|
|
472
|
+
qris_sumopod: "qris",
|
|
464
473
|
gopay_qris: "qris",
|
|
465
474
|
shopeepay_qris: "qris",
|
|
466
475
|
bca_va: "customer_balance",
|
|
@@ -567,6 +576,25 @@ function toStripePaymentMethod(code) {
|
|
|
567
576
|
}
|
|
568
577
|
return lower;
|
|
569
578
|
}
|
|
579
|
+
var CANONICAL_TO_SUMOPOD = {
|
|
580
|
+
qris: "QRIS",
|
|
581
|
+
gopay_qris: "QRIS",
|
|
582
|
+
shopeepay_qris: "QRIS",
|
|
583
|
+
nobu_qris: "QRIS",
|
|
584
|
+
qris_sumopod: "QRIS"
|
|
585
|
+
};
|
|
586
|
+
var SUMOPOD_TO_CANONICAL = {
|
|
587
|
+
QRIS: "qris",
|
|
588
|
+
qris: "qris"
|
|
589
|
+
};
|
|
590
|
+
function toSumopodPaymentMethod(code) {
|
|
591
|
+
if (!code) return void 0;
|
|
592
|
+
const lower = code.toLowerCase().trim();
|
|
593
|
+
if (CANONICAL_TO_SUMOPOD[lower]) {
|
|
594
|
+
return CANONICAL_TO_SUMOPOD[lower];
|
|
595
|
+
}
|
|
596
|
+
return code;
|
|
597
|
+
}
|
|
570
598
|
function toCanonicalPaymentMethod(provider, code) {
|
|
571
599
|
if (!code) return "";
|
|
572
600
|
const upper = code.toUpperCase().trim();
|
|
@@ -574,7 +602,10 @@ function toCanonicalPaymentMethod(provider, code) {
|
|
|
574
602
|
if (provider.toLowerCase() === "duitku" && DUITKU_TO_CANONICAL[upper]) {
|
|
575
603
|
return DUITKU_TO_CANONICAL[upper];
|
|
576
604
|
}
|
|
577
|
-
if (
|
|
605
|
+
if (provider.toLowerCase() === "sumopod" && SUMOPOD_TO_CANONICAL[upper]) {
|
|
606
|
+
return SUMOPOD_TO_CANONICAL[upper];
|
|
607
|
+
}
|
|
608
|
+
if (CANONICAL_TO_MIDTRANS[lower] || CANONICAL_TO_DUITKU[lower] || CANONICAL_TO_IPAYMU[lower] || CANONICAL_TO_XENDIT[lower] || CANONICAL_TO_DOKU[lower] || CANONICAL_TO_PRISMALINK[lower] || CANONICAL_TO_FASPAY[lower] || CANONICAL_TO_FINPAY[lower] || CANONICAL_TO_NICEPAY[lower] || CANONICAL_TO_OY[lower] || CANONICAL_TO_STRIPE[lower] || CANONICAL_TO_SUMOPOD[lower]) {
|
|
578
609
|
return lower;
|
|
579
610
|
}
|
|
580
611
|
return lower;
|
|
@@ -1808,7 +1839,7 @@ var IpaymuProvider = class extends BasePaymentProvider {
|
|
|
1808
1839
|
payload = {
|
|
1809
1840
|
name: customer.name,
|
|
1810
1841
|
email: customer.email,
|
|
1811
|
-
phone: customer.phone
|
|
1842
|
+
...customer.phone ? { phone: customer.phone } : {},
|
|
1812
1843
|
amount: integerAmount,
|
|
1813
1844
|
notifyUrl,
|
|
1814
1845
|
expired: 24,
|
|
@@ -1839,7 +1870,7 @@ var IpaymuProvider = class extends BasePaymentProvider {
|
|
|
1839
1870
|
referenceId: orderId,
|
|
1840
1871
|
buyerName: customer.name,
|
|
1841
1872
|
buyerEmail: customer.email,
|
|
1842
|
-
buyerPhone: customer.phone
|
|
1873
|
+
...customer.phone ? { buyerPhone: customer.phone } : {},
|
|
1843
1874
|
...feeDirection ? { feeDirection } : {},
|
|
1844
1875
|
...escrow !== void 0 ? { escrow } : {},
|
|
1845
1876
|
...subAccount ? { account: subAccount } : {},
|
|
@@ -2069,6 +2100,28 @@ var IpaymuProvider = class extends BasePaymentProvider {
|
|
|
2069
2100
|
};
|
|
2070
2101
|
}
|
|
2071
2102
|
}
|
|
2103
|
+
async probePaymentMethods(config) {
|
|
2104
|
+
try {
|
|
2105
|
+
const res = await this.getPaymentMethods({ amount: 1e4 }, config);
|
|
2106
|
+
if (res.success && res.methods) {
|
|
2107
|
+
return {
|
|
2108
|
+
success: true,
|
|
2109
|
+
enabled: res.methods.map((m) => m.paymentMethod)
|
|
2110
|
+
};
|
|
2111
|
+
}
|
|
2112
|
+
return {
|
|
2113
|
+
success: false,
|
|
2114
|
+
enabled: [],
|
|
2115
|
+
error: res.error || "Failed to probe iPaymu payment methods"
|
|
2116
|
+
};
|
|
2117
|
+
} catch (e) {
|
|
2118
|
+
return {
|
|
2119
|
+
success: false,
|
|
2120
|
+
enabled: [],
|
|
2121
|
+
error: e.message || "Failed to probe iPaymu payment methods"
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2072
2125
|
async checkTransaction(params, config) {
|
|
2073
2126
|
const { merchantOrderId } = params;
|
|
2074
2127
|
const va = config.merchantCode || config.merchantId || "";
|
|
@@ -2356,8 +2409,8 @@ var XenditProvider = class extends BasePaymentProvider {
|
|
|
2356
2409
|
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
2357
2410
|
const webhookToken = config.extra?.webhookToken;
|
|
2358
2411
|
const headerToken = config.extra?.callbackToken || config.extra?.headers?.["x-callback-token"] || config.extra?.headers?.["X-Callback-Token"];
|
|
2359
|
-
let isValid =
|
|
2360
|
-
if (webhookToken
|
|
2412
|
+
let isValid = false;
|
|
2413
|
+
if (webhookToken && headerToken) {
|
|
2361
2414
|
isValid = verifyXenditWebhookToken(headerToken, webhookToken);
|
|
2362
2415
|
}
|
|
2363
2416
|
return {
|
|
@@ -2505,6 +2558,75 @@ var XenditProvider = class extends BasePaymentProvider {
|
|
|
2505
2558
|
category: "Paylater / Cicilan"
|
|
2506
2559
|
}
|
|
2507
2560
|
];
|
|
2561
|
+
const apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
2562
|
+
if (apiKey) {
|
|
2563
|
+
try {
|
|
2564
|
+
const authHeader = getXenditAuthHeader(apiKey);
|
|
2565
|
+
const response = await fetch(`${this.getBaseUrl()}/payment_channels`, {
|
|
2566
|
+
method: "GET",
|
|
2567
|
+
headers: {
|
|
2568
|
+
"Authorization": authHeader,
|
|
2569
|
+
"Content-Type": "application/json"
|
|
2570
|
+
}
|
|
2571
|
+
});
|
|
2572
|
+
if (response.ok) {
|
|
2573
|
+
const channels = await response.json();
|
|
2574
|
+
if (Array.isArray(channels) && channels.length > 0) {
|
|
2575
|
+
const dynamicMethods = [];
|
|
2576
|
+
for (const ch of channels) {
|
|
2577
|
+
if (ch.status && ch.status !== "ACTIVE") continue;
|
|
2578
|
+
const codeLower = (ch.channel_code || "").toLowerCase();
|
|
2579
|
+
let canonicalCode = codeLower;
|
|
2580
|
+
let category = "Virtual Account";
|
|
2581
|
+
if (ch.type === "BANK_TRANSFER" || codeLower.endsWith("_va") || ["bca", "bni", "bri", "mandiri", "permata", "cimb", "bsi"].includes(codeLower)) {
|
|
2582
|
+
canonicalCode = codeLower.endsWith("_va") ? codeLower : `${codeLower}_va`;
|
|
2583
|
+
category = "Virtual Account";
|
|
2584
|
+
} else if (ch.type === "EWALLET" || ["ovo", "dana", "linkaja", "shopeepay", "gopay"].includes(codeLower)) {
|
|
2585
|
+
canonicalCode = codeLower;
|
|
2586
|
+
category = "E-Wallet";
|
|
2587
|
+
} else if (ch.type === "QR_CODE" || codeLower === "qris") {
|
|
2588
|
+
canonicalCode = "qris";
|
|
2589
|
+
category = "QRIS";
|
|
2590
|
+
} else if (ch.type === "RETAIL_OUTLET" || ["alfamart", "indomaret"].includes(codeLower)) {
|
|
2591
|
+
canonicalCode = codeLower;
|
|
2592
|
+
category = "Retail / Gerai";
|
|
2593
|
+
} else if (ch.type === "CARD") {
|
|
2594
|
+
canonicalCode = "credit_card";
|
|
2595
|
+
category = "Kartu Kredit";
|
|
2596
|
+
} else if (ch.type === "PAYLATER" || ["kredivo", "akulaku", "indodana"].includes(codeLower)) {
|
|
2597
|
+
canonicalCode = codeLower;
|
|
2598
|
+
category = "Paylater / Cicilan";
|
|
2599
|
+
}
|
|
2600
|
+
dynamicMethods.push({
|
|
2601
|
+
paymentMethod: canonicalCode,
|
|
2602
|
+
code: ch.channel_code || canonicalCode,
|
|
2603
|
+
paymentName: ch.display_name || ch.name || ch.channel_code,
|
|
2604
|
+
paymentImage: `https://xendit.co/icons/${codeLower}.png`,
|
|
2605
|
+
totalFee: ch.fee ? `${ch.fee}` : "",
|
|
2606
|
+
category,
|
|
2607
|
+
coming_soon: false,
|
|
2608
|
+
extra: ch
|
|
2609
|
+
});
|
|
2610
|
+
}
|
|
2611
|
+
if (dynamicMethods.length > 0) {
|
|
2612
|
+
const categories2 = {};
|
|
2613
|
+
for (const item of dynamicMethods) {
|
|
2614
|
+
if (!categories2[item.category]) categories2[item.category] = [];
|
|
2615
|
+
categories2[item.category].push(item);
|
|
2616
|
+
}
|
|
2617
|
+
return {
|
|
2618
|
+
success: true,
|
|
2619
|
+
provider: "xendit",
|
|
2620
|
+
methods: dynamicMethods,
|
|
2621
|
+
categories: categories2,
|
|
2622
|
+
rawResponse: channels
|
|
2623
|
+
};
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
} catch (e) {
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2508
2630
|
const categories = {};
|
|
2509
2631
|
for (const item of staticMethods) {
|
|
2510
2632
|
if (!categories[item.category]) {
|
|
@@ -2520,6 +2642,28 @@ var XenditProvider = class extends BasePaymentProvider {
|
|
|
2520
2642
|
rawResponse: staticMethods
|
|
2521
2643
|
};
|
|
2522
2644
|
}
|
|
2645
|
+
async probePaymentMethods(config) {
|
|
2646
|
+
try {
|
|
2647
|
+
const res = await this.getPaymentMethods({ amount: 1e4 }, config);
|
|
2648
|
+
if (res.success && res.methods) {
|
|
2649
|
+
return {
|
|
2650
|
+
success: true,
|
|
2651
|
+
enabled: res.methods.map((m) => m.paymentMethod)
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
return {
|
|
2655
|
+
success: false,
|
|
2656
|
+
enabled: [],
|
|
2657
|
+
error: res.error || "Failed to probe Xendit payment methods"
|
|
2658
|
+
};
|
|
2659
|
+
} catch (e) {
|
|
2660
|
+
return {
|
|
2661
|
+
success: false,
|
|
2662
|
+
enabled: [],
|
|
2663
|
+
error: e.message || "Failed to probe Xendit payment methods"
|
|
2664
|
+
};
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2523
2667
|
async checkTransaction(params, config) {
|
|
2524
2668
|
const { merchantOrderId } = params;
|
|
2525
2669
|
const apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
@@ -3316,7 +3460,7 @@ var DokuProvider = class extends BasePaymentProvider {
|
|
|
3316
3460
|
const secretKey = config.secretKey || config.apiKey || "";
|
|
3317
3461
|
const signature = headers["signature"] || headers["Signature"] || config.extra?.dokuSignature || config.extra?.signatureHeader;
|
|
3318
3462
|
const clientId = config.merchantCode || config.clientKey || "";
|
|
3319
|
-
let isValid =
|
|
3463
|
+
let isValid = false;
|
|
3320
3464
|
if (signature || headers && (headers["request-id"] || headers["Request-Id"])) {
|
|
3321
3465
|
isValid = verifyDokuWebhookSignature(headers, body, clientId, secretKey);
|
|
3322
3466
|
}
|
|
@@ -3341,7 +3485,7 @@ var DokuProvider = class extends BasePaymentProvider {
|
|
|
3341
3485
|
verifySnapCallback(body, config, headers) {
|
|
3342
3486
|
const clientSecret = config.apiKey || config.serverKey || config.secretKey || "";
|
|
3343
3487
|
const endpointUrl = config.extra?.notificationPath || headers["x-path"] || config.extra?.headers?.["request-target"] || "/api/payment/webhook";
|
|
3344
|
-
let isValid =
|
|
3488
|
+
let isValid = false;
|
|
3345
3489
|
const incomingSig = headers["x-signature"] || headers["X-SIGNATURE"] || headers["signature"] || headers["Signature"] || "";
|
|
3346
3490
|
if (incomingSig && clientSecret) {
|
|
3347
3491
|
isValid = verifySnapWebhookSignature(headers, body, clientSecret, endpointUrl);
|
|
@@ -8074,6 +8218,285 @@ var TwoCheckoutProvider = class extends BasePaymentProvider {
|
|
|
8074
8218
|
}
|
|
8075
8219
|
};
|
|
8076
8220
|
|
|
8221
|
+
// src/providers/sumopod/signature.ts
|
|
8222
|
+
var import_crypto32 = __toESM(require("crypto"));
|
|
8223
|
+
function verifySumopodSvixSignature(secret, svixId, svixTimestamp, svixSignature, rawBody, toleranceSeconds = 300) {
|
|
8224
|
+
if (!secret || !svixId || !svixTimestamp || !svixSignature || rawBody === void 0 || rawBody === null) {
|
|
8225
|
+
return false;
|
|
8226
|
+
}
|
|
8227
|
+
if (toleranceSeconds > 0) {
|
|
8228
|
+
const timestampSec = Number(svixTimestamp);
|
|
8229
|
+
if (isNaN(timestampSec)) {
|
|
8230
|
+
return false;
|
|
8231
|
+
}
|
|
8232
|
+
const currentSec = Math.floor(Date.now() / 1e3);
|
|
8233
|
+
if (Math.abs(currentSec - timestampSec) > toleranceSeconds) {
|
|
8234
|
+
return false;
|
|
8235
|
+
}
|
|
8236
|
+
}
|
|
8237
|
+
try {
|
|
8238
|
+
const cleanSecret = secret.startsWith("whsec_") ? secret.slice(6) : secret;
|
|
8239
|
+
const secretBytes = Buffer.from(cleanSecret, "base64");
|
|
8240
|
+
const signedContent = `${svixId}.${svixTimestamp}.${rawBody}`;
|
|
8241
|
+
const expectedSignature = import_crypto32.default.createHmac("sha256", secretBytes).update(signedContent).digest("base64");
|
|
8242
|
+
const signatures = svixSignature.split(" ").map((s) => s.includes(",") ? s.split(",")[1] : s).filter(Boolean);
|
|
8243
|
+
return signatures.some((sig) => safeCompare(sig, expectedSignature));
|
|
8244
|
+
} catch {
|
|
8245
|
+
return false;
|
|
8246
|
+
}
|
|
8247
|
+
}
|
|
8248
|
+
function verifySumopodToken(expectedToken, receivedToken) {
|
|
8249
|
+
if (!expectedToken || !receivedToken) return false;
|
|
8250
|
+
return safeCompare(expectedToken.trim(), receivedToken.trim());
|
|
8251
|
+
}
|
|
8252
|
+
|
|
8253
|
+
// src/providers/sumopod/provider.ts
|
|
8254
|
+
var SumopodProvider = class extends BasePaymentProvider {
|
|
8255
|
+
name = "sumopod";
|
|
8256
|
+
getBaseUrl(config) {
|
|
8257
|
+
if (config?.customBaseUrl) return config.customBaseUrl;
|
|
8258
|
+
if (config?.sandbox) return "https://api-pay-sandbox.sumopod.com";
|
|
8259
|
+
return "https://api-pay.sumopod.com";
|
|
8260
|
+
}
|
|
8261
|
+
async createInvoice(params, config) {
|
|
8262
|
+
const { orderId, amount, returnUrl } = params;
|
|
8263
|
+
const apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
8264
|
+
const baseUrl = this.getBaseUrl(config);
|
|
8265
|
+
const integerAmount = Math.round(amount);
|
|
8266
|
+
const payload = {
|
|
8267
|
+
order_id: orderId,
|
|
8268
|
+
amount: integerAmount,
|
|
8269
|
+
currency: (params.currency || "IDR").toUpperCase(),
|
|
8270
|
+
expires_in_hours: params.providerParams?.expires_in_hours ?? 24,
|
|
8271
|
+
...returnUrl || config.returnUrl ? { success_return_url: returnUrl || config.returnUrl } : {},
|
|
8272
|
+
...params.providerParams?.cancel_return_url || config.returnUrl || returnUrl ? { cancel_return_url: params.providerParams?.cancel_return_url || config.returnUrl || returnUrl } : {},
|
|
8273
|
+
payment_method_type_code: "QRIS",
|
|
8274
|
+
...params.providerParams
|
|
8275
|
+
};
|
|
8276
|
+
try {
|
|
8277
|
+
const response = await fetch(`${baseUrl}/api/v1/payments`, {
|
|
8278
|
+
method: "POST",
|
|
8279
|
+
headers: {
|
|
8280
|
+
"Content-Type": "application/json",
|
|
8281
|
+
"Accept": "application/json",
|
|
8282
|
+
"X-Api-Key": apiKey
|
|
8283
|
+
},
|
|
8284
|
+
body: JSON.stringify(payload)
|
|
8285
|
+
});
|
|
8286
|
+
const text = await response.text();
|
|
8287
|
+
let data = null;
|
|
8288
|
+
try {
|
|
8289
|
+
data = JSON.parse(text);
|
|
8290
|
+
} catch {
|
|
8291
|
+
}
|
|
8292
|
+
if (!response.ok || !data || data.error) {
|
|
8293
|
+
return {
|
|
8294
|
+
success: false,
|
|
8295
|
+
provider: "sumopod",
|
|
8296
|
+
orderId,
|
|
8297
|
+
amount: integerAmount,
|
|
8298
|
+
rawResponse: data,
|
|
8299
|
+
error: data?.message || data?.error || `HTTP error! Status: ${response.status} - ${text}`
|
|
8300
|
+
};
|
|
8301
|
+
}
|
|
8302
|
+
const isQris = data.payment_channel_used?.toLowerCase()?.includes("qris") || data.payment_code_type === "QRIS" || data.payment_code_type === "QR_TEXT" || !data.payment_code_type;
|
|
8303
|
+
const isVa = data.payment_code_type === "ACCOUNT_NUMBER";
|
|
8304
|
+
return {
|
|
8305
|
+
success: true,
|
|
8306
|
+
provider: "sumopod",
|
|
8307
|
+
orderId: data.order_id || orderId,
|
|
8308
|
+
amount: data.amount ? Number(data.amount) : integerAmount,
|
|
8309
|
+
reference: data.payment_id,
|
|
8310
|
+
paymentUrl: data.payment_link_url,
|
|
8311
|
+
paymentCode: data.payment_code,
|
|
8312
|
+
qrString: isQris ? data.payment_code || data.payment_link_url : void 0,
|
|
8313
|
+
qrCodeUrl: data.payment_code_type === "QR_IMAGE" ? data.payment_code : void 0,
|
|
8314
|
+
vaNumber: isVa ? data.payment_code : void 0,
|
|
8315
|
+
vaBank: isVa ? data.payment_channel_used?.split(".")[0]?.toLowerCase() : void 0,
|
|
8316
|
+
expiresAt: data.expires_at ? new Date(data.expires_at) : void 0,
|
|
8317
|
+
mode: isQris ? "qris" : isVa ? "va" : "checkout",
|
|
8318
|
+
rawResponse: data
|
|
8319
|
+
};
|
|
8320
|
+
} catch (e) {
|
|
8321
|
+
return {
|
|
8322
|
+
success: false,
|
|
8323
|
+
provider: "sumopod",
|
|
8324
|
+
orderId,
|
|
8325
|
+
amount: integerAmount,
|
|
8326
|
+
rawResponse: null,
|
|
8327
|
+
error: e.message || "Failed to make request to SumoPod API"
|
|
8328
|
+
};
|
|
8329
|
+
}
|
|
8330
|
+
}
|
|
8331
|
+
async verifyCallback(body, config) {
|
|
8332
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
8333
|
+
let parsedBody;
|
|
8334
|
+
try {
|
|
8335
|
+
parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
8336
|
+
} catch {
|
|
8337
|
+
parsedBody = {};
|
|
8338
|
+
}
|
|
8339
|
+
const headers = config.extra?.headers || {};
|
|
8340
|
+
const getHeader = (name) => {
|
|
8341
|
+
const lower = name.toLowerCase();
|
|
8342
|
+
for (const k of Object.keys(headers)) {
|
|
8343
|
+
if (k.toLowerCase() === lower) {
|
|
8344
|
+
const val = headers[k];
|
|
8345
|
+
return Array.isArray(val) ? val[0] : val;
|
|
8346
|
+
}
|
|
8347
|
+
}
|
|
8348
|
+
return void 0;
|
|
8349
|
+
};
|
|
8350
|
+
const svixId = getHeader("svix-id") || config.extra?.svixId;
|
|
8351
|
+
const svixTimestamp = getHeader("svix-timestamp") || config.extra?.svixTimestamp;
|
|
8352
|
+
const svixSignature = getHeader("svix-signature") || config.extra?.svixSignature || config.extra?.signatureHeader;
|
|
8353
|
+
const receivedToken = getHeader("x-webhook-token") || config.extra?.webhookTokenHeader;
|
|
8354
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
8355
|
+
const webhookToken = config.extra?.webhookToken || config.extra?.callbackToken || "";
|
|
8356
|
+
let isValid = false;
|
|
8357
|
+
if (svixId && svixTimestamp && svixSignature && webhookSecret) {
|
|
8358
|
+
isValid = verifySumopodSvixSignature(webhookSecret, svixId, svixTimestamp, svixSignature, rawBody);
|
|
8359
|
+
} else if (receivedToken && webhookToken) {
|
|
8360
|
+
isValid = verifySumopodToken(webhookToken, receivedToken);
|
|
8361
|
+
} else if (!webhookSecret && !webhookToken) {
|
|
8362
|
+
isValid = true;
|
|
8363
|
+
}
|
|
8364
|
+
const eventType = parsedBody?.event_type || "";
|
|
8365
|
+
const data = parsedBody?.data || parsedBody;
|
|
8366
|
+
const orderId = String(data?.order_id || "");
|
|
8367
|
+
const amount = Number(data?.amount || 0);
|
|
8368
|
+
const statusRaw = (data?.status || "").toLowerCase();
|
|
8369
|
+
const isPaid = eventType === "payment.completed" || statusRaw === "completed";
|
|
8370
|
+
const isFailed = eventType === "payment.failed" || statusRaw === "failed";
|
|
8371
|
+
const isExpired = eventType === "payment.expired" || statusRaw === "expired";
|
|
8372
|
+
const isPending = !isPaid && !isFailed && !isExpired;
|
|
8373
|
+
const status = isPaid ? "paid" : isExpired ? "expired" : isFailed ? "failed" : "pending";
|
|
8374
|
+
return {
|
|
8375
|
+
isValid,
|
|
8376
|
+
provider: "sumopod",
|
|
8377
|
+
orderId,
|
|
8378
|
+
amount,
|
|
8379
|
+
status,
|
|
8380
|
+
isPaid,
|
|
8381
|
+
isPending,
|
|
8382
|
+
isFailed,
|
|
8383
|
+
isExpired,
|
|
8384
|
+
statusCode: eventType || statusRaw,
|
|
8385
|
+
transactionTime: data?.completed_at ? new Date(data.completed_at) : void 0,
|
|
8386
|
+
rawPayload: parsedBody
|
|
8387
|
+
};
|
|
8388
|
+
}
|
|
8389
|
+
async getPaymentMethods(params, config) {
|
|
8390
|
+
const amount = params?.amount || 1e4;
|
|
8391
|
+
const percentFee = Math.round(amount * 7e-3);
|
|
8392
|
+
const flatFee = 300;
|
|
8393
|
+
const totalFeeNum = percentFee + flatFee;
|
|
8394
|
+
const methods = [
|
|
8395
|
+
{
|
|
8396
|
+
paymentMethod: "qris",
|
|
8397
|
+
code: "QRIS",
|
|
8398
|
+
paymentName: "QRIS",
|
|
8399
|
+
paymentImage: "https://upload.wikimedia.org/wikipedia/commons/a/a2/Logo_QRIS.svg",
|
|
8400
|
+
totalFee: "0.7% + Rp 300",
|
|
8401
|
+
category: "QRIS",
|
|
8402
|
+
feeDetail: {
|
|
8403
|
+
percent: 0.7,
|
|
8404
|
+
flat: 300,
|
|
8405
|
+
totalFee: totalFeeNum
|
|
8406
|
+
}
|
|
8407
|
+
}
|
|
8408
|
+
];
|
|
8409
|
+
const categories = {
|
|
8410
|
+
QRIS: methods
|
|
8411
|
+
};
|
|
8412
|
+
return {
|
|
8413
|
+
success: true,
|
|
8414
|
+
provider: "sumopod",
|
|
8415
|
+
methods,
|
|
8416
|
+
categories,
|
|
8417
|
+
rawResponse: methods
|
|
8418
|
+
};
|
|
8419
|
+
}
|
|
8420
|
+
async checkTransaction(params, config) {
|
|
8421
|
+
const { merchantOrderId } = params;
|
|
8422
|
+
const apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
8423
|
+
const baseUrl = this.getBaseUrl(config);
|
|
8424
|
+
try {
|
|
8425
|
+
const response = await fetch(`${baseUrl}/api/v1/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
8426
|
+
method: "GET",
|
|
8427
|
+
headers: {
|
|
8428
|
+
"Accept": "application/json",
|
|
8429
|
+
"X-Api-Key": apiKey
|
|
8430
|
+
}
|
|
8431
|
+
});
|
|
8432
|
+
const text = await response.text();
|
|
8433
|
+
let data = null;
|
|
8434
|
+
try {
|
|
8435
|
+
data = JSON.parse(text);
|
|
8436
|
+
} catch {
|
|
8437
|
+
}
|
|
8438
|
+
if (!response.ok || !data || data.error) {
|
|
8439
|
+
return {
|
|
8440
|
+
success: false,
|
|
8441
|
+
provider: "sumopod",
|
|
8442
|
+
orderId: merchantOrderId,
|
|
8443
|
+
reference: merchantOrderId,
|
|
8444
|
+
amount: 0,
|
|
8445
|
+
statusCode: response.status.toString(),
|
|
8446
|
+
status: "failed",
|
|
8447
|
+
isPaid: false,
|
|
8448
|
+
isPending: false,
|
|
8449
|
+
isFailed: true,
|
|
8450
|
+
isExpired: false,
|
|
8451
|
+
statusMessage: data?.message || data?.error || `HTTP error! Status: ${response.status}`,
|
|
8452
|
+
error: data?.message || data?.error,
|
|
8453
|
+
rawResponse: data
|
|
8454
|
+
};
|
|
8455
|
+
}
|
|
8456
|
+
const statusRaw = (data.status || "").toLowerCase();
|
|
8457
|
+
const isPaid = statusRaw === "completed" || statusRaw === "paid";
|
|
8458
|
+
const isFailed = statusRaw === "failed";
|
|
8459
|
+
const isExpired = statusRaw === "expired";
|
|
8460
|
+
const isPending = !isPaid && !isFailed && !isExpired;
|
|
8461
|
+
const status = isPaid ? "paid" : isExpired ? "expired" : isFailed ? "failed" : "pending";
|
|
8462
|
+
return {
|
|
8463
|
+
success: true,
|
|
8464
|
+
provider: "sumopod",
|
|
8465
|
+
orderId: data.order_id || merchantOrderId,
|
|
8466
|
+
reference: data.payment_id || merchantOrderId,
|
|
8467
|
+
amount: Number(data.amount || 0),
|
|
8468
|
+
statusCode: statusRaw,
|
|
8469
|
+
status,
|
|
8470
|
+
isPaid,
|
|
8471
|
+
isPending,
|
|
8472
|
+
isFailed,
|
|
8473
|
+
isExpired,
|
|
8474
|
+
statusMessage: statusRaw,
|
|
8475
|
+
paymentType: data.payment_method || "qris",
|
|
8476
|
+
transactionTime: data.completed_at ? new Date(data.completed_at) : void 0,
|
|
8477
|
+
rawResponse: data
|
|
8478
|
+
};
|
|
8479
|
+
} catch (e) {
|
|
8480
|
+
return {
|
|
8481
|
+
success: false,
|
|
8482
|
+
provider: "sumopod",
|
|
8483
|
+
orderId: merchantOrderId,
|
|
8484
|
+
reference: merchantOrderId,
|
|
8485
|
+
amount: 0,
|
|
8486
|
+
statusCode: "ERROR",
|
|
8487
|
+
status: "failed",
|
|
8488
|
+
isPaid: false,
|
|
8489
|
+
isPending: false,
|
|
8490
|
+
isFailed: true,
|
|
8491
|
+
isExpired: false,
|
|
8492
|
+
statusMessage: e.message,
|
|
8493
|
+
error: e.message,
|
|
8494
|
+
rawResponse: null
|
|
8495
|
+
};
|
|
8496
|
+
}
|
|
8497
|
+
}
|
|
8498
|
+
};
|
|
8499
|
+
|
|
8077
8500
|
// src/clients/duitku.ts
|
|
8078
8501
|
var DuitkuClient = class {
|
|
8079
8502
|
merchantCode;
|
|
@@ -9497,6 +9920,63 @@ var TwoCheckoutClient = class {
|
|
|
9497
9920
|
}
|
|
9498
9921
|
};
|
|
9499
9922
|
|
|
9923
|
+
// src/clients/sumopod.ts
|
|
9924
|
+
var SumopodClient = class {
|
|
9925
|
+
apiKey;
|
|
9926
|
+
baseUrl;
|
|
9927
|
+
constructor(config) {
|
|
9928
|
+
this.apiKey = config.apiKey || config.secretKey || config.serverKey || "";
|
|
9929
|
+
this.baseUrl = config.customBaseUrl || (config.sandbox ? "https://api-pay-sandbox.sumopod.com" : "https://api-pay.sumopod.com");
|
|
9930
|
+
}
|
|
9931
|
+
/**
|
|
9932
|
+
* HTTP request helper dengan header autentikasi X-Api-Key SumoPod
|
|
9933
|
+
*/
|
|
9934
|
+
async request(method, endpoint, body) {
|
|
9935
|
+
const url = endpoint.startsWith("http") ? endpoint : `${this.baseUrl}${endpoint}`;
|
|
9936
|
+
const headers = {
|
|
9937
|
+
"Content-Type": "application/json",
|
|
9938
|
+
"Accept": "application/json",
|
|
9939
|
+
"X-Api-Key": this.apiKey
|
|
9940
|
+
};
|
|
9941
|
+
const fetchOptions = {
|
|
9942
|
+
method,
|
|
9943
|
+
headers
|
|
9944
|
+
};
|
|
9945
|
+
if (method === "POST" && body) {
|
|
9946
|
+
fetchOptions.body = JSON.stringify(body);
|
|
9947
|
+
}
|
|
9948
|
+
const response = await fetch(url, fetchOptions);
|
|
9949
|
+
const text = await response.text();
|
|
9950
|
+
let data = null;
|
|
9951
|
+
try {
|
|
9952
|
+
data = JSON.parse(text);
|
|
9953
|
+
} catch {
|
|
9954
|
+
}
|
|
9955
|
+
if (!response.ok) {
|
|
9956
|
+
throw new Error(
|
|
9957
|
+
data?.message || data?.error || `HTTP error! Status: ${response.status} - ${text}`
|
|
9958
|
+
);
|
|
9959
|
+
}
|
|
9960
|
+
return data;
|
|
9961
|
+
}
|
|
9962
|
+
/**
|
|
9963
|
+
* Buat payment link / sesi pembayaran baru di SumoPod
|
|
9964
|
+
*/
|
|
9965
|
+
async createPayment(params) {
|
|
9966
|
+
return this.request("POST", "/api/v1/payments", {
|
|
9967
|
+
currency: "IDR",
|
|
9968
|
+
payment_method_type_code: "QRIS",
|
|
9969
|
+
...params
|
|
9970
|
+
});
|
|
9971
|
+
}
|
|
9972
|
+
/**
|
|
9973
|
+
* Ambil detail status pembayaran berdasarkan ID pembayaran
|
|
9974
|
+
*/
|
|
9975
|
+
async getPayment(paymentId) {
|
|
9976
|
+
return this.request("GET", `/api/v1/payments/${encodeURIComponent(paymentId)}`);
|
|
9977
|
+
}
|
|
9978
|
+
};
|
|
9979
|
+
|
|
9500
9980
|
// src/core/manager.ts
|
|
9501
9981
|
var PaymentManager = class {
|
|
9502
9982
|
providers = /* @__PURE__ */ new Map();
|
|
@@ -9520,6 +10000,7 @@ var PaymentManager = class {
|
|
|
9520
10000
|
this.registerProvider(new PayuProvider());
|
|
9521
10001
|
this.registerProvider(new BraintreeProvider());
|
|
9522
10002
|
this.registerProvider(new TwoCheckoutProvider());
|
|
10003
|
+
this.registerProvider(new SumopodProvider());
|
|
9523
10004
|
}
|
|
9524
10005
|
registerProvider(provider) {
|
|
9525
10006
|
this.providers.set(provider.name.toLowerCase(), provider);
|
|
@@ -9647,6 +10128,12 @@ var PaymentManager = class {
|
|
|
9647
10128
|
getTwoCheckoutClient(config) {
|
|
9648
10129
|
return new TwoCheckoutClient(config);
|
|
9649
10130
|
}
|
|
10131
|
+
getSumopodProvider() {
|
|
10132
|
+
return this.getProvider("sumopod");
|
|
10133
|
+
}
|
|
10134
|
+
getSumopodClient(config) {
|
|
10135
|
+
return new SumopodClient(config);
|
|
10136
|
+
}
|
|
9650
10137
|
// ─── Unified Operations ──────────────────────────────────────────────────
|
|
9651
10138
|
async createInvoice(providerName, params, config) {
|
|
9652
10139
|
const provider = this.getProvider(providerName);
|
|
@@ -9669,6 +10156,18 @@ var PaymentManager = class {
|
|
|
9669
10156
|
if (provider.probePaymentMethods) {
|
|
9670
10157
|
return provider.probePaymentMethods(config);
|
|
9671
10158
|
}
|
|
10159
|
+
try {
|
|
10160
|
+
if (typeof provider.getPaymentMethods === "function") {
|
|
10161
|
+
const res = await provider.getPaymentMethods({ amount: 1e4 }, config);
|
|
10162
|
+
if (res && res.success && Array.isArray(res.methods) && res.methods.length > 0) {
|
|
10163
|
+
return {
|
|
10164
|
+
success: true,
|
|
10165
|
+
enabled: res.methods.map((m) => m.paymentMethod)
|
|
10166
|
+
};
|
|
10167
|
+
}
|
|
10168
|
+
}
|
|
10169
|
+
} catch (e) {
|
|
10170
|
+
}
|
|
9672
10171
|
return { success: false, enabled: [], error: `Provider '${providerName}' does not support payment methods probing` };
|
|
9673
10172
|
}
|
|
9674
10173
|
// ─── Unified Advanced Operations (Refund / Balance / Disburse) ─────────────
|
|
@@ -9918,7 +10417,7 @@ function buildPaymentMethodDescriptor(pm, _providerName) {
|
|
|
9918
10417
|
badge: feeDisplay ? `${badge} \u2022 Fee ${feeDisplay}` : badge,
|
|
9919
10418
|
image: pm.paymentImage || void 0,
|
|
9920
10419
|
category,
|
|
9921
|
-
coming_soon: false,
|
|
10420
|
+
coming_soon: pm.coming_soon ?? false,
|
|
9922
10421
|
totalFee: feeDisplay || void 0
|
|
9923
10422
|
};
|
|
9924
10423
|
}
|
|
@@ -9968,10 +10467,28 @@ var ProviderRegistry = class {
|
|
|
9968
10467
|
return ties.length === 1 ? top.name : void 0;
|
|
9969
10468
|
}
|
|
9970
10469
|
/**
|
|
9971
|
-
* Autodetect provider dari struktur payload webhook.
|
|
10470
|
+
* Autodetect provider dari struktur payload webhook dan header.
|
|
9972
10471
|
* Mengembalikan nama provider jika dikenali, else undefined.
|
|
9973
10472
|
*/
|
|
9974
|
-
detectFromWebhook(payload) {
|
|
10473
|
+
detectFromWebhook(payload, headers) {
|
|
10474
|
+
if (headers) {
|
|
10475
|
+
const h = {};
|
|
10476
|
+
for (const k of Object.keys(headers)) {
|
|
10477
|
+
h[k.toLowerCase()] = headers[k];
|
|
10478
|
+
}
|
|
10479
|
+
if (h["stripe-signature"]) return "stripe";
|
|
10480
|
+
if (h["x-callback-token"]) return "xendit";
|
|
10481
|
+
if (h["x-razorpay-signature"]) return "razorpay";
|
|
10482
|
+
if (h["cko-signature"]) return "checkoutcom";
|
|
10483
|
+
if (h["openpayu-signature"]) return "payu";
|
|
10484
|
+
if (h["x-square-hmacsha256-signature"] || h["x-square-signature"]) return "square";
|
|
10485
|
+
if (h["bt_signature"]) return "braintree";
|
|
10486
|
+
if (h["x-oy-username"]) return "oy";
|
|
10487
|
+
if (h["signature"] && (h["client-id"] || h["request-id"])) return "doku";
|
|
10488
|
+
if (h["x-signature"] && (payload?.trx_id || payload?.via || payload?.sid)) return "ipaymu";
|
|
10489
|
+
if (h["svix-signature"] || h["svix-id"]) return "sumopod";
|
|
10490
|
+
if (h["x-webhook-token"]) return "sumopod";
|
|
10491
|
+
}
|
|
9975
10492
|
if (!payload) return void 0;
|
|
9976
10493
|
const p = payload;
|
|
9977
10494
|
if (p.signature_key && p.transaction_status) return "midtrans";
|
|
@@ -9985,7 +10502,10 @@ var ProviderRegistry = class {
|
|
|
9985
10502
|
if (p.merchant_id && p.order_id && p.signature) return "prismalink";
|
|
9986
10503
|
if (p.object === "event" || p.type && p.data?.object && p.api_version) return "stripe";
|
|
9987
10504
|
if (p.event && p.payload?.payment?.entity) return "razorpay";
|
|
9988
|
-
if (p.
|
|
10505
|
+
if (p.event_type && p.data?.payment_id) return "sumopod";
|
|
10506
|
+
if (p.external_id && (p.status || p.paid_amount || p.payment_method || p.payment_channel || p.id) || p.event?.startsWith("payment.") || p.event?.startsWith("qr.") || p.data?.reference_id) {
|
|
10507
|
+
return "xendit";
|
|
10508
|
+
}
|
|
9989
10509
|
if (p.event_type && p.resource && (p.event_type.startsWith("PAYMENT.") || p.event_type.startsWith("CHECKOUT.ORDER."))) return "paypal";
|
|
9990
10510
|
if (p.notificationItems || p.merchantAccountCode && p.pspReference && p.eventCode) return "adyen";
|
|
9991
10511
|
if (p.type && p.data?._links && (p.type.startsWith("payment_") || p.type.startsWith("refund_"))) return "checkoutcom";
|
|
@@ -10015,7 +10535,8 @@ var ENV_KEYS = {
|
|
|
10015
10535
|
square: ["SQUARE_ACCESS_TOKEN", "SQUARE_LOCATION_ID", "SQUARE_WEBHOOK_SIGNATURE_KEY"],
|
|
10016
10536
|
payu: ["PAYU_POS_ID", "PAYU_MD5_KEY"],
|
|
10017
10537
|
braintree: ["BRAINTREE_MERCHANT_ID", "BRAINTREE_PUBLIC_KEY", "BRAINTREE_PRIVATE_KEY"],
|
|
10018
|
-
twocheckout: ["TWOCHECKOUT_MERCHANT_CODE", "TWOCHECKOUT_SECRET_KEY", "TWOCHECKOUT_SECRET_WORD"]
|
|
10538
|
+
twocheckout: ["TWOCHECKOUT_MERCHANT_CODE", "TWOCHECKOUT_SECRET_KEY", "TWOCHECKOUT_SECRET_WORD"],
|
|
10539
|
+
sumopod: ["SUMOPOD_API_KEY", "SUMOPOD_WEBHOOK_SECRET"]
|
|
10019
10540
|
};
|
|
10020
10541
|
var WORKING_METHODS = {
|
|
10021
10542
|
midtrans: Object.keys(CANONICAL_TO_MIDTRANS),
|
|
@@ -10029,6 +10550,7 @@ var WORKING_METHODS = {
|
|
|
10029
10550
|
nicepay: Object.keys(CANONICAL_TO_NICEPAY),
|
|
10030
10551
|
oy: Object.keys(CANONICAL_TO_OY),
|
|
10031
10552
|
stripe: Object.keys(CANONICAL_TO_STRIPE),
|
|
10553
|
+
sumopod: Object.keys(CANONICAL_TO_SUMOPOD),
|
|
10032
10554
|
paypal: ["credit_card", "paylater", "paypal", "bank_transfer"],
|
|
10033
10555
|
adyen: ["credit_card", "paypal", "qris", "apple_pay", "google_pay", "klarna", "sepa"],
|
|
10034
10556
|
checkoutcom: ["credit_card", "paypal", "apple_pay", "google_pay", "klarna", "sofort", "bank_transfer"],
|
|
@@ -10057,7 +10579,8 @@ var OPERATIONS = {
|
|
|
10057
10579
|
square: { refund: true, checkBalance: true, disburse: false },
|
|
10058
10580
|
payu: { refund: true, checkBalance: false, disburse: false },
|
|
10059
10581
|
braintree: { refund: true, checkBalance: false, disburse: false },
|
|
10060
|
-
twocheckout: { refund: true, checkBalance: false, disburse: false }
|
|
10582
|
+
twocheckout: { refund: true, checkBalance: false, disburse: false },
|
|
10583
|
+
sumopod: { refund: false, checkBalance: false, disburse: false }
|
|
10061
10584
|
};
|
|
10062
10585
|
function buildDefaultDescriptors() {
|
|
10063
10586
|
return Object.keys(ENV_KEYS).map((name) => ({
|
|
@@ -10174,9 +10697,13 @@ var SPECIFIC = {
|
|
|
10174
10697
|
apiKey: ["TWOCHECKOUT_SECRET_KEY"],
|
|
10175
10698
|
merchantCode: ["TWOCHECKOUT_MERCHANT_CODE"],
|
|
10176
10699
|
merchantId: ["TWOCHECKOUT_MERCHANT_CODE"]
|
|
10700
|
+
},
|
|
10701
|
+
sumopod: {
|
|
10702
|
+
apiKey: ["SUMOPOD_API_KEY", "SUMOPOD_PRODUCTION_API_KEY", "SUMOPOD_SANDBOX_API_KEY"]
|
|
10177
10703
|
}
|
|
10178
10704
|
};
|
|
10179
10705
|
function firstDefined(env, keys) {
|
|
10706
|
+
if (!keys) return void 0;
|
|
10180
10707
|
for (const k of keys) {
|
|
10181
10708
|
const v = env[k];
|
|
10182
10709
|
if (typeof v === "string" && v.trim().length > 0) return v.trim();
|
|
@@ -10205,7 +10732,8 @@ function resolveSandbox(env, provider) {
|
|
|
10205
10732
|
payu: ["PAYU_SANDBOX"],
|
|
10206
10733
|
braintree: ["BRAINTREE_SANDBOX"],
|
|
10207
10734
|
twocheckout: ["TWOCHECKOUT_SANDBOX"],
|
|
10208
|
-
xendit: ["XENDIT_SANDBOX"]
|
|
10735
|
+
xendit: ["XENDIT_SANDBOX"],
|
|
10736
|
+
sumopod: ["SUMOPOD_SANDBOX"]
|
|
10209
10737
|
};
|
|
10210
10738
|
const specific = firstDefined(env, specificMap[provider]);
|
|
10211
10739
|
if (specific !== void 0) {
|
|
@@ -10237,8 +10765,8 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
10237
10765
|
const publicKey = customConfig?.publicKey || firstDefined(env, ["BUAYAR_PUBLIC_KEY", "PG_PUBLIC_KEY", "PUBLIC_KEY"]) || cfg.clientKey;
|
|
10238
10766
|
const privateKey = customConfig?.privateKey || firstDefined(env, ["BUAYAR_PRIVATE_KEY", "PG_PRIVATE_KEY", "PRIVATE_KEY"]) || (provider === "braintree" ? cfg.apiKey : void 0);
|
|
10239
10767
|
const extra = {
|
|
10240
|
-
webhookToken: env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
|
|
10241
|
-
webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.CHECKOUTCOM_WEBHOOK_SECRET || env.RAZORPAY_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
|
|
10768
|
+
webhookToken: (env.SUMOPOD_SANDBOX === "true" ? env.SUMOPOD_SANDBOX_WEBHOOK_TOKEN : env.SUMOPOD_PRODUCTION_WEBHOOK_TOKEN) || env.SUMOPOD_WEBHOOK_TOKEN || env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
|
|
10769
|
+
webhookSecret: (env.SUMOPOD_SANDBOX === "true" ? env.SUMOPOD_SANDBOX_WEBHOOK_SECRET : env.SUMOPOD_PRODUCTION_WEBHOOK_SECRET) || env.SUMOPOD_WEBHOOK_SECRET || env.STRIPE_WEBHOOK_SECRET || env.CHECKOUTCOM_WEBHOOK_SECRET || env.RAZORPAY_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
|
|
10242
10770
|
merchantName: env.FASPAY_MERCHANT_NAME || env.BUAYAR_MERCHANT_NAME,
|
|
10243
10771
|
userId: env.FASPAY_USER_ID,
|
|
10244
10772
|
iMid: env.NICEPAY_IMID,
|
|
@@ -10339,10 +10867,10 @@ var Buayar = class {
|
|
|
10339
10867
|
return { methods: desc.methods, operations: desc.operations };
|
|
10340
10868
|
}
|
|
10341
10869
|
/**
|
|
10342
|
-
* Deteksi nama provider dari struktur payload webhook.
|
|
10870
|
+
* Deteksi nama provider dari struktur payload webhook dan opsional headers.
|
|
10343
10871
|
*/
|
|
10344
|
-
detectProviderFromPayload(payload) {
|
|
10345
|
-
return this.registry.detectFromWebhook(payload);
|
|
10872
|
+
detectProviderFromPayload(payload, headers) {
|
|
10873
|
+
return this.registry.detectFromWebhook(payload, headers);
|
|
10346
10874
|
}
|
|
10347
10875
|
/**
|
|
10348
10876
|
* Deteksi nama provider aktif dari variabel lingkungan (kredensial yang terisi).
|
|
@@ -10470,15 +10998,48 @@ var Buayar = class {
|
|
|
10470
10998
|
if (oyUser) {
|
|
10471
10999
|
mergedConfig.extra.oyUsername = Array.isArray(oyUser) ? oyUser[0] : oyUser;
|
|
10472
11000
|
}
|
|
11001
|
+
const svixId = headers["svix-id"] || headers["Svix-Id"];
|
|
11002
|
+
const svixTimestamp = headers["svix-timestamp"] || headers["Svix-Timestamp"];
|
|
11003
|
+
const svixSignature = headers["svix-signature"] || headers["Svix-Signature"];
|
|
11004
|
+
const sumopodToken = headers["x-webhook-token"] || headers["X-Webhook-Token"];
|
|
11005
|
+
if (svixId) mergedConfig.extra.svixId = Array.isArray(svixId) ? svixId[0] : svixId;
|
|
11006
|
+
if (svixTimestamp) mergedConfig.extra.svixTimestamp = Array.isArray(svixTimestamp) ? svixTimestamp[0] : svixTimestamp;
|
|
11007
|
+
if (svixSignature) mergedConfig.extra.svixSignature = Array.isArray(svixSignature) ? svixSignature[0] : svixSignature;
|
|
11008
|
+
if (sumopodToken) mergedConfig.extra.webhookTokenHeader = Array.isArray(sumopodToken) ? sumopodToken[0] : sumopodToken;
|
|
11009
|
+
}
|
|
11010
|
+
let providerName = configOverride?.provider !== void 0 ? configOverride.provider : this.provider;
|
|
11011
|
+
if (!providerName) {
|
|
11012
|
+
const detected = this.registry.detectFromWebhook(payload, headers);
|
|
11013
|
+
if (detected) providerName = detected;
|
|
11014
|
+
}
|
|
11015
|
+
if (!providerName) {
|
|
11016
|
+
return {
|
|
11017
|
+
isValid: false,
|
|
11018
|
+
isPaid: false,
|
|
11019
|
+
isPending: false,
|
|
11020
|
+
isFailed: true,
|
|
11021
|
+
isExpired: false,
|
|
11022
|
+
status: "failed",
|
|
11023
|
+
orderId: "",
|
|
11024
|
+
amount: 0,
|
|
11025
|
+
provider: "unknown",
|
|
11026
|
+
error: "Unable to detect payment provider for webhook. Please specify provider in configuration or override.",
|
|
11027
|
+
rawPayload: payload
|
|
11028
|
+
};
|
|
10473
11029
|
}
|
|
10474
|
-
let providerName = configOverride?.provider || this.provider;
|
|
10475
|
-
const detected = this.registry.detectFromWebhook(payload);
|
|
10476
|
-
if (detected) providerName = detected;
|
|
10477
11030
|
return this.manager.verifyCallback(providerName, payload, mergedConfig);
|
|
10478
11031
|
}
|
|
10479
11032
|
async handleWebhook(payload, headers, configOverride) {
|
|
10480
11033
|
return this.verifyWebhook(payload, headers, configOverride);
|
|
10481
11034
|
}
|
|
11035
|
+
/**
|
|
11036
|
+
* Probe payment methods yang benar-benar aktif di akun merchant gateway.
|
|
11037
|
+
*/
|
|
11038
|
+
async probePaymentMethods(configOverride) {
|
|
11039
|
+
const mergedConfig = { ...this.config, ...configOverride };
|
|
11040
|
+
const providerName = configOverride?.provider || this.provider;
|
|
11041
|
+
return this.manager.probePaymentMethods(providerName, mergedConfig);
|
|
11042
|
+
}
|
|
10482
11043
|
/**
|
|
10483
11044
|
* Unified Refund — berlaku untuk semua provider yang mendukung refund.
|
|
10484
11045
|
* Provider tanpa fitur refund mengembalikan `{ supported: false }`, bukan error.
|
|
@@ -10565,6 +11126,9 @@ var Buayar = class {
|
|
|
10565
11126
|
getTwoCheckoutClient(configOverride) {
|
|
10566
11127
|
return new TwoCheckoutClient({ ...this.config, ...configOverride });
|
|
10567
11128
|
}
|
|
11129
|
+
getSumopodClient(configOverride) {
|
|
11130
|
+
return new SumopodClient({ ...this.config, ...configOverride });
|
|
11131
|
+
}
|
|
10568
11132
|
};
|
|
10569
11133
|
var buayar = new Buayar();
|
|
10570
11134
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -10585,6 +11149,7 @@ var buayar = new Buayar();
|
|
|
10585
11149
|
CANONICAL_TO_OY,
|
|
10586
11150
|
CANONICAL_TO_PRISMALINK,
|
|
10587
11151
|
CANONICAL_TO_STRIPE,
|
|
11152
|
+
CANONICAL_TO_SUMOPOD,
|
|
10588
11153
|
CANONICAL_TO_XENDIT,
|
|
10589
11154
|
CORE_API_METHODS,
|
|
10590
11155
|
CheckoutComClient,
|
|
@@ -10618,12 +11183,15 @@ var buayar = new Buayar();
|
|
|
10618
11183
|
ProviderRegistry,
|
|
10619
11184
|
RazorpayClient,
|
|
10620
11185
|
RazorpayProvider,
|
|
11186
|
+
SUMOPOD_TO_CANONICAL,
|
|
10621
11187
|
SnapApiError,
|
|
10622
11188
|
SnapClient,
|
|
10623
11189
|
SquareClient,
|
|
10624
11190
|
SquareProvider,
|
|
10625
11191
|
StripeClient,
|
|
10626
11192
|
StripeProvider,
|
|
11193
|
+
SumopodClient,
|
|
11194
|
+
SumopodProvider,
|
|
10627
11195
|
TwoCheckoutClient,
|
|
10628
11196
|
TwoCheckoutProvider,
|
|
10629
11197
|
XenditClient,
|
|
@@ -10683,6 +11251,7 @@ var buayar = new Buayar();
|
|
|
10683
11251
|
toOyPaymentMethod,
|
|
10684
11252
|
toPrismalinkPaymentMethod,
|
|
10685
11253
|
toStripePaymentMethod,
|
|
11254
|
+
toSumopodPaymentMethod,
|
|
10686
11255
|
toXenditPaymentMethod,
|
|
10687
11256
|
verifyAdyenWebhook,
|
|
10688
11257
|
verifyBraintreeWebhook,
|
|
@@ -10702,6 +11271,8 @@ var buayar = new Buayar();
|
|
|
10702
11271
|
verifySnapWebhookSignature,
|
|
10703
11272
|
verifySquareWebhook,
|
|
10704
11273
|
verifyStripeWebhook,
|
|
11274
|
+
verifySumopodSvixSignature,
|
|
11275
|
+
verifySumopodToken,
|
|
10705
11276
|
verifyTwoCheckoutWebhook,
|
|
10706
11277
|
verifyXenditWebhookToken
|
|
10707
11278
|
});
|