@crediblemark/buayar 0.8.6 → 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 +97 -3
- package/dist/index.d.ts +97 -3
- package/dist/index.js +409 -6
- package/dist/index.mjs +402 -6
- package/docs/guide.md +6 -2
- 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;
|
|
@@ -8187,6 +8218,285 @@ var TwoCheckoutProvider = class extends BasePaymentProvider {
|
|
|
8187
8218
|
}
|
|
8188
8219
|
};
|
|
8189
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
|
+
|
|
8190
8500
|
// src/clients/duitku.ts
|
|
8191
8501
|
var DuitkuClient = class {
|
|
8192
8502
|
merchantCode;
|
|
@@ -9610,6 +9920,63 @@ var TwoCheckoutClient = class {
|
|
|
9610
9920
|
}
|
|
9611
9921
|
};
|
|
9612
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
|
+
|
|
9613
9980
|
// src/core/manager.ts
|
|
9614
9981
|
var PaymentManager = class {
|
|
9615
9982
|
providers = /* @__PURE__ */ new Map();
|
|
@@ -9633,6 +10000,7 @@ var PaymentManager = class {
|
|
|
9633
10000
|
this.registerProvider(new PayuProvider());
|
|
9634
10001
|
this.registerProvider(new BraintreeProvider());
|
|
9635
10002
|
this.registerProvider(new TwoCheckoutProvider());
|
|
10003
|
+
this.registerProvider(new SumopodProvider());
|
|
9636
10004
|
}
|
|
9637
10005
|
registerProvider(provider) {
|
|
9638
10006
|
this.providers.set(provider.name.toLowerCase(), provider);
|
|
@@ -9760,6 +10128,12 @@ var PaymentManager = class {
|
|
|
9760
10128
|
getTwoCheckoutClient(config) {
|
|
9761
10129
|
return new TwoCheckoutClient(config);
|
|
9762
10130
|
}
|
|
10131
|
+
getSumopodProvider() {
|
|
10132
|
+
return this.getProvider("sumopod");
|
|
10133
|
+
}
|
|
10134
|
+
getSumopodClient(config) {
|
|
10135
|
+
return new SumopodClient(config);
|
|
10136
|
+
}
|
|
9763
10137
|
// ─── Unified Operations ──────────────────────────────────────────────────
|
|
9764
10138
|
async createInvoice(providerName, params, config) {
|
|
9765
10139
|
const provider = this.getProvider(providerName);
|
|
@@ -10112,6 +10486,8 @@ var ProviderRegistry = class {
|
|
|
10112
10486
|
if (h["x-oy-username"]) return "oy";
|
|
10113
10487
|
if (h["signature"] && (h["client-id"] || h["request-id"])) return "doku";
|
|
10114
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";
|
|
10115
10491
|
}
|
|
10116
10492
|
if (!payload) return void 0;
|
|
10117
10493
|
const p = payload;
|
|
@@ -10126,6 +10502,7 @@ var ProviderRegistry = class {
|
|
|
10126
10502
|
if (p.merchant_id && p.order_id && p.signature) return "prismalink";
|
|
10127
10503
|
if (p.object === "event" || p.type && p.data?.object && p.api_version) return "stripe";
|
|
10128
10504
|
if (p.event && p.payload?.payment?.entity) return "razorpay";
|
|
10505
|
+
if (p.event_type && p.data?.payment_id) return "sumopod";
|
|
10129
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) {
|
|
10130
10507
|
return "xendit";
|
|
10131
10508
|
}
|
|
@@ -10158,7 +10535,8 @@ var ENV_KEYS = {
|
|
|
10158
10535
|
square: ["SQUARE_ACCESS_TOKEN", "SQUARE_LOCATION_ID", "SQUARE_WEBHOOK_SIGNATURE_KEY"],
|
|
10159
10536
|
payu: ["PAYU_POS_ID", "PAYU_MD5_KEY"],
|
|
10160
10537
|
braintree: ["BRAINTREE_MERCHANT_ID", "BRAINTREE_PUBLIC_KEY", "BRAINTREE_PRIVATE_KEY"],
|
|
10161
|
-
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"]
|
|
10162
10540
|
};
|
|
10163
10541
|
var WORKING_METHODS = {
|
|
10164
10542
|
midtrans: Object.keys(CANONICAL_TO_MIDTRANS),
|
|
@@ -10172,6 +10550,7 @@ var WORKING_METHODS = {
|
|
|
10172
10550
|
nicepay: Object.keys(CANONICAL_TO_NICEPAY),
|
|
10173
10551
|
oy: Object.keys(CANONICAL_TO_OY),
|
|
10174
10552
|
stripe: Object.keys(CANONICAL_TO_STRIPE),
|
|
10553
|
+
sumopod: Object.keys(CANONICAL_TO_SUMOPOD),
|
|
10175
10554
|
paypal: ["credit_card", "paylater", "paypal", "bank_transfer"],
|
|
10176
10555
|
adyen: ["credit_card", "paypal", "qris", "apple_pay", "google_pay", "klarna", "sepa"],
|
|
10177
10556
|
checkoutcom: ["credit_card", "paypal", "apple_pay", "google_pay", "klarna", "sofort", "bank_transfer"],
|
|
@@ -10200,7 +10579,8 @@ var OPERATIONS = {
|
|
|
10200
10579
|
square: { refund: true, checkBalance: true, disburse: false },
|
|
10201
10580
|
payu: { refund: true, checkBalance: false, disburse: false },
|
|
10202
10581
|
braintree: { refund: true, checkBalance: false, disburse: false },
|
|
10203
|
-
twocheckout: { refund: true, checkBalance: false, disburse: false }
|
|
10582
|
+
twocheckout: { refund: true, checkBalance: false, disburse: false },
|
|
10583
|
+
sumopod: { refund: false, checkBalance: false, disburse: false }
|
|
10204
10584
|
};
|
|
10205
10585
|
function buildDefaultDescriptors() {
|
|
10206
10586
|
return Object.keys(ENV_KEYS).map((name) => ({
|
|
@@ -10317,9 +10697,13 @@ var SPECIFIC = {
|
|
|
10317
10697
|
apiKey: ["TWOCHECKOUT_SECRET_KEY"],
|
|
10318
10698
|
merchantCode: ["TWOCHECKOUT_MERCHANT_CODE"],
|
|
10319
10699
|
merchantId: ["TWOCHECKOUT_MERCHANT_CODE"]
|
|
10700
|
+
},
|
|
10701
|
+
sumopod: {
|
|
10702
|
+
apiKey: ["SUMOPOD_API_KEY", "SUMOPOD_PRODUCTION_API_KEY", "SUMOPOD_SANDBOX_API_KEY"]
|
|
10320
10703
|
}
|
|
10321
10704
|
};
|
|
10322
10705
|
function firstDefined(env, keys) {
|
|
10706
|
+
if (!keys) return void 0;
|
|
10323
10707
|
for (const k of keys) {
|
|
10324
10708
|
const v = env[k];
|
|
10325
10709
|
if (typeof v === "string" && v.trim().length > 0) return v.trim();
|
|
@@ -10348,7 +10732,8 @@ function resolveSandbox(env, provider) {
|
|
|
10348
10732
|
payu: ["PAYU_SANDBOX"],
|
|
10349
10733
|
braintree: ["BRAINTREE_SANDBOX"],
|
|
10350
10734
|
twocheckout: ["TWOCHECKOUT_SANDBOX"],
|
|
10351
|
-
xendit: ["XENDIT_SANDBOX"]
|
|
10735
|
+
xendit: ["XENDIT_SANDBOX"],
|
|
10736
|
+
sumopod: ["SUMOPOD_SANDBOX"]
|
|
10352
10737
|
};
|
|
10353
10738
|
const specific = firstDefined(env, specificMap[provider]);
|
|
10354
10739
|
if (specific !== void 0) {
|
|
@@ -10380,8 +10765,8 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
10380
10765
|
const publicKey = customConfig?.publicKey || firstDefined(env, ["BUAYAR_PUBLIC_KEY", "PG_PUBLIC_KEY", "PUBLIC_KEY"]) || cfg.clientKey;
|
|
10381
10766
|
const privateKey = customConfig?.privateKey || firstDefined(env, ["BUAYAR_PRIVATE_KEY", "PG_PRIVATE_KEY", "PRIVATE_KEY"]) || (provider === "braintree" ? cfg.apiKey : void 0);
|
|
10382
10767
|
const extra = {
|
|
10383
|
-
webhookToken: env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
|
|
10384
|
-
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,
|
|
10385
10770
|
merchantName: env.FASPAY_MERCHANT_NAME || env.BUAYAR_MERCHANT_NAME,
|
|
10386
10771
|
userId: env.FASPAY_USER_ID,
|
|
10387
10772
|
iMid: env.NICEPAY_IMID,
|
|
@@ -10613,6 +10998,14 @@ var Buayar = class {
|
|
|
10613
10998
|
if (oyUser) {
|
|
10614
10999
|
mergedConfig.extra.oyUsername = Array.isArray(oyUser) ? oyUser[0] : oyUser;
|
|
10615
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;
|
|
10616
11009
|
}
|
|
10617
11010
|
let providerName = configOverride?.provider !== void 0 ? configOverride.provider : this.provider;
|
|
10618
11011
|
if (!providerName) {
|
|
@@ -10733,6 +11126,9 @@ var Buayar = class {
|
|
|
10733
11126
|
getTwoCheckoutClient(configOverride) {
|
|
10734
11127
|
return new TwoCheckoutClient({ ...this.config, ...configOverride });
|
|
10735
11128
|
}
|
|
11129
|
+
getSumopodClient(configOverride) {
|
|
11130
|
+
return new SumopodClient({ ...this.config, ...configOverride });
|
|
11131
|
+
}
|
|
10736
11132
|
};
|
|
10737
11133
|
var buayar = new Buayar();
|
|
10738
11134
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -10753,6 +11149,7 @@ var buayar = new Buayar();
|
|
|
10753
11149
|
CANONICAL_TO_OY,
|
|
10754
11150
|
CANONICAL_TO_PRISMALINK,
|
|
10755
11151
|
CANONICAL_TO_STRIPE,
|
|
11152
|
+
CANONICAL_TO_SUMOPOD,
|
|
10756
11153
|
CANONICAL_TO_XENDIT,
|
|
10757
11154
|
CORE_API_METHODS,
|
|
10758
11155
|
CheckoutComClient,
|
|
@@ -10786,12 +11183,15 @@ var buayar = new Buayar();
|
|
|
10786
11183
|
ProviderRegistry,
|
|
10787
11184
|
RazorpayClient,
|
|
10788
11185
|
RazorpayProvider,
|
|
11186
|
+
SUMOPOD_TO_CANONICAL,
|
|
10789
11187
|
SnapApiError,
|
|
10790
11188
|
SnapClient,
|
|
10791
11189
|
SquareClient,
|
|
10792
11190
|
SquareProvider,
|
|
10793
11191
|
StripeClient,
|
|
10794
11192
|
StripeProvider,
|
|
11193
|
+
SumopodClient,
|
|
11194
|
+
SumopodProvider,
|
|
10795
11195
|
TwoCheckoutClient,
|
|
10796
11196
|
TwoCheckoutProvider,
|
|
10797
11197
|
XenditClient,
|
|
@@ -10851,6 +11251,7 @@ var buayar = new Buayar();
|
|
|
10851
11251
|
toOyPaymentMethod,
|
|
10852
11252
|
toPrismalinkPaymentMethod,
|
|
10853
11253
|
toStripePaymentMethod,
|
|
11254
|
+
toSumopodPaymentMethod,
|
|
10854
11255
|
toXenditPaymentMethod,
|
|
10855
11256
|
verifyAdyenWebhook,
|
|
10856
11257
|
verifyBraintreeWebhook,
|
|
@@ -10870,6 +11271,8 @@ var buayar = new Buayar();
|
|
|
10870
11271
|
verifySnapWebhookSignature,
|
|
10871
11272
|
verifySquareWebhook,
|
|
10872
11273
|
verifyStripeWebhook,
|
|
11274
|
+
verifySumopodSvixSignature,
|
|
11275
|
+
verifySumopodToken,
|
|
10873
11276
|
verifyTwoCheckoutWebhook,
|
|
10874
11277
|
verifyXenditWebhookToken
|
|
10875
11278
|
});
|