@rikology/adonisjs-xendit 1.0.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/CHANGELOG.md +29 -0
- package/LICENSE.md +9 -0
- package/README.md +537 -0
- package/build/configure.d.ts +6 -0
- package/build/configure.js +45 -0
- package/build/index.d.ts +16 -0
- package/build/index.js +70 -0
- package/build/providers/xendit_provider.d.ts +12 -0
- package/build/providers/xendit_provider.js +19 -0
- package/build/src/clients/balance_client.d.ts +8 -0
- package/build/src/clients/credit_card_client.d.ts +10 -0
- package/build/src/clients/direct_debit_client.d.ts +10 -0
- package/build/src/clients/disbursement_client.d.ts +10 -0
- package/build/src/clients/ewallet_client.d.ts +11 -0
- package/build/src/clients/invoice_client.d.ts +12 -0
- package/build/src/clients/qris_client.d.ts +9 -0
- package/build/src/clients/retail_outlet_client.d.ts +9 -0
- package/build/src/clients/va_client.d.ts +10 -0
- package/build/src/define_config.d.ts +21 -0
- package/build/src/http_client.d.ts +15 -0
- package/build/src/types.d.ts +609 -0
- package/build/src/types.js +1 -0
- package/build/src/webhook.d.ts +5 -0
- package/build/src/xendit_exception.d.ts +37 -0
- package/build/src/xendit_exception.js +2 -0
- package/build/src/xendit_manager.d.ts +23 -0
- package/build/stubs/config/xendit.stub +12 -0
- package/build/stubs/main.d.ts +5 -0
- package/build/xendit_exception-kaFnYOo7.js +81 -0
- package/build/xendit_manager-DOa0yE8A.js +332 -0
- package/package.json +188 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2025-01-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Initial stable release
|
|
13
|
+
- **9 Payment Products**: Invoice, Virtual Account, E-Wallet, QRIS, Retail Outlet, Credit Card, Direct Debit, Disbursement, Balance
|
|
14
|
+
- **Type-safe API**: Full TypeScript types for all request/response shapes
|
|
15
|
+
- **IoC Container Integration**: `xendit.manager` singleton registered via provider
|
|
16
|
+
- **Webhook Helpers**: Built-in webhook payload parsing with callback token verification
|
|
17
|
+
- **Configurable**: `node ace configure` prompts for API key and generates config
|
|
18
|
+
- **Error Handling**: Custom `XenditException` with structured error responses
|
|
19
|
+
- **Idempotency Support**: Optional idempotency keys for safe retries
|
|
20
|
+
- **Retry Logic**: Automatic retry with exponential backoff for failed requests
|
|
21
|
+
- **Comprehensive Tests**: 100+ test cases with >80% code coverage
|
|
22
|
+
|
|
23
|
+
### Security
|
|
24
|
+
|
|
25
|
+
- HMAC-SHA256 webhook signature verification with timing-safe comparison
|
|
26
|
+
- Secure API key handling through environment variables
|
|
27
|
+
- No sensitive data logging
|
|
28
|
+
|
|
29
|
+
[1.0.0]: https://github.com/rikoriswandha/adonisjs-xendit/releases/tag/v1.0.0
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Riko Riswandha <rikoriswandha@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
# @rikology/adonisjs-xendit
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@rikology/adonisjs-xendit)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
[](https://adonisjs.com/)
|
|
7
|
+
|
|
8
|
+
AdonisJS v7 package for [Xendit](https://www.xendit.co/) payment gateway integration. Provides a typed, idiomatic wrapper around Xendit's API with support for invoices, virtual accounts, e-wallets, QRIS, retail outlets, credit cards, direct debit, disbursements, and balance queries.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **9 Payment Products** — Invoice, Virtual Account, E-Wallet, QRIS, Retail Outlet, Credit Card, Direct Debit, Disbursement, Balance
|
|
13
|
+
- **Type-safe** — Full TypeScript types for all request/response shapes
|
|
14
|
+
- **IoC Container Integration** — `xendit.manager` singleton registered via provider
|
|
15
|
+
- **Webhook Helpers** — Built-in webhook payload parsing with callback token verification
|
|
16
|
+
- **Configurable** — `node ace configure` prompts for API key and generates config
|
|
17
|
+
- **Error Handling** — Custom `XenditException` with structured error responses
|
|
18
|
+
- **Idempotency Support** — Optional idempotency keys for safe retries
|
|
19
|
+
- **Production Ready** — Comprehensive test suite with >80% coverage
|
|
20
|
+
- **Retry Logic** — Automatic retry with exponential backoff for failed requests
|
|
21
|
+
|
|
22
|
+
## Table of Contents
|
|
23
|
+
|
|
24
|
+
- [Installation](#installation)
|
|
25
|
+
- [Configuration](#configuration)
|
|
26
|
+
- [Usage](#usage)
|
|
27
|
+
- [Invoice](#invoice)
|
|
28
|
+
- [Virtual Account](#virtual-account)
|
|
29
|
+
- [E-Wallet](#e-wallet)
|
|
30
|
+
- [QRIS](#qris)
|
|
31
|
+
- [Retail Outlet](#retail-outlet)
|
|
32
|
+
- [Credit Card](#credit-card)
|
|
33
|
+
- [Direct Debit](#direct-debit)
|
|
34
|
+
- [Disbursement](#disbursement)
|
|
35
|
+
- [Balance](#balance)
|
|
36
|
+
- [Webhook Handling](#webhook-handling)
|
|
37
|
+
- [Error Handling](#error-handling)
|
|
38
|
+
- [Exported Types](#exported-types)
|
|
39
|
+
- [Requirements](#requirements)
|
|
40
|
+
- [Changelog](#changelog)
|
|
41
|
+
- [Contributing](#contributing)
|
|
42
|
+
- [Security](#security)
|
|
43
|
+
- [Support](#support)
|
|
44
|
+
- [License](#license)
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
npm install @rikology/adonisjs-xendit
|
|
50
|
+
# or
|
|
51
|
+
yarn add @rikology/adonisjs-xendit
|
|
52
|
+
# or
|
|
53
|
+
pnpm add @rikology/adonisjs-xendit
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then configure the package:
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
node ace configure @rikology/adonisjs-xendit
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The configure command will:
|
|
63
|
+
- Prompt for your Xendit secret key
|
|
64
|
+
- Generate `config/xendit.ts`
|
|
65
|
+
- Add `XENDIT_SECRET_KEY`, `XENDIT_ENVIRONMENT`, and `XENDIT_CALLBACK_TOKEN` to `.env`
|
|
66
|
+
- Register the provider in `adonisrc.ts`
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
// config/xendit.ts
|
|
72
|
+
import { defineConfig } from '@rikology/adonisjs-xendit'
|
|
73
|
+
import env from '#start/env'
|
|
74
|
+
|
|
75
|
+
export default defineConfig({
|
|
76
|
+
secretKey: env.get('XENDIT_SECRET_KEY'),
|
|
77
|
+
environment: env.get('XENDIT_ENVIRONMENT', 'sandbox'),
|
|
78
|
+
callbackToken: env.get('XENDIT_CALLBACK_TOKEN'),
|
|
79
|
+
timeoutMs: 30_000,
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
| Option | Required | Description |
|
|
84
|
+
|--------|----------|-------------|
|
|
85
|
+
| `secretKey` | Yes | Your Xendit API secret key |
|
|
86
|
+
| `environment` | Yes | `sandbox` or `production` |
|
|
87
|
+
| `callbackToken` | No | Token for webhook callback verification |
|
|
88
|
+
| `timeoutMs` | No | HTTP request timeout (default: 30000ms) |
|
|
89
|
+
|
|
90
|
+
## Usage
|
|
91
|
+
|
|
92
|
+
### Via IoC Container
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { inject } from '@adonisjs/core'
|
|
96
|
+
import type { XenditManager } from '@rikology/adonisjs-xendit'
|
|
97
|
+
|
|
98
|
+
@inject()
|
|
99
|
+
export default class PaymentsController {
|
|
100
|
+
constructor(private xendit: XenditManager) {}
|
|
101
|
+
|
|
102
|
+
async createInvoice() {
|
|
103
|
+
const invoice = await this.xendit.invoice().create({
|
|
104
|
+
external_id: 'order-123',
|
|
105
|
+
amount: 50000,
|
|
106
|
+
description: 'Test invoice',
|
|
107
|
+
invoice_duration: 86400,
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
return invoice
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Available Clients
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const manager = new XenditManager(config)
|
|
119
|
+
|
|
120
|
+
manager.invoice() // InvoiceClient
|
|
121
|
+
manager.va() // VirtualAccountClient
|
|
122
|
+
manager.ewallet() // EWalletClient
|
|
123
|
+
manager.qris() // QrisClient
|
|
124
|
+
manager.retailOutlet() // RetailOutletClient
|
|
125
|
+
manager.creditCard() // CreditCardClient
|
|
126
|
+
manager.directDebit() // DirectDebitClient
|
|
127
|
+
manager.disbursement() // DisbursementClient
|
|
128
|
+
manager.balance() // BalanceClient
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Invoice
|
|
132
|
+
|
|
133
|
+
Create and manage invoices for one-time payments.
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
// Create an invoice
|
|
137
|
+
const invoice = await xendit.invoice().create({
|
|
138
|
+
external_id: 'order-123',
|
|
139
|
+
amount: 50000,
|
|
140
|
+
description: 'Test invoice',
|
|
141
|
+
invoice_duration: 86400,
|
|
142
|
+
payer_email: 'customer@example.com',
|
|
143
|
+
customer: {
|
|
144
|
+
given_names: 'John',
|
|
145
|
+
surname: 'Doe',
|
|
146
|
+
email: 'john@example.com',
|
|
147
|
+
mobile_number: '+6281234567890',
|
|
148
|
+
},
|
|
149
|
+
items: [
|
|
150
|
+
{ name: 'Product A', quantity: 1, price: 50000 },
|
|
151
|
+
],
|
|
152
|
+
success_redirect_url: 'https://example.com/success',
|
|
153
|
+
failure_redirect_url: 'https://example.com/failure',
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// Get invoice by ID
|
|
157
|
+
const invoice = await xendit.invoice().getById('inv_123')
|
|
158
|
+
|
|
159
|
+
// List invoices with filters
|
|
160
|
+
const invoices = await xendit.invoice().list({
|
|
161
|
+
status: 'PAID',
|
|
162
|
+
limit: 10,
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
// Expire an invoice
|
|
166
|
+
const expired = await xendit.invoice().expire('inv_123')
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Virtual Account
|
|
170
|
+
|
|
171
|
+
Create virtual accounts for bank transfers.
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
// Create a virtual account
|
|
175
|
+
const va = await xendit.va().create({
|
|
176
|
+
external_id: 'va-123',
|
|
177
|
+
bank_code: 'BCA',
|
|
178
|
+
name: 'John Doe',
|
|
179
|
+
is_closed: true,
|
|
180
|
+
expected_amount: 100000,
|
|
181
|
+
is_single_use: true,
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
// Get VA by ID
|
|
185
|
+
const va = await xendit.va().getById('va_123')
|
|
186
|
+
|
|
187
|
+
// Update VA
|
|
188
|
+
const updated = await xendit.va().update('va_123', {
|
|
189
|
+
name: 'Jane Doe',
|
|
190
|
+
expected_amount: 150000,
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
// Get VA payments
|
|
194
|
+
const payments = await xendit.va().getPayment('va_123')
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Supported banks: `BCA`, `BNI`, `BRI`, `MANDIRI`, `PERMATA`, `CIMB`, `BSI`, and more.
|
|
198
|
+
|
|
199
|
+
### E-Wallet
|
|
200
|
+
|
|
201
|
+
Process payments through popular e-wallets.
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
// Create OVO payment
|
|
205
|
+
const charge = await xendit.ewallet().createOvo({
|
|
206
|
+
reference_id: 'order-123',
|
|
207
|
+
currency: 'IDR',
|
|
208
|
+
amount: 50000,
|
|
209
|
+
channel_code: 'ID_OVO',
|
|
210
|
+
channel_properties: {
|
|
211
|
+
mobile_number: '+6281234567890',
|
|
212
|
+
},
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
// Create DANA payment
|
|
216
|
+
const charge = await xendit.ewallet().createDana({
|
|
217
|
+
reference_id: 'order-124',
|
|
218
|
+
currency: 'IDR',
|
|
219
|
+
amount: 75000,
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
// Create LinkAja payment
|
|
223
|
+
const charge = await xendit.ewallet().createLinkAja({
|
|
224
|
+
reference_id: 'order-125',
|
|
225
|
+
currency: 'IDR',
|
|
226
|
+
amount: 100000,
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
// Create ShopeePay payment
|
|
230
|
+
const charge = await xendit.ewallet().createShopeepay({
|
|
231
|
+
reference_id: 'order-126',
|
|
232
|
+
currency: 'IDR',
|
|
233
|
+
amount: 25000,
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
// Check payment status
|
|
237
|
+
const status = await xendit.ewallet().getStatus('ewc_123')
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### QRIS
|
|
241
|
+
|
|
242
|
+
Generate QR codes for QRIS payments.
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
// Create dynamic QR code
|
|
246
|
+
const qr = await xendit.qris().create({
|
|
247
|
+
external_id: 'order-123',
|
|
248
|
+
type: 'DYNAMIC',
|
|
249
|
+
amount: 50000,
|
|
250
|
+
currency: 'IDR',
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
// Create static QR code
|
|
254
|
+
const qr = await xendit.qris().create({
|
|
255
|
+
external_id: 'store-123',
|
|
256
|
+
type: 'STATIC',
|
|
257
|
+
currency: 'IDR',
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
// Get QR code by ID
|
|
261
|
+
const qr = await xendit.qris().getById('qr_123')
|
|
262
|
+
|
|
263
|
+
// Simulate payment (sandbox only)
|
|
264
|
+
const payment = await xendit.qris().simulate('qr_123', { amount: 50000 })
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Retail Outlet
|
|
268
|
+
|
|
269
|
+
Create payments through retail outlets like Alfamart and Indomaret.
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
// Create retail outlet payment
|
|
273
|
+
const payment = await xendit.retailOutlet().create({
|
|
274
|
+
external_id: 'order-123',
|
|
275
|
+
retail_outlet_name: 'ALFAMART',
|
|
276
|
+
name: 'John Doe',
|
|
277
|
+
expected_amount: 50000,
|
|
278
|
+
is_single_use: true,
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
// Get payment by ID
|
|
282
|
+
const payment = await xendit.retailOutlet().getById('ro_123')
|
|
283
|
+
|
|
284
|
+
// Update payment
|
|
285
|
+
const updated = await xendit.retailOutlet().update('ro_123', {
|
|
286
|
+
name: 'Jane Doe',
|
|
287
|
+
expected_amount: 75000,
|
|
288
|
+
})
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Supported outlets: `ALFAMART`, `ALFAMIDI`, `INDOMARET`, and more.
|
|
292
|
+
|
|
293
|
+
### Credit Card
|
|
294
|
+
|
|
295
|
+
Process credit card payments.
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
// Create authorization
|
|
299
|
+
const auth = await xendit.creditCard().createAuthorization({
|
|
300
|
+
token_id: 'token_123',
|
|
301
|
+
external_id: 'order-123',
|
|
302
|
+
amount: 100000,
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
// Create charge
|
|
306
|
+
const charge = await xendit.creditCard().createCharge({
|
|
307
|
+
token_id: 'token_123',
|
|
308
|
+
external_id: 'order-123',
|
|
309
|
+
amount: 100000,
|
|
310
|
+
capture: true,
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
// Create refund
|
|
314
|
+
const refund = await xendit.creditCard().createRefund('charge_123', {
|
|
315
|
+
external_id: 'refund-123',
|
|
316
|
+
amount: 50000,
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
// Get charge details
|
|
320
|
+
const charge = await xendit.creditCard().getCharge('charge_123')
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Direct Debit
|
|
324
|
+
|
|
325
|
+
Process direct debit payments.
|
|
326
|
+
|
|
327
|
+
```ts
|
|
328
|
+
// Create payment method
|
|
329
|
+
const method = await xendit.directDebit().createPaymentMethod({
|
|
330
|
+
customer_id: 'cust_123',
|
|
331
|
+
channel_code: 'BRI',
|
|
332
|
+
properties: {
|
|
333
|
+
account_number: '1234567890',
|
|
334
|
+
},
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
// Validate OTP
|
|
338
|
+
const validated = await xendit.directDebit().validateOTP('pm_123', {
|
|
339
|
+
otp_code: '123456',
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
// Create payment
|
|
343
|
+
const payment = await xendit.directDebit().createPayment({
|
|
344
|
+
reference_id: 'order-123',
|
|
345
|
+
payment_method_id: 'pm_123',
|
|
346
|
+
currency: 'IDR',
|
|
347
|
+
amount: 100000,
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
// Get payment details
|
|
351
|
+
const payment = await xendit.directDebit().getPayment('pay_123')
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Disbursement
|
|
355
|
+
|
|
356
|
+
Send money to bank accounts and e-wallets.
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
// Create disbursement
|
|
360
|
+
const disbursement = await xendit.disbursement().create({
|
|
361
|
+
external_id: 'disb-123',
|
|
362
|
+
amount: 100000,
|
|
363
|
+
bank_code: 'BCA',
|
|
364
|
+
account_holder_name: 'John Doe',
|
|
365
|
+
account_number: '1234567890',
|
|
366
|
+
description: 'Payout for order #123',
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
// Get disbursement by ID
|
|
370
|
+
const disbursement = await xendit.disbursement().getById('disb_123')
|
|
371
|
+
|
|
372
|
+
// Create batch disbursement
|
|
373
|
+
const batch = await xendit.disbursement().createBatch({
|
|
374
|
+
reference: 'batch-123',
|
|
375
|
+
disbursements: [
|
|
376
|
+
{
|
|
377
|
+
external_id: 'disb-1',
|
|
378
|
+
amount: 50000,
|
|
379
|
+
bank_code: 'BCA',
|
|
380
|
+
account_holder_name: 'Alice',
|
|
381
|
+
account_number: '1111111111',
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
external_id: 'disb-2',
|
|
385
|
+
amount: 50000,
|
|
386
|
+
bank_code: 'BNI',
|
|
387
|
+
account_holder_name: 'Bob',
|
|
388
|
+
account_number: '2222222222',
|
|
389
|
+
},
|
|
390
|
+
],
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
// Get available banks
|
|
394
|
+
const banks = await xendit.disbursement().getAvailableBanks()
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Balance
|
|
398
|
+
|
|
399
|
+
Check your Xendit account balance.
|
|
400
|
+
|
|
401
|
+
```ts
|
|
402
|
+
// Get total balance
|
|
403
|
+
const balance = await xendit.balance().get()
|
|
404
|
+
|
|
405
|
+
// Get balance by account type
|
|
406
|
+
const cashBalance = await xendit.balance().getByAccountType('CASH')
|
|
407
|
+
const holdingBalance = await xendit.balance().getByAccountType('HOLDING')
|
|
408
|
+
const taxBalance = await xendit.balance().getByAccountType('TAX')
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
## Webhook Handling
|
|
412
|
+
|
|
413
|
+
```ts
|
|
414
|
+
import { XenditWebhook } from '@rikology/adonisjs-xendit'
|
|
415
|
+
|
|
416
|
+
export default class WebhooksController {
|
|
417
|
+
async handle(req: HttpContext) {
|
|
418
|
+
const callbackToken = process.env.XENDIT_CALLBACK_TOKEN!
|
|
419
|
+
const signature = req.request.header('x-callback-token')!
|
|
420
|
+
const payload = JSON.stringify(req.request.all())
|
|
421
|
+
|
|
422
|
+
// Verify callback token
|
|
423
|
+
if (!XenditWebhook.verify(payload, callbackToken, signature)) {
|
|
424
|
+
return req.response.forbidden('Invalid callback token')
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Parse and validate payload
|
|
428
|
+
const event = XenditWebhook.parseEvent(payload)
|
|
429
|
+
|
|
430
|
+
// Process based on event type
|
|
431
|
+
switch (event.event) {
|
|
432
|
+
case 'invoice.paid':
|
|
433
|
+
// Handle paid invoice
|
|
434
|
+
console.log('Invoice paid:', event.data)
|
|
435
|
+
break
|
|
436
|
+
case 'invoice.expired':
|
|
437
|
+
// Handle expired invoice
|
|
438
|
+
console.log('Invoice expired:', event.data)
|
|
439
|
+
break
|
|
440
|
+
case 'va.paid':
|
|
441
|
+
// Handle VA payment
|
|
442
|
+
console.log('VA paid:', event.data)
|
|
443
|
+
break
|
|
444
|
+
case 'disbursement.completed':
|
|
445
|
+
// Handle completed disbursement
|
|
446
|
+
console.log('Disbursement completed:', event.data)
|
|
447
|
+
break
|
|
448
|
+
default:
|
|
449
|
+
console.log('Unhandled event:', event.event)
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## Error Handling
|
|
456
|
+
|
|
457
|
+
```ts
|
|
458
|
+
import { XenditException } from '@rikology/adonisjs-xendit'
|
|
459
|
+
|
|
460
|
+
try {
|
|
461
|
+
await xendit.invoice().create({ ... })
|
|
462
|
+
} catch (error) {
|
|
463
|
+
if (error instanceof XenditException) {
|
|
464
|
+
console.log(error.code) // XENDIT_API_ERROR
|
|
465
|
+
console.log(error.status) // HTTP status code
|
|
466
|
+
console.log(error.message) // Error message
|
|
467
|
+
console.log(error.rawResponse) // Full error response body
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Error Types
|
|
473
|
+
|
|
474
|
+
| Error Class | Status Code | Description |
|
|
475
|
+
|-------------|-------------|-------------|
|
|
476
|
+
| `XenditValidationError` | 400 | Invalid request parameters |
|
|
477
|
+
| `XenditAuthenticationError` | 401 | Invalid API key |
|
|
478
|
+
| `XenditNotFoundError` | 404 | Resource not found |
|
|
479
|
+
| `XenditConflictError` | 409 | Duplicate external ID |
|
|
480
|
+
| `XenditRateLimitError` | 429 | Rate limit exceeded |
|
|
481
|
+
| `XenditServerError` | 500 | Xendit server error |
|
|
482
|
+
| `XenditNetworkError` | 0 | Network/timeout error |
|
|
483
|
+
|
|
484
|
+
## Exported Types
|
|
485
|
+
|
|
486
|
+
```ts
|
|
487
|
+
import type {
|
|
488
|
+
XenditConfig,
|
|
489
|
+
CreateInvoiceRequest,
|
|
490
|
+
Invoice,
|
|
491
|
+
CreateVirtualAccountRequest,
|
|
492
|
+
VirtualAccount,
|
|
493
|
+
CreateEWalletChargeRequest,
|
|
494
|
+
EWalletCharge,
|
|
495
|
+
CreateQRCodeRequest,
|
|
496
|
+
QRCode,
|
|
497
|
+
CreateRetailOutletRequest,
|
|
498
|
+
RetailOutlet,
|
|
499
|
+
CreateCreditCardChargeRequest,
|
|
500
|
+
CreditCardCharge,
|
|
501
|
+
CreateDirectDebitPaymentRequest,
|
|
502
|
+
DirectDebitPayment,
|
|
503
|
+
CreateDisbursementRequest,
|
|
504
|
+
Disbursement,
|
|
505
|
+
Balance,
|
|
506
|
+
// ... and more
|
|
507
|
+
} from '@rikology/adonisjs-xendit'
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
See `src/types.ts` for the complete type definitions.
|
|
511
|
+
|
|
512
|
+
## Requirements
|
|
513
|
+
|
|
514
|
+
- Node.js >= 20.0.0
|
|
515
|
+
- AdonisJS v7
|
|
516
|
+
|
|
517
|
+
## Changelog
|
|
518
|
+
|
|
519
|
+
See [CHANGELOG.md](CHANGELOG.md) for a history of changes.
|
|
520
|
+
|
|
521
|
+
## Contributing
|
|
522
|
+
|
|
523
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on how to get started.
|
|
524
|
+
|
|
525
|
+
## Security
|
|
526
|
+
|
|
527
|
+
If you discover any security-related issues, please email [rikoriswandha@gmail.com](mailto:rikoriswandha@gmail.com) instead of using the issue tracker. See our [Security Policy](SECURITY.md) for more details.
|
|
528
|
+
|
|
529
|
+
## Support
|
|
530
|
+
|
|
531
|
+
- 📖 [Documentation](https://github.com/rikoriswandha/adonisjs-xendit#readme)
|
|
532
|
+
- 🐛 [Issue Tracker](https://github.com/rikoriswandha/adonisjs-xendit/issues)
|
|
533
|
+
- 📧 [Email](mailto:rikoriswandha@gmail.com)
|
|
534
|
+
|
|
535
|
+
## License
|
|
536
|
+
|
|
537
|
+
MIT
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
//#region configure.ts
|
|
6
|
+
const stubsRoot = join(dirname(fileURLToPath(import.meta.url)), "stubs");
|
|
7
|
+
/**
|
|
8
|
+
* Configures the @rikology/adonisjs-xendit package
|
|
9
|
+
|
|
10
|
+
*/
|
|
11
|
+
async function configure(command) {
|
|
12
|
+
const codemods = await command.createCodemods();
|
|
13
|
+
/**
|
|
14
|
+
* Prompt for Xendit API key (masked input)
|
|
15
|
+
*/
|
|
16
|
+
const secretKey = await command.prompt.secure("Enter your Xendit API key", { validate: (value) => value ? true : "Xendit API key is required" });
|
|
17
|
+
if (await access(command.app.configPath("xendit.ts"), constants.F_OK).then(() => true).catch(() => false)) if (!await command.prompt.confirm("A config/xendit.ts file already exists. Do you want to overwrite it?")) command.logger.info("Skipped publishing config/xendit.ts");
|
|
18
|
+
else {
|
|
19
|
+
await codemods.makeUsingStub(stubsRoot, "config/xendit.stub", {});
|
|
20
|
+
command.logger.success("Updated config/xendit.ts");
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
await codemods.makeUsingStub(stubsRoot, "config/xendit.stub", {});
|
|
24
|
+
command.logger.success("Created config/xendit.ts");
|
|
25
|
+
}
|
|
26
|
+
await codemods.defineEnvVariables({
|
|
27
|
+
XENDIT_SECRET_KEY: secretKey,
|
|
28
|
+
XENDIT_ENVIRONMENT: "sandbox",
|
|
29
|
+
XENDIT_CALLBACK_TOKEN: ""
|
|
30
|
+
}, { omitFromExample: ["XENDIT_SECRET_KEY", "XENDIT_CALLBACK_TOKEN"] });
|
|
31
|
+
await codemods.defineEnvValidations({ variables: {
|
|
32
|
+
XENDIT_SECRET_KEY: "Env.schema.string()",
|
|
33
|
+
XENDIT_ENVIRONMENT: "Env.schema.enum(['sandbox', 'production'] as const)",
|
|
34
|
+
XENDIT_CALLBACK_TOKEN: "Env.schema.string.optional()"
|
|
35
|
+
} });
|
|
36
|
+
/**
|
|
37
|
+
* Register provider
|
|
38
|
+
*/
|
|
39
|
+
await codemods.updateRcFile((rcFile) => {
|
|
40
|
+
rcFile.addProvider("@rikology/adonisjs-xendit/xendit_provider");
|
|
41
|
+
});
|
|
42
|
+
command.logger.success("Xendit package configured successfully");
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { configure };
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { configure } from './configure.ts';
|
|
2
|
+
export { stubsRoot } from './stubs/main.ts';
|
|
3
|
+
export { defineConfig } from './src/define_config.ts';
|
|
4
|
+
export { XenditManager } from './src/xendit_manager.ts';
|
|
5
|
+
export { XenditWebhook } from './src/webhook.ts';
|
|
6
|
+
export * as errors from './src/xendit_exception.ts';
|
|
7
|
+
export type * from './src/types.ts';
|
|
8
|
+
export { BalanceClient } from './src/clients/balance_client.ts';
|
|
9
|
+
export { CreditCardClient } from './src/clients/credit_card_client.ts';
|
|
10
|
+
export { DirectDebitClient } from './src/clients/direct_debit_client.ts';
|
|
11
|
+
export { DisbursementClient } from './src/clients/disbursement_client.ts';
|
|
12
|
+
export { EWalletClient } from './src/clients/ewallet_client.ts';
|
|
13
|
+
export { InvoiceClient } from './src/clients/invoice_client.ts';
|
|
14
|
+
export { QrisClient } from './src/clients/qris_client.ts';
|
|
15
|
+
export { RetailOutletClient } from './src/clients/retail_outlet_client.ts';
|
|
16
|
+
export { VirtualAccountClient } from './src/clients/va_client.ts';
|