@crediblemark/buayar 0.2.0 → 0.2.1
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 +12 -2
- package/dist/index.d.mts +68 -2
- package/dist/index.d.ts +68 -2
- package/dist/index.js +497 -4
- package/dist/index.mjs +491 -4
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -281,6 +281,17 @@ var CANONICAL_TO_OY = {
|
|
|
281
281
|
alfamart: { type: "cstore", channel: "alfamart" },
|
|
282
282
|
indomaret: { type: "cstore", channel: "indomaret" }
|
|
283
283
|
};
|
|
284
|
+
var CANONICAL_TO_STRIPE = {
|
|
285
|
+
credit_card: "card",
|
|
286
|
+
qris: "qris",
|
|
287
|
+
gopay_qris: "qris",
|
|
288
|
+
shopeepay_qris: "qris",
|
|
289
|
+
bca_va: "customer_balance",
|
|
290
|
+
mandiri_va: "customer_balance",
|
|
291
|
+
bni_va: "customer_balance",
|
|
292
|
+
bri_va: "customer_balance",
|
|
293
|
+
permata_va: "customer_balance"
|
|
294
|
+
};
|
|
284
295
|
function toDuitkuPaymentMethod(code) {
|
|
285
296
|
if (!code) return void 0;
|
|
286
297
|
const lower = code.toLowerCase().trim();
|
|
@@ -368,6 +379,14 @@ function toOyPaymentMethod(code) {
|
|
|
368
379
|
}
|
|
369
380
|
return void 0;
|
|
370
381
|
}
|
|
382
|
+
function toStripePaymentMethod(code) {
|
|
383
|
+
if (!code) return void 0;
|
|
384
|
+
const lower = code.toLowerCase().trim();
|
|
385
|
+
if (CANONICAL_TO_STRIPE[lower]) {
|
|
386
|
+
return CANONICAL_TO_STRIPE[lower];
|
|
387
|
+
}
|
|
388
|
+
return lower;
|
|
389
|
+
}
|
|
371
390
|
function toCanonicalPaymentMethod(provider, code) {
|
|
372
391
|
if (!code) return "";
|
|
373
392
|
const upper = code.toUpperCase().trim();
|
|
@@ -375,7 +394,7 @@ function toCanonicalPaymentMethod(provider, code) {
|
|
|
375
394
|
if (provider.toLowerCase() === "duitku" && DUITKU_TO_CANONICAL[upper]) {
|
|
376
395
|
return DUITKU_TO_CANONICAL[upper];
|
|
377
396
|
}
|
|
378
|
-
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]) {
|
|
397
|
+
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]) {
|
|
379
398
|
return lower;
|
|
380
399
|
}
|
|
381
400
|
return lower;
|
|
@@ -4886,6 +4905,368 @@ var OyProvider = class extends BasePaymentProvider {
|
|
|
4886
4905
|
}
|
|
4887
4906
|
};
|
|
4888
4907
|
|
|
4908
|
+
// src/providers/stripe/signature.ts
|
|
4909
|
+
function serializeStripeParams(obj, prefix = "") {
|
|
4910
|
+
const pairs = [];
|
|
4911
|
+
if (obj === null || obj === void 0) {
|
|
4912
|
+
return "";
|
|
4913
|
+
}
|
|
4914
|
+
for (const key of Object.keys(obj)) {
|
|
4915
|
+
const val = obj[key];
|
|
4916
|
+
if (val === void 0 || val === null) continue;
|
|
4917
|
+
const fullKey = prefix ? `${prefix}[${key}]` : key;
|
|
4918
|
+
if (typeof val === "object" && !(val instanceof Date)) {
|
|
4919
|
+
const nested = serializeStripeParams(val, fullKey);
|
|
4920
|
+
if (nested) pairs.push(nested);
|
|
4921
|
+
} else {
|
|
4922
|
+
pairs.push(`${encodeURIComponent(fullKey)}=${encodeURIComponent(String(val))}`);
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
return pairs.join("&");
|
|
4926
|
+
}
|
|
4927
|
+
function verifyStripeWebhook(rawPayload, signatureHeader, webhookSecret, toleranceSeconds = 300) {
|
|
4928
|
+
if (!signatureHeader || !webhookSecret) {
|
|
4929
|
+
return true;
|
|
4930
|
+
}
|
|
4931
|
+
const items = signatureHeader.split(",");
|
|
4932
|
+
let timestamp = "";
|
|
4933
|
+
const signatures = [];
|
|
4934
|
+
for (const item of items) {
|
|
4935
|
+
const [key, value] = item.trim().split("=");
|
|
4936
|
+
if (key === "t") {
|
|
4937
|
+
timestamp = value;
|
|
4938
|
+
} else if (key === "v1") {
|
|
4939
|
+
signatures.push(value);
|
|
4940
|
+
}
|
|
4941
|
+
}
|
|
4942
|
+
if (!timestamp || signatures.length === 0) {
|
|
4943
|
+
return false;
|
|
4944
|
+
}
|
|
4945
|
+
const payloadString = typeof rawPayload === "string" ? rawPayload : JSON.stringify(rawPayload);
|
|
4946
|
+
const signedPayload = `${timestamp}.${payloadString}`;
|
|
4947
|
+
const expectedSignature = hmacSha256(signedPayload, webhookSecret);
|
|
4948
|
+
return signatures.some((sig) => safeCompare(sig.toLowerCase(), expectedSignature.toLowerCase()));
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4951
|
+
// src/providers/stripe/provider.ts
|
|
4952
|
+
var StripeProvider = class extends BasePaymentProvider {
|
|
4953
|
+
name = "stripe";
|
|
4954
|
+
getBaseUrl() {
|
|
4955
|
+
return "https://api.stripe.com/v1";
|
|
4956
|
+
}
|
|
4957
|
+
async createInvoice(params, config) {
|
|
4958
|
+
const { orderId, amount, productDetails, customer, returnUrl } = params;
|
|
4959
|
+
const secretKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
4960
|
+
const integerAmount = Math.round(amount);
|
|
4961
|
+
const stripeMethod = toStripePaymentMethod(params.paymentMethod);
|
|
4962
|
+
const isDirect = !!params.paymentMethod;
|
|
4963
|
+
const baseUrl = this.getBaseUrl();
|
|
4964
|
+
const headers = {
|
|
4965
|
+
"Authorization": `Bearer ${secretKey}`,
|
|
4966
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
4967
|
+
};
|
|
4968
|
+
try {
|
|
4969
|
+
if (isDirect) {
|
|
4970
|
+
const url = `${baseUrl}/payment_intents`;
|
|
4971
|
+
const payload = {
|
|
4972
|
+
amount: integerAmount,
|
|
4973
|
+
currency: (params.currency || "idr").toLowerCase(),
|
|
4974
|
+
description: productDetails,
|
|
4975
|
+
receipt_email: customer?.email,
|
|
4976
|
+
payment_method_types: [stripeMethod || "card"],
|
|
4977
|
+
metadata: {
|
|
4978
|
+
order_id: orderId,
|
|
4979
|
+
customer_name: customer?.name
|
|
4980
|
+
},
|
|
4981
|
+
...params.providerParams
|
|
4982
|
+
};
|
|
4983
|
+
const response = await fetch(url, {
|
|
4984
|
+
method: "POST",
|
|
4985
|
+
headers,
|
|
4986
|
+
body: serializeStripeParams(payload)
|
|
4987
|
+
});
|
|
4988
|
+
const text = await response.text();
|
|
4989
|
+
let data = null;
|
|
4990
|
+
try {
|
|
4991
|
+
data = JSON.parse(text);
|
|
4992
|
+
} catch (e) {
|
|
4993
|
+
}
|
|
4994
|
+
if (!response.ok || !data || data.error) {
|
|
4995
|
+
return {
|
|
4996
|
+
success: false,
|
|
4997
|
+
provider: "stripe",
|
|
4998
|
+
orderId,
|
|
4999
|
+
amount: integerAmount,
|
|
5000
|
+
rawResponse: data,
|
|
5001
|
+
error: data?.error?.message || `HTTP error! Status: ${response.status} - ${text}`
|
|
5002
|
+
};
|
|
5003
|
+
}
|
|
5004
|
+
return {
|
|
5005
|
+
success: true,
|
|
5006
|
+
provider: "stripe",
|
|
5007
|
+
orderId,
|
|
5008
|
+
amount: data.amount ? Number(data.amount) : integerAmount,
|
|
5009
|
+
reference: data.id,
|
|
5010
|
+
paymentCode: data.client_secret,
|
|
5011
|
+
rawResponse: data
|
|
5012
|
+
};
|
|
5013
|
+
} else {
|
|
5014
|
+
const url = `${baseUrl}/checkout/sessions`;
|
|
5015
|
+
const successUrl = returnUrl || config.returnUrl || "https://example.com/payment/success";
|
|
5016
|
+
const cancelUrl = returnUrl || config.returnUrl || "https://example.com/payment/cancel";
|
|
5017
|
+
const payload = {
|
|
5018
|
+
mode: "payment",
|
|
5019
|
+
client_reference_id: orderId,
|
|
5020
|
+
customer_email: customer?.email,
|
|
5021
|
+
line_items: [
|
|
5022
|
+
{
|
|
5023
|
+
price_data: {
|
|
5024
|
+
currency: (params.currency || "idr").toLowerCase(),
|
|
5025
|
+
product_data: {
|
|
5026
|
+
name: productDetails
|
|
5027
|
+
},
|
|
5028
|
+
unit_amount: integerAmount
|
|
5029
|
+
},
|
|
5030
|
+
quantity: 1
|
|
5031
|
+
}
|
|
5032
|
+
],
|
|
5033
|
+
metadata: {
|
|
5034
|
+
order_id: orderId
|
|
5035
|
+
},
|
|
5036
|
+
success_url: successUrl,
|
|
5037
|
+
cancel_url: cancelUrl,
|
|
5038
|
+
...params.providerParams
|
|
5039
|
+
};
|
|
5040
|
+
const response = await fetch(url, {
|
|
5041
|
+
method: "POST",
|
|
5042
|
+
headers,
|
|
5043
|
+
body: serializeStripeParams(payload)
|
|
5044
|
+
});
|
|
5045
|
+
const text = await response.text();
|
|
5046
|
+
let data = null;
|
|
5047
|
+
try {
|
|
5048
|
+
data = JSON.parse(text);
|
|
5049
|
+
} catch (e) {
|
|
5050
|
+
}
|
|
5051
|
+
if (!response.ok || !data || data.error) {
|
|
5052
|
+
return {
|
|
5053
|
+
success: false,
|
|
5054
|
+
provider: "stripe",
|
|
5055
|
+
orderId,
|
|
5056
|
+
amount: integerAmount,
|
|
5057
|
+
rawResponse: data,
|
|
5058
|
+
error: data?.error?.message || `HTTP error! Status: ${response.status} - ${text}`
|
|
5059
|
+
};
|
|
5060
|
+
}
|
|
5061
|
+
return {
|
|
5062
|
+
success: true,
|
|
5063
|
+
provider: "stripe",
|
|
5064
|
+
orderId: data.client_reference_id || orderId,
|
|
5065
|
+
amount: data.amount_total ? Number(data.amount_total) : integerAmount,
|
|
5066
|
+
reference: data.id,
|
|
5067
|
+
paymentUrl: data.url,
|
|
5068
|
+
rawResponse: data
|
|
5069
|
+
};
|
|
5070
|
+
}
|
|
5071
|
+
} catch (e) {
|
|
5072
|
+
return {
|
|
5073
|
+
success: false,
|
|
5074
|
+
provider: "stripe",
|
|
5075
|
+
orderId,
|
|
5076
|
+
amount: integerAmount,
|
|
5077
|
+
rawResponse: null,
|
|
5078
|
+
error: e.message || "Failed to make request to Stripe API"
|
|
5079
|
+
};
|
|
5080
|
+
}
|
|
5081
|
+
}
|
|
5082
|
+
async verifyCallback(body, config) {
|
|
5083
|
+
const webhookSecret = config.extra?.webhookSecret || config.secretKey || "";
|
|
5084
|
+
const signatureHeader = config.extra?.signatureHeader || "";
|
|
5085
|
+
const isValid = verifyStripeWebhook(body, signatureHeader, webhookSecret);
|
|
5086
|
+
const eventType = body.type || "";
|
|
5087
|
+
const obj = body.data?.object || body;
|
|
5088
|
+
const orderId = obj.metadata?.order_id || obj.client_reference_id || obj.id || "";
|
|
5089
|
+
const amount = obj.amount_total || obj.amount || 0;
|
|
5090
|
+
const paymentStatus = (obj.payment_status || obj.status || "").toLowerCase();
|
|
5091
|
+
const isPaid = eventType === "checkout.session.completed" && (paymentStatus === "paid" || paymentStatus === "complete") || eventType === "payment_intent.succeeded" && paymentStatus === "succeeded" || eventType === "charge.succeeded" && (paymentStatus === "succeeded" || paymentStatus === "paid") || paymentStatus === "paid" || paymentStatus === "succeeded";
|
|
5092
|
+
const isPending = paymentStatus === "unpaid" || paymentStatus === "processing" || paymentStatus === "requires_action";
|
|
5093
|
+
const isExpired = paymentStatus === "expired" || eventType === "checkout.session.expired";
|
|
5094
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5095
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5096
|
+
return {
|
|
5097
|
+
isValid,
|
|
5098
|
+
provider: "stripe",
|
|
5099
|
+
orderId: String(orderId),
|
|
5100
|
+
amount: Number(amount) || 0,
|
|
5101
|
+
status,
|
|
5102
|
+
isPaid,
|
|
5103
|
+
isPending,
|
|
5104
|
+
isFailed,
|
|
5105
|
+
isExpired,
|
|
5106
|
+
statusCode: eventType || paymentStatus,
|
|
5107
|
+
rawPayload: body
|
|
5108
|
+
};
|
|
5109
|
+
}
|
|
5110
|
+
async getPaymentMethods(params, config) {
|
|
5111
|
+
const staticMethods = [
|
|
5112
|
+
{
|
|
5113
|
+
paymentMethod: "credit_card",
|
|
5114
|
+
code: "credit_card",
|
|
5115
|
+
paymentName: "Credit / Debit Card (Visa, Mastercard, JCB, Amex)",
|
|
5116
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5117
|
+
totalFee: "2.9% + IDR 2,000",
|
|
5118
|
+
category: "Kartu Kredit"
|
|
5119
|
+
},
|
|
5120
|
+
{
|
|
5121
|
+
paymentMethod: "qris",
|
|
5122
|
+
code: "qris",
|
|
5123
|
+
paymentName: "QRIS (Indonesia)",
|
|
5124
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5125
|
+
totalFee: "0.7%",
|
|
5126
|
+
category: "QRIS"
|
|
5127
|
+
},
|
|
5128
|
+
{
|
|
5129
|
+
paymentMethod: "bca_va",
|
|
5130
|
+
code: "bca_va",
|
|
5131
|
+
paymentName: "BCA Virtual Account (Bank Transfer)",
|
|
5132
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5133
|
+
totalFee: "IDR 4,000",
|
|
5134
|
+
category: "Virtual Account"
|
|
5135
|
+
},
|
|
5136
|
+
{
|
|
5137
|
+
paymentMethod: "mandiri_va",
|
|
5138
|
+
code: "mandiri_va",
|
|
5139
|
+
paymentName: "Mandiri Virtual Account (Bank Transfer)",
|
|
5140
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5141
|
+
totalFee: "IDR 4,000",
|
|
5142
|
+
category: "Virtual Account"
|
|
5143
|
+
},
|
|
5144
|
+
{
|
|
5145
|
+
paymentMethod: "bni_va",
|
|
5146
|
+
code: "bni_va",
|
|
5147
|
+
paymentName: "BNI Virtual Account (Bank Transfer)",
|
|
5148
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5149
|
+
totalFee: "IDR 4,000",
|
|
5150
|
+
category: "Virtual Account"
|
|
5151
|
+
},
|
|
5152
|
+
{
|
|
5153
|
+
paymentMethod: "bri_va",
|
|
5154
|
+
code: "bri_va",
|
|
5155
|
+
paymentName: "BRI Virtual Account (Bank Transfer)",
|
|
5156
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5157
|
+
totalFee: "IDR 4,000",
|
|
5158
|
+
category: "Virtual Account"
|
|
5159
|
+
},
|
|
5160
|
+
{
|
|
5161
|
+
paymentMethod: "permata_va",
|
|
5162
|
+
code: "permata_va",
|
|
5163
|
+
paymentName: "Permata Virtual Account (Bank Transfer)",
|
|
5164
|
+
paymentImage: "https://stripe.com/img/v3/home/social.png",
|
|
5165
|
+
totalFee: "IDR 4,000",
|
|
5166
|
+
category: "Virtual Account"
|
|
5167
|
+
}
|
|
5168
|
+
];
|
|
5169
|
+
const categories = {};
|
|
5170
|
+
for (const item of staticMethods) {
|
|
5171
|
+
if (!categories[item.category]) {
|
|
5172
|
+
categories[item.category] = [];
|
|
5173
|
+
}
|
|
5174
|
+
categories[item.category].push(item);
|
|
5175
|
+
}
|
|
5176
|
+
return {
|
|
5177
|
+
success: true,
|
|
5178
|
+
provider: "stripe",
|
|
5179
|
+
methods: staticMethods,
|
|
5180
|
+
categories,
|
|
5181
|
+
rawResponse: staticMethods
|
|
5182
|
+
};
|
|
5183
|
+
}
|
|
5184
|
+
async checkTransaction(params, config) {
|
|
5185
|
+
const { merchantOrderId } = params;
|
|
5186
|
+
const secretKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5187
|
+
const baseUrl = this.getBaseUrl();
|
|
5188
|
+
let endpoint = `/checkout/sessions/${encodeURIComponent(merchantOrderId)}`;
|
|
5189
|
+
if (merchantOrderId.startsWith("pi_")) {
|
|
5190
|
+
endpoint = `/payment_intents/${encodeURIComponent(merchantOrderId)}`;
|
|
5191
|
+
}
|
|
5192
|
+
const url = `${baseUrl}${endpoint}`;
|
|
5193
|
+
const headers = {
|
|
5194
|
+
"Authorization": `Bearer ${secretKey}`,
|
|
5195
|
+
"Accept": "application/json"
|
|
5196
|
+
};
|
|
5197
|
+
try {
|
|
5198
|
+
const response = await fetch(url, {
|
|
5199
|
+
method: "GET",
|
|
5200
|
+
headers
|
|
5201
|
+
});
|
|
5202
|
+
const text = await response.text();
|
|
5203
|
+
let data = null;
|
|
5204
|
+
try {
|
|
5205
|
+
data = JSON.parse(text);
|
|
5206
|
+
} catch (e) {
|
|
5207
|
+
}
|
|
5208
|
+
if (!response.ok || !data || data.error) {
|
|
5209
|
+
return {
|
|
5210
|
+
success: false,
|
|
5211
|
+
provider: "stripe",
|
|
5212
|
+
orderId: merchantOrderId,
|
|
5213
|
+
reference: "",
|
|
5214
|
+
amount: 0,
|
|
5215
|
+
statusCode: response.status.toString(),
|
|
5216
|
+
status: "failed",
|
|
5217
|
+
isPaid: false,
|
|
5218
|
+
isPending: false,
|
|
5219
|
+
isFailed: true,
|
|
5220
|
+
isExpired: false,
|
|
5221
|
+
statusMessage: data?.error?.message || `HTTP error! Status: ${response.status}`,
|
|
5222
|
+
error: data?.error?.message || `HTTP error! Status: ${response.status}`,
|
|
5223
|
+
rawResponse: data
|
|
5224
|
+
};
|
|
5225
|
+
}
|
|
5226
|
+
const paymentStatus = (data.payment_status || data.status || "").toLowerCase();
|
|
5227
|
+
const isPaid = paymentStatus === "paid" || paymentStatus === "succeeded" || paymentStatus === "complete";
|
|
5228
|
+
const isPending = paymentStatus === "unpaid" || paymentStatus === "processing" || paymentStatus === "requires_action";
|
|
5229
|
+
const isExpired = paymentStatus === "expired";
|
|
5230
|
+
const isFailed = !isPaid && !isPending && !isExpired;
|
|
5231
|
+
const status = isPaid ? "paid" : isPending ? "pending" : isExpired ? "expired" : "failed";
|
|
5232
|
+
return {
|
|
5233
|
+
success: true,
|
|
5234
|
+
provider: "stripe",
|
|
5235
|
+
orderId: data.metadata?.order_id || data.client_reference_id || data.id || merchantOrderId,
|
|
5236
|
+
reference: data.id || "",
|
|
5237
|
+
amount: data.amount_total ? Number(data.amount_total) : data.amount ? Number(data.amount) : 0,
|
|
5238
|
+
statusCode: paymentStatus,
|
|
5239
|
+
status,
|
|
5240
|
+
isPaid,
|
|
5241
|
+
isPending,
|
|
5242
|
+
isFailed,
|
|
5243
|
+
isExpired,
|
|
5244
|
+
statusMessage: paymentStatus,
|
|
5245
|
+
paymentType: data.payment_method_types?.[0] || "card",
|
|
5246
|
+
transactionTime: data.created ? new Date(data.created * 1e3) : void 0,
|
|
5247
|
+
rawResponse: data
|
|
5248
|
+
};
|
|
5249
|
+
} catch (e) {
|
|
5250
|
+
return {
|
|
5251
|
+
success: false,
|
|
5252
|
+
provider: "stripe",
|
|
5253
|
+
orderId: merchantOrderId,
|
|
5254
|
+
reference: "",
|
|
5255
|
+
amount: 0,
|
|
5256
|
+
statusCode: "ERROR",
|
|
5257
|
+
status: "failed",
|
|
5258
|
+
isPaid: false,
|
|
5259
|
+
isPending: false,
|
|
5260
|
+
isFailed: true,
|
|
5261
|
+
isExpired: false,
|
|
5262
|
+
statusMessage: e.message || "Failed to check transaction status in Stripe",
|
|
5263
|
+
error: e.message || "Failed to check transaction status in Stripe",
|
|
5264
|
+
rawResponse: null
|
|
5265
|
+
};
|
|
5266
|
+
}
|
|
5267
|
+
}
|
|
5268
|
+
};
|
|
5269
|
+
|
|
4889
5270
|
// src/clients/duitku.ts
|
|
4890
5271
|
var DuitkuClient = class {
|
|
4891
5272
|
merchantCode;
|
|
@@ -5581,6 +5962,76 @@ var OyClient = class {
|
|
|
5581
5962
|
}
|
|
5582
5963
|
};
|
|
5583
5964
|
|
|
5965
|
+
// src/clients/stripe.ts
|
|
5966
|
+
var StripeClient = class {
|
|
5967
|
+
secretKey;
|
|
5968
|
+
constructor(config) {
|
|
5969
|
+
this.secretKey = config.apiKey || config.serverKey || config.secretKey || "";
|
|
5970
|
+
}
|
|
5971
|
+
getBaseUrl() {
|
|
5972
|
+
return "https://api.stripe.com/v1";
|
|
5973
|
+
}
|
|
5974
|
+
/**
|
|
5975
|
+
* Helper HTTP Request ke Stripe API
|
|
5976
|
+
*/
|
|
5977
|
+
async request(method, endpoint, body) {
|
|
5978
|
+
const url = `${this.getBaseUrl()}${endpoint}`;
|
|
5979
|
+
const headers = {
|
|
5980
|
+
"Authorization": `Bearer ${this.secretKey}`,
|
|
5981
|
+
"Accept": "application/json"
|
|
5982
|
+
};
|
|
5983
|
+
const fetchOptions = {
|
|
5984
|
+
method,
|
|
5985
|
+
headers
|
|
5986
|
+
};
|
|
5987
|
+
if (method === "POST" && body) {
|
|
5988
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded";
|
|
5989
|
+
fetchOptions.body = serializeStripeParams(body);
|
|
5990
|
+
}
|
|
5991
|
+
const response = await fetch(url, fetchOptions);
|
|
5992
|
+
const text = await response.text();
|
|
5993
|
+
let data = null;
|
|
5994
|
+
try {
|
|
5995
|
+
data = JSON.parse(text);
|
|
5996
|
+
} catch (e) {
|
|
5997
|
+
}
|
|
5998
|
+
if (!response.ok || data?.error) {
|
|
5999
|
+
throw new Error(data?.error?.message || `HTTP error! Status: ${response.status} - ${text}`);
|
|
6000
|
+
}
|
|
6001
|
+
return data;
|
|
6002
|
+
}
|
|
6003
|
+
/**
|
|
6004
|
+
* Ambil detail Checkout Session
|
|
6005
|
+
*/
|
|
6006
|
+
async retrieveCheckoutSession(sessionId) {
|
|
6007
|
+
return this.request("GET", `/checkout/sessions/${encodeURIComponent(sessionId)}`);
|
|
6008
|
+
}
|
|
6009
|
+
/**
|
|
6010
|
+
* Ambil detail Payment Intent
|
|
6011
|
+
*/
|
|
6012
|
+
async retrievePaymentIntent(paymentIntentId) {
|
|
6013
|
+
return this.request("GET", `/payment_intents/${encodeURIComponent(paymentIntentId)}`);
|
|
6014
|
+
}
|
|
6015
|
+
/**
|
|
6016
|
+
* Cek saldo akun Stripe (Balance)
|
|
6017
|
+
*/
|
|
6018
|
+
async checkBalance() {
|
|
6019
|
+
return this.request("GET", "/balance");
|
|
6020
|
+
}
|
|
6021
|
+
/**
|
|
6022
|
+
* Buat refund dana
|
|
6023
|
+
*/
|
|
6024
|
+
async createRefund(paymentIntentId, amount) {
|
|
6025
|
+
const payload = {
|
|
6026
|
+
payment_intent: paymentIntentId
|
|
6027
|
+
};
|
|
6028
|
+
if (amount) {
|
|
6029
|
+
payload.amount = Math.round(amount);
|
|
6030
|
+
}
|
|
6031
|
+
return this.request("POST", "/refunds", payload);
|
|
6032
|
+
}
|
|
6033
|
+
};
|
|
6034
|
+
|
|
5584
6035
|
// src/core/manager.ts
|
|
5585
6036
|
var PaymentManager = class {
|
|
5586
6037
|
providers = /* @__PURE__ */ new Map();
|
|
@@ -5595,6 +6046,7 @@ var PaymentManager = class {
|
|
|
5595
6046
|
this.registerProvider(new FinpayProvider());
|
|
5596
6047
|
this.registerProvider(new NicepayProvider());
|
|
5597
6048
|
this.registerProvider(new OyProvider());
|
|
6049
|
+
this.registerProvider(new StripeProvider());
|
|
5598
6050
|
}
|
|
5599
6051
|
registerProvider(provider) {
|
|
5600
6052
|
this.providers.set(provider.name.toLowerCase(), provider);
|
|
@@ -5666,6 +6118,12 @@ var PaymentManager = class {
|
|
|
5666
6118
|
getOyClient(config) {
|
|
5667
6119
|
return new OyClient(config);
|
|
5668
6120
|
}
|
|
6121
|
+
getStripeProvider() {
|
|
6122
|
+
return this.getProvider("stripe");
|
|
6123
|
+
}
|
|
6124
|
+
getStripeClient(config) {
|
|
6125
|
+
return new StripeClient(config);
|
|
6126
|
+
}
|
|
5669
6127
|
async createInvoice(providerName, params, config) {
|
|
5670
6128
|
const provider = this.getProvider(providerName);
|
|
5671
6129
|
return provider.createInvoice(params, config);
|
|
@@ -5723,6 +6181,8 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
5723
6181
|
sandbox = env.NICEPAY_SANDBOX === "true" || env.NICEPAY_SANDBOX === "1";
|
|
5724
6182
|
} else if (env.OY_SANDBOX !== void 0) {
|
|
5725
6183
|
sandbox = env.OY_SANDBOX === "true" || env.OY_SANDBOX === "1";
|
|
6184
|
+
} else if (env.STRIPE_SANDBOX !== void 0) {
|
|
6185
|
+
sandbox = env.STRIPE_SANDBOX === "true" || env.STRIPE_SANDBOX === "1";
|
|
5726
6186
|
} else {
|
|
5727
6187
|
sandbox = env.NODE_ENV !== "production";
|
|
5728
6188
|
}
|
|
@@ -5748,6 +6208,8 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
5748
6208
|
apiKey = env.NICEPAY_KEY || env.NICEPAY_MERCHANT_KEY || env.NICEPAY_SECRET_KEY || env.NICEPAY_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
5749
6209
|
} else if (provider === "oy" || provider === "oyindonesia") {
|
|
5750
6210
|
apiKey = env.OY_API_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
6211
|
+
} else if (provider === "stripe") {
|
|
6212
|
+
apiKey = env.STRIPE_SECRET_KEY || env.STRIPE_KEY || env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY;
|
|
5751
6213
|
} else {
|
|
5752
6214
|
apiKey = env.BUAYAR_API_KEY || env.PG_API_KEY || env.PAYMENT_API_KEY || env.PG_SECRET_KEY || env.BUAYAR_SECRET_KEY;
|
|
5753
6215
|
}
|
|
@@ -5782,17 +6244,21 @@ function resolveConfigFromEnv(customConfig) {
|
|
|
5782
6244
|
} else if (provider === "oy" || provider === "oyindonesia") {
|
|
5783
6245
|
merchantCode = merchantCode || env.OY_USERNAME || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
5784
6246
|
clientKey = clientKey || env.OY_USERNAME || env.BUAYAR_CLIENT_KEY;
|
|
6247
|
+
} else if (provider === "stripe") {
|
|
6248
|
+
clientKey = clientKey || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY || env.BUAYAR_CLIENT_KEY || env.BUAYAR_PUBLIC_KEY;
|
|
6249
|
+
merchantCode = merchantCode || clientKey || "stripe";
|
|
5785
6250
|
} else {
|
|
5786
6251
|
merchantCode = merchantCode || env.BUAYAR_MERCHANT_CODE || env.PG_MERCHANT_CODE || env.PAYMENT_MERCHANT_CODE;
|
|
5787
6252
|
}
|
|
5788
6253
|
const projectId = customConfig?.projectId || env.BUAYAR_PROJECT_ID || env.PG_PROJECT_ID || env.PROJECT_ID;
|
|
5789
|
-
const publicKey = customConfig?.publicKey || env.BUAYAR_PUBLIC_KEY || env.PG_PUBLIC_KEY || env.PUBLIC_KEY;
|
|
6254
|
+
const publicKey = customConfig?.publicKey || env.BUAYAR_PUBLIC_KEY || env.PG_PUBLIC_KEY || env.PUBLIC_KEY || env.STRIPE_PUBLIC_KEY || env.STRIPE_PUBLISHABLE_KEY;
|
|
5790
6255
|
const privateKey = customConfig?.privateKey || env.BUAYAR_PRIVATE_KEY || env.PG_PRIVATE_KEY || env.PRIVATE_KEY;
|
|
5791
|
-
const secretKey = customConfig?.secretKey || env.BUAYAR_SECRET_KEY || env.PG_SECRET_KEY || env.SECRET_KEY || env.XENDIT_SECRET_KEY || env.DOKU_SECRET_KEY || env.PRISMALINK_SECRET_KEY || env.FASPAY_PASSWORD || env.FINPAY_MERCHANT_KEY || env.NICEPAY_KEY || env.OY_API_KEY;
|
|
6256
|
+
const secretKey = customConfig?.secretKey || env.BUAYAR_SECRET_KEY || env.PG_SECRET_KEY || env.SECRET_KEY || env.XENDIT_SECRET_KEY || env.DOKU_SECRET_KEY || env.PRISMALINK_SECRET_KEY || env.FASPAY_PASSWORD || env.FINPAY_MERCHANT_KEY || env.NICEPAY_KEY || env.OY_API_KEY || env.STRIPE_SECRET_KEY;
|
|
5792
6257
|
const callbackUrl = customConfig?.callbackUrl || env.BUAYAR_CALLBACK_URL || env.PG_CALLBACK_URL || env.PAYMENT_CALLBACK_URL;
|
|
5793
6258
|
const returnUrl = customConfig?.returnUrl || env.BUAYAR_RETURN_URL || env.PG_RETURN_URL || env.PAYMENT_RETURN_URL;
|
|
5794
6259
|
const extra = {
|
|
5795
6260
|
webhookToken: env.XENDIT_WEBHOOK_TOKEN || env.BUAYAR_WEBHOOK_TOKEN,
|
|
6261
|
+
webhookSecret: env.STRIPE_WEBHOOK_SECRET || env.BUAYAR_WEBHOOK_SECRET,
|
|
5796
6262
|
merchantName: env.FASPAY_MERCHANT_NAME || env.BUAYAR_MERCHANT_NAME,
|
|
5797
6263
|
userId: env.FASPAY_USER_ID,
|
|
5798
6264
|
iMid: env.NICEPAY_IMID,
|
|
@@ -5838,7 +6304,7 @@ var Buayar = class {
|
|
|
5838
6304
|
this.config = resolveConfigFromEnv({ ...this.config, ...config });
|
|
5839
6305
|
}
|
|
5840
6306
|
/**
|
|
5841
|
-
* Dapatkan nama provider aktif ('midtrans' | 'duitku' | 'ipaymu' | 'xendit' | 'doku' | 'prismalink' | 'faspay' | 'finpay' | 'nicepay' | 'oy' | ...)
|
|
6307
|
+
* Dapatkan nama provider aktif ('midtrans' | 'duitku' | 'ipaymu' | 'xendit' | 'doku' | 'prismalink' | 'faspay' | 'finpay' | 'nicepay' | 'oy' | 'stripe' | ...)
|
|
5842
6308
|
*/
|
|
5843
6309
|
get provider() {
|
|
5844
6310
|
return this.config.provider || "midtrans";
|
|
@@ -5886,6 +6352,13 @@ var Buayar = class {
|
|
|
5886
6352
|
*/
|
|
5887
6353
|
async verifyWebhook(payload, headers, configOverride) {
|
|
5888
6354
|
const mergedConfig = { ...this.config, ...configOverride };
|
|
6355
|
+
if (headers) {
|
|
6356
|
+
const sigHeader = headers["stripe-signature"] || headers["Stripe-Signature"];
|
|
6357
|
+
if (sigHeader) {
|
|
6358
|
+
if (!mergedConfig.extra) mergedConfig.extra = {};
|
|
6359
|
+
mergedConfig.extra.signatureHeader = Array.isArray(sigHeader) ? sigHeader[0] : sigHeader;
|
|
6360
|
+
}
|
|
6361
|
+
}
|
|
5889
6362
|
let providerName = configOverride?.provider || this.provider;
|
|
5890
6363
|
if (payload) {
|
|
5891
6364
|
if (payload.signature_key && payload.transaction_status) {
|
|
@@ -5906,6 +6379,8 @@ var Buayar = class {
|
|
|
5906
6379
|
providerName = "oy";
|
|
5907
6380
|
} else if (payload.merchant_id && payload.order_id && payload.signature) {
|
|
5908
6381
|
providerName = "prismalink";
|
|
6382
|
+
} else if (payload.object === "event" || payload.type && payload.data?.object && payload.api_version) {
|
|
6383
|
+
providerName = "stripe";
|
|
5909
6384
|
} else if (payload.external_id || payload.event?.startsWith("payment.") || payload.event?.startsWith("qr.") || payload.data?.reference_id) {
|
|
5910
6385
|
providerName = "xendit";
|
|
5911
6386
|
}
|
|
@@ -5975,6 +6450,12 @@ var Buayar = class {
|
|
|
5975
6450
|
...configOverride
|
|
5976
6451
|
});
|
|
5977
6452
|
}
|
|
6453
|
+
getStripeClient(configOverride) {
|
|
6454
|
+
return new StripeClient({
|
|
6455
|
+
...this.config,
|
|
6456
|
+
...configOverride
|
|
6457
|
+
});
|
|
6458
|
+
}
|
|
5978
6459
|
};
|
|
5979
6460
|
var buayar = new Buayar();
|
|
5980
6461
|
export {
|
|
@@ -5989,6 +6470,7 @@ export {
|
|
|
5989
6470
|
CANONICAL_TO_NICEPAY,
|
|
5990
6471
|
CANONICAL_TO_OY,
|
|
5991
6472
|
CANONICAL_TO_PRISMALINK,
|
|
6473
|
+
CANONICAL_TO_STRIPE,
|
|
5992
6474
|
CANONICAL_TO_XENDIT,
|
|
5993
6475
|
CORE_API_METHODS,
|
|
5994
6476
|
DUITKU_TO_CANONICAL,
|
|
@@ -6013,6 +6495,8 @@ export {
|
|
|
6013
6495
|
PaymentManager,
|
|
6014
6496
|
PrismalinkClient,
|
|
6015
6497
|
PrismalinkProvider,
|
|
6498
|
+
StripeClient,
|
|
6499
|
+
StripeProvider,
|
|
6016
6500
|
XenditClient,
|
|
6017
6501
|
XenditProvider,
|
|
6018
6502
|
buayar,
|
|
@@ -6036,6 +6520,7 @@ export {
|
|
|
6036
6520
|
paymentManager,
|
|
6037
6521
|
resolveConfigFromEnv,
|
|
6038
6522
|
safeCompare,
|
|
6523
|
+
serializeStripeParams,
|
|
6039
6524
|
sha256,
|
|
6040
6525
|
sha512,
|
|
6041
6526
|
toCanonicalPaymentMethod,
|
|
@@ -6047,6 +6532,7 @@ export {
|
|
|
6047
6532
|
toNicepayPaymentMethod,
|
|
6048
6533
|
toOyPaymentMethod,
|
|
6049
6534
|
toPrismalinkPaymentMethod,
|
|
6535
|
+
toStripePaymentMethod,
|
|
6050
6536
|
toXenditPaymentMethod,
|
|
6051
6537
|
verifyDokuWebhookSignature,
|
|
6052
6538
|
verifyDuitkuCallbackSignature,
|
|
@@ -6056,5 +6542,6 @@ export {
|
|
|
6056
6542
|
verifyNicepayWebhook,
|
|
6057
6543
|
verifyOyWebhook,
|
|
6058
6544
|
verifyPrismalinkSignature,
|
|
6545
|
+
verifyStripeWebhook,
|
|
6059
6546
|
verifyXenditWebhookToken
|
|
6060
6547
|
};
|
package/package.json
CHANGED