@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.mjs
CHANGED
|
@@ -291,6 +291,8 @@ var CANONICAL_TO_OY = {
|
|
|
291
291
|
var CANONICAL_TO_STRIPE = {
|
|
292
292
|
credit_card: "card",
|
|
293
293
|
qris: "qris",
|
|
294
|
+
QRIS_SUMOPOD: "qris",
|
|
295
|
+
qris_sumopod: "qris",
|
|
294
296
|
gopay_qris: "qris",
|
|
295
297
|
shopeepay_qris: "qris",
|
|
296
298
|
bca_va: "customer_balance",
|
|
@@ -397,6 +399,25 @@ function toStripePaymentMethod(code) {
|
|
|
397
399
|
}
|
|
398
400
|
return lower;
|
|
399
401
|
}
|
|
402
|
+
var CANONICAL_TO_SUMOPOD = {
|
|
403
|
+
qris: "QRIS",
|
|
404
|
+
gopay_qris: "QRIS",
|
|
405
|
+
shopeepay_qris: "QRIS",
|
|
406
|
+
nobu_qris: "QRIS",
|
|
407
|
+
qris_sumopod: "QRIS"
|
|
408
|
+
};
|
|
409
|
+
var SUMOPOD_TO_CANONICAL = {
|
|
410
|
+
QRIS: "qris",
|
|
411
|
+
qris: "qris"
|
|
412
|
+
};
|
|
413
|
+
function toSumopodPaymentMethod(code) {
|
|
414
|
+
if (!code) return void 0;
|
|
415
|
+
const lower = code.toLowerCase().trim();
|
|
416
|
+
if (CANONICAL_TO_SUMOPOD[lower]) {
|
|
417
|
+
return CANONICAL_TO_SUMOPOD[lower];
|
|
418
|
+
}
|
|
419
|
+
return code;
|
|
420
|
+
}
|
|
400
421
|
function toCanonicalPaymentMethod(provider, code) {
|
|
401
422
|
if (!code) return "";
|
|
402
423
|
const upper = code.toUpperCase().trim();
|
|
@@ -404,7 +425,10 @@ function toCanonicalPaymentMethod(provider, code) {
|
|
|
404
425
|
if (provider.toLowerCase() === "duitku" && DUITKU_TO_CANONICAL[upper]) {
|
|
405
426
|
return DUITKU_TO_CANONICAL[upper];
|
|
406
427
|
}
|
|
407
|
-
if (
|
|
428
|
+
if (provider.toLowerCase() === "sumopod" && SUMOPOD_TO_CANONICAL[upper]) {
|
|
429
|
+
return SUMOPOD_TO_CANONICAL[upper];
|
|
430
|
+
}
|
|
431
|
+
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]) {
|
|
408
432
|
return lower;
|
|
409
433
|
}
|
|
410
434
|
return lower;
|
|
@@ -1638,7 +1662,7 @@ var IpaymuProvider = class extends BasePaymentProvider {
|
|
|
1638
1662
|
payload = {
|
|
1639
1663
|
name: customer.name,
|
|
1640
1664
|
email: customer.email,
|
|
1641
|
-
phone: customer.phone
|
|
1665
|
+
...customer.phone ? { phone: customer.phone } : {},
|
|
1642
1666
|
amount: integerAmount,
|
|
1643
1667
|
notifyUrl,
|
|
1644
1668
|
expired: 24,
|
|
@@ -1669,7 +1693,7 @@ var IpaymuProvider = class extends BasePaymentProvider {
|
|
|
1669
1693
|
referenceId: orderId,
|
|
1670
1694
|
buyerName: customer.name,
|
|
1671
1695
|
buyerEmail: customer.email,
|
|
1672
|
-
buyerPhone: customer.phone
|
|
1696
|
+
...customer.phone ? { buyerPhone: customer.phone } : {},
|
|
1673
1697
|
...feeDirection ? { feeDirection } : {},
|
|
1674
1698
|
...escrow !== void 0 ? { escrow } : {},
|
|
1675
1699
|
...subAccount ? { account: subAccount } : {},
|
|
@@ -1899,6 +1923,28 @@ var IpaymuProvider = class extends BasePaymentProvider {
|
|
|
1899
1923
|
};
|
|
1900
1924
|
}
|
|
1901
1925
|
}
|
|
1926
|
+
async probePaymentMethods(config) {
|
|
1927
|
+
try {
|
|
1928
|
+
const res = await this.getPaymentMethods({ amount: 1e4 }, config);
|
|
1929
|
+
if (res.success && res.methods) {
|
|
1930
|
+
return {
|
|
1931
|
+
success: true,
|
|
1932
|
+
enabled: res.methods.map((m) => m.paymentMethod)
|
|
1933
|
+
};
|
|
1934
|
+
}
|
|
1935
|
+
return {
|
|
1936
|
+
success: false,
|
|
1937
|
+
enabled: [],
|
|
1938
|
+
error: res.error || "Failed to probe iPaymu payment methods"
|
|
1939
|
+
};
|
|
1940
|
+
} catch (e) {
|
|
1941
|
+
return {
|
|
1942
|
+
success: false,
|
|
1943
|
+
enabled: [],
|
|
1944
|
+
error: e.message || "Failed to probe iPaymu payment methods"
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1902
1948
|
async checkTransaction(params, config) {
|
|
1903
1949
|
const { merchantOrderId } = params;
|
|
1904
1950
|
const va = config.merchantCode || config.merchantId || "";
|
|
@@ -2186,8 +2232,8 @@ var XenditProvider = class extends BasePaymentProvider {
|
|
|
2186
2232
|
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
2187
2233
|
const webhookToken = config.extra?.webhookToken;
|
|
2188
2234
|
const headerToken = config.extra?.callbackToken || config.extra?.headers?.["x-callback-token"] || config.extra?.headers?.["X-Callback-Token"];
|
|
2189
|
-
let isValid =
|
|
2190
|
-
if (webhookToken
|
|
2235
|
+
let isValid = false;
|
|
2236
|
+
if (webhookToken && headerToken) {
|
|
2191
2237
|
isValid = verifyXenditWebhookToken(headerToken, webhookToken);
|
|
2192
2238
|
}
|
|
2193
2239
|
return {
|
|
@@ -2335,6 +2381,75 @@ var XenditProvider = class extends BasePaymentProvider {
|
|
|
2335
2381
|
category: "Paylater / Cicilan"
|
|
2336
2382
|
}
|
|
2337
2383
|
];
|
|
2384
|
+
const apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
2385
|
+
if (apiKey) {
|
|
2386
|
+
try {
|
|
2387
|
+
const authHeader = getXenditAuthHeader(apiKey);
|
|
2388
|
+
const response = await fetch(`${this.getBaseUrl()}/payment_channels`, {
|
|
2389
|
+
method: "GET",
|
|
2390
|
+
headers: {
|
|
2391
|
+
"Authorization": authHeader,
|
|
2392
|
+
"Content-Type": "application/json"
|
|
2393
|
+
}
|
|
2394
|
+
});
|
|
2395
|
+
if (response.ok) {
|
|
2396
|
+
const channels = await response.json();
|
|
2397
|
+
if (Array.isArray(channels) && channels.length > 0) {
|
|
2398
|
+
const dynamicMethods = [];
|
|
2399
|
+
for (const ch of channels) {
|
|
2400
|
+
if (ch.status && ch.status !== "ACTIVE") continue;
|
|
2401
|
+
const codeLower = (ch.channel_code || "").toLowerCase();
|
|
2402
|
+
let canonicalCode = codeLower;
|
|
2403
|
+
let category = "Virtual Account";
|
|
2404
|
+
if (ch.type === "BANK_TRANSFER" || codeLower.endsWith("_va") || ["bca", "bni", "bri", "mandiri", "permata", "cimb", "bsi"].includes(codeLower)) {
|
|
2405
|
+
canonicalCode = codeLower.endsWith("_va") ? codeLower : `${codeLower}_va`;
|
|
2406
|
+
category = "Virtual Account";
|
|
2407
|
+
} else if (ch.type === "EWALLET" || ["ovo", "dana", "linkaja", "shopeepay", "gopay"].includes(codeLower)) {
|
|
2408
|
+
canonicalCode = codeLower;
|
|
2409
|
+
category = "E-Wallet";
|
|
2410
|
+
} else if (ch.type === "QR_CODE" || codeLower === "qris") {
|
|
2411
|
+
canonicalCode = "qris";
|
|
2412
|
+
category = "QRIS";
|
|
2413
|
+
} else if (ch.type === "RETAIL_OUTLET" || ["alfamart", "indomaret"].includes(codeLower)) {
|
|
2414
|
+
canonicalCode = codeLower;
|
|
2415
|
+
category = "Retail / Gerai";
|
|
2416
|
+
} else if (ch.type === "CARD") {
|
|
2417
|
+
canonicalCode = "credit_card";
|
|
2418
|
+
category = "Kartu Kredit";
|
|
2419
|
+
} else if (ch.type === "PAYLATER" || ["kredivo", "akulaku", "indodana"].includes(codeLower)) {
|
|
2420
|
+
canonicalCode = codeLower;
|
|
2421
|
+
category = "Paylater / Cicilan";
|
|
2422
|
+
}
|
|
2423
|
+
dynamicMethods.push({
|
|
2424
|
+
paymentMethod: canonicalCode,
|
|
2425
|
+
code: ch.channel_code || canonicalCode,
|
|
2426
|
+
paymentName: ch.display_name || ch.name || ch.channel_code,
|
|
2427
|
+
paymentImage: `https://xendit.co/icons/${codeLower}.png`,
|
|
2428
|
+
totalFee: ch.fee ? `${ch.fee}` : "",
|
|
2429
|
+
category,
|
|
2430
|
+
coming_soon: false,
|
|
2431
|
+
extra: ch
|
|
2432
|
+
});
|
|
2433
|
+
}
|
|
2434
|
+
if (dynamicMethods.length > 0) {
|
|
2435
|
+
const categories2 = {};
|
|
2436
|
+
for (const item of dynamicMethods) {
|
|
2437
|
+
if (!categories2[item.category]) categories2[item.category] = [];
|
|
2438
|
+
categories2[item.category].push(item);
|
|
2439
|
+
}
|
|
2440
|
+
return {
|
|
2441
|
+
success: true,
|
|
2442
|
+
provider: "xendit",
|
|
2443
|
+
methods: dynamicMethods,
|
|
2444
|
+
categories: categories2,
|
|
2445
|
+
rawResponse: channels
|
|
2446
|
+
};
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
} catch (e) {
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2338
2453
|
const categories = {};
|
|
2339
2454
|
for (const item of staticMethods) {
|
|
2340
2455
|
if (!categories[item.category]) {
|
|
@@ -2350,6 +2465,28 @@ var XenditProvider = class extends BasePaymentProvider {
|
|
|
2350
2465
|
rawResponse: staticMethods
|
|
2351
2466
|
};
|
|
2352
2467
|
}
|
|
2468
|
+
async probePaymentMethods(config) {
|
|
2469
|
+
try {
|
|
2470
|
+
const res = await this.getPaymentMethods({ amount: 1e4 }, config);
|
|
2471
|
+
if (res.success && res.methods) {
|
|
2472
|
+
return {
|
|
2473
|
+
success: true,
|
|
2474
|
+
enabled: res.methods.map((m) => m.paymentMethod)
|
|
2475
|
+
};
|
|
2476
|
+
}
|
|
2477
|
+
return {
|
|
2478
|
+
success: false,
|
|
2479
|
+
enabled: [],
|
|
2480
|
+
error: res.error || "Failed to probe Xendit payment methods"
|
|
2481
|
+
};
|
|
2482
|
+
} catch (e) {
|
|
2483
|
+
return {
|
|
2484
|
+
success: false,
|
|
2485
|
+
enabled: [],
|
|
2486
|
+
error: e.message || "Failed to probe Xendit payment methods"
|
|
2487
|
+
};
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2353
2490
|
async checkTransaction(params, config) {
|
|
2354
2491
|
const { merchantOrderId } = params;
|
|
2355
2492
|
const apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
@@ -3146,7 +3283,7 @@ var DokuProvider = class extends BasePaymentProvider {
|
|
|
3146
3283
|
const secretKey = config.secretKey || config.apiKey || "";
|
|
3147
3284
|
const signature = headers["signature"] || headers["Signature"] || config.extra?.dokuSignature || config.extra?.signatureHeader;
|
|
3148
3285
|
const clientId = config.merchantCode || config.clientKey || "";
|
|
3149
|
-
let isValid =
|
|
3286
|
+
let isValid = false;
|
|
3150
3287
|
if (signature || headers && (headers["request-id"] || headers["Request-Id"])) {
|
|
3151
3288
|
isValid = verifyDokuWebhookSignature(headers, body, clientId, secretKey);
|
|
3152
3289
|
}
|
|
@@ -3171,7 +3308,7 @@ var DokuProvider = class extends BasePaymentProvider {
|
|
|
3171
3308
|
verifySnapCallback(body, config, headers) {
|
|
3172
3309
|
const clientSecret = config.apiKey || config.serverKey || config.secretKey || "";
|
|
3173
3310
|
const endpointUrl = config.extra?.notificationPath || headers["x-path"] || config.extra?.headers?.["request-target"] || "/api/payment/webhook";
|
|
3174
|
-
let isValid =
|
|
3311
|
+
let isValid = false;
|
|
3175
3312
|
const incomingSig = headers["x-signature"] || headers["X-SIGNATURE"] || headers["signature"] || headers["Signature"] || "";
|
|
3176
3313
|
if (incomingSig && clientSecret) {
|
|
3177
3314
|
isValid = verifySnapWebhookSignature(headers, body, clientSecret, endpointUrl);
|
|
@@ -7904,6 +8041,285 @@ var TwoCheckoutProvider = class extends BasePaymentProvider {
|
|
|
7904
8041
|
}
|
|
7905
8042
|
};
|
|
7906
8043
|
|
|
8044
|
+
// src/providers/sumopod/signature.ts
|
|
8045
|
+
import crypto6 from "crypto";
|
|
8046
|
+
function verifySumopodSvixSignature(secret, svixId, svixTimestamp, svixSignature, rawBody, toleranceSeconds = 300) {
|
|
8047
|
+
if (!secret || !svixId || !svixTimestamp || !svixSignature || rawBody === void 0 || rawBody === null) {
|
|
8048
|
+
return false;
|
|
8049
|
+
}
|
|
8050
|
+
if (toleranceSeconds > 0) {
|
|
8051
|
+
const timestampSec = Number(svixTimestamp);
|
|
8052
|
+
if (isNaN(timestampSec)) {
|
|
8053
|
+
return false;
|
|
8054
|
+
}
|
|
8055
|
+
const currentSec = Math.floor(Date.now() / 1e3);
|
|
8056
|
+
if (Math.abs(currentSec - timestampSec) > toleranceSeconds) {
|
|
8057
|
+
return false;
|
|
8058
|
+
}
|
|
8059
|
+
}
|
|
8060
|
+
try {
|
|
8061
|
+
const cleanSecret = secret.startsWith("whsec_") ? secret.slice(6) : secret;
|
|
8062
|
+
const secretBytes = Buffer.from(cleanSecret, "base64");
|
|
8063
|
+
const signedContent = `${svixId}.${svixTimestamp}.${rawBody}`;
|
|
8064
|
+
const expectedSignature = crypto6.createHmac("sha256", secretBytes).update(signedContent).digest("base64");
|
|
8065
|
+
const signatures = svixSignature.split(" ").map((s) => s.includes(",") ? s.split(",")[1] : s).filter(Boolean);
|
|
8066
|
+
return signatures.some((sig) => safeCompare(sig, expectedSignature));
|
|
8067
|
+
} catch {
|
|
8068
|
+
return false;
|
|
8069
|
+
}
|
|
8070
|
+
}
|
|
8071
|
+
function verifySumopodToken(expectedToken, receivedToken) {
|
|
8072
|
+
if (!expectedToken || !receivedToken) return false;
|
|
8073
|
+
return safeCompare(expectedToken.trim(), receivedToken.trim());
|
|
8074
|
+
}
|
|
8075
|
+
|
|
8076
|
+
// src/providers/sumopod/provider.ts
|
|
8077
|
+
var SumopodProvider = class extends BasePaymentProvider {
|
|
8078
|
+
name = "sumopod";
|
|
8079
|
+
getBaseUrl(config) {
|
|
8080
|
+
if (config?.customBaseUrl) return config.customBaseUrl;
|
|
8081
|
+
if (config?.sandbox) return "https://api-pay-sandbox.sumopod.com";
|
|
8082
|
+
return "https://api-pay.sumopod.com";
|
|
8083
|
+
}
|
|
8084
|
+
async createInvoice(params, config) {
|
|
8085
|
+
const { orderId, amount, returnUrl } = params;
|
|
8086
|
+
const apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
8087
|
+
const baseUrl = this.getBaseUrl(config);
|
|
8088
|
+
const integerAmount = Math.round(amount);
|
|
8089
|
+
const payload = {
|
|
8090
|
+
order_id: orderId,
|
|
8091
|
+
amount: integerAmount,
|
|
8092
|
+
currency: (params.currency || "IDR").toUpperCase(),
|
|
8093
|
+
expires_in_hours: params.providerParams?.expires_in_hours ?? 24,
|
|
8094
|
+
...returnUrl || config.returnUrl ? { success_return_url: returnUrl || config.returnUrl } : {},
|
|
8095
|
+
...params.providerParams?.cancel_return_url || config.returnUrl || returnUrl ? { cancel_return_url: params.providerParams?.cancel_return_url || config.returnUrl || returnUrl } : {},
|
|
8096
|
+
payment_method_type_code: "QRIS",
|
|
8097
|
+
...params.providerParams
|
|
8098
|
+
};
|
|
8099
|
+
try {
|
|
8100
|
+
const response = await fetch(`${baseUrl}/api/v1/payments`, {
|
|
8101
|
+
method: "POST",
|
|
8102
|
+
headers: {
|
|
8103
|
+
"Content-Type": "application/json",
|
|
8104
|
+
"Accept": "application/json",
|
|
8105
|
+
"X-Api-Key": apiKey
|
|
8106
|
+
},
|
|
8107
|
+
body: JSON.stringify(payload)
|
|
8108
|
+
});
|
|
8109
|
+
const text = await response.text();
|
|
8110
|
+
let data = null;
|
|
8111
|
+
try {
|
|
8112
|
+
data = JSON.parse(text);
|
|
8113
|
+
} catch {
|
|
8114
|
+
}
|
|
8115
|
+
if (!response.ok || !data || data.error) {
|
|
8116
|
+
return {
|
|
8117
|
+
success: false,
|
|
8118
|
+
provider: "sumopod",
|
|
8119
|
+
orderId,
|
|
8120
|
+
amount: integerAmount,
|
|
8121
|
+
rawResponse: data,
|
|
8122
|
+
error: data?.message || data?.error || `HTTP error! Status: ${response.status} - ${text}`
|
|
8123
|
+
};
|
|
8124
|
+
}
|
|
8125
|
+
const isQris = data.payment_channel_used?.toLowerCase()?.includes("qris") || data.payment_code_type === "QRIS" || data.payment_code_type === "QR_TEXT" || !data.payment_code_type;
|
|
8126
|
+
const isVa = data.payment_code_type === "ACCOUNT_NUMBER";
|
|
8127
|
+
return {
|
|
8128
|
+
success: true,
|
|
8129
|
+
provider: "sumopod",
|
|
8130
|
+
orderId: data.order_id || orderId,
|
|
8131
|
+
amount: data.amount ? Number(data.amount) : integerAmount,
|
|
8132
|
+
reference: data.payment_id,
|
|
8133
|
+
paymentUrl: data.payment_link_url,
|
|
8134
|
+
paymentCode: data.payment_code,
|
|
8135
|
+
qrString: isQris ? data.payment_code || data.payment_link_url : void 0,
|
|
8136
|
+
qrCodeUrl: data.payment_code_type === "QR_IMAGE" ? data.payment_code : void 0,
|
|
8137
|
+
vaNumber: isVa ? data.payment_code : void 0,
|
|
8138
|
+
vaBank: isVa ? data.payment_channel_used?.split(".")[0]?.toLowerCase() : void 0,
|
|
8139
|
+
expiresAt: data.expires_at ? new Date(data.expires_at) : void 0,
|
|
8140
|
+
mode: isQris ? "qris" : isVa ? "va" : "checkout",
|
|
8141
|
+
rawResponse: data
|
|
8142
|
+
};
|
|
8143
|
+
} catch (e) {
|
|
8144
|
+
return {
|
|
8145
|
+
success: false,
|
|
8146
|
+
provider: "sumopod",
|
|
8147
|
+
orderId,
|
|
8148
|
+
amount: integerAmount,
|
|
8149
|
+
rawResponse: null,
|
|
8150
|
+
error: e.message || "Failed to make request to SumoPod API"
|
|
8151
|
+
};
|
|
8152
|
+
}
|
|
8153
|
+
}
|
|
8154
|
+
async verifyCallback(body, config) {
|
|
8155
|
+
const rawBody = typeof body === "string" ? body : JSON.stringify(body);
|
|
8156
|
+
let parsedBody;
|
|
8157
|
+
try {
|
|
8158
|
+
parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
8159
|
+
} catch {
|
|
8160
|
+
parsedBody = {};
|
|
8161
|
+
}
|
|
8162
|
+
const headers = config.extra?.headers || {};
|
|
8163
|
+
const getHeader = (name) => {
|
|
8164
|
+
const lower = name.toLowerCase();
|
|
8165
|
+
for (const k of Object.keys(headers)) {
|
|
8166
|
+
if (k.toLowerCase() === lower) {
|
|
8167
|
+
const val = headers[k];
|
|
8168
|
+
return Array.isArray(val) ? val[0] : val;
|
|
8169
|
+
}
|
|
8170
|
+
}
|
|
8171
|
+
return void 0;
|
|
8172
|
+
};
|
|
8173
|
+
const svixId = getHeader("svix-id") || config.extra?.svixId;
|
|
8174
|
+
const svixTimestamp = getHeader("svix-timestamp") || config.extra?.svixTimestamp;
|
|
8175
|
+
const svixSignature = getHeader("svix-signature") || config.extra?.svixSignature || config.extra?.signatureHeader;
|
|
8176
|
+
const receivedToken = getHeader("x-webhook-token") || config.extra?.webhookTokenHeader;
|
|
8177
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
8178
|
+
const webhookToken = config.extra?.webhookToken || config.extra?.callbackToken || "";
|
|
8179
|
+
let isValid = false;
|
|
8180
|
+
if (svixId && svixTimestamp && svixSignature && webhookSecret) {
|
|
8181
|
+
isValid = verifySumopodSvixSignature(webhookSecret, svixId, svixTimestamp, svixSignature, rawBody);
|
|
8182
|
+
} else if (receivedToken && webhookToken) {
|
|
8183
|
+
isValid = verifySumopodToken(webhookToken, receivedToken);
|
|
8184
|
+
} else if (!webhookSecret && !webhookToken) {
|
|
8185
|
+
isValid = true;
|
|
8186
|
+
}
|
|
8187
|
+
const eventType = parsedBody?.event_type || "";
|
|
8188
|
+
const data = parsedBody?.data || parsedBody;
|
|
8189
|
+
const orderId = String(data?.order_id || "");
|
|
8190
|
+
const amount = Number(data?.amount || 0);
|
|
8191
|
+
const statusRaw = (data?.status || "").toLowerCase();
|
|
8192
|
+
const isPaid = eventType === "payment.completed" || statusRaw === "completed";
|
|
8193
|
+
const isFailed = eventType === "payment.failed" || statusRaw === "failed";
|
|
8194
|
+
const isExpired = eventType === "payment.expired" || statusRaw === "expired";
|
|
8195
|
+
const isPending = !isPaid && !isFailed && !isExpired;
|
|
8196
|
+
const status = isPaid ? "paid" : isExpired ? "expired" : isFailed ? "failed" : "pending";
|
|
8197
|
+
return {
|
|
8198
|
+
isValid,
|
|
8199
|
+
provider: "sumopod",
|
|
8200
|
+
orderId,
|
|
8201
|
+
amount,
|
|
8202
|
+
status,
|
|
8203
|
+
isPaid,
|
|
8204
|
+
isPending,
|
|
8205
|
+
isFailed,
|
|
8206
|
+
isExpired,
|
|
8207
|
+
statusCode: eventType || statusRaw,
|
|
8208
|
+
transactionTime: data?.completed_at ? new Date(data.completed_at) : void 0,
|
|
8209
|
+
rawPayload: parsedBody
|
|
8210
|
+
};
|
|
8211
|
+
}
|
|
8212
|
+
async getPaymentMethods(params, config) {
|
|
8213
|
+
const amount = params?.amount || 1e4;
|
|
8214
|
+
const percentFee = Math.round(amount * 7e-3);
|
|
8215
|
+
const flatFee = 300;
|
|
8216
|
+
const totalFeeNum = percentFee + flatFee;
|
|
8217
|
+
const methods = [
|
|
8218
|
+
{
|
|
8219
|
+
paymentMethod: "qris",
|
|
8220
|
+
code: "QRIS",
|
|
8221
|
+
paymentName: "QRIS",
|
|
8222
|
+
paymentImage: "https://upload.wikimedia.org/wikipedia/commons/a/a2/Logo_QRIS.svg",
|
|
8223
|
+
totalFee: "0.7% + Rp 300",
|
|
8224
|
+
category: "QRIS",
|
|
8225
|
+
feeDetail: {
|
|
8226
|
+
percent: 0.7,
|
|
8227
|
+
flat: 300,
|
|
8228
|
+
totalFee: totalFeeNum
|
|
8229
|
+
}
|
|
8230
|
+
}
|
|
8231
|
+
];
|
|
8232
|
+
const categories = {
|
|
8233
|
+
QRIS: methods
|
|
8234
|
+
};
|
|
8235
|
+
return {
|
|
8236
|
+
success: true,
|
|
8237
|
+
provider: "sumopod",
|
|
8238
|
+
methods,
|
|
8239
|
+
categories,
|
|
8240
|
+
rawResponse: methods
|
|
8241
|
+
};
|
|
8242
|
+
}
|
|
8243
|
+
async checkTransaction(params, config) {
|
|
8244
|
+
const { merchantOrderId } = params;
|
|
8245
|
+
const apiKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
8246
|
+
const baseUrl = this.getBaseUrl(config);
|
|
8247
|
+
try {
|
|
8248
|
+
const response = await fetch(`${baseUrl}/api/v1/payments/${encodeURIComponent(merchantOrderId)}`, {
|
|
8249
|
+
method: "GET",
|
|
8250
|
+
headers: {
|
|
8251
|
+
"Accept": "application/json",
|
|
8252
|
+
"X-Api-Key": apiKey
|
|
8253
|
+
}
|
|
8254
|
+
});
|
|
8255
|
+
const text = await response.text();
|
|
8256
|
+
let data = null;
|
|
8257
|
+
try {
|
|
8258
|
+
data = JSON.parse(text);
|
|
8259
|
+
} catch {
|
|
8260
|
+
}
|
|
8261
|
+
if (!response.ok || !data || data.error) {
|
|
8262
|
+
return {
|
|
8263
|
+
success: false,
|
|
8264
|
+
provider: "sumopod",
|
|
8265
|
+
orderId: merchantOrderId,
|
|
8266
|
+
reference: merchantOrderId,
|
|
8267
|
+
amount: 0,
|
|
8268
|
+
statusCode: response.status.toString(),
|
|
8269
|
+
status: "failed",
|
|
8270
|
+
isPaid: false,
|
|
8271
|
+
isPending: false,
|
|
8272
|
+
isFailed: true,
|
|
8273
|
+
isExpired: false,
|
|
8274
|
+
statusMessage: data?.message || data?.error || `HTTP error! Status: ${response.status}`,
|
|
8275
|
+
error: data?.message || data?.error,
|
|
8276
|
+
rawResponse: data
|
|
8277
|
+
};
|
|
8278
|
+
}
|
|
8279
|
+
const statusRaw = (data.status || "").toLowerCase();
|
|
8280
|
+
const isPaid = statusRaw === "completed" || statusRaw === "paid";
|
|
8281
|
+
const isFailed = statusRaw === "failed";
|
|
8282
|
+
const isExpired = statusRaw === "expired";
|
|
8283
|
+
const isPending = !isPaid && !isFailed && !isExpired;
|
|
8284
|
+
const status = isPaid ? "paid" : isExpired ? "expired" : isFailed ? "failed" : "pending";
|
|
8285
|
+
return {
|
|
8286
|
+
success: true,
|
|
8287
|
+
provider: "sumopod",
|
|
8288
|
+
orderId: data.order_id || merchantOrderId,
|
|
8289
|
+
reference: data.payment_id || merchantOrderId,
|
|
8290
|
+
amount: Number(data.amount || 0),
|
|
8291
|
+
statusCode: statusRaw,
|
|
8292
|
+
status,
|
|
8293
|
+
isPaid,
|
|
8294
|
+
isPending,
|
|
8295
|
+
isFailed,
|
|
8296
|
+
isExpired,
|
|
8297
|
+
statusMessage: statusRaw,
|
|
8298
|
+
paymentType: data.payment_method || "qris",
|
|
8299
|
+
transactionTime: data.completed_at ? new Date(data.completed_at) : void 0,
|
|
8300
|
+
rawResponse: data
|
|
8301
|
+
};
|
|
8302
|
+
} catch (e) {
|
|
8303
|
+
return {
|
|
8304
|
+
success: false,
|
|
8305
|
+
provider: "sumopod",
|
|
8306
|
+
orderId: merchantOrderId,
|
|
8307
|
+
reference: merchantOrderId,
|
|
8308
|
+
amount: 0,
|
|
8309
|
+
statusCode: "ERROR",
|
|
8310
|
+
status: "failed",
|
|
8311
|
+
isPaid: false,
|
|
8312
|
+
isPending: false,
|
|
8313
|
+
isFailed: true,
|
|
8314
|
+
isExpired: false,
|
|
8315
|
+
statusMessage: e.message,
|
|
8316
|
+
error: e.message,
|
|
8317
|
+
rawResponse: null
|
|
8318
|
+
};
|
|
8319
|
+
}
|
|
8320
|
+
}
|
|
8321
|
+
};
|
|
8322
|
+
|
|
7907
8323
|
// src/clients/duitku.ts
|
|
7908
8324
|
var DuitkuClient = class {
|
|
7909
8325
|
merchantCode;
|
|
@@ -9327,6 +9743,63 @@ var TwoCheckoutClient = class {
|
|
|
9327
9743
|
}
|
|
9328
9744
|
};
|
|
9329
9745
|
|
|
9746
|
+
// src/clients/sumopod.ts
|
|
9747
|
+
var SumopodClient = class {
|
|
9748
|
+
apiKey;
|
|
9749
|
+
baseUrl;
|
|
9750
|
+
constructor(config) {
|
|
9751
|
+
this.apiKey = config.apiKey || config.secretKey || config.serverKey || "";
|
|
9752
|
+
this.baseUrl = config.customBaseUrl || (config.sandbox ? "https://api-pay-sandbox.sumopod.com" : "https://api-pay.sumopod.com");
|
|
9753
|
+
}
|
|
9754
|
+
/**
|
|
9755
|
+
* HTTP request helper dengan header autentikasi X-Api-Key SumoPod
|
|
9756
|
+
*/
|
|
9757
|
+
async request(method, endpoint, body) {
|
|
9758
|
+
const url = endpoint.startsWith("http") ? endpoint : `${this.baseUrl}${endpoint}`;
|
|
9759
|
+
const headers = {
|
|
9760
|
+
"Content-Type": "application/json",
|
|
9761
|
+
"Accept": "application/json",
|
|
9762
|
+
"X-Api-Key": this.apiKey
|
|
9763
|
+
};
|
|
9764
|
+
const fetchOptions = {
|
|
9765
|
+
method,
|
|
9766
|
+
headers
|
|
9767
|
+
};
|
|
9768
|
+
if (method === "POST" && body) {
|
|
9769
|
+
fetchOptions.body = JSON.stringify(body);
|
|
9770
|
+
}
|
|
9771
|
+
const response = await fetch(url, fetchOptions);
|
|
9772
|
+
const text = await response.text();
|
|
9773
|
+
let data = null;
|
|
9774
|
+
try {
|
|
9775
|
+
data = JSON.parse(text);
|
|
9776
|
+
} catch {
|
|
9777
|
+
}
|
|
9778
|
+
if (!response.ok) {
|
|
9779
|
+
throw new Error(
|
|
9780
|
+
data?.message || data?.error || `HTTP error! Status: ${response.status} - ${text}`
|
|
9781
|
+
);
|
|
9782
|
+
}
|
|
9783
|
+
return data;
|
|
9784
|
+
}
|
|
9785
|
+
/**
|
|
9786
|
+
* Buat payment link / sesi pembayaran baru di SumoPod
|
|
9787
|
+
*/
|
|
9788
|
+
async createPayment(params) {
|
|
9789
|
+
return this.request("POST", "/api/v1/payments", {
|
|
9790
|
+
currency: "IDR",
|
|
9791
|
+
payment_method_type_code: "QRIS",
|
|
9792
|
+
...params
|
|
9793
|
+
});
|
|
9794
|
+
}
|
|
9795
|
+
/**
|
|
9796
|
+
* Ambil detail status pembayaran berdasarkan ID pembayaran
|
|
9797
|
+
*/
|
|
9798
|
+
async getPayment(paymentId) {
|
|
9799
|
+
return this.request("GET", `/api/v1/payments/${encodeURIComponent(paymentId)}`);
|
|
9800
|
+
}
|
|
9801
|
+
};
|
|
9802
|
+
|
|
9330
9803
|
// src/core/manager.ts
|
|
9331
9804
|
var PaymentManager = class {
|
|
9332
9805
|
providers = /* @__PURE__ */ new Map();
|
|
@@ -9350,6 +9823,7 @@ var PaymentManager = class {
|
|
|
9350
9823
|
this.registerProvider(new PayuProvider());
|
|
9351
9824
|
this.registerProvider(new BraintreeProvider());
|
|
9352
9825
|
this.registerProvider(new TwoCheckoutProvider());
|
|
9826
|
+
this.registerProvider(new SumopodProvider());
|
|
9353
9827
|
}
|
|
9354
9828
|
registerProvider(provider) {
|
|
9355
9829
|
this.providers.set(provider.name.toLowerCase(), provider);
|
|
@@ -9477,6 +9951,12 @@ var PaymentManager = class {
|
|
|
9477
9951
|
getTwoCheckoutClient(config) {
|
|
9478
9952
|
return new TwoCheckoutClient(config);
|
|
9479
9953
|
}
|
|
9954
|
+
getSumopodProvider() {
|
|
9955
|
+
return this.getProvider("sumopod");
|
|
9956
|
+
}
|
|
9957
|
+
getSumopodClient(config) {
|
|
9958
|
+
return new SumopodClient(config);
|
|
9959
|
+
}
|
|
9480
9960
|
// ─── Unified Operations ──────────────────────────────────────────────────
|
|
9481
9961
|
async createInvoice(providerName, params, config) {
|
|
9482
9962
|
const provider = this.getProvider(providerName);
|
|
@@ -9499,6 +9979,18 @@ var PaymentManager = class {
|
|
|
9499
9979
|
if (provider.probePaymentMethods) {
|
|
9500
9980
|
return provider.probePaymentMethods(config);
|
|
9501
9981
|
}
|
|
9982
|
+
try {
|
|
9983
|
+
if (typeof provider.getPaymentMethods === "function") {
|
|
9984
|
+
const res = await provider.getPaymentMethods({ amount: 1e4 }, config);
|
|
9985
|
+
if (res && res.success && Array.isArray(res.methods) && res.methods.length > 0) {
|
|
9986
|
+
return {
|
|
9987
|
+
success: true,
|
|
9988
|
+
enabled: res.methods.map((m) => m.paymentMethod)
|
|
9989
|
+
};
|
|
9990
|
+
}
|
|
9991
|
+
}
|
|
9992
|
+
} catch (e) {
|
|
9993
|
+
}
|
|
9502
9994
|
return { success: false, enabled: [], error: `Provider '${providerName}' does not support payment methods probing` };
|
|
9503
9995
|
}
|
|
9504
9996
|
// ─── Unified Advanced Operations (Refund / Balance / Disburse) ─────────────
|
|
@@ -9748,7 +10240,7 @@ function buildPaymentMethodDescriptor(pm, _providerName) {
|
|
|
9748
10240
|
badge: feeDisplay ? `${badge} \u2022 Fee ${feeDisplay}` : badge,
|
|
9749
10241
|
image: pm.paymentImage || void 0,
|
|
9750
10242
|
category,
|
|
9751
|
-
coming_soon: false,
|
|
10243
|
+
coming_soon: pm.coming_soon ?? false,
|
|
9752
10244
|
totalFee: feeDisplay || void 0
|
|
9753
10245
|
};
|
|
9754
10246
|
}
|
|
@@ -9798,10 +10290,28 @@ var ProviderRegistry = class {
|
|
|
9798
10290
|
return ties.length === 1 ? top.name : void 0;
|
|
9799
10291
|
}
|
|
9800
10292
|
/**
|
|
9801
|
-
* Autodetect provider dari struktur payload webhook.
|
|
10293
|
+
* Autodetect provider dari struktur payload webhook dan header.
|
|
9802
10294
|
* Mengembalikan nama provider jika dikenali, else undefined.
|
|
9803
10295
|
*/
|
|
9804
|
-
detectFromWebhook(payload) {
|
|
10296
|
+
detectFromWebhook(payload, headers) {
|
|
10297
|
+
if (headers) {
|
|
10298
|
+
const h = {};
|
|
10299
|
+
for (const k of Object.keys(headers)) {
|
|
10300
|
+
h[k.toLowerCase()] = headers[k];
|
|
10301
|
+
}
|
|
10302
|
+
if (h["stripe-signature"]) return "stripe";
|
|
10303
|
+
if (h["x-callback-token"]) return "xendit";
|
|
10304
|
+
if (h["x-razorpay-signature"]) return "razorpay";
|
|
10305
|
+
if (h["cko-signature"]) return "checkoutcom";
|
|
10306
|
+
if (h["openpayu-signature"]) return "payu";
|
|
10307
|
+
if (h["x-square-hmacsha256-signature"] || h["x-square-signature"]) return "square";
|
|
10308
|
+
if (h["bt_signature"]) return "braintree";
|
|
10309
|
+
if (h["x-oy-username"]) return "oy";
|
|
10310
|
+
if (h["signature"] && (h["client-id"] || h["request-id"])) return "doku";
|
|
10311
|
+
if (h["x-signature"] && (payload?.trx_id || payload?.via || payload?.sid)) return "ipaymu";
|
|
10312
|
+
if (h["svix-signature"] || h["svix-id"]) return "sumopod";
|
|
10313
|
+
if (h["x-webhook-token"]) return "sumopod";
|
|
10314
|
+
}
|
|
9805
10315
|
if (!payload) return void 0;
|
|
9806
10316
|
const p = payload;
|
|
9807
10317
|
if (p.signature_key && p.transaction_status) return "midtrans";
|
|
@@ -9815,7 +10325,10 @@ var ProviderRegistry = class {
|
|
|
9815
10325
|
if (p.merchant_id && p.order_id && p.signature) return "prismalink";
|
|
9816
10326
|
if (p.object === "event" || p.type && p.data?.object && p.api_version) return "stripe";
|
|
9817
10327
|
if (p.event && p.payload?.payment?.entity) return "razorpay";
|
|
9818
|
-
if (p.
|
|
10328
|
+
if (p.event_type && p.data?.payment_id) return "sumopod";
|
|
10329
|
+
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) {
|
|
10330
|
+
return "xendit";
|
|
10331
|
+
}
|
|
9819
10332
|
if (p.event_type && p.resource && (p.event_type.startsWith("PAYMENT.") || p.event_type.startsWith("CHECKOUT.ORDER."))) return "paypal";
|
|
9820
10333
|
if (p.notificationItems || p.merchantAccountCode && p.pspReference && p.eventCode) return "adyen";
|
|
9821
10334
|
if (p.type && p.data?._links && (p.type.startsWith("payment_") || p.type.startsWith("refund_"))) return "checkoutcom";
|
|
@@ -9845,7 +10358,8 @@ var ENV_KEYS = {
|
|
|
9845
10358
|
square: ["SQUARE_ACCESS_TOKEN", "SQUARE_LOCATION_ID", "SQUARE_WEBHOOK_SIGNATURE_KEY"],
|
|
9846
10359
|
payu: ["PAYU_POS_ID", "PAYU_MD5_KEY"],
|
|
9847
10360
|
braintree: ["BRAINTREE_MERCHANT_ID", "BRAINTREE_PUBLIC_KEY", "BRAINTREE_PRIVATE_KEY"],
|
|
9848
|
-
twocheckout: ["TWOCHECKOUT_MERCHANT_CODE", "TWOCHECKOUT_SECRET_KEY", "TWOCHECKOUT_SECRET_WORD"]
|
|
10361
|
+
twocheckout: ["TWOCHECKOUT_MERCHANT_CODE", "TWOCHECKOUT_SECRET_KEY", "TWOCHECKOUT_SECRET_WORD"],
|
|
10362
|
+
sumopod: ["SUMOPOD_API_KEY", "SUMOPOD_WEBHOOK_SECRET"]
|
|
9849
10363
|
};
|
|
9850
10364
|
var WORKING_METHODS = {
|
|
9851
10365
|
midtrans: Object.keys(CANONICAL_TO_MIDTRANS),
|
|
@@ -9859,6 +10373,7 @@ var WORKING_METHODS = {
|
|
|
9859
10373
|
nicepay: Object.keys(CANONICAL_TO_NICEPAY),
|
|
9860
10374
|
oy: Object.keys(CANONICAL_TO_OY),
|
|
9861
10375
|
stripe: Object.keys(CANONICAL_TO_STRIPE),
|
|
10376
|
+
sumopod: Object.keys(CANONICAL_TO_SUMOPOD),
|
|
9862
10377
|
paypal: ["credit_card", "paylater", "paypal", "bank_transfer"],
|
|
9863
10378
|
adyen: ["credit_card", "paypal", "qris", "apple_pay", "google_pay", "klarna", "sepa"],
|
|
9864
10379
|
checkoutcom: ["credit_card", "paypal", "apple_pay", "google_pay", "klarna", "sofort", "bank_transfer"],
|
|
@@ -9887,7 +10402,8 @@ var OPERATIONS = {
|
|
|
9887
10402
|
square: { refund: true, checkBalance: true, disburse: false },
|
|
9888
10403
|
payu: { refund: true, checkBalance: false, disburse: false },
|
|
9889
10404
|
braintree: { refund: true, checkBalance: false, disburse: false },
|
|
9890
|
-
twocheckout: { refund: true, checkBalance: false, disburse: false }
|
|
10405
|
+
twocheckout: { refund: true, checkBalance: false, disburse: false },
|
|
10406
|
+
sumopod: { refund: false, checkBalance: false, disburse: false }
|
|
9891
10407
|
};
|
|
9892
10408
|
function buildDefaultDescriptors() {
|
|
9893
10409
|
return Object.keys(ENV_KEYS).map((name) => ({
|
|
@@ -10004,9 +10520,13 @@ var SPECIFIC = {
|
|
|
10004
10520
|
apiKey: ["TWOCHECKOUT_SECRET_KEY"],
|
|
10005
10521
|
merchantCode: ["TWOCHECKOUT_MERCHANT_CODE"],
|
|
10006
10522
|
merchantId: ["TWOCHECKOUT_MERCHANT_CODE"]
|
|
10523
|
+
},
|
|
10524
|
+
sumopod: {
|
|
10525
|
+
apiKey: ["SUMOPOD_API_KEY", "SUMOPOD_PRODUCTION_API_KEY", "SUMOPOD_SANDBOX_API_KEY"]
|
|
10007
10526
|
}
|
|
10008
10527
|
};
|
|
10009
10528
|
function firstDefined(env, keys) {
|
|
10529
|
+
if (!keys) return void 0;
|
|
10010
10530
|
for (const k of keys) {
|
|
10011
10531
|
const v = env[k];
|
|
10012
10532
|
if (typeof v === "string" && v.trim().length > 0) return v.trim();
|
|
@@ -10035,7 +10555,8 @@ function resolveSandbox(env, provider) {
|
|
|
10035
10555
|
payu: ["PAYU_SANDBOX"],
|
|
10036
10556
|
braintree: ["BRAINTREE_SANDBOX"],
|
|
10037
10557
|
twocheckout: ["TWOCHECKOUT_SANDBOX"],
|
|
10038
|
-
xendit: ["XENDIT_SANDBOX"]
|
|
10558
|
+
xendit: ["XENDIT_SANDBOX"],
|
|
10559
|
+
sumopod: ["SUMOPOD_SANDBOX"]
|
|
10039
10560
|
};
|
|
10040
10561
|
const specific = firstDefined(env, specificMap[provider]);
|
|
10041
10562
|
if (specific !== void 0) {
|
|
@@ -10067,8 +10588,8 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
10067
10588
|
const publicKey = customConfig?.publicKey || firstDefined(env, ["BUAYAR_PUBLIC_KEY", "PG_PUBLIC_KEY", "PUBLIC_KEY"]) || cfg.clientKey;
|
|
10068
10589
|
const privateKey = customConfig?.privateKey || firstDefined(env, ["BUAYAR_PRIVATE_KEY", "PG_PRIVATE_KEY", "PRIVATE_KEY"]) || (provider === "braintree" ? cfg.apiKey : void 0);
|
|
10069
10590
|
const extra = {
|
|
10070
|
-
webhookToken: env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
|
|
10071
|
-
webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.CHECKOUTCOM_WEBHOOK_SECRET || env.RAZORPAY_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
|
|
10591
|
+
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,
|
|
10592
|
+
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,
|
|
10072
10593
|
merchantName: env.FASPAY_MERCHANT_NAME || env.BUAYAR_MERCHANT_NAME,
|
|
10073
10594
|
userId: env.FASPAY_USER_ID,
|
|
10074
10595
|
iMid: env.NICEPAY_IMID,
|
|
@@ -10169,10 +10690,10 @@ var Buayar = class {
|
|
|
10169
10690
|
return { methods: desc.methods, operations: desc.operations };
|
|
10170
10691
|
}
|
|
10171
10692
|
/**
|
|
10172
|
-
* Deteksi nama provider dari struktur payload webhook.
|
|
10693
|
+
* Deteksi nama provider dari struktur payload webhook dan opsional headers.
|
|
10173
10694
|
*/
|
|
10174
|
-
detectProviderFromPayload(payload) {
|
|
10175
|
-
return this.registry.detectFromWebhook(payload);
|
|
10695
|
+
detectProviderFromPayload(payload, headers) {
|
|
10696
|
+
return this.registry.detectFromWebhook(payload, headers);
|
|
10176
10697
|
}
|
|
10177
10698
|
/**
|
|
10178
10699
|
* Deteksi nama provider aktif dari variabel lingkungan (kredensial yang terisi).
|
|
@@ -10300,15 +10821,48 @@ var Buayar = class {
|
|
|
10300
10821
|
if (oyUser) {
|
|
10301
10822
|
mergedConfig.extra.oyUsername = Array.isArray(oyUser) ? oyUser[0] : oyUser;
|
|
10302
10823
|
}
|
|
10824
|
+
const svixId = headers["svix-id"] || headers["Svix-Id"];
|
|
10825
|
+
const svixTimestamp = headers["svix-timestamp"] || headers["Svix-Timestamp"];
|
|
10826
|
+
const svixSignature = headers["svix-signature"] || headers["Svix-Signature"];
|
|
10827
|
+
const sumopodToken = headers["x-webhook-token"] || headers["X-Webhook-Token"];
|
|
10828
|
+
if (svixId) mergedConfig.extra.svixId = Array.isArray(svixId) ? svixId[0] : svixId;
|
|
10829
|
+
if (svixTimestamp) mergedConfig.extra.svixTimestamp = Array.isArray(svixTimestamp) ? svixTimestamp[0] : svixTimestamp;
|
|
10830
|
+
if (svixSignature) mergedConfig.extra.svixSignature = Array.isArray(svixSignature) ? svixSignature[0] : svixSignature;
|
|
10831
|
+
if (sumopodToken) mergedConfig.extra.webhookTokenHeader = Array.isArray(sumopodToken) ? sumopodToken[0] : sumopodToken;
|
|
10832
|
+
}
|
|
10833
|
+
let providerName = configOverride?.provider !== void 0 ? configOverride.provider : this.provider;
|
|
10834
|
+
if (!providerName) {
|
|
10835
|
+
const detected = this.registry.detectFromWebhook(payload, headers);
|
|
10836
|
+
if (detected) providerName = detected;
|
|
10837
|
+
}
|
|
10838
|
+
if (!providerName) {
|
|
10839
|
+
return {
|
|
10840
|
+
isValid: false,
|
|
10841
|
+
isPaid: false,
|
|
10842
|
+
isPending: false,
|
|
10843
|
+
isFailed: true,
|
|
10844
|
+
isExpired: false,
|
|
10845
|
+
status: "failed",
|
|
10846
|
+
orderId: "",
|
|
10847
|
+
amount: 0,
|
|
10848
|
+
provider: "unknown",
|
|
10849
|
+
error: "Unable to detect payment provider for webhook. Please specify provider in configuration or override.",
|
|
10850
|
+
rawPayload: payload
|
|
10851
|
+
};
|
|
10303
10852
|
}
|
|
10304
|
-
let providerName = configOverride?.provider || this.provider;
|
|
10305
|
-
const detected = this.registry.detectFromWebhook(payload);
|
|
10306
|
-
if (detected) providerName = detected;
|
|
10307
10853
|
return this.manager.verifyCallback(providerName, payload, mergedConfig);
|
|
10308
10854
|
}
|
|
10309
10855
|
async handleWebhook(payload, headers, configOverride) {
|
|
10310
10856
|
return this.verifyWebhook(payload, headers, configOverride);
|
|
10311
10857
|
}
|
|
10858
|
+
/**
|
|
10859
|
+
* Probe payment methods yang benar-benar aktif di akun merchant gateway.
|
|
10860
|
+
*/
|
|
10861
|
+
async probePaymentMethods(configOverride) {
|
|
10862
|
+
const mergedConfig = { ...this.config, ...configOverride };
|
|
10863
|
+
const providerName = configOverride?.provider || this.provider;
|
|
10864
|
+
return this.manager.probePaymentMethods(providerName, mergedConfig);
|
|
10865
|
+
}
|
|
10312
10866
|
/**
|
|
10313
10867
|
* Unified Refund — berlaku untuk semua provider yang mendukung refund.
|
|
10314
10868
|
* Provider tanpa fitur refund mengembalikan `{ supported: false }`, bukan error.
|
|
@@ -10395,6 +10949,9 @@ var Buayar = class {
|
|
|
10395
10949
|
getTwoCheckoutClient(configOverride) {
|
|
10396
10950
|
return new TwoCheckoutClient({ ...this.config, ...configOverride });
|
|
10397
10951
|
}
|
|
10952
|
+
getSumopodClient(configOverride) {
|
|
10953
|
+
return new SumopodClient({ ...this.config, ...configOverride });
|
|
10954
|
+
}
|
|
10398
10955
|
};
|
|
10399
10956
|
var buayar = new Buayar();
|
|
10400
10957
|
export {
|
|
@@ -10414,6 +10971,7 @@ export {
|
|
|
10414
10971
|
CANONICAL_TO_OY,
|
|
10415
10972
|
CANONICAL_TO_PRISMALINK,
|
|
10416
10973
|
CANONICAL_TO_STRIPE,
|
|
10974
|
+
CANONICAL_TO_SUMOPOD,
|
|
10417
10975
|
CANONICAL_TO_XENDIT,
|
|
10418
10976
|
CORE_API_METHODS,
|
|
10419
10977
|
CheckoutComClient,
|
|
@@ -10447,12 +11005,15 @@ export {
|
|
|
10447
11005
|
ProviderRegistry,
|
|
10448
11006
|
RazorpayClient,
|
|
10449
11007
|
RazorpayProvider,
|
|
11008
|
+
SUMOPOD_TO_CANONICAL,
|
|
10450
11009
|
SnapApiError,
|
|
10451
11010
|
SnapClient,
|
|
10452
11011
|
SquareClient,
|
|
10453
11012
|
SquareProvider,
|
|
10454
11013
|
StripeClient,
|
|
10455
11014
|
StripeProvider,
|
|
11015
|
+
SumopodClient,
|
|
11016
|
+
SumopodProvider,
|
|
10456
11017
|
TwoCheckoutClient,
|
|
10457
11018
|
TwoCheckoutProvider,
|
|
10458
11019
|
XenditClient,
|
|
@@ -10512,6 +11073,7 @@ export {
|
|
|
10512
11073
|
toOyPaymentMethod,
|
|
10513
11074
|
toPrismalinkPaymentMethod,
|
|
10514
11075
|
toStripePaymentMethod,
|
|
11076
|
+
toSumopodPaymentMethod,
|
|
10515
11077
|
toXenditPaymentMethod,
|
|
10516
11078
|
verifyAdyenWebhook,
|
|
10517
11079
|
verifyBraintreeWebhook,
|
|
@@ -10531,6 +11093,8 @@ export {
|
|
|
10531
11093
|
verifySnapWebhookSignature,
|
|
10532
11094
|
verifySquareWebhook,
|
|
10533
11095
|
verifyStripeWebhook,
|
|
11096
|
+
verifySumopodSvixSignature,
|
|
11097
|
+
verifySumopodToken,
|
|
10534
11098
|
verifyTwoCheckoutWebhook,
|
|
10535
11099
|
verifyXenditWebhookToken
|
|
10536
11100
|
};
|