aba-payway 0.1.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # aba-payway
2
+
3
+ Type-safe TypeScript SDK for [ABA PayWay](https://www.payway.com.kh/) — Cambodia's #1 payment gateway.
4
+
5
+ > **Unofficial community SDK.** Not affiliated with ABA Bank.
6
+
7
+ ## Features
8
+
9
+ - Zero runtime dependencies — uses Node.js built-in `crypto` and native `fetch`
10
+ - Full TypeScript support with strict types
11
+ - Dual ESM + CJS output
12
+ - Simple, clean API with camelCase interface
13
+ - Works with Node.js, Bun, Next.js, Express, Hono, and any JS runtime with `fetch`
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ # bun
19
+ bun add aba-payway
20
+
21
+ # npm
22
+ npm install aba-payway
23
+
24
+ # pnpm
25
+ pnpm add aba-payway
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ```typescript
31
+ import { PayWay } from 'aba-payway'
32
+
33
+ const payway = new PayWay({
34
+ merchantId: 'your_merchant_id',
35
+ apiKey: 'your_api_key',
36
+ })
37
+
38
+ // Generate checkout params (synchronous — no API call)
39
+ const params = payway.createTransaction({
40
+ transactionId: 'order-001',
41
+ amount: 10.00,
42
+ items: 'Product A',
43
+ returnUrl: 'https://yoursite.com/callback',
44
+ })
45
+
46
+ // Send `params` to your frontend, populate ABA's hidden form,
47
+ // and call AbaPayway.checkout() to open the payment dialog.
48
+ // See examples/server.ts for a complete working example.
49
+ ```
50
+
51
+ ## API Reference
52
+
53
+ ### `new PayWay(config)`
54
+
55
+ | Parameter | Type | Required | Default | Description |
56
+ |---|---|---|---|---|
57
+ | `merchantId` | `string` | Yes | — | Your ABA PayWay merchant ID |
58
+ | `apiKey` | `string` | Yes | — | Your ABA PayWay API key |
59
+ | `production` | `boolean` | No | `false` | Use production environment |
60
+
61
+ ### `payway.createTransaction(options)`
62
+
63
+ Generate checkout parameters for a payment. **Synchronous** — computes the HMAC hash and returns form params without making any API calls.
64
+
65
+ Returns `CheckoutParams` — snake_case form parameters to submit via ABA's checkout JS SDK.
66
+
67
+ | Parameter | Type | Required | Description |
68
+ |---|---|---|---|
69
+ | `transactionId` | `string` | Yes | Unique transaction ID (max 20 chars) |
70
+ | `amount` | `number` | Yes | Purchase amount |
71
+ | `currency` | `'USD' \| 'KHR'` | No | Default: `'USD'` |
72
+ | `paymentOption` | `PaymentOption` | No | `cards`, `abapay_khqr`, `abapay_khqr_deeplink`, `alipay`, `wechat`, `google_pay` |
73
+ | `firstName` | `string` | No | Buyer's first name |
74
+ | `lastName` | `string` | No | Buyer's last name |
75
+ | `email` | `string` | No | Buyer's email |
76
+ | `phone` | `string` | No | Buyer's phone |
77
+ | `items` | `string \| ItemEntry[]` | No | Item description — string or `{ name, quantity, price }[]` |
78
+ | `returnUrl` | `string` | No | Callback URL for payment completion |
79
+ | `cancelUrl` | `string` | No | Redirect URL when user closes payment |
80
+ | `continueSuccessUrl` | `string` | No | Redirect URL after success |
81
+ | `type` | `'purchase' \| 'pre-auth'` | No | Default: `'purchase'` |
82
+ | `shipping` | `number` | No | Shipping fee |
83
+ | `viewType` | `string` | No | `'hosted_view'` or `'popup'` |
84
+ | `lifetime` | `number` | No | Payment lifetime in minutes (3–43200) |
85
+ | `skipSuccessPage` | `number` | No | `0` (don't skip) or `1` (skip) |
86
+ | `payout` | `string` | No | Payout details (JSON string) |
87
+ | `returnDeeplink` | `string` | No | Mobile app deeplink |
88
+ | `googlePayToken` | `string` | No | Required if `paymentOption` is `'google_pay'` |
89
+
90
+ > `items`, `returnUrl`, `returnDeeplink`, and `payout` are automatically base64-encoded by the SDK.
91
+
92
+ ### `payway.checkTransaction(transactionId)`
93
+
94
+ Check the status of a transaction.
95
+
96
+ ```typescript
97
+ const result = await payway.checkTransaction('order-001')
98
+ console.log(result.status.code) // '00' = success
99
+ console.log(result.data.payment_status) // 'APPROVED' | 'DECLINED' | 'PENDING' | ...
100
+ ```
101
+
102
+ ### `payway.listTransactions(options?)`
103
+
104
+ List transactions with optional filters. Max 3-day date range.
105
+
106
+ ```typescript
107
+ const list = await payway.listTransactions({
108
+ fromDate: '2025-03-01 00:00:00',
109
+ toDate: '2025-03-03 23:59:59',
110
+ status: 'APPROVED',
111
+ page: 1,
112
+ pagination: 20,
113
+ })
114
+ ```
115
+
116
+ | Parameter | Type | Description |
117
+ |---|---|---|
118
+ | `fromDate` | `string` | Start date: `'YYYY-MM-DD HH:mm:ss'` |
119
+ | `toDate` | `string` | End date: `'YYYY-MM-DD HH:mm:ss'` |
120
+ | `fromAmount` | `number` | Minimum amount filter |
121
+ | `toAmount` | `number` | Maximum amount filter |
122
+ | `status` | `string` | Comma-separated: `APPROVED`, `DECLINED`, `PENDING`, `PRE-AUTH`, `CANCELLED`, `REFUNDED` |
123
+ | `page` | `number` | Page number (default: `1`) |
124
+ | `pagination` | `number` | Records per page (default: `40`, max: `1000`) |
125
+
126
+ ## Error Handling
127
+
128
+ ```typescript
129
+ import { PayWay, PayWayAPIError, PayWayConfigError } from 'aba-payway'
130
+ ```
131
+
132
+ | Error Class | When Thrown |
133
+ |---|---|
134
+ | `PayWayConfigError` | Missing or invalid constructor config |
135
+ | `PayWayAPIError` | ABA API returns non-2xx response (has `statusCode` and `responseBody` properties) |
136
+ | `PayWayError` | Base error class |
137
+ | `PayWayHashError` | Hash generation failure |
138
+
139
+ ## Framework Examples
140
+
141
+ ### Next.js (App Router)
142
+
143
+ ```typescript
144
+ // app/api/pay/route.ts
145
+ import { PayWay } from 'aba-payway'
146
+
147
+ const payway = new PayWay({
148
+ merchantId: process.env.PAYWAY_MERCHANT_ID!,
149
+ apiKey: process.env.PAYWAY_API_KEY!,
150
+ production: process.env.NODE_ENV === 'production',
151
+ })
152
+
153
+ export async function POST(request: Request) {
154
+ const { orderId, amount } = await request.json()
155
+
156
+ const params = payway.createTransaction({
157
+ transactionId: orderId,
158
+ amount,
159
+ items: 'Order payment',
160
+ returnUrl: `${process.env.NEXT_PUBLIC_URL}/api/pay/callback`,
161
+ })
162
+
163
+ return Response.json(params)
164
+ }
165
+ ```
166
+
167
+ ### Express
168
+
169
+ ```typescript
170
+ import express from 'express'
171
+ import { PayWay } from 'aba-payway'
172
+
173
+ const app = express()
174
+ app.use(express.json())
175
+
176
+ const payway = new PayWay({
177
+ merchantId: process.env.PAYWAY_MERCHANT_ID!,
178
+ apiKey: process.env.PAYWAY_API_KEY!,
179
+ })
180
+
181
+ app.post('/pay', (req, res) => {
182
+ const params = payway.createTransaction({
183
+ transactionId: req.body.orderId,
184
+ amount: req.body.amount,
185
+ items: 'Order payment',
186
+ returnUrl: 'https://yoursite.com/callback',
187
+ })
188
+ res.json(params)
189
+ })
190
+ ```
191
+
192
+ ## Sandbox Test Cards
193
+
194
+ | Card | Number | Expiry | CVV | Result |
195
+ |---|---|---|---|---|
196
+ | Mastercard | `5156 8399 3770 6777` | `01/30` | `993` | Approved |
197
+ | Visa | `4286 0900 0000 0206` | `04/30` | `777` | Approved |
198
+ | Mastercard | `5156 8302 7256 1029` | `04/30` | `777` | Declined |
199
+ | Visa | `4156 8399 3770 6777` | `01/30` | `993` | Declined |
200
+
201
+ ## Documentation
202
+
203
+ For the full ABA PayWay API documentation, see [aba-payway-docs](https://github.com/Joselay/aba-payway-docs).
204
+
205
+ ## License
206
+
207
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ENDPOINTS: () => ENDPOINTS,
24
+ PRODUCTION_BASE_URL: () => PRODUCTION_BASE_URL,
25
+ PayWay: () => PayWay,
26
+ PayWayAPIError: () => PayWayAPIError,
27
+ PayWayConfigError: () => PayWayConfigError,
28
+ PayWayError: () => PayWayError,
29
+ PayWayHashError: () => PayWayHashError,
30
+ SANDBOX_BASE_URL: () => SANDBOX_BASE_URL,
31
+ buildFormData: () => buildFormData,
32
+ createHash: () => createHash,
33
+ formatAmount: () => formatAmount,
34
+ formatRequestTime: () => formatRequestTime,
35
+ toBase64: () => toBase64
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+
39
+ // src/constants.ts
40
+ var SANDBOX_BASE_URL = "https://checkout-sandbox.payway.com.kh";
41
+ var PRODUCTION_BASE_URL = "https://checkout.payway.com.kh";
42
+ var ENDPOINTS = {
43
+ purchase: "/api/payment-gateway/v1/payments/purchase",
44
+ checkTransaction: "/api/payment-gateway/v1/payments/check-transaction-2",
45
+ transactionList: "/api/payment-gateway/v1/payments/transaction-list-2"
46
+ };
47
+
48
+ // src/errors.ts
49
+ var PayWayError = class extends Error {
50
+ constructor(message) {
51
+ super(message);
52
+ this.name = "PayWayError";
53
+ }
54
+ };
55
+ var PayWayAPIError = class extends PayWayError {
56
+ statusCode;
57
+ responseBody;
58
+ constructor(message, statusCode, responseBody) {
59
+ super(message);
60
+ this.name = "PayWayAPIError";
61
+ this.statusCode = statusCode;
62
+ this.responseBody = responseBody;
63
+ }
64
+ };
65
+ var PayWayConfigError = class extends PayWayError {
66
+ constructor(message) {
67
+ super(message);
68
+ this.name = "PayWayConfigError";
69
+ }
70
+ };
71
+ var PayWayHashError = class extends PayWayError {
72
+ constructor(message) {
73
+ super(message);
74
+ this.name = "PayWayHashError";
75
+ }
76
+ };
77
+
78
+ // src/hash.ts
79
+ var import_node_crypto = require("crypto");
80
+ function createHash(values, apiKey) {
81
+ const message = values.join("");
82
+ const hmac = (0, import_node_crypto.createHmac)("sha512", apiKey);
83
+ hmac.update(message);
84
+ return hmac.digest("base64");
85
+ }
86
+
87
+ // src/utils.ts
88
+ function formatRequestTime(date = /* @__PURE__ */ new Date()) {
89
+ const year = date.getUTCFullYear().toString();
90
+ const month = (date.getUTCMonth() + 1).toString().padStart(2, "0");
91
+ const day = date.getUTCDate().toString().padStart(2, "0");
92
+ const hours = date.getUTCHours().toString().padStart(2, "0");
93
+ const minutes = date.getUTCMinutes().toString().padStart(2, "0");
94
+ const seconds = date.getUTCSeconds().toString().padStart(2, "0");
95
+ return `${year}${month}${day}${hours}${minutes}${seconds}`;
96
+ }
97
+ function buildFormData(params) {
98
+ const formData = new FormData();
99
+ for (const [key, value] of Object.entries(params)) {
100
+ if (value !== void 0 && value !== null && value !== "") {
101
+ formData.append(key, value);
102
+ }
103
+ }
104
+ return formData;
105
+ }
106
+ function formatAmount(amount, currency = "USD") {
107
+ if (currency.toUpperCase() === "KHR") {
108
+ return Math.round(amount).toString();
109
+ }
110
+ return amount.toFixed(2);
111
+ }
112
+ function toBase64(value) {
113
+ return Buffer.from(value).toString("base64");
114
+ }
115
+
116
+ // src/client.ts
117
+ var PayWay = class {
118
+ merchantId;
119
+ apiKey;
120
+ baseUrl;
121
+ constructor(config) {
122
+ if (!config.merchantId) {
123
+ throw new PayWayConfigError("merchantId is required");
124
+ }
125
+ if (!config.apiKey) {
126
+ throw new PayWayConfigError("apiKey is required");
127
+ }
128
+ this.merchantId = config.merchantId;
129
+ this.apiKey = config.apiKey;
130
+ this.baseUrl = config.production ? PRODUCTION_BASE_URL : SANDBOX_BASE_URL;
131
+ }
132
+ /**
133
+ * Generate checkout parameters for a transaction.
134
+ * Returns form params to be submitted from the browser via ABA's checkout JS SDK.
135
+ */
136
+ createTransaction(options) {
137
+ const reqTime = formatRequestTime();
138
+ const currency = options.currency ?? "USD";
139
+ const amount = formatAmount(options.amount, currency);
140
+ const type = options.type ?? "purchase";
141
+ let items;
142
+ if (Array.isArray(options.items)) {
143
+ items = toBase64(JSON.stringify(options.items));
144
+ } else if (options.items) {
145
+ items = toBase64(options.items);
146
+ } else {
147
+ items = "";
148
+ }
149
+ const returnUrl = options.returnUrl ? toBase64(options.returnUrl) : "";
150
+ const returnDeeplink = options.returnDeeplink ? toBase64(options.returnDeeplink) : "";
151
+ const payout = options.payout ? toBase64(options.payout) : "";
152
+ const shipping = options.shipping !== void 0 ? formatAmount(options.shipping, currency) : "";
153
+ const hashValues = [
154
+ reqTime,
155
+ this.merchantId,
156
+ options.transactionId,
157
+ amount,
158
+ items,
159
+ shipping,
160
+ options.firstName ?? "",
161
+ options.lastName ?? "",
162
+ options.email ?? "",
163
+ options.phone ?? "",
164
+ type,
165
+ options.paymentOption ?? "",
166
+ returnUrl,
167
+ options.cancelUrl ?? "",
168
+ options.continueSuccessUrl ?? "",
169
+ returnDeeplink,
170
+ currency,
171
+ options.customFields ?? "",
172
+ options.returnParams ?? "",
173
+ options.viewType ?? "",
174
+ options.paymentGate?.toString() ?? "",
175
+ payout,
176
+ options.lifetime?.toString() ?? "",
177
+ options.additionalParams ?? "",
178
+ options.googlePayToken ?? "",
179
+ options.skipSuccessPage?.toString() ?? ""
180
+ ];
181
+ const hash = createHash(hashValues, this.apiKey);
182
+ return {
183
+ action: `${this.baseUrl}${ENDPOINTS.purchase}`,
184
+ hash,
185
+ tran_id: options.transactionId,
186
+ amount,
187
+ items,
188
+ currency,
189
+ firstname: options.firstName ?? "",
190
+ lastname: options.lastName ?? "",
191
+ email: options.email ?? "",
192
+ phone: options.phone ?? "",
193
+ type,
194
+ payment_option: options.paymentOption ?? "",
195
+ return_url: returnUrl,
196
+ cancel_url: options.cancelUrl ?? "",
197
+ continue_success_url: options.continueSuccessUrl ?? "",
198
+ return_deeplink: returnDeeplink,
199
+ return_params: options.returnParams ?? "",
200
+ shipping,
201
+ merchant_id: this.merchantId,
202
+ req_time: reqTime,
203
+ custom_fields: options.customFields ?? "",
204
+ payout,
205
+ lifetime: options.lifetime?.toString() ?? "",
206
+ additional_params: options.additionalParams ?? "",
207
+ google_pay_token: options.googlePayToken ?? "",
208
+ skip_success_page: options.skipSuccessPage?.toString() ?? "",
209
+ view_type: options.viewType ?? "",
210
+ payment_gate: options.paymentGate?.toString() ?? ""
211
+ };
212
+ }
213
+ async checkTransaction(transactionId) {
214
+ const reqTime = formatRequestTime();
215
+ const hashValues = [reqTime, this.merchantId, transactionId];
216
+ const hash = createHash(hashValues, this.apiKey);
217
+ const params = {
218
+ hash,
219
+ tran_id: transactionId,
220
+ req_time: reqTime,
221
+ merchant_id: this.merchantId
222
+ };
223
+ return this.request(
224
+ ENDPOINTS.checkTransaction,
225
+ params
226
+ );
227
+ }
228
+ async listTransactions(options = {}) {
229
+ const reqTime = formatRequestTime();
230
+ const hashValues = [
231
+ reqTime,
232
+ this.merchantId,
233
+ options.fromDate ?? "",
234
+ options.toDate ?? "",
235
+ options.fromAmount?.toString() ?? "",
236
+ options.toAmount?.toString() ?? "",
237
+ options.status ?? "",
238
+ options.page?.toString() ?? "",
239
+ options.pagination?.toString() ?? ""
240
+ ];
241
+ const hash = createHash(hashValues, this.apiKey);
242
+ const params = {
243
+ hash,
244
+ from_date: options.fromDate,
245
+ to_date: options.toDate,
246
+ from_amount: options.fromAmount?.toString(),
247
+ to_amount: options.toAmount?.toString(),
248
+ status: options.status,
249
+ page: options.page?.toString(),
250
+ pagination: options.pagination?.toString(),
251
+ req_time: reqTime,
252
+ merchant_id: this.merchantId
253
+ };
254
+ return this.request(
255
+ ENDPOINTS.transactionList,
256
+ params
257
+ );
258
+ }
259
+ async request(endpoint, params) {
260
+ const url = `${this.baseUrl}${endpoint}`;
261
+ const formData = new FormData();
262
+ for (const [key, value] of Object.entries(params)) {
263
+ if (value !== void 0 && value !== null && value !== "") {
264
+ formData.append(key, value);
265
+ }
266
+ }
267
+ const response = await fetch(url, {
268
+ method: "POST",
269
+ body: formData
270
+ });
271
+ if (!response.ok) {
272
+ const text = await response.text();
273
+ let body = text;
274
+ try {
275
+ body = JSON.parse(text);
276
+ } catch {
277
+ }
278
+ throw new PayWayAPIError(
279
+ `PayWay API error: ${response.status} ${response.statusText}`,
280
+ response.status,
281
+ body
282
+ );
283
+ }
284
+ return await response.json();
285
+ }
286
+ };
287
+ // Annotate the CommonJS export names for ESM import in node:
288
+ 0 && (module.exports = {
289
+ ENDPOINTS,
290
+ PRODUCTION_BASE_URL,
291
+ PayWay,
292
+ PayWayAPIError,
293
+ PayWayConfigError,
294
+ PayWayError,
295
+ PayWayHashError,
296
+ SANDBOX_BASE_URL,
297
+ buildFormData,
298
+ createHash,
299
+ formatAmount,
300
+ formatRequestTime,
301
+ toBase64
302
+ });
303
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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":[]}
@@ -0,0 +1,187 @@
1
+ interface PayWayConfig {
2
+ merchantId: string;
3
+ apiKey: string;
4
+ production?: boolean;
5
+ }
6
+ type PaymentOption = "cards" | "abapay_khqr" | "abapay_khqr_deeplink" | "alipay" | "wechat" | "google_pay";
7
+ type Currency = "USD" | "KHR";
8
+ type TransactionType = "purchase" | "pre-auth";
9
+ type TransactionStatus = "APPROVED" | "DECLINED" | "PENDING" | "PRE-AUTH" | "CANCELLED" | "REFUNDED";
10
+ interface CreateTransactionOptions {
11
+ transactionId: string;
12
+ amount: number;
13
+ currency?: Currency;
14
+ paymentOption?: PaymentOption;
15
+ firstName?: string;
16
+ lastName?: string;
17
+ email?: string;
18
+ phone?: string;
19
+ /** Items as a string, or an array of objects (will be JSON-stringified and base64-encoded) */
20
+ items?: string | ItemEntry[];
21
+ returnUrl?: string;
22
+ cancelUrl?: string;
23
+ continueSuccessUrl?: string;
24
+ returnDeeplink?: string;
25
+ returnParams?: string;
26
+ shipping?: number;
27
+ type?: TransactionType;
28
+ customFields?: string;
29
+ payout?: string;
30
+ lifetime?: number;
31
+ additionalParams?: string;
32
+ googlePayToken?: string;
33
+ skipSuccessPage?: number;
34
+ viewType?: string;
35
+ paymentGate?: number;
36
+ }
37
+ interface ItemEntry {
38
+ name: string;
39
+ quantity: string;
40
+ price: string;
41
+ }
42
+ /** Form parameters returned by createTransaction, to be submitted from the browser */
43
+ interface CheckoutParams {
44
+ action: string;
45
+ hash: string;
46
+ tran_id: string;
47
+ amount: string;
48
+ items: string;
49
+ currency: Currency;
50
+ firstname: string;
51
+ lastname: string;
52
+ email: string;
53
+ phone: string;
54
+ type: TransactionType;
55
+ payment_option: PaymentOption | "";
56
+ return_url: string;
57
+ cancel_url: string;
58
+ continue_success_url: string;
59
+ return_deeplink: string;
60
+ return_params: string;
61
+ shipping: string;
62
+ merchant_id: string;
63
+ req_time: string;
64
+ custom_fields: string;
65
+ payout: string;
66
+ lifetime: string;
67
+ additional_params: string;
68
+ google_pay_token: string;
69
+ skip_success_page: string;
70
+ view_type: string;
71
+ payment_gate: string;
72
+ }
73
+ interface CheckTransactionOptions {
74
+ transactionId: string;
75
+ }
76
+ interface ListTransactionsOptions {
77
+ fromDate?: string;
78
+ toDate?: string;
79
+ fromAmount?: number;
80
+ toAmount?: number;
81
+ status?: string;
82
+ page?: number;
83
+ pagination?: number;
84
+ }
85
+ interface PayWayResponse<T> {
86
+ status: PayWayResponseStatus;
87
+ description?: string;
88
+ data?: T;
89
+ }
90
+ interface PayWayResponseStatus {
91
+ code: string;
92
+ message?: string;
93
+ tran_id?: string;
94
+ }
95
+ interface CheckTransactionData {
96
+ payment_status_code: number;
97
+ total_amount: number;
98
+ original_amount: number;
99
+ refund_amount: number;
100
+ discount_amount: number;
101
+ payment_amount: number;
102
+ payment_currency: string;
103
+ apv: string;
104
+ payment_status: string;
105
+ transaction_date: string;
106
+ }
107
+ interface TransactionListItem {
108
+ transaction_id: string;
109
+ transaction_date: string;
110
+ apv: string;
111
+ payment_status: string;
112
+ payment_status_code: number;
113
+ original_amount: number;
114
+ original_currency: string;
115
+ total_amount: number;
116
+ discount_amount: number;
117
+ refund_amount: number;
118
+ payment_amount: number;
119
+ payment_currency: string;
120
+ first_name: string;
121
+ last_name: string;
122
+ email: string;
123
+ phone: string;
124
+ bank_ref: string;
125
+ payer_account: string;
126
+ bank_name: string;
127
+ card_source: string;
128
+ payment_type: string;
129
+ }
130
+ interface ListTransactionsData {
131
+ data: TransactionListItem[];
132
+ page: string;
133
+ pagination: string;
134
+ }
135
+ interface ListTransactionsResponse {
136
+ data: TransactionListItem[];
137
+ page: string;
138
+ pagination: string;
139
+ status: PayWayResponseStatus;
140
+ }
141
+
142
+ declare class PayWay {
143
+ private readonly merchantId;
144
+ private readonly apiKey;
145
+ private readonly baseUrl;
146
+ constructor(config: PayWayConfig);
147
+ /**
148
+ * Generate checkout parameters for a transaction.
149
+ * Returns form params to be submitted from the browser via ABA's checkout JS SDK.
150
+ */
151
+ createTransaction(options: CreateTransactionOptions): CheckoutParams;
152
+ checkTransaction(transactionId: string): Promise<PayWayResponse<CheckTransactionData>>;
153
+ listTransactions(options?: ListTransactionsOptions): Promise<ListTransactionsResponse>;
154
+ private request;
155
+ }
156
+
157
+ declare const SANDBOX_BASE_URL = "https://checkout-sandbox.payway.com.kh";
158
+ declare const PRODUCTION_BASE_URL = "https://checkout.payway.com.kh";
159
+ declare const ENDPOINTS: {
160
+ readonly purchase: "/api/payment-gateway/v1/payments/purchase";
161
+ readonly checkTransaction: "/api/payment-gateway/v1/payments/check-transaction-2";
162
+ readonly transactionList: "/api/payment-gateway/v1/payments/transaction-list-2";
163
+ };
164
+
165
+ declare class PayWayError extends Error {
166
+ constructor(message: string);
167
+ }
168
+ declare class PayWayAPIError extends PayWayError {
169
+ readonly statusCode: number;
170
+ readonly responseBody: unknown;
171
+ constructor(message: string, statusCode: number, responseBody?: unknown);
172
+ }
173
+ declare class PayWayConfigError extends PayWayError {
174
+ constructor(message: string);
175
+ }
176
+ declare class PayWayHashError extends PayWayError {
177
+ constructor(message: string);
178
+ }
179
+
180
+ declare function createHash(values: string[], apiKey: string): string;
181
+
182
+ declare function formatRequestTime(date?: Date): string;
183
+ declare function buildFormData(params: Record<string, string | undefined>): FormData;
184
+ declare function formatAmount(amount: number, currency?: string): string;
185
+ declare function toBase64(value: string): string;
186
+
187
+ export { type CheckTransactionData, type CheckTransactionOptions, type CheckoutParams, type CreateTransactionOptions, type Currency, ENDPOINTS, type ItemEntry, type ListTransactionsData, type ListTransactionsOptions, type ListTransactionsResponse, PRODUCTION_BASE_URL, PayWay, PayWayAPIError, type PayWayConfig, PayWayConfigError, PayWayError, PayWayHashError, type PayWayResponse, type PayWayResponseStatus, type PaymentOption, SANDBOX_BASE_URL, type TransactionListItem, type TransactionStatus, type TransactionType, buildFormData, createHash, formatAmount, formatRequestTime, toBase64 };
@@ -0,0 +1,187 @@
1
+ interface PayWayConfig {
2
+ merchantId: string;
3
+ apiKey: string;
4
+ production?: boolean;
5
+ }
6
+ type PaymentOption = "cards" | "abapay_khqr" | "abapay_khqr_deeplink" | "alipay" | "wechat" | "google_pay";
7
+ type Currency = "USD" | "KHR";
8
+ type TransactionType = "purchase" | "pre-auth";
9
+ type TransactionStatus = "APPROVED" | "DECLINED" | "PENDING" | "PRE-AUTH" | "CANCELLED" | "REFUNDED";
10
+ interface CreateTransactionOptions {
11
+ transactionId: string;
12
+ amount: number;
13
+ currency?: Currency;
14
+ paymentOption?: PaymentOption;
15
+ firstName?: string;
16
+ lastName?: string;
17
+ email?: string;
18
+ phone?: string;
19
+ /** Items as a string, or an array of objects (will be JSON-stringified and base64-encoded) */
20
+ items?: string | ItemEntry[];
21
+ returnUrl?: string;
22
+ cancelUrl?: string;
23
+ continueSuccessUrl?: string;
24
+ returnDeeplink?: string;
25
+ returnParams?: string;
26
+ shipping?: number;
27
+ type?: TransactionType;
28
+ customFields?: string;
29
+ payout?: string;
30
+ lifetime?: number;
31
+ additionalParams?: string;
32
+ googlePayToken?: string;
33
+ skipSuccessPage?: number;
34
+ viewType?: string;
35
+ paymentGate?: number;
36
+ }
37
+ interface ItemEntry {
38
+ name: string;
39
+ quantity: string;
40
+ price: string;
41
+ }
42
+ /** Form parameters returned by createTransaction, to be submitted from the browser */
43
+ interface CheckoutParams {
44
+ action: string;
45
+ hash: string;
46
+ tran_id: string;
47
+ amount: string;
48
+ items: string;
49
+ currency: Currency;
50
+ firstname: string;
51
+ lastname: string;
52
+ email: string;
53
+ phone: string;
54
+ type: TransactionType;
55
+ payment_option: PaymentOption | "";
56
+ return_url: string;
57
+ cancel_url: string;
58
+ continue_success_url: string;
59
+ return_deeplink: string;
60
+ return_params: string;
61
+ shipping: string;
62
+ merchant_id: string;
63
+ req_time: string;
64
+ custom_fields: string;
65
+ payout: string;
66
+ lifetime: string;
67
+ additional_params: string;
68
+ google_pay_token: string;
69
+ skip_success_page: string;
70
+ view_type: string;
71
+ payment_gate: string;
72
+ }
73
+ interface CheckTransactionOptions {
74
+ transactionId: string;
75
+ }
76
+ interface ListTransactionsOptions {
77
+ fromDate?: string;
78
+ toDate?: string;
79
+ fromAmount?: number;
80
+ toAmount?: number;
81
+ status?: string;
82
+ page?: number;
83
+ pagination?: number;
84
+ }
85
+ interface PayWayResponse<T> {
86
+ status: PayWayResponseStatus;
87
+ description?: string;
88
+ data?: T;
89
+ }
90
+ interface PayWayResponseStatus {
91
+ code: string;
92
+ message?: string;
93
+ tran_id?: string;
94
+ }
95
+ interface CheckTransactionData {
96
+ payment_status_code: number;
97
+ total_amount: number;
98
+ original_amount: number;
99
+ refund_amount: number;
100
+ discount_amount: number;
101
+ payment_amount: number;
102
+ payment_currency: string;
103
+ apv: string;
104
+ payment_status: string;
105
+ transaction_date: string;
106
+ }
107
+ interface TransactionListItem {
108
+ transaction_id: string;
109
+ transaction_date: string;
110
+ apv: string;
111
+ payment_status: string;
112
+ payment_status_code: number;
113
+ original_amount: number;
114
+ original_currency: string;
115
+ total_amount: number;
116
+ discount_amount: number;
117
+ refund_amount: number;
118
+ payment_amount: number;
119
+ payment_currency: string;
120
+ first_name: string;
121
+ last_name: string;
122
+ email: string;
123
+ phone: string;
124
+ bank_ref: string;
125
+ payer_account: string;
126
+ bank_name: string;
127
+ card_source: string;
128
+ payment_type: string;
129
+ }
130
+ interface ListTransactionsData {
131
+ data: TransactionListItem[];
132
+ page: string;
133
+ pagination: string;
134
+ }
135
+ interface ListTransactionsResponse {
136
+ data: TransactionListItem[];
137
+ page: string;
138
+ pagination: string;
139
+ status: PayWayResponseStatus;
140
+ }
141
+
142
+ declare class PayWay {
143
+ private readonly merchantId;
144
+ private readonly apiKey;
145
+ private readonly baseUrl;
146
+ constructor(config: PayWayConfig);
147
+ /**
148
+ * Generate checkout parameters for a transaction.
149
+ * Returns form params to be submitted from the browser via ABA's checkout JS SDK.
150
+ */
151
+ createTransaction(options: CreateTransactionOptions): CheckoutParams;
152
+ checkTransaction(transactionId: string): Promise<PayWayResponse<CheckTransactionData>>;
153
+ listTransactions(options?: ListTransactionsOptions): Promise<ListTransactionsResponse>;
154
+ private request;
155
+ }
156
+
157
+ declare const SANDBOX_BASE_URL = "https://checkout-sandbox.payway.com.kh";
158
+ declare const PRODUCTION_BASE_URL = "https://checkout.payway.com.kh";
159
+ declare const ENDPOINTS: {
160
+ readonly purchase: "/api/payment-gateway/v1/payments/purchase";
161
+ readonly checkTransaction: "/api/payment-gateway/v1/payments/check-transaction-2";
162
+ readonly transactionList: "/api/payment-gateway/v1/payments/transaction-list-2";
163
+ };
164
+
165
+ declare class PayWayError extends Error {
166
+ constructor(message: string);
167
+ }
168
+ declare class PayWayAPIError extends PayWayError {
169
+ readonly statusCode: number;
170
+ readonly responseBody: unknown;
171
+ constructor(message: string, statusCode: number, responseBody?: unknown);
172
+ }
173
+ declare class PayWayConfigError extends PayWayError {
174
+ constructor(message: string);
175
+ }
176
+ declare class PayWayHashError extends PayWayError {
177
+ constructor(message: string);
178
+ }
179
+
180
+ declare function createHash(values: string[], apiKey: string): string;
181
+
182
+ declare function formatRequestTime(date?: Date): string;
183
+ declare function buildFormData(params: Record<string, string | undefined>): FormData;
184
+ declare function formatAmount(amount: number, currency?: string): string;
185
+ declare function toBase64(value: string): string;
186
+
187
+ export { type CheckTransactionData, type CheckTransactionOptions, type CheckoutParams, type CreateTransactionOptions, type Currency, ENDPOINTS, type ItemEntry, type ListTransactionsData, type ListTransactionsOptions, type ListTransactionsResponse, PRODUCTION_BASE_URL, PayWay, PayWayAPIError, type PayWayConfig, PayWayConfigError, PayWayError, PayWayHashError, type PayWayResponse, type PayWayResponseStatus, type PaymentOption, SANDBOX_BASE_URL, type TransactionListItem, type TransactionStatus, type TransactionType, buildFormData, createHash, formatAmount, formatRequestTime, toBase64 };
package/dist/index.js ADDED
@@ -0,0 +1,264 @@
1
+ // src/constants.ts
2
+ var SANDBOX_BASE_URL = "https://checkout-sandbox.payway.com.kh";
3
+ var PRODUCTION_BASE_URL = "https://checkout.payway.com.kh";
4
+ var ENDPOINTS = {
5
+ purchase: "/api/payment-gateway/v1/payments/purchase",
6
+ checkTransaction: "/api/payment-gateway/v1/payments/check-transaction-2",
7
+ transactionList: "/api/payment-gateway/v1/payments/transaction-list-2"
8
+ };
9
+
10
+ // src/errors.ts
11
+ var PayWayError = class extends Error {
12
+ constructor(message) {
13
+ super(message);
14
+ this.name = "PayWayError";
15
+ }
16
+ };
17
+ var PayWayAPIError = class extends PayWayError {
18
+ statusCode;
19
+ responseBody;
20
+ constructor(message, statusCode, responseBody) {
21
+ super(message);
22
+ this.name = "PayWayAPIError";
23
+ this.statusCode = statusCode;
24
+ this.responseBody = responseBody;
25
+ }
26
+ };
27
+ var PayWayConfigError = class extends PayWayError {
28
+ constructor(message) {
29
+ super(message);
30
+ this.name = "PayWayConfigError";
31
+ }
32
+ };
33
+ var PayWayHashError = class extends PayWayError {
34
+ constructor(message) {
35
+ super(message);
36
+ this.name = "PayWayHashError";
37
+ }
38
+ };
39
+
40
+ // src/hash.ts
41
+ import { createHmac } from "crypto";
42
+ function createHash(values, apiKey) {
43
+ const message = values.join("");
44
+ const hmac = createHmac("sha512", apiKey);
45
+ hmac.update(message);
46
+ return hmac.digest("base64");
47
+ }
48
+
49
+ // src/utils.ts
50
+ function formatRequestTime(date = /* @__PURE__ */ new Date()) {
51
+ const year = date.getUTCFullYear().toString();
52
+ const month = (date.getUTCMonth() + 1).toString().padStart(2, "0");
53
+ const day = date.getUTCDate().toString().padStart(2, "0");
54
+ const hours = date.getUTCHours().toString().padStart(2, "0");
55
+ const minutes = date.getUTCMinutes().toString().padStart(2, "0");
56
+ const seconds = date.getUTCSeconds().toString().padStart(2, "0");
57
+ return `${year}${month}${day}${hours}${minutes}${seconds}`;
58
+ }
59
+ function buildFormData(params) {
60
+ const formData = new FormData();
61
+ for (const [key, value] of Object.entries(params)) {
62
+ if (value !== void 0 && value !== null && value !== "") {
63
+ formData.append(key, value);
64
+ }
65
+ }
66
+ return formData;
67
+ }
68
+ function formatAmount(amount, currency = "USD") {
69
+ if (currency.toUpperCase() === "KHR") {
70
+ return Math.round(amount).toString();
71
+ }
72
+ return amount.toFixed(2);
73
+ }
74
+ function toBase64(value) {
75
+ return Buffer.from(value).toString("base64");
76
+ }
77
+
78
+ // src/client.ts
79
+ var PayWay = class {
80
+ merchantId;
81
+ apiKey;
82
+ baseUrl;
83
+ constructor(config) {
84
+ if (!config.merchantId) {
85
+ throw new PayWayConfigError("merchantId is required");
86
+ }
87
+ if (!config.apiKey) {
88
+ throw new PayWayConfigError("apiKey is required");
89
+ }
90
+ this.merchantId = config.merchantId;
91
+ this.apiKey = config.apiKey;
92
+ this.baseUrl = config.production ? PRODUCTION_BASE_URL : SANDBOX_BASE_URL;
93
+ }
94
+ /**
95
+ * Generate checkout parameters for a transaction.
96
+ * Returns form params to be submitted from the browser via ABA's checkout JS SDK.
97
+ */
98
+ createTransaction(options) {
99
+ const reqTime = formatRequestTime();
100
+ const currency = options.currency ?? "USD";
101
+ const amount = formatAmount(options.amount, currency);
102
+ const type = options.type ?? "purchase";
103
+ let items;
104
+ if (Array.isArray(options.items)) {
105
+ items = toBase64(JSON.stringify(options.items));
106
+ } else if (options.items) {
107
+ items = toBase64(options.items);
108
+ } else {
109
+ items = "";
110
+ }
111
+ const returnUrl = options.returnUrl ? toBase64(options.returnUrl) : "";
112
+ const returnDeeplink = options.returnDeeplink ? toBase64(options.returnDeeplink) : "";
113
+ const payout = options.payout ? toBase64(options.payout) : "";
114
+ const shipping = options.shipping !== void 0 ? formatAmount(options.shipping, currency) : "";
115
+ const hashValues = [
116
+ reqTime,
117
+ this.merchantId,
118
+ options.transactionId,
119
+ amount,
120
+ items,
121
+ shipping,
122
+ options.firstName ?? "",
123
+ options.lastName ?? "",
124
+ options.email ?? "",
125
+ options.phone ?? "",
126
+ type,
127
+ options.paymentOption ?? "",
128
+ returnUrl,
129
+ options.cancelUrl ?? "",
130
+ options.continueSuccessUrl ?? "",
131
+ returnDeeplink,
132
+ currency,
133
+ options.customFields ?? "",
134
+ options.returnParams ?? "",
135
+ options.viewType ?? "",
136
+ options.paymentGate?.toString() ?? "",
137
+ payout,
138
+ options.lifetime?.toString() ?? "",
139
+ options.additionalParams ?? "",
140
+ options.googlePayToken ?? "",
141
+ options.skipSuccessPage?.toString() ?? ""
142
+ ];
143
+ const hash = createHash(hashValues, this.apiKey);
144
+ return {
145
+ action: `${this.baseUrl}${ENDPOINTS.purchase}`,
146
+ hash,
147
+ tran_id: options.transactionId,
148
+ amount,
149
+ items,
150
+ currency,
151
+ firstname: options.firstName ?? "",
152
+ lastname: options.lastName ?? "",
153
+ email: options.email ?? "",
154
+ phone: options.phone ?? "",
155
+ type,
156
+ payment_option: options.paymentOption ?? "",
157
+ return_url: returnUrl,
158
+ cancel_url: options.cancelUrl ?? "",
159
+ continue_success_url: options.continueSuccessUrl ?? "",
160
+ return_deeplink: returnDeeplink,
161
+ return_params: options.returnParams ?? "",
162
+ shipping,
163
+ merchant_id: this.merchantId,
164
+ req_time: reqTime,
165
+ custom_fields: options.customFields ?? "",
166
+ payout,
167
+ lifetime: options.lifetime?.toString() ?? "",
168
+ additional_params: options.additionalParams ?? "",
169
+ google_pay_token: options.googlePayToken ?? "",
170
+ skip_success_page: options.skipSuccessPage?.toString() ?? "",
171
+ view_type: options.viewType ?? "",
172
+ payment_gate: options.paymentGate?.toString() ?? ""
173
+ };
174
+ }
175
+ async checkTransaction(transactionId) {
176
+ const reqTime = formatRequestTime();
177
+ const hashValues = [reqTime, this.merchantId, transactionId];
178
+ const hash = createHash(hashValues, this.apiKey);
179
+ const params = {
180
+ hash,
181
+ tran_id: transactionId,
182
+ req_time: reqTime,
183
+ merchant_id: this.merchantId
184
+ };
185
+ return this.request(
186
+ ENDPOINTS.checkTransaction,
187
+ params
188
+ );
189
+ }
190
+ async listTransactions(options = {}) {
191
+ const reqTime = formatRequestTime();
192
+ const hashValues = [
193
+ reqTime,
194
+ this.merchantId,
195
+ options.fromDate ?? "",
196
+ options.toDate ?? "",
197
+ options.fromAmount?.toString() ?? "",
198
+ options.toAmount?.toString() ?? "",
199
+ options.status ?? "",
200
+ options.page?.toString() ?? "",
201
+ options.pagination?.toString() ?? ""
202
+ ];
203
+ const hash = createHash(hashValues, this.apiKey);
204
+ const params = {
205
+ hash,
206
+ from_date: options.fromDate,
207
+ to_date: options.toDate,
208
+ from_amount: options.fromAmount?.toString(),
209
+ to_amount: options.toAmount?.toString(),
210
+ status: options.status,
211
+ page: options.page?.toString(),
212
+ pagination: options.pagination?.toString(),
213
+ req_time: reqTime,
214
+ merchant_id: this.merchantId
215
+ };
216
+ return this.request(
217
+ ENDPOINTS.transactionList,
218
+ params
219
+ );
220
+ }
221
+ async request(endpoint, params) {
222
+ const url = `${this.baseUrl}${endpoint}`;
223
+ const formData = new FormData();
224
+ for (const [key, value] of Object.entries(params)) {
225
+ if (value !== void 0 && value !== null && value !== "") {
226
+ formData.append(key, value);
227
+ }
228
+ }
229
+ const response = await fetch(url, {
230
+ method: "POST",
231
+ body: formData
232
+ });
233
+ if (!response.ok) {
234
+ const text = await response.text();
235
+ let body = text;
236
+ try {
237
+ body = JSON.parse(text);
238
+ } catch {
239
+ }
240
+ throw new PayWayAPIError(
241
+ `PayWay API error: ${response.status} ${response.statusText}`,
242
+ response.status,
243
+ body
244
+ );
245
+ }
246
+ return await response.json();
247
+ }
248
+ };
249
+ export {
250
+ ENDPOINTS,
251
+ PRODUCTION_BASE_URL,
252
+ PayWay,
253
+ PayWayAPIError,
254
+ PayWayConfigError,
255
+ PayWayError,
256
+ PayWayHashError,
257
+ SANDBOX_BASE_URL,
258
+ buildFormData,
259
+ createHash,
260
+ formatAmount,
261
+ formatRequestTime,
262
+ toBase64
263
+ };
264
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants.ts","../src/errors.ts","../src/hash.ts","../src/utils.ts","../src/client.ts"],"sourcesContent":["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":[]}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "aba-payway",
3
+ "version": "0.1.0",
4
+ "description": "Type-safe TypeScript SDK for ABA PayWay — Cambodia's #1 payment gateway",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "test": "vitest run",
27
+ "test:watch": "vitest",
28
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
29
+ "lint": "biome check .",
30
+ "lint:fix": "biome check --write .",
31
+ "prepublishOnly": "bun run build"
32
+ },
33
+ "keywords": [
34
+ "aba",
35
+ "payway",
36
+ "cambodia",
37
+ "payment",
38
+ "payment-gateway",
39
+ "typescript",
40
+ "sdk"
41
+ ],
42
+ "license": "MIT",
43
+ "author": "Joselay",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/Joselay/aba-payway.git"
47
+ },
48
+ "homepage": "https://github.com/Joselay/aba-payway#readme",
49
+ "bugs": {
50
+ "url": "https://github.com/Joselay/aba-payway/issues"
51
+ },
52
+ "devDependencies": {
53
+ "@biomejs/biome": "^2.4.4",
54
+ "@types/bun": "latest",
55
+ "tsup": "^8.5.1",
56
+ "typescript": "^5.9.3",
57
+ "vitest": "^4.0.18"
58
+ }
59
+ }