aba-payway 0.1.0 → 0.2.0
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/LICENSE +1 -1
- package/README.md +78 -5
- package/dist/index.cjs +258 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +184 -24
- package/dist/index.d.ts +184 -24
- package/dist/index.js +257 -26
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -56,7 +56,8 @@ const params = payway.createTransaction({
|
|
|
56
56
|
|---|---|---|---|---|
|
|
57
57
|
| `merchantId` | `string` | Yes | — | Your ABA PayWay merchant ID |
|
|
58
58
|
| `apiKey` | `string` | Yes | — | Your ABA PayWay API key |
|
|
59
|
-
| `
|
|
59
|
+
| `environment` | `'sandbox' \| 'production'` | No | `'sandbox'` | Target environment |
|
|
60
|
+
| `baseUrl` | `string` | No | — | Override the base URL directly (takes priority over `environment`) |
|
|
60
61
|
|
|
61
62
|
### `payway.createTransaction(options)`
|
|
62
63
|
|
|
@@ -96,7 +97,7 @@ Check the status of a transaction.
|
|
|
96
97
|
```typescript
|
|
97
98
|
const result = await payway.checkTransaction('order-001')
|
|
98
99
|
console.log(result.status.code) // '00' = success
|
|
99
|
-
console.log(result.data
|
|
100
|
+
console.log(result.data?.payment_status) // 'APPROVED' | 'DECLINED' | 'PENDING' | ...
|
|
100
101
|
```
|
|
101
102
|
|
|
102
103
|
### `payway.listTransactions(options?)`
|
|
@@ -105,8 +106,8 @@ List transactions with optional filters. Max 3-day date range.
|
|
|
105
106
|
|
|
106
107
|
```typescript
|
|
107
108
|
const list = await payway.listTransactions({
|
|
108
|
-
fromDate: '
|
|
109
|
-
toDate: '
|
|
109
|
+
fromDate: '2026-03-01 00:00:00',
|
|
110
|
+
toDate: '2026-03-03 23:59:59',
|
|
110
111
|
status: 'APPROVED',
|
|
111
112
|
page: 1,
|
|
112
113
|
pagination: 20,
|
|
@@ -123,6 +124,78 @@ const list = await payway.listTransactions({
|
|
|
123
124
|
| `page` | `number` | Page number (default: `1`) |
|
|
124
125
|
| `pagination` | `number` | Records per page (default: `40`, max: `1000`) |
|
|
125
126
|
|
|
127
|
+
### `payway.getTransactionDetails(transactionId)`
|
|
128
|
+
|
|
129
|
+
Get detailed information about a transaction, including its operation history.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
const details = await payway.getTransactionDetails('order-001')
|
|
133
|
+
console.log(details.data?.payment_status) // 'APPROVED'
|
|
134
|
+
console.log(details.data?.transaction_operations) // [{ status, amount, ... }]
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `payway.closeTransaction(transactionId)`
|
|
138
|
+
|
|
139
|
+
Close (cancel) a pending transaction. The payment status becomes `CANCELLED`.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const result = await payway.closeTransaction('order-001')
|
|
143
|
+
console.log(result.status.code) // '00' = success
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### `payway.getExchangeRate()`
|
|
147
|
+
|
|
148
|
+
Fetch the latest exchange rates from ABA Bank for 12 currencies.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const rates = await payway.getExchangeRate()
|
|
152
|
+
console.log(rates.exchange_rates.eur) // { sell: '...', buy: '...' }
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### `payway.generateQR(options)`
|
|
156
|
+
|
|
157
|
+
Generate a dynamic QR code for payment via ABA KHQR, WeChat Pay, or Alipay.
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const qr = await payway.generateQR({
|
|
161
|
+
transactionId: 'qr-001',
|
|
162
|
+
amount: 10.00,
|
|
163
|
+
paymentOption: 'abapay_khqr',
|
|
164
|
+
qrImageTemplate: 'template1',
|
|
165
|
+
lifetime: 30,
|
|
166
|
+
})
|
|
167
|
+
console.log(qr.qrString) // QR content string
|
|
168
|
+
console.log(qr.abapay_deeplink) // ABA Mobile deep link
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
| Parameter | Type | Required | Description |
|
|
172
|
+
|---|---|---|---|
|
|
173
|
+
| `transactionId` | `string` | Yes | Unique transaction ID (max 20 chars) |
|
|
174
|
+
| `amount` | `number` | Yes | Payment amount (min: 100 KHR or 0.01 USD) |
|
|
175
|
+
| `paymentOption` | `QRPaymentOption` | Yes | `abapay_khqr`, `wechat` (USD only), `alipay` (USD only) |
|
|
176
|
+
| `qrImageTemplate` | `string` | Yes | QR image template name |
|
|
177
|
+
| `currency` | `'USD' \| 'KHR'` | No | Default: `'USD'` |
|
|
178
|
+
| `lifetime` | `number` | No | Lifetime in minutes (3–43200) |
|
|
179
|
+
| `firstName` | `string` | No | Payer's first name |
|
|
180
|
+
| `lastName` | `string` | No | Payer's last name |
|
|
181
|
+
| `email` | `string` | No | Payer's email |
|
|
182
|
+
| `phone` | `string` | No | Payer's phone |
|
|
183
|
+
| `purchaseType` | `'purchase' \| 'pre-auth'` | No | Default: `'purchase'` |
|
|
184
|
+
| `items` | `string` | No | Item description (auto base64-encoded) |
|
|
185
|
+
| `callbackUrl` | `string` | No | Payment callback URL (auto base64-encoded) |
|
|
186
|
+
| `returnDeeplink` | `string` | No | Mobile deeplink (auto base64-encoded) |
|
|
187
|
+
| `payout` | `string` | No | Payout JSON string (auto base64-encoded) |
|
|
188
|
+
|
|
189
|
+
### `payway.getTransactionsByRef(merchantRef)`
|
|
190
|
+
|
|
191
|
+
Get transactions by merchant reference. Returns up to the last 50 transactions.
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
const txns = await payway.getTransactionsByRef('REF-001')
|
|
195
|
+
for (const txn of txns.data) {
|
|
196
|
+
console.log(txn.transaction_id, txn.payment_status)
|
|
197
|
+
}
|
|
198
|
+
|
|
126
199
|
## Error Handling
|
|
127
200
|
|
|
128
201
|
```typescript
|
|
@@ -147,7 +220,7 @@ import { PayWay } from 'aba-payway'
|
|
|
147
220
|
const payway = new PayWay({
|
|
148
221
|
merchantId: process.env.PAYWAY_MERCHANT_ID!,
|
|
149
222
|
apiKey: process.env.PAYWAY_API_KEY!,
|
|
150
|
-
|
|
223
|
+
environment: process.env.NODE_ENV === 'production' ? 'production' : 'sandbox',
|
|
151
224
|
})
|
|
152
225
|
|
|
153
226
|
export async function POST(request: Request) {
|
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
BASE_URLS: () => BASE_URLS,
|
|
23
24
|
ENDPOINTS: () => ENDPOINTS,
|
|
24
25
|
PRODUCTION_BASE_URL: () => PRODUCTION_BASE_URL,
|
|
25
26
|
PayWay: () => PayWay,
|
|
@@ -37,18 +38,27 @@ __export(index_exports, {
|
|
|
37
38
|
module.exports = __toCommonJS(index_exports);
|
|
38
39
|
|
|
39
40
|
// src/constants.ts
|
|
40
|
-
var
|
|
41
|
-
|
|
41
|
+
var BASE_URLS = {
|
|
42
|
+
sandbox: "https://checkout-sandbox.payway.com.kh",
|
|
43
|
+
production: "https://checkout.payway.com.kh"
|
|
44
|
+
};
|
|
45
|
+
var SANDBOX_BASE_URL = BASE_URLS.sandbox;
|
|
46
|
+
var PRODUCTION_BASE_URL = BASE_URLS.production;
|
|
42
47
|
var ENDPOINTS = {
|
|
43
48
|
purchase: "/api/payment-gateway/v1/payments/purchase",
|
|
44
49
|
checkTransaction: "/api/payment-gateway/v1/payments/check-transaction-2",
|
|
45
|
-
transactionList: "/api/payment-gateway/v1/payments/transaction-list-2"
|
|
50
|
+
transactionList: "/api/payment-gateway/v1/payments/transaction-list-2",
|
|
51
|
+
transactionDetail: "/api/payment-gateway/v1/payments/transaction-detail",
|
|
52
|
+
closeTransaction: "/api/payment-gateway/v1/payments/close-transaction",
|
|
53
|
+
exchangeRate: "/api/payment-gateway/v1/exchange-rate",
|
|
54
|
+
generateQR: "/api/payment-gateway/v1/payments/generate-qr",
|
|
55
|
+
getTransactionsByRef: "/api/payment-gateway/v1/payments/get-transactions-by-mc-ref"
|
|
46
56
|
};
|
|
47
57
|
|
|
48
58
|
// src/errors.ts
|
|
49
59
|
var PayWayError = class extends Error {
|
|
50
|
-
constructor(message) {
|
|
51
|
-
super(message);
|
|
60
|
+
constructor(message, options) {
|
|
61
|
+
super(message, options);
|
|
52
62
|
this.name = "PayWayError";
|
|
53
63
|
}
|
|
54
64
|
};
|
|
@@ -94,17 +104,24 @@ function formatRequestTime(date = /* @__PURE__ */ new Date()) {
|
|
|
94
104
|
const seconds = date.getUTCSeconds().toString().padStart(2, "0");
|
|
95
105
|
return `${year}${month}${day}${hours}${minutes}${seconds}`;
|
|
96
106
|
}
|
|
97
|
-
function
|
|
98
|
-
const
|
|
107
|
+
function filterParams(params) {
|
|
108
|
+
const out = {};
|
|
99
109
|
for (const [key, value] of Object.entries(params)) {
|
|
100
|
-
if (value !== void 0 && value !==
|
|
101
|
-
|
|
110
|
+
if (value !== void 0 && value !== "") {
|
|
111
|
+
out[key] = value;
|
|
102
112
|
}
|
|
103
113
|
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
function buildFormData(params) {
|
|
117
|
+
const formData = new FormData();
|
|
118
|
+
for (const [key, value] of Object.entries(filterParams(params))) {
|
|
119
|
+
formData.append(key, String(value));
|
|
120
|
+
}
|
|
104
121
|
return formData;
|
|
105
122
|
}
|
|
106
123
|
function formatAmount(amount, currency = "USD") {
|
|
107
|
-
if (currency
|
|
124
|
+
if (currency === "KHR") {
|
|
108
125
|
return Math.round(amount).toString();
|
|
109
126
|
}
|
|
110
127
|
return amount.toFixed(2);
|
|
@@ -118,6 +135,11 @@ var PayWay = class {
|
|
|
118
135
|
merchantId;
|
|
119
136
|
apiKey;
|
|
120
137
|
baseUrl;
|
|
138
|
+
timeout;
|
|
139
|
+
/**
|
|
140
|
+
* @param config - Merchant credentials and environment selection.
|
|
141
|
+
* @throws {PayWayConfigError} If `merchantId` or `apiKey` is empty.
|
|
142
|
+
*/
|
|
121
143
|
constructor(config) {
|
|
122
144
|
if (!config.merchantId) {
|
|
123
145
|
throw new PayWayConfigError("merchantId is required");
|
|
@@ -127,13 +149,28 @@ var PayWay = class {
|
|
|
127
149
|
}
|
|
128
150
|
this.merchantId = config.merchantId;
|
|
129
151
|
this.apiKey = config.apiKey;
|
|
130
|
-
this.baseUrl = config.
|
|
152
|
+
this.baseUrl = config.baseUrl ?? BASE_URLS[config.environment ?? "sandbox"];
|
|
153
|
+
this.timeout = config.timeout ?? 3e4;
|
|
131
154
|
}
|
|
132
155
|
/**
|
|
133
156
|
* Generate checkout parameters for a transaction.
|
|
134
157
|
* Returns form params to be submitted from the browser via ABA's checkout JS SDK.
|
|
135
158
|
*/
|
|
136
159
|
createTransaction(options) {
|
|
160
|
+
if (!options.transactionId) {
|
|
161
|
+
throw new PayWayConfigError("transactionId is required");
|
|
162
|
+
}
|
|
163
|
+
if (options.transactionId.length > 20) {
|
|
164
|
+
throw new PayWayConfigError(
|
|
165
|
+
"transactionId must be at most 20 characters"
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
if (options.amount <= 0) {
|
|
169
|
+
throw new PayWayConfigError("amount must be greater than 0");
|
|
170
|
+
}
|
|
171
|
+
if (options.lifetime !== void 0 && (options.lifetime < 3 || options.lifetime > 43200)) {
|
|
172
|
+
throw new PayWayConfigError("lifetime must be between 3 and 43200");
|
|
173
|
+
}
|
|
137
174
|
const reqTime = formatRequestTime();
|
|
138
175
|
const currency = options.currency ?? "USD";
|
|
139
176
|
const amount = formatAmount(options.amount, currency);
|
|
@@ -170,8 +207,6 @@ var PayWay = class {
|
|
|
170
207
|
currency,
|
|
171
208
|
options.customFields ?? "",
|
|
172
209
|
options.returnParams ?? "",
|
|
173
|
-
options.viewType ?? "",
|
|
174
|
-
options.paymentGate?.toString() ?? "",
|
|
175
210
|
payout,
|
|
176
211
|
options.lifetime?.toString() ?? "",
|
|
177
212
|
options.additionalParams ?? "",
|
|
@@ -210,7 +245,15 @@ var PayWay = class {
|
|
|
210
245
|
payment_gate: options.paymentGate?.toString() ?? ""
|
|
211
246
|
};
|
|
212
247
|
}
|
|
248
|
+
/**
|
|
249
|
+
* Check the status of a transaction.
|
|
250
|
+
* @param transactionId - The unique transaction ID to look up.
|
|
251
|
+
* @throws {PayWayAPIError} If the API returns a non-2xx response.
|
|
252
|
+
*/
|
|
213
253
|
async checkTransaction(transactionId) {
|
|
254
|
+
if (!transactionId) {
|
|
255
|
+
throw new PayWayConfigError("transactionId is required");
|
|
256
|
+
}
|
|
214
257
|
const reqTime = formatRequestTime();
|
|
215
258
|
const hashValues = [reqTime, this.merchantId, transactionId];
|
|
216
259
|
const hash = createHash(hashValues, this.apiKey);
|
|
@@ -225,6 +268,11 @@ var PayWay = class {
|
|
|
225
268
|
params
|
|
226
269
|
);
|
|
227
270
|
}
|
|
271
|
+
/**
|
|
272
|
+
* List transactions with optional filters. Max 3-day date range.
|
|
273
|
+
* @param options - Filter and pagination options.
|
|
274
|
+
* @throws {PayWayAPIError} If the API returns a non-2xx response.
|
|
275
|
+
*/
|
|
228
276
|
async listTransactions(options = {}) {
|
|
229
277
|
const reqTime = formatRequestTime();
|
|
230
278
|
const hashValues = [
|
|
@@ -256,29 +304,212 @@ var PayWay = class {
|
|
|
256
304
|
params
|
|
257
305
|
);
|
|
258
306
|
}
|
|
259
|
-
|
|
307
|
+
/**
|
|
308
|
+
* Get detailed information about a transaction, including its operation history.
|
|
309
|
+
* @param transactionId - The unique transaction ID to look up.
|
|
310
|
+
* @throws {PayWayAPIError} If the API returns a non-2xx response.
|
|
311
|
+
*/
|
|
312
|
+
async getTransactionDetails(transactionId) {
|
|
313
|
+
if (!transactionId) {
|
|
314
|
+
throw new PayWayConfigError("transactionId is required");
|
|
315
|
+
}
|
|
316
|
+
const reqTime = formatRequestTime();
|
|
317
|
+
const hashValues = [reqTime, this.merchantId, transactionId];
|
|
318
|
+
const hash = createHash(hashValues, this.apiKey);
|
|
319
|
+
const params = {
|
|
320
|
+
hash,
|
|
321
|
+
tran_id: transactionId,
|
|
322
|
+
req_time: reqTime,
|
|
323
|
+
merchant_id: this.merchantId
|
|
324
|
+
};
|
|
325
|
+
return this.request(
|
|
326
|
+
ENDPOINTS.transactionDetail,
|
|
327
|
+
params,
|
|
328
|
+
"json"
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Close (cancel) a pending transaction.
|
|
333
|
+
* @param transactionId - The transaction ID to close.
|
|
334
|
+
* @throws {PayWayAPIError} If the API returns a non-2xx response.
|
|
335
|
+
*/
|
|
336
|
+
async closeTransaction(transactionId) {
|
|
337
|
+
if (!transactionId) {
|
|
338
|
+
throw new PayWayConfigError("transactionId is required");
|
|
339
|
+
}
|
|
340
|
+
const reqTime = formatRequestTime();
|
|
341
|
+
const hashValues = [reqTime, this.merchantId, transactionId];
|
|
342
|
+
const hash = createHash(hashValues, this.apiKey);
|
|
343
|
+
const params = {
|
|
344
|
+
hash,
|
|
345
|
+
tran_id: transactionId,
|
|
346
|
+
req_time: reqTime,
|
|
347
|
+
merchant_id: this.merchantId
|
|
348
|
+
};
|
|
349
|
+
return this.request(
|
|
350
|
+
ENDPOINTS.closeTransaction,
|
|
351
|
+
params,
|
|
352
|
+
"json"
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Fetch the latest exchange rates from ABA Bank.
|
|
357
|
+
* @throws {PayWayAPIError} If the API returns a non-2xx response.
|
|
358
|
+
*/
|
|
359
|
+
async getExchangeRate() {
|
|
360
|
+
const reqTime = formatRequestTime();
|
|
361
|
+
const hashValues = [reqTime, this.merchantId];
|
|
362
|
+
const hash = createHash(hashValues, this.apiKey);
|
|
363
|
+
const params = {
|
|
364
|
+
hash,
|
|
365
|
+
req_time: reqTime,
|
|
366
|
+
merchant_id: this.merchantId
|
|
367
|
+
};
|
|
368
|
+
return this.request(
|
|
369
|
+
ENDPOINTS.exchangeRate,
|
|
370
|
+
params,
|
|
371
|
+
"json"
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Generate a QR code for payment via ABA KHQR, WeChat Pay, or Alipay.
|
|
376
|
+
* @param options - QR generation options.
|
|
377
|
+
* @throws {PayWayConfigError} If required options are missing or invalid.
|
|
378
|
+
* @throws {PayWayAPIError} If the API returns a non-2xx response.
|
|
379
|
+
*/
|
|
380
|
+
async generateQR(options) {
|
|
381
|
+
if (!options.transactionId) {
|
|
382
|
+
throw new PayWayConfigError("transactionId is required");
|
|
383
|
+
}
|
|
384
|
+
if (options.amount <= 0) {
|
|
385
|
+
throw new PayWayConfigError("amount must be greater than 0");
|
|
386
|
+
}
|
|
387
|
+
if (!options.paymentOption) {
|
|
388
|
+
throw new PayWayConfigError("paymentOption is required");
|
|
389
|
+
}
|
|
390
|
+
if (!options.qrImageTemplate) {
|
|
391
|
+
throw new PayWayConfigError("qrImageTemplate is required");
|
|
392
|
+
}
|
|
393
|
+
if (options.lifetime !== void 0 && (options.lifetime < 3 || options.lifetime > 43200)) {
|
|
394
|
+
throw new PayWayConfigError("lifetime must be between 3 and 43200");
|
|
395
|
+
}
|
|
396
|
+
const reqTime = formatRequestTime();
|
|
397
|
+
const currency = options.currency ?? "USD";
|
|
398
|
+
const amount = formatAmount(options.amount, currency);
|
|
399
|
+
const items = options.items ? toBase64(options.items) : "";
|
|
400
|
+
const callbackUrl = options.callbackUrl ? toBase64(options.callbackUrl) : "";
|
|
401
|
+
const returnDeeplink = options.returnDeeplink ? toBase64(options.returnDeeplink) : "";
|
|
402
|
+
const customFields = options.customFields ? toBase64(options.customFields) : "";
|
|
403
|
+
const payout = options.payout ? toBase64(options.payout) : "";
|
|
404
|
+
const hashValues = [
|
|
405
|
+
reqTime,
|
|
406
|
+
this.merchantId,
|
|
407
|
+
options.transactionId,
|
|
408
|
+
amount,
|
|
409
|
+
items,
|
|
410
|
+
options.firstName ?? "",
|
|
411
|
+
options.lastName ?? "",
|
|
412
|
+
options.email ?? "",
|
|
413
|
+
options.phone ?? "",
|
|
414
|
+
options.purchaseType ?? "",
|
|
415
|
+
options.paymentOption,
|
|
416
|
+
callbackUrl,
|
|
417
|
+
returnDeeplink,
|
|
418
|
+
currency,
|
|
419
|
+
customFields,
|
|
420
|
+
options.returnParams ?? "",
|
|
421
|
+
payout,
|
|
422
|
+
options.lifetime?.toString() ?? "",
|
|
423
|
+
options.qrImageTemplate
|
|
424
|
+
];
|
|
425
|
+
const hash = createHash(hashValues, this.apiKey);
|
|
426
|
+
const params = {
|
|
427
|
+
hash,
|
|
428
|
+
req_time: reqTime,
|
|
429
|
+
merchant_id: this.merchantId,
|
|
430
|
+
tran_id: options.transactionId,
|
|
431
|
+
amount: options.amount,
|
|
432
|
+
currency,
|
|
433
|
+
payment_option: options.paymentOption,
|
|
434
|
+
lifetime: options.lifetime,
|
|
435
|
+
qr_image_template: options.qrImageTemplate,
|
|
436
|
+
first_name: options.firstName,
|
|
437
|
+
last_name: options.lastName,
|
|
438
|
+
email: options.email,
|
|
439
|
+
phone: options.phone,
|
|
440
|
+
purchase_type: options.purchaseType,
|
|
441
|
+
items: items || void 0,
|
|
442
|
+
callback_url: callbackUrl || void 0,
|
|
443
|
+
return_deeplink: returnDeeplink || void 0,
|
|
444
|
+
custom_fields: customFields || void 0,
|
|
445
|
+
return_params: options.returnParams,
|
|
446
|
+
payout: payout || void 0
|
|
447
|
+
};
|
|
448
|
+
return this.request(
|
|
449
|
+
ENDPOINTS.generateQR,
|
|
450
|
+
params,
|
|
451
|
+
"json"
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Get transactions by merchant reference. Returns up to the last 50 transactions.
|
|
456
|
+
* @param merchantRef - Your merchant reference number.
|
|
457
|
+
* @throws {PayWayAPIError} If the API returns a non-2xx response.
|
|
458
|
+
*/
|
|
459
|
+
async getTransactionsByRef(merchantRef) {
|
|
460
|
+
if (!merchantRef) {
|
|
461
|
+
throw new PayWayConfigError("merchantRef is required");
|
|
462
|
+
}
|
|
463
|
+
const reqTime = formatRequestTime();
|
|
464
|
+
const hashValues = [reqTime, this.merchantId, merchantRef];
|
|
465
|
+
const hash = createHash(hashValues, this.apiKey);
|
|
466
|
+
const params = {
|
|
467
|
+
hash,
|
|
468
|
+
merchant_ref: merchantRef,
|
|
469
|
+
req_time: reqTime,
|
|
470
|
+
merchant_id: this.merchantId
|
|
471
|
+
};
|
|
472
|
+
return this.request(
|
|
473
|
+
ENDPOINTS.getTransactionsByRef,
|
|
474
|
+
params,
|
|
475
|
+
"json"
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
async request(endpoint, params, format = "form") {
|
|
260
479
|
const url = `${this.baseUrl}${endpoint}`;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
480
|
+
let body;
|
|
481
|
+
const headers = {};
|
|
482
|
+
if (format === "json") {
|
|
483
|
+
body = JSON.stringify(filterParams(params));
|
|
484
|
+
headers["Content-Type"] = "application/json";
|
|
485
|
+
} else {
|
|
486
|
+
body = buildFormData(params);
|
|
487
|
+
}
|
|
488
|
+
let response;
|
|
489
|
+
try {
|
|
490
|
+
response = await fetch(url, {
|
|
491
|
+
method: "POST",
|
|
492
|
+
body,
|
|
493
|
+
headers,
|
|
494
|
+
signal: AbortSignal.timeout(this.timeout)
|
|
495
|
+
});
|
|
496
|
+
} catch (error) {
|
|
497
|
+
throw new PayWayError(
|
|
498
|
+
error instanceof Error ? error.message : "Network request failed",
|
|
499
|
+
{ cause: error }
|
|
500
|
+
);
|
|
266
501
|
}
|
|
267
|
-
const response = await fetch(url, {
|
|
268
|
-
method: "POST",
|
|
269
|
-
body: formData
|
|
270
|
-
});
|
|
271
502
|
if (!response.ok) {
|
|
272
503
|
const text = await response.text();
|
|
273
|
-
let
|
|
504
|
+
let responseBody = text;
|
|
274
505
|
try {
|
|
275
|
-
|
|
506
|
+
responseBody = JSON.parse(text);
|
|
276
507
|
} catch {
|
|
277
508
|
}
|
|
278
509
|
throw new PayWayAPIError(
|
|
279
510
|
`PayWay API error: ${response.status} ${response.statusText}`,
|
|
280
511
|
response.status,
|
|
281
|
-
|
|
512
|
+
responseBody
|
|
282
513
|
);
|
|
283
514
|
}
|
|
284
515
|
return await response.json();
|
|
@@ -286,6 +517,7 @@ var PayWay = class {
|
|
|
286
517
|
};
|
|
287
518
|
// Annotate the CommonJS export names for ESM import in node:
|
|
288
519
|
0 && (module.exports = {
|
|
520
|
+
BASE_URLS,
|
|
289
521
|
ENDPOINTS,
|
|
290
522
|
PRODUCTION_BASE_URL,
|
|
291
523
|
PayWay,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/errors.ts","../src/hash.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["export { PayWay } from \"./client.ts\";\nexport {\n\tENDPOINTS,\n\tPRODUCTION_BASE_URL,\n\tSANDBOX_BASE_URL,\n} from \"./constants.ts\";\nexport {\n\tPayWayAPIError,\n\tPayWayConfigError,\n\tPayWayError,\n\tPayWayHashError,\n} from \"./errors.ts\";\nexport { createHash } from \"./hash.ts\";\nexport type {\n\tCheckoutParams,\n\tCheckTransactionData,\n\tCheckTransactionOptions,\n\tCreateTransactionOptions,\n\tCurrency,\n\tItemEntry,\n\tListTransactionsData,\n\tListTransactionsOptions,\n\tListTransactionsResponse,\n\tPaymentOption,\n\tPayWayConfig,\n\tPayWayResponse,\n\tPayWayResponseStatus,\n\tTransactionListItem,\n\tTransactionStatus,\n\tTransactionType,\n} from \"./types.ts\";\nexport {\n\tbuildFormData,\n\tformatAmount,\n\tformatRequestTime,\n\ttoBase64,\n} from \"./utils.ts\";\n","export const SANDBOX_BASE_URL = \"https://checkout-sandbox.payway.com.kh\";\nexport const PRODUCTION_BASE_URL = \"https://checkout.payway.com.kh\";\n\nexport const ENDPOINTS = {\n\tpurchase: \"/api/payment-gateway/v1/payments/purchase\",\n\tcheckTransaction: \"/api/payment-gateway/v1/payments/check-transaction-2\",\n\ttransactionList: \"/api/payment-gateway/v1/payments/transaction-list-2\",\n} as const;\n","export class PayWayError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"PayWayError\";\n\t}\n}\n\nexport class PayWayAPIError extends PayWayError {\n\tpublic readonly statusCode: number;\n\tpublic readonly responseBody: unknown;\n\n\tconstructor(message: string, statusCode: number, responseBody?: unknown) {\n\t\tsuper(message);\n\t\tthis.name = \"PayWayAPIError\";\n\t\tthis.statusCode = statusCode;\n\t\tthis.responseBody = responseBody;\n\t}\n}\n\nexport class PayWayConfigError extends PayWayError {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"PayWayConfigError\";\n\t}\n}\n\nexport class PayWayHashError extends PayWayError {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"PayWayHashError\";\n\t}\n}\n","import { createHmac } from \"node:crypto\";\n\nexport function createHash(values: string[], apiKey: string): string {\n\tconst message = values.join(\"\");\n\tconst hmac = createHmac(\"sha512\", apiKey);\n\thmac.update(message);\n\treturn hmac.digest(\"base64\");\n}\n","export function formatRequestTime(date: Date = new Date()): string {\n\tconst year = date.getUTCFullYear().toString();\n\tconst month = (date.getUTCMonth() + 1).toString().padStart(2, \"0\");\n\tconst day = date.getUTCDate().toString().padStart(2, \"0\");\n\tconst hours = date.getUTCHours().toString().padStart(2, \"0\");\n\tconst minutes = date.getUTCMinutes().toString().padStart(2, \"0\");\n\tconst seconds = date.getUTCSeconds().toString().padStart(2, \"0\");\n\treturn `${year}${month}${day}${hours}${minutes}${seconds}`;\n}\n\nexport function buildFormData(\n\tparams: Record<string, string | undefined>,\n): FormData {\n\tconst formData = new FormData();\n\tfor (const [key, value] of Object.entries(params)) {\n\t\tif (value !== undefined && value !== null && value !== \"\") {\n\t\t\tformData.append(key, value);\n\t\t}\n\t}\n\treturn formData;\n}\n\nexport function formatAmount(amount: number, currency = \"USD\"): string {\n\tif (currency.toUpperCase() === \"KHR\") {\n\t\treturn Math.round(amount).toString();\n\t}\n\treturn amount.toFixed(2);\n}\n\nexport function toBase64(value: string): string {\n\treturn Buffer.from(value).toString(\"base64\");\n}\n","import {\n\tENDPOINTS,\n\tPRODUCTION_BASE_URL,\n\tSANDBOX_BASE_URL,\n} from \"./constants.ts\";\nimport { PayWayAPIError, PayWayConfigError } from \"./errors.ts\";\nimport { createHash } from \"./hash.ts\";\nimport type {\n\tCheckoutParams,\n\tCheckTransactionData,\n\tCreateTransactionOptions,\n\tListTransactionsOptions,\n\tListTransactionsResponse,\n\tPayWayConfig,\n\tPayWayResponse,\n} from \"./types.ts\";\nimport { formatAmount, formatRequestTime, toBase64 } from \"./utils.ts\";\n\nexport class PayWay {\n\tprivate readonly merchantId: string;\n\tprivate readonly apiKey: string;\n\tprivate readonly baseUrl: string;\n\n\tconstructor(config: PayWayConfig) {\n\t\tif (!config.merchantId) {\n\t\t\tthrow new PayWayConfigError(\"merchantId is required\");\n\t\t}\n\t\tif (!config.apiKey) {\n\t\t\tthrow new PayWayConfigError(\"apiKey is required\");\n\t\t}\n\n\t\tthis.merchantId = config.merchantId;\n\t\tthis.apiKey = config.apiKey;\n\t\tthis.baseUrl = config.production ? PRODUCTION_BASE_URL : SANDBOX_BASE_URL;\n\t}\n\n\t/**\n\t * Generate checkout parameters for a transaction.\n\t * Returns form params to be submitted from the browser via ABA's checkout JS SDK.\n\t */\n\tcreateTransaction(options: CreateTransactionOptions): CheckoutParams {\n\t\tconst reqTime = formatRequestTime();\n\t\tconst currency = options.currency ?? \"USD\";\n\t\tconst amount = formatAmount(options.amount, currency);\n\t\tconst type = options.type ?? \"purchase\";\n\n\t\t// Items: if array, JSON-stringify and base64-encode; if string, base64-encode as-is\n\t\tlet items: string;\n\t\tif (Array.isArray(options.items)) {\n\t\t\titems = toBase64(JSON.stringify(options.items));\n\t\t} else if (options.items) {\n\t\t\titems = toBase64(options.items);\n\t\t} else {\n\t\t\titems = \"\";\n\t\t}\n\n\t\t// Return URL and return deeplink must be base64-encoded per ABA docs\n\t\tconst returnUrl = options.returnUrl ? toBase64(options.returnUrl) : \"\";\n\t\tconst returnDeeplink = options.returnDeeplink\n\t\t\t? toBase64(options.returnDeeplink)\n\t\t\t: \"\";\n\n\t\t// Payout must be base64-encoded JSON string per ABA docs\n\t\tconst payout = options.payout ? toBase64(options.payout) : \"\";\n\n\t\tconst shipping =\n\t\t\toptions.shipping !== undefined\n\t\t\t\t? formatAmount(options.shipping, currency)\n\t\t\t\t: \"\";\n\n\t\t// Hash field order must match ABA's expected order exactly\n\t\tconst hashValues = [\n\t\t\treqTime,\n\t\t\tthis.merchantId,\n\t\t\toptions.transactionId,\n\t\t\tamount,\n\t\t\titems,\n\t\t\tshipping,\n\t\t\toptions.firstName ?? \"\",\n\t\t\toptions.lastName ?? \"\",\n\t\t\toptions.email ?? \"\",\n\t\t\toptions.phone ?? \"\",\n\t\t\ttype,\n\t\t\toptions.paymentOption ?? \"\",\n\t\t\treturnUrl,\n\t\t\toptions.cancelUrl ?? \"\",\n\t\t\toptions.continueSuccessUrl ?? \"\",\n\t\t\treturnDeeplink,\n\t\t\tcurrency,\n\t\t\toptions.customFields ?? \"\",\n\t\t\toptions.returnParams ?? \"\",\n\t\t\toptions.viewType ?? \"\",\n\t\t\toptions.paymentGate?.toString() ?? \"\",\n\t\t\tpayout,\n\t\t\toptions.lifetime?.toString() ?? \"\",\n\t\t\toptions.additionalParams ?? \"\",\n\t\t\toptions.googlePayToken ?? \"\",\n\t\t\toptions.skipSuccessPage?.toString() ?? \"\",\n\t\t];\n\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\treturn {\n\t\t\taction: `${this.baseUrl}${ENDPOINTS.purchase}`,\n\t\t\thash,\n\t\t\ttran_id: options.transactionId,\n\t\t\tamount,\n\t\t\titems,\n\t\t\tcurrency,\n\t\t\tfirstname: options.firstName ?? \"\",\n\t\t\tlastname: options.lastName ?? \"\",\n\t\t\temail: options.email ?? \"\",\n\t\t\tphone: options.phone ?? \"\",\n\t\t\ttype,\n\t\t\tpayment_option: options.paymentOption ?? \"\",\n\t\t\treturn_url: returnUrl,\n\t\t\tcancel_url: options.cancelUrl ?? \"\",\n\t\t\tcontinue_success_url: options.continueSuccessUrl ?? \"\",\n\t\t\treturn_deeplink: returnDeeplink,\n\t\t\treturn_params: options.returnParams ?? \"\",\n\t\t\tshipping,\n\t\t\tmerchant_id: this.merchantId,\n\t\t\treq_time: reqTime,\n\t\t\tcustom_fields: options.customFields ?? \"\",\n\t\t\tpayout,\n\t\t\tlifetime: options.lifetime?.toString() ?? \"\",\n\t\t\tadditional_params: options.additionalParams ?? \"\",\n\t\t\tgoogle_pay_token: options.googlePayToken ?? \"\",\n\t\t\tskip_success_page: options.skipSuccessPage?.toString() ?? \"\",\n\t\t\tview_type: options.viewType ?? \"\",\n\t\t\tpayment_gate: options.paymentGate?.toString() ?? \"\",\n\t\t};\n\t}\n\n\tasync checkTransaction(\n\t\ttransactionId: string,\n\t): Promise<PayWayResponse<CheckTransactionData>> {\n\t\tconst reqTime = formatRequestTime();\n\n\t\tconst hashValues = [reqTime, this.merchantId, transactionId];\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\tconst params: Record<string, string | undefined> = {\n\t\t\thash,\n\t\t\ttran_id: transactionId,\n\t\t\treq_time: reqTime,\n\t\t\tmerchant_id: this.merchantId,\n\t\t};\n\n\t\treturn this.request<PayWayResponse<CheckTransactionData>>(\n\t\t\tENDPOINTS.checkTransaction,\n\t\t\tparams,\n\t\t);\n\t}\n\n\tasync listTransactions(\n\t\toptions: ListTransactionsOptions = {},\n\t): Promise<ListTransactionsResponse> {\n\t\tconst reqTime = formatRequestTime();\n\n\t\tconst hashValues = [\n\t\t\treqTime,\n\t\t\tthis.merchantId,\n\t\t\toptions.fromDate ?? \"\",\n\t\t\toptions.toDate ?? \"\",\n\t\t\toptions.fromAmount?.toString() ?? \"\",\n\t\t\toptions.toAmount?.toString() ?? \"\",\n\t\t\toptions.status ?? \"\",\n\t\t\toptions.page?.toString() ?? \"\",\n\t\t\toptions.pagination?.toString() ?? \"\",\n\t\t];\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\tconst params: Record<string, string | undefined> = {\n\t\t\thash,\n\t\t\tfrom_date: options.fromDate,\n\t\t\tto_date: options.toDate,\n\t\t\tfrom_amount: options.fromAmount?.toString(),\n\t\t\tto_amount: options.toAmount?.toString(),\n\t\t\tstatus: options.status,\n\t\t\tpage: options.page?.toString(),\n\t\t\tpagination: options.pagination?.toString(),\n\t\t\treq_time: reqTime,\n\t\t\tmerchant_id: this.merchantId,\n\t\t};\n\n\t\treturn this.request<ListTransactionsResponse>(\n\t\t\tENDPOINTS.transactionList,\n\t\t\tparams,\n\t\t);\n\t}\n\n\tprivate async request<T>(\n\t\tendpoint: string,\n\t\tparams: Record<string, string | undefined>,\n\t): Promise<T> {\n\t\tconst url = `${this.baseUrl}${endpoint}`;\n\t\tconst formData = new FormData();\n\t\tfor (const [key, value] of Object.entries(params)) {\n\t\t\tif (value !== undefined && value !== null && value !== \"\") {\n\t\t\t\tformData.append(key, value);\n\t\t\t}\n\t\t}\n\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: formData,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text();\n\t\t\tlet body: unknown = text;\n\t\t\ttry {\n\t\t\t\tbody = JSON.parse(text);\n\t\t\t} catch {\n\t\t\t\t// keep as text\n\t\t\t}\n\t\t\tthrow new PayWayAPIError(\n\t\t\t\t`PayWay API error: ${response.status} ${response.statusText}`,\n\t\t\t\tresponse.status,\n\t\t\t\tbody,\n\t\t\t);\n\t\t}\n\n\t\treturn (await response.json()) as T;\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/errors.ts","../src/hash.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["export { PayWay } from \"./client.ts\";\nexport {\n\tBASE_URLS,\n\tENDPOINTS,\n\tPRODUCTION_BASE_URL,\n\tSANDBOX_BASE_URL,\n} from \"./constants.ts\";\nexport {\n\tPayWayAPIError,\n\tPayWayConfigError,\n\tPayWayError,\n\tPayWayHashError,\n} from \"./errors.ts\";\nexport { createHash } from \"./hash.ts\";\nexport type {\n\tCheckoutParams,\n\tCheckTransactionData,\n\tCloseTransactionResponse,\n\tCreateTransactionOptions,\n\tCurrency,\n\tEnvironment,\n\tExchangeRate,\n\tExchangeRateCurrency,\n\tExchangeRateResponse,\n\tGenerateQROptions,\n\tGenerateQRResponse,\n\tGetTransactionsByRefResponse,\n\tItemEntry,\n\tListTransactionsOptions,\n\tListTransactionsResponse,\n\tPaymentOption,\n\tPayWayConfig,\n\tPayWayResponse,\n\tPayWayResponseStatus,\n\tQRPaymentOption,\n\tTransactionByRefItem,\n\tTransactionDetailData,\n\tTransactionListItem,\n\tTransactionOperation,\n\tTransactionStatus,\n\tTransactionType,\n} from \"./types.ts\";\nexport {\n\tbuildFormData,\n\tformatAmount,\n\tformatRequestTime,\n\ttoBase64,\n} from \"./utils.ts\";\n","import type { Environment } from \"./types.ts\";\n\nexport const BASE_URLS: Record<Environment, string> = {\n\tsandbox: \"https://checkout-sandbox.payway.com.kh\",\n\tproduction: \"https://checkout.payway.com.kh\",\n};\n\nexport const SANDBOX_BASE_URL = BASE_URLS.sandbox;\nexport const PRODUCTION_BASE_URL = BASE_URLS.production;\n\nexport const ENDPOINTS = {\n\tpurchase: \"/api/payment-gateway/v1/payments/purchase\",\n\tcheckTransaction: \"/api/payment-gateway/v1/payments/check-transaction-2\",\n\ttransactionList: \"/api/payment-gateway/v1/payments/transaction-list-2\",\n\ttransactionDetail: \"/api/payment-gateway/v1/payments/transaction-detail\",\n\tcloseTransaction: \"/api/payment-gateway/v1/payments/close-transaction\",\n\texchangeRate: \"/api/payment-gateway/v1/exchange-rate\",\n\tgenerateQR: \"/api/payment-gateway/v1/payments/generate-qr\",\n\tgetTransactionsByRef:\n\t\t\"/api/payment-gateway/v1/payments/get-transactions-by-mc-ref\",\n} as const;\n","/** Base error class for all PayWay SDK errors. */\nexport class PayWayError extends Error {\n\tconstructor(message: string, options?: ErrorOptions) {\n\t\tsuper(message, options);\n\t\tthis.name = \"PayWayError\";\n\t}\n}\n\n/** Thrown when the ABA PayWay API returns a non-2xx HTTP response. */\nexport class PayWayAPIError extends PayWayError {\n\tpublic readonly statusCode: number;\n\tpublic readonly responseBody: unknown;\n\n\tconstructor(message: string, statusCode: number, responseBody?: unknown) {\n\t\tsuper(message);\n\t\tthis.name = \"PayWayAPIError\";\n\t\tthis.statusCode = statusCode;\n\t\tthis.responseBody = responseBody;\n\t}\n}\n\n/** Thrown when the SDK is constructed with missing or invalid configuration. */\nexport class PayWayConfigError extends PayWayError {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"PayWayConfigError\";\n\t}\n}\n\n/** Thrown when HMAC hash generation fails. */\nexport class PayWayHashError extends PayWayError {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"PayWayHashError\";\n\t}\n}\n","import { createHmac } from \"node:crypto\";\n\n/** Generate an HMAC-SHA512 hash from concatenated values, returned as a base64 string. */\nexport function createHash(values: readonly string[], apiKey: string): string {\n\tconst message = values.join(\"\");\n\tconst hmac = createHmac(\"sha512\", apiKey);\n\thmac.update(message);\n\treturn hmac.digest(\"base64\");\n}\n","import type { Currency } from \"./types.ts\";\n\n/** Format a Date as `yyyyMMddHHmmss` in UTC, used for ABA's `req_time` parameter. */\nexport function formatRequestTime(date: Date = new Date()): string {\n\tconst year = date.getUTCFullYear().toString();\n\tconst month = (date.getUTCMonth() + 1).toString().padStart(2, \"0\");\n\tconst day = date.getUTCDate().toString().padStart(2, \"0\");\n\tconst hours = date.getUTCHours().toString().padStart(2, \"0\");\n\tconst minutes = date.getUTCMinutes().toString().padStart(2, \"0\");\n\tconst seconds = date.getUTCSeconds().toString().padStart(2, \"0\");\n\treturn `${year}${month}${day}${hours}${minutes}${seconds}`;\n}\n\n/** Filter out `undefined` and empty string values from a params object. */\nexport function filterParams(params: object): Record<string, string | number> {\n\tconst out: Record<string, string | number> = {};\n\tfor (const [key, value] of Object.entries(params)) {\n\t\tif (value !== undefined && value !== \"\") {\n\t\t\tout[key] = value as string | number;\n\t\t}\n\t}\n\treturn out;\n}\n\n/** Build a FormData object from a record, skipping `undefined`, `null`, and empty string values. */\nexport function buildFormData(params: object): FormData {\n\tconst formData = new FormData();\n\tfor (const [key, value] of Object.entries(filterParams(params))) {\n\t\tformData.append(key, String(value));\n\t}\n\treturn formData;\n}\n\n/** Format a numeric amount as a string: 2 decimal places for USD, rounded integer for KHR. */\nexport function formatAmount(\n\tamount: number,\n\tcurrency: Currency = \"USD\",\n): string {\n\tif (currency === \"KHR\") {\n\t\treturn Math.round(amount).toString();\n\t}\n\treturn amount.toFixed(2);\n}\n\n/** Base64-encode a string value using Node.js Buffer. */\nexport function toBase64(value: string): string {\n\treturn Buffer.from(value).toString(\"base64\");\n}\n","import { BASE_URLS, ENDPOINTS } from \"./constants.ts\";\nimport { PayWayAPIError, PayWayConfigError, PayWayError } from \"./errors.ts\";\nimport { createHash } from \"./hash.ts\";\nimport type {\n\tCheckoutParams,\n\tCheckTransactionData,\n\tCloseTransactionResponse,\n\tCreateTransactionOptions,\n\tExchangeRateParams,\n\tExchangeRateResponse,\n\tGenerateQROptions,\n\tGenerateQRParams,\n\tGenerateQRResponse,\n\tGetTransactionsByRefParams,\n\tGetTransactionsByRefResponse,\n\tListTransactionsOptions,\n\tListTransactionsParams,\n\tListTransactionsResponse,\n\tPayWayConfig,\n\tPayWayResponse,\n\tRequestParams,\n\tTransactionDetailData,\n\tTransactionParams,\n} from \"./types.ts\";\nimport {\n\tbuildFormData,\n\tfilterParams,\n\tformatAmount,\n\tformatRequestTime,\n\ttoBase64,\n} from \"./utils.ts\";\n\n/**\n * Main SDK client for ABA PayWay.\n * Provides methods for creating transactions, checking status, and listing transactions.\n */\nexport class PayWay {\n\tprivate readonly merchantId: string;\n\tprivate readonly apiKey: string;\n\tprivate readonly baseUrl: string;\n\tprivate readonly timeout: number;\n\n\t/**\n\t * @param config - Merchant credentials and environment selection.\n\t * @throws {PayWayConfigError} If `merchantId` or `apiKey` is empty.\n\t */\n\tconstructor(config: PayWayConfig) {\n\t\tif (!config.merchantId) {\n\t\t\tthrow new PayWayConfigError(\"merchantId is required\");\n\t\t}\n\t\tif (!config.apiKey) {\n\t\t\tthrow new PayWayConfigError(\"apiKey is required\");\n\t\t}\n\n\t\tthis.merchantId = config.merchantId;\n\t\tthis.apiKey = config.apiKey;\n\t\tthis.baseUrl = config.baseUrl ?? BASE_URLS[config.environment ?? \"sandbox\"];\n\t\tthis.timeout = config.timeout ?? 30_000;\n\t}\n\n\t/**\n\t * Generate checkout parameters for a transaction.\n\t * Returns form params to be submitted from the browser via ABA's checkout JS SDK.\n\t */\n\tcreateTransaction(options: CreateTransactionOptions): CheckoutParams {\n\t\tif (!options.transactionId) {\n\t\t\tthrow new PayWayConfigError(\"transactionId is required\");\n\t\t}\n\t\tif (options.transactionId.length > 20) {\n\t\t\tthrow new PayWayConfigError(\n\t\t\t\t\"transactionId must be at most 20 characters\",\n\t\t\t);\n\t\t}\n\t\tif (options.amount <= 0) {\n\t\t\tthrow new PayWayConfigError(\"amount must be greater than 0\");\n\t\t}\n\t\tif (\n\t\t\toptions.lifetime !== undefined &&\n\t\t\t(options.lifetime < 3 || options.lifetime > 43_200)\n\t\t) {\n\t\t\tthrow new PayWayConfigError(\"lifetime must be between 3 and 43200\");\n\t\t}\n\n\t\tconst reqTime = formatRequestTime();\n\t\tconst currency = options.currency ?? \"USD\";\n\t\tconst amount = formatAmount(options.amount, currency);\n\t\tconst type = options.type ?? \"purchase\";\n\n\t\t// Items: if array, JSON-stringify and base64-encode; if string, base64-encode as-is\n\t\tlet items: string;\n\t\tif (Array.isArray(options.items)) {\n\t\t\titems = toBase64(JSON.stringify(options.items));\n\t\t} else if (options.items) {\n\t\t\titems = toBase64(options.items);\n\t\t} else {\n\t\t\titems = \"\";\n\t\t}\n\n\t\t// Return URL and return deeplink must be base64-encoded per ABA docs\n\t\tconst returnUrl = options.returnUrl ? toBase64(options.returnUrl) : \"\";\n\t\tconst returnDeeplink = options.returnDeeplink\n\t\t\t? toBase64(options.returnDeeplink)\n\t\t\t: \"\";\n\n\t\t// Payout must be base64-encoded JSON string per ABA docs\n\t\tconst payout = options.payout ? toBase64(options.payout) : \"\";\n\n\t\tconst shipping =\n\t\t\toptions.shipping !== undefined\n\t\t\t\t? formatAmount(options.shipping, currency)\n\t\t\t\t: \"\";\n\n\t\t// Hash field order from remote docs (view_type and payment_gate are NOT in hash)\n\t\tconst hashValues = [\n\t\t\treqTime,\n\t\t\tthis.merchantId,\n\t\t\toptions.transactionId,\n\t\t\tamount,\n\t\t\titems,\n\t\t\tshipping,\n\t\t\toptions.firstName ?? \"\",\n\t\t\toptions.lastName ?? \"\",\n\t\t\toptions.email ?? \"\",\n\t\t\toptions.phone ?? \"\",\n\t\t\ttype,\n\t\t\toptions.paymentOption ?? \"\",\n\t\t\treturnUrl,\n\t\t\toptions.cancelUrl ?? \"\",\n\t\t\toptions.continueSuccessUrl ?? \"\",\n\t\t\treturnDeeplink,\n\t\t\tcurrency,\n\t\t\toptions.customFields ?? \"\",\n\t\t\toptions.returnParams ?? \"\",\n\t\t\tpayout,\n\t\t\toptions.lifetime?.toString() ?? \"\",\n\t\t\toptions.additionalParams ?? \"\",\n\t\t\toptions.googlePayToken ?? \"\",\n\t\t\toptions.skipSuccessPage?.toString() ?? \"\",\n\t\t];\n\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\treturn {\n\t\t\taction: `${this.baseUrl}${ENDPOINTS.purchase}`,\n\t\t\thash,\n\t\t\ttran_id: options.transactionId,\n\t\t\tamount,\n\t\t\titems,\n\t\t\tcurrency,\n\t\t\tfirstname: options.firstName ?? \"\",\n\t\t\tlastname: options.lastName ?? \"\",\n\t\t\temail: options.email ?? \"\",\n\t\t\tphone: options.phone ?? \"\",\n\t\t\ttype,\n\t\t\tpayment_option: options.paymentOption ?? \"\",\n\t\t\treturn_url: returnUrl,\n\t\t\tcancel_url: options.cancelUrl ?? \"\",\n\t\t\tcontinue_success_url: options.continueSuccessUrl ?? \"\",\n\t\t\treturn_deeplink: returnDeeplink,\n\t\t\treturn_params: options.returnParams ?? \"\",\n\t\t\tshipping,\n\t\t\tmerchant_id: this.merchantId,\n\t\t\treq_time: reqTime,\n\t\t\tcustom_fields: options.customFields ?? \"\",\n\t\t\tpayout,\n\t\t\tlifetime: options.lifetime?.toString() ?? \"\",\n\t\t\tadditional_params: options.additionalParams ?? \"\",\n\t\t\tgoogle_pay_token: options.googlePayToken ?? \"\",\n\t\t\tskip_success_page: options.skipSuccessPage?.toString() ?? \"\",\n\t\t\tview_type: options.viewType ?? \"\",\n\t\t\tpayment_gate: options.paymentGate?.toString() ?? \"\",\n\t\t};\n\t}\n\n\t/**\n\t * Check the status of a transaction.\n\t * @param transactionId - The unique transaction ID to look up.\n\t * @throws {PayWayAPIError} If the API returns a non-2xx response.\n\t */\n\tasync checkTransaction(\n\t\ttransactionId: string,\n\t): Promise<PayWayResponse<CheckTransactionData>> {\n\t\tif (!transactionId) {\n\t\t\tthrow new PayWayConfigError(\"transactionId is required\");\n\t\t}\n\n\t\tconst reqTime = formatRequestTime();\n\n\t\tconst hashValues = [reqTime, this.merchantId, transactionId];\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\tconst params: TransactionParams = {\n\t\t\thash,\n\t\t\ttran_id: transactionId,\n\t\t\treq_time: reqTime,\n\t\t\tmerchant_id: this.merchantId,\n\t\t};\n\n\t\treturn this.request<PayWayResponse<CheckTransactionData>>(\n\t\t\tENDPOINTS.checkTransaction,\n\t\t\tparams,\n\t\t);\n\t}\n\n\t/**\n\t * List transactions with optional filters. Max 3-day date range.\n\t * @param options - Filter and pagination options.\n\t * @throws {PayWayAPIError} If the API returns a non-2xx response.\n\t */\n\tasync listTransactions(\n\t\toptions: ListTransactionsOptions = {},\n\t): Promise<ListTransactionsResponse> {\n\t\tconst reqTime = formatRequestTime();\n\n\t\tconst hashValues = [\n\t\t\treqTime,\n\t\t\tthis.merchantId,\n\t\t\toptions.fromDate ?? \"\",\n\t\t\toptions.toDate ?? \"\",\n\t\t\toptions.fromAmount?.toString() ?? \"\",\n\t\t\toptions.toAmount?.toString() ?? \"\",\n\t\t\toptions.status ?? \"\",\n\t\t\toptions.page?.toString() ?? \"\",\n\t\t\toptions.pagination?.toString() ?? \"\",\n\t\t];\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\tconst params: ListTransactionsParams = {\n\t\t\thash,\n\t\t\tfrom_date: options.fromDate,\n\t\t\tto_date: options.toDate,\n\t\t\tfrom_amount: options.fromAmount?.toString(),\n\t\t\tto_amount: options.toAmount?.toString(),\n\t\t\tstatus: options.status,\n\t\t\tpage: options.page?.toString(),\n\t\t\tpagination: options.pagination?.toString(),\n\t\t\treq_time: reqTime,\n\t\t\tmerchant_id: this.merchantId,\n\t\t};\n\n\t\treturn this.request<ListTransactionsResponse>(\n\t\t\tENDPOINTS.transactionList,\n\t\t\tparams,\n\t\t);\n\t}\n\n\t/**\n\t * Get detailed information about a transaction, including its operation history.\n\t * @param transactionId - The unique transaction ID to look up.\n\t * @throws {PayWayAPIError} If the API returns a non-2xx response.\n\t */\n\tasync getTransactionDetails(\n\t\ttransactionId: string,\n\t): Promise<PayWayResponse<TransactionDetailData>> {\n\t\tif (!transactionId) {\n\t\t\tthrow new PayWayConfigError(\"transactionId is required\");\n\t\t}\n\n\t\tconst reqTime = formatRequestTime();\n\t\tconst hashValues = [reqTime, this.merchantId, transactionId];\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\tconst params: TransactionParams = {\n\t\t\thash,\n\t\t\ttran_id: transactionId,\n\t\t\treq_time: reqTime,\n\t\t\tmerchant_id: this.merchantId,\n\t\t};\n\n\t\treturn this.request<PayWayResponse<TransactionDetailData>>(\n\t\t\tENDPOINTS.transactionDetail,\n\t\t\tparams,\n\t\t\t\"json\",\n\t\t);\n\t}\n\n\t/**\n\t * Close (cancel) a pending transaction.\n\t * @param transactionId - The transaction ID to close.\n\t * @throws {PayWayAPIError} If the API returns a non-2xx response.\n\t */\n\tasync closeTransaction(\n\t\ttransactionId: string,\n\t): Promise<CloseTransactionResponse> {\n\t\tif (!transactionId) {\n\t\t\tthrow new PayWayConfigError(\"transactionId is required\");\n\t\t}\n\n\t\tconst reqTime = formatRequestTime();\n\t\tconst hashValues = [reqTime, this.merchantId, transactionId];\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\tconst params: TransactionParams = {\n\t\t\thash,\n\t\t\ttran_id: transactionId,\n\t\t\treq_time: reqTime,\n\t\t\tmerchant_id: this.merchantId,\n\t\t};\n\n\t\treturn this.request<CloseTransactionResponse>(\n\t\t\tENDPOINTS.closeTransaction,\n\t\t\tparams,\n\t\t\t\"json\",\n\t\t);\n\t}\n\n\t/**\n\t * Fetch the latest exchange rates from ABA Bank.\n\t * @throws {PayWayAPIError} If the API returns a non-2xx response.\n\t */\n\tasync getExchangeRate(): Promise<ExchangeRateResponse> {\n\t\tconst reqTime = formatRequestTime();\n\t\tconst hashValues = [reqTime, this.merchantId];\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\tconst params: ExchangeRateParams = {\n\t\t\thash,\n\t\t\treq_time: reqTime,\n\t\t\tmerchant_id: this.merchantId,\n\t\t};\n\n\t\treturn this.request<ExchangeRateResponse>(\n\t\t\tENDPOINTS.exchangeRate,\n\t\t\tparams,\n\t\t\t\"json\",\n\t\t);\n\t}\n\n\t/**\n\t * Generate a QR code for payment via ABA KHQR, WeChat Pay, or Alipay.\n\t * @param options - QR generation options.\n\t * @throws {PayWayConfigError} If required options are missing or invalid.\n\t * @throws {PayWayAPIError} If the API returns a non-2xx response.\n\t */\n\tasync generateQR(options: GenerateQROptions): Promise<GenerateQRResponse> {\n\t\tif (!options.transactionId) {\n\t\t\tthrow new PayWayConfigError(\"transactionId is required\");\n\t\t}\n\t\tif (options.amount <= 0) {\n\t\t\tthrow new PayWayConfigError(\"amount must be greater than 0\");\n\t\t}\n\t\tif (!options.paymentOption) {\n\t\t\tthrow new PayWayConfigError(\"paymentOption is required\");\n\t\t}\n\t\tif (!options.qrImageTemplate) {\n\t\t\tthrow new PayWayConfigError(\"qrImageTemplate is required\");\n\t\t}\n\t\tif (\n\t\t\toptions.lifetime !== undefined &&\n\t\t\t(options.lifetime < 3 || options.lifetime > 43_200)\n\t\t) {\n\t\t\tthrow new PayWayConfigError(\"lifetime must be between 3 and 43200\");\n\t\t}\n\n\t\tconst reqTime = formatRequestTime();\n\t\tconst currency = options.currency ?? \"USD\";\n\t\tconst amount = formatAmount(options.amount, currency);\n\n\t\t// Base64-encode fields per ABA docs\n\t\tconst items = options.items ? toBase64(options.items) : \"\";\n\t\tconst callbackUrl = options.callbackUrl\n\t\t\t? toBase64(options.callbackUrl)\n\t\t\t: \"\";\n\t\tconst returnDeeplink = options.returnDeeplink\n\t\t\t? toBase64(options.returnDeeplink)\n\t\t\t: \"\";\n\t\tconst customFields = options.customFields\n\t\t\t? toBase64(options.customFields)\n\t\t\t: \"\";\n\t\tconst payout = options.payout ? toBase64(options.payout) : \"\";\n\n\t\t// Hash field order from remote docs (differs from parameter table order)\n\t\tconst hashValues = [\n\t\t\treqTime,\n\t\t\tthis.merchantId,\n\t\t\toptions.transactionId,\n\t\t\tamount,\n\t\t\titems,\n\t\t\toptions.firstName ?? \"\",\n\t\t\toptions.lastName ?? \"\",\n\t\t\toptions.email ?? \"\",\n\t\t\toptions.phone ?? \"\",\n\t\t\toptions.purchaseType ?? \"\",\n\t\t\toptions.paymentOption,\n\t\t\tcallbackUrl,\n\t\t\treturnDeeplink,\n\t\t\tcurrency,\n\t\t\tcustomFields,\n\t\t\toptions.returnParams ?? \"\",\n\t\t\tpayout,\n\t\t\toptions.lifetime?.toString() ?? \"\",\n\t\t\toptions.qrImageTemplate,\n\t\t];\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\tconst params: GenerateQRParams = {\n\t\t\thash,\n\t\t\treq_time: reqTime,\n\t\t\tmerchant_id: this.merchantId,\n\t\t\ttran_id: options.transactionId,\n\t\t\tamount: options.amount,\n\t\t\tcurrency,\n\t\t\tpayment_option: options.paymentOption,\n\t\t\tlifetime: options.lifetime,\n\t\t\tqr_image_template: options.qrImageTemplate,\n\t\t\tfirst_name: options.firstName,\n\t\t\tlast_name: options.lastName,\n\t\t\temail: options.email,\n\t\t\tphone: options.phone,\n\t\t\tpurchase_type: options.purchaseType,\n\t\t\titems: items || undefined,\n\t\t\tcallback_url: callbackUrl || undefined,\n\t\t\treturn_deeplink: returnDeeplink || undefined,\n\t\t\tcustom_fields: customFields || undefined,\n\t\t\treturn_params: options.returnParams,\n\t\t\tpayout: payout || undefined,\n\t\t};\n\n\t\treturn this.request<GenerateQRResponse>(\n\t\t\tENDPOINTS.generateQR,\n\t\t\tparams,\n\t\t\t\"json\",\n\t\t);\n\t}\n\n\t/**\n\t * Get transactions by merchant reference. Returns up to the last 50 transactions.\n\t * @param merchantRef - Your merchant reference number.\n\t * @throws {PayWayAPIError} If the API returns a non-2xx response.\n\t */\n\tasync getTransactionsByRef(\n\t\tmerchantRef: string,\n\t): Promise<GetTransactionsByRefResponse> {\n\t\tif (!merchantRef) {\n\t\t\tthrow new PayWayConfigError(\"merchantRef is required\");\n\t\t}\n\n\t\tconst reqTime = formatRequestTime();\n\t\tconst hashValues = [reqTime, this.merchantId, merchantRef];\n\t\tconst hash = createHash(hashValues, this.apiKey);\n\n\t\tconst params: GetTransactionsByRefParams = {\n\t\t\thash,\n\t\t\tmerchant_ref: merchantRef,\n\t\t\treq_time: reqTime,\n\t\t\tmerchant_id: this.merchantId,\n\t\t};\n\n\t\treturn this.request<GetTransactionsByRefResponse>(\n\t\t\tENDPOINTS.getTransactionsByRef,\n\t\t\tparams,\n\t\t\t\"json\",\n\t\t);\n\t}\n\n\tprivate async request<T>(\n\t\tendpoint: (typeof ENDPOINTS)[keyof typeof ENDPOINTS],\n\t\tparams: RequestParams,\n\t\tformat: \"form\" | \"json\" = \"form\",\n\t): Promise<T> {\n\t\tconst url = `${this.baseUrl}${endpoint}`;\n\n\t\tlet body: FormData | string;\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (format === \"json\") {\n\t\t\tbody = JSON.stringify(filterParams(params));\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t} else {\n\t\t\tbody = buildFormData(params);\n\t\t}\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody,\n\t\t\t\theaders,\n\t\t\t\tsignal: AbortSignal.timeout(this.timeout),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthrow new PayWayError(\n\t\t\t\terror instanceof Error ? error.message : \"Network request failed\",\n\t\t\t\t{ cause: error },\n\t\t\t);\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text();\n\t\t\tlet responseBody: unknown = text;\n\t\t\ttry {\n\t\t\t\tresponseBody = JSON.parse(text);\n\t\t\t} catch {\n\t\t\t\t// keep as text\n\t\t\t}\n\t\t\tthrow new PayWayAPIError(\n\t\t\t\t`PayWay API error: ${response.status} ${response.statusText}`,\n\t\t\t\tresponse.status,\n\t\t\t\tresponseBody,\n\t\t\t);\n\t\t}\n\n\t\treturn (await response.json()) as T;\n\t}\n}\n"],"mappings":"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","names":[]}
|