@yosle/tropipayjs 0.2.2 → 0.3.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/README.md +69 -9
- package/index.d.ts +358 -75
- package/index.js +427 -355
- package/index.js.map +1 -0
- package/package.json +18 -11
- package/.nvmrc +0 -1
- package/.vscode/launch.json +0 -18
- package/api/TropipayAPI.d.ts +0 -133
- package/config/TropipayConfig.d.ts +0 -2
- package/constants/TropipayConstants.d.ts +0 -2
- package/depositAccount/depositAccounts.d.ts +0 -36
- package/docs/readme.md +0 -3
- package/globals.d.ts +0 -75
- package/hooks/TropipayHooks.d.ts +0 -38
- package/interfaces/countries/index.d.ts +0 -1
- package/interfaces/depositaccounts/index.d.ts +0 -68
- package/interfaces/index.d.ts +0 -176
- package/interfaces/mediation/index.d.ts +0 -22
- package/interfaces/paymentlink/index.d.ts +0 -87
- package/jest.config.js +0 -5
- package/mediationPaymentCard/MediationPaymentCard.d.ts +0 -17
- package/paymentcard/PaymentCard.d.ts +0 -37
- package/paymentcard/paymentcard.spec.d.ts +0 -1
- package/rollup.config.js +0 -24
- package/src/api/TropipayAPI.ts +0 -459
- package/src/config/TropipayConfig.ts +0 -2
- package/src/constants/TropipayConstants.ts +0 -2
- package/src/depositAccount/depositAccounts.ts +0 -139
- package/src/hooks/TropipayHooks.ts +0 -154
- package/src/index.ts +0 -29
- package/src/interfaces/depositaccounts/index.ts +0 -70
- package/src/interfaces/index.js +0 -2
- package/src/interfaces/index.ts +0 -212
- package/src/interfaces/mediation/index.ts +0 -23
- package/src/interfaces/paymentlink/index.d.ts +0 -36
- package/src/interfaces/paymentlink/index.js +0 -3
- package/src/interfaces/paymentlink/index.ts +0 -91
- package/src/mediationPaymentCard/MediationPaymentCard.ts +0 -42
- package/src/mocks/tropipay.ts +0 -0
- package/src/paymentcard/PaymentCard.ts +0 -123
- package/src/paymentcard/paymentcard.spec.ts +0 -79
- package/src/utils/TropipayUtils.ts +0 -126
- package/src/utils/errors.ts +0 -92
- package/tsconfig.json +0 -96
- package/utils/TropipayUtils.d.ts +0 -45
- package/utils/errors.d.ts +0 -16
package/index.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
3
|
var axios = require('axios');
|
|
6
4
|
var crypto = require('crypto');
|
|
7
5
|
var fs = require('fs/promises');
|
|
8
6
|
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
function _interopNamespace(e) {
|
|
12
|
-
if (e && e.__esModule) return e;
|
|
7
|
+
function _interopNamespaceDefault(e) {
|
|
13
8
|
var n = Object.create(null);
|
|
14
9
|
if (e) {
|
|
15
10
|
Object.keys(e).forEach(function (k) {
|
|
@@ -22,15 +17,23 @@ function _interopNamespace(e) {
|
|
|
22
17
|
}
|
|
23
18
|
});
|
|
24
19
|
}
|
|
25
|
-
n
|
|
20
|
+
n.default = e;
|
|
26
21
|
return Object.freeze(n);
|
|
27
22
|
}
|
|
28
23
|
|
|
29
|
-
var
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
var crypto__namespace = /*#__PURE__*/_interopNamespaceDefault(crypto);
|
|
25
|
+
|
|
26
|
+
const MAX_IMAGE_SIZE_MB = 2;
|
|
27
|
+
/**
|
|
28
|
+
* Base path for the Tropipay API. All SDK endpoints target API v3
|
|
29
|
+
* (v2 is deprecated).
|
|
30
|
+
*/
|
|
31
|
+
const API_BASE = "/api/v3";
|
|
32
32
|
|
|
33
33
|
function handleExceptions(error) {
|
|
34
|
+
// already mapped (e.g. thrown by login() inside the request interceptor)
|
|
35
|
+
if (error instanceof TropipayJSException)
|
|
36
|
+
return error;
|
|
34
37
|
if (error instanceof axios.AxiosError) {
|
|
35
38
|
if (error.response) {
|
|
36
39
|
const axiosResponse = error.response;
|
|
@@ -86,7 +89,7 @@ class TropipayHooks {
|
|
|
86
89
|
* you must select from the list of available events, otherwise
|
|
87
90
|
* it will not produce an error but it will not be executed.
|
|
88
91
|
* For get full list of available events see endpoint
|
|
89
|
-
* GET /api/
|
|
92
|
+
* GET /api/v3/user/hooks/events.
|
|
90
93
|
* @param target String representing the type of event supported.
|
|
91
94
|
* It is currently available: 'web' (allows to receive information in a url),
|
|
92
95
|
* 'email' (allows to receive information in an email address).
|
|
@@ -97,20 +100,11 @@ class TropipayHooks {
|
|
|
97
100
|
* @returns
|
|
98
101
|
*/
|
|
99
102
|
async subscribe({ eventType, target, value, }) {
|
|
100
|
-
if (!Tropipay.accessToken) {
|
|
101
|
-
await this.tropipay.login();
|
|
102
|
-
}
|
|
103
103
|
try {
|
|
104
|
-
const hooks = await this.tropipay.request.post(
|
|
104
|
+
const hooks = await this.tropipay.request.post(`${API_BASE}/user/hooks`, {
|
|
105
105
|
event: eventType,
|
|
106
106
|
target: target,
|
|
107
107
|
value: value,
|
|
108
|
-
}, {
|
|
109
|
-
headers: {
|
|
110
|
-
"Content-Type": "application/json",
|
|
111
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
112
|
-
Accept: "application/json",
|
|
113
|
-
},
|
|
114
108
|
});
|
|
115
109
|
return hooks.data;
|
|
116
110
|
}
|
|
@@ -126,17 +120,8 @@ class TropipayHooks {
|
|
|
126
120
|
* @returns All subscribed hooks or empty Array if none exist.
|
|
127
121
|
*/
|
|
128
122
|
async list(eventType) {
|
|
129
|
-
if (!Tropipay.accessToken) {
|
|
130
|
-
await this.tropipay.login();
|
|
131
|
-
}
|
|
132
123
|
try {
|
|
133
|
-
const hooks = await this.tropipay.request.get(
|
|
134
|
-
headers: {
|
|
135
|
-
"Content-Type": "application/json",
|
|
136
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
137
|
-
Accept: "application/json",
|
|
138
|
-
},
|
|
139
|
-
});
|
|
124
|
+
const hooks = await this.tropipay.request.get(`${API_BASE}/user/hooks/${eventType || ""}`);
|
|
140
125
|
return hooks.data;
|
|
141
126
|
}
|
|
142
127
|
catch (error) {
|
|
@@ -144,20 +129,11 @@ class TropipayHooks {
|
|
|
144
129
|
}
|
|
145
130
|
}
|
|
146
131
|
async update(eventType, target, value) {
|
|
147
|
-
if (!Tropipay.accessToken) {
|
|
148
|
-
await this.tropipay.login();
|
|
149
|
-
}
|
|
150
132
|
try {
|
|
151
|
-
const hooks = await this.tropipay.request.put(
|
|
133
|
+
const hooks = await this.tropipay.request.put(`${API_BASE}/user/hooks`, {
|
|
152
134
|
event: eventType,
|
|
153
135
|
target: target,
|
|
154
136
|
value: value,
|
|
155
|
-
}, {
|
|
156
|
-
headers: {
|
|
157
|
-
"Content-Type": "application/json",
|
|
158
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
159
|
-
Accept: "application/json",
|
|
160
|
-
},
|
|
161
137
|
});
|
|
162
138
|
return hooks.data;
|
|
163
139
|
}
|
|
@@ -166,36 +142,17 @@ class TropipayHooks {
|
|
|
166
142
|
}
|
|
167
143
|
}
|
|
168
144
|
async delete(eventType, target) {
|
|
169
|
-
if (!Tropipay.accessToken) {
|
|
170
|
-
await this.tropipay.login();
|
|
171
|
-
}
|
|
172
145
|
try {
|
|
173
|
-
const hooks = await this.tropipay.request.delete(
|
|
174
|
-
headers: {
|
|
175
|
-
"Content-Type": "application/json",
|
|
176
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
177
|
-
Accept: "application/json",
|
|
178
|
-
},
|
|
179
|
-
});
|
|
146
|
+
const hooks = await this.tropipay.request.delete(`${API_BASE}/user/hooks/${eventType}/${target}`);
|
|
180
147
|
return hooks.data;
|
|
181
148
|
}
|
|
182
149
|
catch (error) {
|
|
183
|
-
console.trace(error);
|
|
184
150
|
throw handleExceptions(error);
|
|
185
151
|
}
|
|
186
152
|
}
|
|
187
153
|
async events() {
|
|
188
|
-
if (!Tropipay.accessToken) {
|
|
189
|
-
await this.tropipay.login();
|
|
190
|
-
}
|
|
191
154
|
try {
|
|
192
|
-
const hooks = await this.tropipay.request.get(
|
|
193
|
-
headers: {
|
|
194
|
-
"Content-Type": "application/json",
|
|
195
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
196
|
-
Accept: "application/json",
|
|
197
|
-
},
|
|
198
|
-
});
|
|
155
|
+
const hooks = await this.tropipay.request.get(`${API_BASE}/user/hooks/events`);
|
|
199
156
|
return hooks.data;
|
|
200
157
|
}
|
|
201
158
|
catch (error) {
|
|
@@ -211,22 +168,15 @@ class PaymentCard {
|
|
|
211
168
|
}
|
|
212
169
|
/**
|
|
213
170
|
* Create a paymentLink with the specified options.
|
|
171
|
+
* Supports multi-account via the optional `accountId` field of the
|
|
172
|
+
* payload (defaults to the user's default account).
|
|
214
173
|
* @param payload PaymentLinkPayload Object.
|
|
215
174
|
* @returns Promise<PaymentLink> or throws an Exception.
|
|
216
|
-
* @see https://
|
|
175
|
+
* @see https://doc.tropipay.com/docs/api-reference/payment-cards
|
|
217
176
|
*/
|
|
218
177
|
async create(payload) {
|
|
219
|
-
if (!Tropipay.accessToken) {
|
|
220
|
-
await this.tropipay.login();
|
|
221
|
-
}
|
|
222
178
|
try {
|
|
223
|
-
const paylink = await this.tropipay.request.post(
|
|
224
|
-
headers: {
|
|
225
|
-
"Content-Type": "application/json",
|
|
226
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
227
|
-
Accept: "application/json",
|
|
228
|
-
},
|
|
229
|
-
});
|
|
179
|
+
const paylink = await this.tropipay.request.post(`${API_BASE}/paymentcards`, payload);
|
|
230
180
|
return paylink.data;
|
|
231
181
|
}
|
|
232
182
|
catch (error) {
|
|
@@ -239,21 +189,12 @@ class PaymentCard {
|
|
|
239
189
|
* @returns Array of paymentlinks
|
|
240
190
|
*/
|
|
241
191
|
async list() {
|
|
242
|
-
if (!Tropipay.accessToken) {
|
|
243
|
-
await this.tropipay.login();
|
|
244
|
-
}
|
|
245
192
|
try {
|
|
246
|
-
const paymentcards = await this.tropipay.request.get(
|
|
247
|
-
headers: {
|
|
248
|
-
"Content-Type": "application/json",
|
|
249
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
250
|
-
Accept: "application/json",
|
|
251
|
-
},
|
|
252
|
-
});
|
|
193
|
+
const paymentcards = await this.tropipay.request.get(`${API_BASE}/paymentcards`);
|
|
253
194
|
return paymentcards.data;
|
|
254
195
|
}
|
|
255
196
|
catch (error) {
|
|
256
|
-
throw
|
|
197
|
+
throw handleExceptions(error);
|
|
257
198
|
}
|
|
258
199
|
}
|
|
259
200
|
/**
|
|
@@ -264,17 +205,25 @@ class PaymentCard {
|
|
|
264
205
|
* @throws {Error} If an error occurs while retrieving the payment card.
|
|
265
206
|
*/
|
|
266
207
|
async get(id) {
|
|
267
|
-
|
|
268
|
-
await this.tropipay.
|
|
208
|
+
try {
|
|
209
|
+
const paymentcard = await this.tropipay.request.get(`${API_BASE}/paymentcards/${id}`);
|
|
210
|
+
return paymentcard.data;
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
throw handleExceptions(error);
|
|
269
214
|
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Updates a payment card. Send the card id in `cardId` plus the
|
|
218
|
+
* fields to modify.
|
|
219
|
+
*
|
|
220
|
+
* @param payload Object with `cardId` and the fields to update.
|
|
221
|
+
* @return {Promise<any>} A Promise that resolves to the updated payment card data.
|
|
222
|
+
* @throws {Error} If an error occurs while updating the payment card.
|
|
223
|
+
*/
|
|
224
|
+
async update(payload) {
|
|
270
225
|
try {
|
|
271
|
-
const paymentcard = await this.tropipay.request.
|
|
272
|
-
headers: {
|
|
273
|
-
"Content-Type": "application/json",
|
|
274
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
275
|
-
Accept: "application/json",
|
|
276
|
-
},
|
|
277
|
-
});
|
|
226
|
+
const paymentcard = await this.tropipay.request.put(`${API_BASE}/paymentcards/`, payload);
|
|
278
227
|
return paymentcard.data;
|
|
279
228
|
}
|
|
280
229
|
catch (error) {
|
|
@@ -290,16 +239,8 @@ class PaymentCard {
|
|
|
290
239
|
* @throws {Error} If an error occurs while deleting the payment card.
|
|
291
240
|
*/
|
|
292
241
|
async delete(id) {
|
|
293
|
-
if (!Tropipay.accessToken) {
|
|
294
|
-
await this.tropipay.login();
|
|
295
|
-
}
|
|
296
242
|
try {
|
|
297
|
-
const paymentcard = await this.tropipay.request.delete(
|
|
298
|
-
headers: {
|
|
299
|
-
"Content-Type": "application/json",
|
|
300
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
301
|
-
Accept: "application/json",
|
|
302
|
-
},
|
|
243
|
+
const paymentcard = await this.tropipay.request.delete(`${API_BASE}/paymentcards/`, {
|
|
303
244
|
data: {
|
|
304
245
|
cardId: id,
|
|
305
246
|
},
|
|
@@ -312,40 +253,6 @@ class PaymentCard {
|
|
|
312
253
|
}
|
|
313
254
|
}
|
|
314
255
|
|
|
315
|
-
class MediationPaymentCard {
|
|
316
|
-
tropipay;
|
|
317
|
-
constructor(tropipayInstance) {
|
|
318
|
-
this.tropipay = tropipayInstance;
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* (ONLY FOR BUSINESS ACCOUNTS) Create a mediation paymentcard (an escrow payment link) with the specified options.
|
|
322
|
-
* This allows a payment to be made to persons belonging or not to the TropiPay platform with the
|
|
323
|
-
* particularity that the payment will be held in custody or retained until it is released with
|
|
324
|
-
* the approval of the payer.
|
|
325
|
-
* @param payload PaymentLinkPayload Object.
|
|
326
|
-
* @returns Promise<PaymentLink> or throws an Exception.
|
|
327
|
-
* @see https://tpp.stoplight.io/docs/tropipay-api-doc/12a128ff971e4-creating-a-mediation-payment-card
|
|
328
|
-
*/
|
|
329
|
-
async create(payload) {
|
|
330
|
-
if (!Tropipay.accessToken) {
|
|
331
|
-
await this.tropipay.login();
|
|
332
|
-
}
|
|
333
|
-
try {
|
|
334
|
-
const paylink = await this.tropipay.request.post("/api/v2/paymentcards/mediation", payload, {
|
|
335
|
-
headers: {
|
|
336
|
-
"Content-Type": "application/json",
|
|
337
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
338
|
-
Accept: "application/json",
|
|
339
|
-
},
|
|
340
|
-
});
|
|
341
|
-
return paylink.data;
|
|
342
|
-
}
|
|
343
|
-
catch (error) {
|
|
344
|
-
throw handleExceptions(error);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
256
|
class DepositAccounts {
|
|
350
257
|
tropipay;
|
|
351
258
|
constructor(tropipayInstance) {
|
|
@@ -356,44 +263,28 @@ class DepositAccounts {
|
|
|
356
263
|
* @returns Array of DepositAccounts
|
|
357
264
|
*/
|
|
358
265
|
async list() {
|
|
359
|
-
if (!Tropipay.accessToken) {
|
|
360
|
-
await this.tropipay.login();
|
|
361
|
-
}
|
|
362
266
|
try {
|
|
363
|
-
const deposit = await this.tropipay.request.get(
|
|
364
|
-
headers: {
|
|
365
|
-
"Content-Type": "application/json",
|
|
366
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
367
|
-
Accept: "application/json",
|
|
368
|
-
},
|
|
369
|
-
});
|
|
267
|
+
const deposit = await this.tropipay.request.get(`${API_BASE}/deposit_accounts`);
|
|
370
268
|
return deposit.data;
|
|
371
269
|
}
|
|
372
270
|
catch (error) {
|
|
373
|
-
|
|
271
|
+
throw handleExceptions(error);
|
|
374
272
|
}
|
|
375
273
|
}
|
|
376
274
|
/**
|
|
377
275
|
* Adds a new beneficiary to the user account.
|
|
276
|
+
* For crypto wallet beneficiaries use `beneficiaryType: 3`, put the
|
|
277
|
+
* wallet address in `accountNumber` and set the `network`.
|
|
378
278
|
* @param payload
|
|
379
279
|
* @returns
|
|
380
280
|
*/
|
|
381
281
|
async create(depositAccountObj) {
|
|
382
|
-
if (!Tropipay.accessToken) {
|
|
383
|
-
await this.tropipay.login();
|
|
384
|
-
}
|
|
385
282
|
try {
|
|
386
|
-
const deposit = await this.tropipay.request.post(
|
|
387
|
-
headers: {
|
|
388
|
-
"Content-Type": "application/json",
|
|
389
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
390
|
-
Accept: "application/json",
|
|
391
|
-
},
|
|
392
|
-
});
|
|
283
|
+
const deposit = await this.tropipay.request.post(`${API_BASE}/deposit_accounts`, depositAccountObj);
|
|
393
284
|
return deposit.data;
|
|
394
285
|
}
|
|
395
286
|
catch (error) {
|
|
396
|
-
|
|
287
|
+
throw handleExceptions(error);
|
|
397
288
|
}
|
|
398
289
|
}
|
|
399
290
|
/**
|
|
@@ -403,67 +294,192 @@ class DepositAccounts {
|
|
|
403
294
|
* @returns
|
|
404
295
|
*/
|
|
405
296
|
async get(id) {
|
|
406
|
-
if (!Tropipay.accessToken) {
|
|
407
|
-
await this.tropipay.login();
|
|
408
|
-
}
|
|
409
297
|
try {
|
|
410
|
-
const deposit = await this.tropipay.request.get(
|
|
411
|
-
headers: {
|
|
412
|
-
"Content-Type": "application/json",
|
|
413
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
414
|
-
Accept: "application/json",
|
|
415
|
-
},
|
|
416
|
-
});
|
|
298
|
+
const deposit = await this.tropipay.request.get(`${API_BASE}/deposit_accounts/${id}`);
|
|
417
299
|
return deposit.data;
|
|
418
300
|
}
|
|
419
301
|
catch (error) {
|
|
420
|
-
|
|
302
|
+
throw handleExceptions(error);
|
|
421
303
|
}
|
|
422
304
|
}
|
|
423
305
|
/**
|
|
424
306
|
* Updates certain beneficiary data.
|
|
425
|
-
* @param depositAccountObj
|
|
307
|
+
* @param depositAccountObj Object with the beneficiary id and the fields to update.
|
|
426
308
|
* @returns
|
|
427
309
|
*/
|
|
428
310
|
async update(depositAccountObj) {
|
|
429
|
-
if (!Tropipay.accessToken) {
|
|
430
|
-
await this.tropipay.login();
|
|
431
|
-
}
|
|
432
311
|
try {
|
|
433
|
-
const deposit = await this.tropipay.request.put(
|
|
434
|
-
headers: {
|
|
435
|
-
"Content-Type": "application/json",
|
|
436
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
437
|
-
Accept: "application/json",
|
|
438
|
-
},
|
|
439
|
-
});
|
|
312
|
+
const deposit = await this.tropipay.request.put(`${API_BASE}/deposit_accounts`, depositAccountObj);
|
|
440
313
|
return deposit.data;
|
|
441
314
|
}
|
|
442
315
|
catch (error) {
|
|
443
|
-
|
|
316
|
+
throw handleExceptions(error);
|
|
444
317
|
}
|
|
445
318
|
}
|
|
446
319
|
/**
|
|
447
|
-
*
|
|
320
|
+
* Deletes the beneficiary indicated by id
|
|
448
321
|
* @param id
|
|
449
322
|
* @returns
|
|
450
323
|
*/
|
|
451
324
|
async delete(id) {
|
|
452
|
-
|
|
453
|
-
await this.tropipay.
|
|
325
|
+
try {
|
|
326
|
+
const deposit = await this.tropipay.request.delete(`${API_BASE}/deposit_accounts/${id}`);
|
|
327
|
+
return deposit.data;
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
throw handleExceptions(error);
|
|
454
331
|
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Validates a beneficiary account number (bank account, card or
|
|
335
|
+
* crypto wallet address) before creating it.
|
|
336
|
+
* @param payload Account number data to validate (e.g. { accountNumber, paymentType, network, currency })
|
|
337
|
+
* @returns
|
|
338
|
+
*/
|
|
339
|
+
async validateAccountNumber(payload) {
|
|
455
340
|
try {
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
341
|
+
const validation = await this.tropipay.request.post(`${API_BASE}/deposit_accounts/validate_account_number`, payload);
|
|
342
|
+
return validation.data;
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
throw handleExceptions(error);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Multi-account support. A Tropipay user can hold several accounts
|
|
352
|
+
* (one per currency). Use `list()` to discover the `accountId` values
|
|
353
|
+
* accepted by `paymentCards.create()` and `transfers.payout()`.
|
|
354
|
+
*/
|
|
355
|
+
class Accounts {
|
|
356
|
+
tropipay;
|
|
357
|
+
constructor(tropipayInstance) {
|
|
358
|
+
this.tropipay = tropipayInstance;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* List all the accounts of the current user with their id,
|
|
362
|
+
* accountNumber, currency, balance and enabled payment methods.
|
|
363
|
+
* @param type Optional comma-separated account types filter.
|
|
364
|
+
* @returns Array of Account objects.
|
|
365
|
+
*/
|
|
366
|
+
async list(type) {
|
|
367
|
+
try {
|
|
368
|
+
const accounts = await this.tropipay.request.get(`${API_BASE}/accounts`, {
|
|
369
|
+
params: type ? { type } : undefined,
|
|
462
370
|
});
|
|
463
|
-
|
|
371
|
+
// accept both a plain array and a paginated { count, rows } body
|
|
372
|
+
const data = accounts.data;
|
|
373
|
+
return Array.isArray(data) ? data : data?.rows ?? [];
|
|
464
374
|
}
|
|
465
375
|
catch (error) {
|
|
466
|
-
|
|
376
|
+
throw handleExceptions(error);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Get the balance of every account of the user.
|
|
381
|
+
* @returns Balances for all accounts.
|
|
382
|
+
*/
|
|
383
|
+
async allBalances() {
|
|
384
|
+
try {
|
|
385
|
+
const balances = await this.tropipay.request.get(`${API_BASE}/accounts/allBalance`);
|
|
386
|
+
return balances.data;
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
throw handleExceptions(error);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Get the balance of one account by its account number
|
|
394
|
+
* (note: accountNumber, not account id — get it from `list()`).
|
|
395
|
+
* @param accountNumber The account number.
|
|
396
|
+
*/
|
|
397
|
+
async balance(accountNumber) {
|
|
398
|
+
try {
|
|
399
|
+
const balance = await this.tropipay.request.get(`${API_BASE}/accounts/balance/${accountNumber}`);
|
|
400
|
+
return balance.data;
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
throw handleExceptions(error);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* List the movements of one account.
|
|
408
|
+
* @param accountId The account id (from `list()`).
|
|
409
|
+
* @param options Pagination: limit (max 50, default 20) and offset.
|
|
410
|
+
*/
|
|
411
|
+
async movements(accountId, options = {}) {
|
|
412
|
+
try {
|
|
413
|
+
const movements = await this.tropipay.request.get(`${API_BASE}/accounts/${accountId}/movements`, {
|
|
414
|
+
params: { limit: options.limit ?? 20, offset: options.offset ?? 0 },
|
|
415
|
+
});
|
|
416
|
+
return movements.data;
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
throw handleExceptions(error);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Money transfers (payouts) to beneficiaries. Requires 2FA and the
|
|
426
|
+
* ALLOW_EXTERNAL_TRANSFER permission on the Tropipay account.
|
|
427
|
+
*
|
|
428
|
+
* Typical flow:
|
|
429
|
+
* 1. `simulate(payload)` to preview amounts and fees.
|
|
430
|
+
* 2. `requestSecurityCode()` to receive the 2FA code (SMS/email).
|
|
431
|
+
* 3. `payout({ ...payload, securityCode })` to execute the transfer.
|
|
432
|
+
*/
|
|
433
|
+
class Transfers {
|
|
434
|
+
tropipay;
|
|
435
|
+
constructor(tropipayInstance) {
|
|
436
|
+
this.tropipay = tropipayInstance;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Simulate a payout without executing it: returns the resulting
|
|
440
|
+
* amounts, rates and fees for the given payload.
|
|
441
|
+
* Note the payload shape differs from `payout()`: it uses
|
|
442
|
+
* `currencyToPay`/`currencyToGet`, `amountToPay`/`amountToGet` and
|
|
443
|
+
* requires `accountId`.
|
|
444
|
+
* @param payload Simulation data (no securityCode needed).
|
|
445
|
+
*/
|
|
446
|
+
async simulate(payload) {
|
|
447
|
+
try {
|
|
448
|
+
const simulation = await this.tropipay.request.post(`${API_BASE}/booking/payout/simulate`, payload);
|
|
449
|
+
return simulation.data;
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
throw handleExceptions(error);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Execute a payout (external transfer) to a beneficiary.
|
|
457
|
+
* Requires the 2FA `securityCode` in the payload (use
|
|
458
|
+
* `requestSecurityCode()` first; in Development mode "123456" works).
|
|
459
|
+
* Supports multi-account via the optional `accountId` field.
|
|
460
|
+
* @param payload Payout data including securityCode.
|
|
461
|
+
*/
|
|
462
|
+
async payout(payload) {
|
|
463
|
+
try {
|
|
464
|
+
const booking = await this.tropipay.request.post(`${API_BASE}/booking/payout`, payload);
|
|
465
|
+
return booking.data;
|
|
466
|
+
}
|
|
467
|
+
catch (error) {
|
|
468
|
+
throw handleExceptions(error);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Request the 2FA security code needed to confirm a payout.
|
|
473
|
+
* The code is delivered by SMS or email depending on the user's
|
|
474
|
+
* 2FA settings.
|
|
475
|
+
*/
|
|
476
|
+
async requestSecurityCode() {
|
|
477
|
+
try {
|
|
478
|
+
const response = await this.tropipay.request.post(`${API_BASE}/booking/sendSecurityCode`, {});
|
|
479
|
+
return response.data;
|
|
480
|
+
}
|
|
481
|
+
catch (error) {
|
|
482
|
+
throw handleExceptions(error);
|
|
467
483
|
}
|
|
468
484
|
}
|
|
469
485
|
}
|
|
@@ -474,19 +490,22 @@ class DepositAccounts {
|
|
|
474
490
|
* @author Yosleivy Baez Acosta
|
|
475
491
|
*
|
|
476
492
|
*/
|
|
493
|
+
const TOKEN_URL = `${API_BASE}/access/token`;
|
|
477
494
|
class Tropipay {
|
|
478
495
|
clientId;
|
|
479
496
|
clientSecret;
|
|
480
497
|
scopes;
|
|
481
498
|
request;
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
499
|
+
// Per instance, so several credentials (or environments) never share a token
|
|
500
|
+
accessToken = null;
|
|
501
|
+
refreshToken = null;
|
|
502
|
+
expiresIn = null;
|
|
485
503
|
serverMode;
|
|
486
504
|
hooks;
|
|
487
505
|
paymentCards;
|
|
488
506
|
depositAccounts;
|
|
489
|
-
|
|
507
|
+
accounts;
|
|
508
|
+
transfers;
|
|
490
509
|
/**
|
|
491
510
|
* Initializes a new instance of the Tropipay class.
|
|
492
511
|
*
|
|
@@ -519,87 +538,77 @@ class Tropipay {
|
|
|
519
538
|
this.serverMode = config.serverMode || "Development";
|
|
520
539
|
const tpp_env = this.serverMode === "Production"
|
|
521
540
|
? "https://www.tropipay.com"
|
|
522
|
-
: "https://tropipay
|
|
523
|
-
this.request =
|
|
541
|
+
: "https://sandbox.tropipay.me";
|
|
542
|
+
this.request = axios.create({
|
|
524
543
|
baseURL: config.customTropipayUrl || tpp_env,
|
|
525
544
|
headers: {
|
|
526
545
|
"Content-Type": "application/json",
|
|
527
546
|
Accept: "application/json",
|
|
528
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
529
547
|
},
|
|
530
548
|
});
|
|
531
|
-
//
|
|
549
|
+
// Log in (or refresh an expired token) and attach the current token to
|
|
550
|
+
// every request. The token endpoint itself is skipped, otherwise login()
|
|
551
|
+
// would re-enter this interceptor forever.
|
|
532
552
|
this.request.interceptors.request.use(async (config) => {
|
|
553
|
+
if (config.url === TOKEN_URL)
|
|
554
|
+
return config;
|
|
533
555
|
const currentTimestamp = Math.floor(Date.now() / 1000); // Current time in seconds
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
await this.login();
|
|
538
|
-
}
|
|
539
|
-
catch (error) {
|
|
540
|
-
// Handle token refresh error
|
|
541
|
-
Tropipay.accessToken = null;
|
|
542
|
-
Tropipay.refreshToken = null;
|
|
543
|
-
throw handleExceptions(error);
|
|
544
|
-
}
|
|
556
|
+
const expired = this.expiresIn !== null && this.expiresIn < currentTimestamp;
|
|
557
|
+
if (!this.accessToken || expired) {
|
|
558
|
+
await this.login();
|
|
545
559
|
}
|
|
560
|
+
config.headers.Authorization = `Bearer ${this.accessToken}`;
|
|
546
561
|
return config;
|
|
547
562
|
}, (error) => {
|
|
548
563
|
return Promise.reject(error);
|
|
549
564
|
});
|
|
550
565
|
this.hooks = new TropipayHooks(this);
|
|
551
566
|
this.paymentCards = new PaymentCard(this);
|
|
552
|
-
this.mediationPaymentCard = new MediationPaymentCard(this);
|
|
553
567
|
this.depositAccounts = new DepositAccounts(this);
|
|
568
|
+
this.accounts = new Accounts(this);
|
|
569
|
+
this.transfers = new Transfers(this);
|
|
554
570
|
}
|
|
555
571
|
async login() {
|
|
556
572
|
try {
|
|
557
|
-
if (
|
|
558
|
-
const { data } = await this.request.post(
|
|
573
|
+
if (this.refreshToken) {
|
|
574
|
+
const { data } = await this.request.post(TOKEN_URL, {
|
|
559
575
|
client_id: this.clientId,
|
|
560
576
|
client_secret: this.clientSecret,
|
|
561
577
|
grant_type: "refresh_token",
|
|
562
|
-
refresh_token:
|
|
563
|
-
}, {
|
|
564
|
-
headers: {
|
|
565
|
-
"Content-Type": "application/json",
|
|
566
|
-
Accept: "application/json",
|
|
567
|
-
},
|
|
578
|
+
refresh_token: this.refreshToken,
|
|
568
579
|
});
|
|
580
|
+
this.accessToken = data.access_token;
|
|
581
|
+
this.refreshToken = data.refresh_token;
|
|
582
|
+
this.expiresIn = data.expires_in;
|
|
569
583
|
return data;
|
|
570
584
|
}
|
|
571
585
|
// normal credetials login
|
|
572
|
-
const { data } = await this.request.post(
|
|
586
|
+
const { data } = await this.request.post(TOKEN_URL, {
|
|
573
587
|
client_id: this.clientId,
|
|
574
588
|
client_secret: this.clientSecret,
|
|
575
589
|
grant_type: "client_credentials",
|
|
576
590
|
scope: this.scopes.join(" "), // "ALLOW_GET_PROFILE_DATA ALLOW_PAYMENT_IN ALLOW_EXTERNAL_CHARGE KYC3_FULL_ALLOW ALLOW_PAYMENT_OUT ALLOW_MARKET_PURCHASES ALLOW_GET_BALANCE ALLOW_GET_MOVEMENT_LIST ALLOW_GET_CREDENTIAL",
|
|
577
|
-
}, {
|
|
578
|
-
headers: {
|
|
579
|
-
"Content-Type": "application/json",
|
|
580
|
-
Accept: "application/json",
|
|
581
|
-
},
|
|
582
591
|
});
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
592
|
+
this.accessToken = data.access_token;
|
|
593
|
+
this.refreshToken = data.refresh_token;
|
|
594
|
+
this.expiresIn = data.expires_in;
|
|
586
595
|
return data;
|
|
587
596
|
}
|
|
588
597
|
catch (error) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
598
|
+
this.accessToken = null;
|
|
599
|
+
this.refreshToken = null;
|
|
600
|
+
this.expiresIn = null;
|
|
592
601
|
throw handleExceptions(error);
|
|
593
602
|
}
|
|
594
603
|
}
|
|
595
604
|
/**
|
|
596
605
|
* Get the list of all supported countries by Tropipay.
|
|
597
606
|
* @returns Array of Countries Data
|
|
598
|
-
* @see https://
|
|
607
|
+
* @see https://doc.tropipay.com/docs/api-reference/countries
|
|
599
608
|
*/
|
|
600
609
|
async countries() {
|
|
601
610
|
try {
|
|
602
|
-
const countries = await this.request.get(
|
|
611
|
+
const countries = await this.request.get(`${API_BASE}/countries`);
|
|
603
612
|
return countries.data;
|
|
604
613
|
}
|
|
605
614
|
catch (error) {
|
|
@@ -607,21 +616,14 @@ class Tropipay {
|
|
|
607
616
|
}
|
|
608
617
|
}
|
|
609
618
|
/**
|
|
610
|
-
* Get user
|
|
619
|
+
* Get balance of the user's default account.
|
|
620
|
+
* For per-account balances use `accounts.balance()` or
|
|
621
|
+
* `accounts.allBalances()`.
|
|
611
622
|
* @returns balance Object { balance: number, pendingIn: number, pendingOut: number }
|
|
612
623
|
*/
|
|
613
624
|
async getBalance() {
|
|
614
|
-
if (!Tropipay.accessToken) {
|
|
615
|
-
await this.login();
|
|
616
|
-
}
|
|
617
625
|
try {
|
|
618
|
-
const balance = await this.request.get(
|
|
619
|
-
headers: {
|
|
620
|
-
"Content-Type": "application/json",
|
|
621
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
622
|
-
Accept: "application/json",
|
|
623
|
-
},
|
|
624
|
-
});
|
|
626
|
+
const balance = await this.request.get(`${API_BASE}/users/balance`);
|
|
625
627
|
return balance.data;
|
|
626
628
|
}
|
|
627
629
|
catch (error) {
|
|
@@ -634,15 +636,15 @@ class Tropipay {
|
|
|
634
636
|
* when adding new beneficiaries to some user.
|
|
635
637
|
*
|
|
636
638
|
* @returns Array of Country Objects
|
|
637
|
-
* @see https://
|
|
639
|
+
* @see https://doc.tropipay.com/docs/api-reference/countries
|
|
638
640
|
*/
|
|
639
641
|
async destinations() {
|
|
640
642
|
try {
|
|
641
|
-
const countries = await this.request.get(
|
|
643
|
+
const countries = await this.request.get(`${API_BASE}/countries/destinations`);
|
|
642
644
|
return countries.data;
|
|
643
645
|
}
|
|
644
646
|
catch (error) {
|
|
645
|
-
throw
|
|
647
|
+
throw handleExceptions(error);
|
|
646
648
|
}
|
|
647
649
|
}
|
|
648
650
|
/**
|
|
@@ -650,16 +652,9 @@ class Tropipay {
|
|
|
650
652
|
* @returns Array of account Object or throws an error
|
|
651
653
|
*/
|
|
652
654
|
async favorites() {
|
|
653
|
-
if (!Tropipay.accessToken) {
|
|
654
|
-
await this.login();
|
|
655
|
-
}
|
|
656
655
|
try {
|
|
657
|
-
const favoritesList = await this.request.get(
|
|
658
|
-
|
|
659
|
-
"Content-Type": "application/json",
|
|
660
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
661
|
-
Accept: "application/json",
|
|
662
|
-
},
|
|
656
|
+
const favoritesList = await this.request.get(`${API_BASE}/paymentcards/filters`, {
|
|
657
|
+
params: { favorite: true },
|
|
663
658
|
});
|
|
664
659
|
return favoritesList?.data?.rows;
|
|
665
660
|
}
|
|
@@ -669,20 +664,16 @@ class Tropipay {
|
|
|
669
664
|
}
|
|
670
665
|
/**
|
|
671
666
|
* List all account movements. You can optionaly specify
|
|
672
|
-
* offset and limit params for pagination
|
|
667
|
+
* offset and limit params for pagination (limit is capped
|
|
668
|
+
* to 50 by the API).
|
|
669
|
+
* For the movements of one specific account use
|
|
670
|
+
* `accounts.movements(accountId)`.
|
|
673
671
|
* @returns
|
|
674
672
|
*/
|
|
675
673
|
async movements(offset = 0, limit = 10) {
|
|
676
|
-
if (!Tropipay.accessToken)
|
|
677
|
-
await this.login();
|
|
678
674
|
try {
|
|
679
|
-
const movements = await this.request.get(
|
|
675
|
+
const movements = await this.request.get(`${API_BASE}/movements`, {
|
|
680
676
|
params: { limit: limit, offset: offset },
|
|
681
|
-
headers: {
|
|
682
|
-
"Content-Type": "application/json",
|
|
683
|
-
Accept: "application/json",
|
|
684
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
685
|
-
},
|
|
686
677
|
});
|
|
687
678
|
return movements.data;
|
|
688
679
|
}
|
|
@@ -695,10 +686,8 @@ class Tropipay {
|
|
|
695
686
|
* @returns account object
|
|
696
687
|
*/
|
|
697
688
|
async profile() {
|
|
698
|
-
if (!Tropipay.accessToken)
|
|
699
|
-
await this.login();
|
|
700
689
|
try {
|
|
701
|
-
const profile = await this.request.get(
|
|
690
|
+
const profile = await this.request.get(`${API_BASE}/users/profile`);
|
|
702
691
|
return profile.data;
|
|
703
692
|
}
|
|
704
693
|
catch (error) {
|
|
@@ -711,51 +700,16 @@ class Tropipay {
|
|
|
711
700
|
* @param originCurrency Target currency code supported by Tropipay.
|
|
712
701
|
* @param targetCurrency Must be 'EUR'? (not documented by Tropipay)
|
|
713
702
|
* @returns Conversion rate (number)
|
|
714
|
-
* @see https://
|
|
703
|
+
* @see https://doc.tropipay.com/docs/api-reference/movements
|
|
715
704
|
*/
|
|
716
705
|
async rates(originCurrency, targetCurrency = "EUR") {
|
|
717
|
-
if (!Tropipay.accessToken) {
|
|
718
|
-
await this.login();
|
|
719
|
-
}
|
|
720
706
|
try {
|
|
721
|
-
const rates = await this.request.post(
|
|
707
|
+
const rates = await this.request.post(`${API_BASE}/movements/get_rate`, {
|
|
722
708
|
currencyFrom: originCurrency,
|
|
723
709
|
currencyTo: targetCurrency,
|
|
724
|
-
}, {
|
|
725
|
-
headers: {
|
|
726
|
-
"Content-Type": "application/json",
|
|
727
|
-
Accept: "application/json",
|
|
728
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
729
|
-
},
|
|
730
710
|
});
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
catch (error) {
|
|
734
|
-
throw handleExceptions(error);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
/**
|
|
738
|
-
* (ONLY in Bussiness Accounts)
|
|
739
|
-
* An escrow payment link. This allows a payment to be made to persons
|
|
740
|
-
* belonging or not to the TropiPay platform with the particularity
|
|
741
|
-
* that the payment will be held in custody or retained until it is
|
|
742
|
-
* released with the approval of the payer.
|
|
743
|
-
* @deprecated This method is no longer supported and may be removed in a future release.
|
|
744
|
-
* @see https://tpp.stoplight.io/docs/tropipay-api-doc/12a128ff971e4-creating-a-mediation-payment-card
|
|
745
|
-
* @param config Payload with the payment details
|
|
746
|
-
*/
|
|
747
|
-
async createMediationPaymentCard(config) {
|
|
748
|
-
if (!Tropipay.accessToken)
|
|
749
|
-
await this.login();
|
|
750
|
-
try {
|
|
751
|
-
const mediation = await this.request.post("/api/v2/paymentcards/mediation", config, {
|
|
752
|
-
headers: {
|
|
753
|
-
"Content-Type": "application/json",
|
|
754
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
755
|
-
Accept: "application/json",
|
|
756
|
-
},
|
|
757
|
-
});
|
|
758
|
-
return mediation.data;
|
|
711
|
+
// the v3 API returns the rate as a numeric string
|
|
712
|
+
return Number(rates.data.rate);
|
|
759
713
|
}
|
|
760
714
|
catch (error) {
|
|
761
715
|
throw handleExceptions(error);
|
|
@@ -776,20 +730,11 @@ class Tropipay {
|
|
|
776
730
|
* the code received via SMS in Production (obtained via requestSecurityCode()).
|
|
777
731
|
*/
|
|
778
732
|
async refundMovement(orderCode, amount, securityCode) {
|
|
779
|
-
if (!Tropipay.accessToken) {
|
|
780
|
-
await this.login();
|
|
781
|
-
}
|
|
782
733
|
if (!this.scopes.includes("ALLOW_REFUND")) {
|
|
783
734
|
throw new TropipayJSException("The credential does not have the ALLOW_REFUND scope required to perform refunds. If you believe your account should have this permission, please contact Tropipay support.", 403, null);
|
|
784
735
|
}
|
|
785
736
|
try {
|
|
786
|
-
const response = await this.request.post(
|
|
787
|
-
headers: {
|
|
788
|
-
"Content-Type": "application/json",
|
|
789
|
-
Accept: "application/json",
|
|
790
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
791
|
-
},
|
|
792
|
-
});
|
|
737
|
+
const response = await this.request.post(`${API_BASE}/movements/in/refund`, { orderCode, amount, securityCode });
|
|
793
738
|
return response.data;
|
|
794
739
|
}
|
|
795
740
|
catch (error) {
|
|
@@ -809,17 +754,8 @@ class Tropipay {
|
|
|
809
754
|
* @returns The API response confirming the code was sent
|
|
810
755
|
*/
|
|
811
756
|
async requestSecurityCode(type = "sms") {
|
|
812
|
-
if (!Tropipay.accessToken) {
|
|
813
|
-
await this.login();
|
|
814
|
-
}
|
|
815
757
|
try {
|
|
816
|
-
const response = await this.request.post(
|
|
817
|
-
headers: {
|
|
818
|
-
"Content-Type": "application/json",
|
|
819
|
-
Accept: "application/json",
|
|
820
|
-
Authorization: `Bearer ${Tropipay.accessToken}`,
|
|
821
|
-
},
|
|
822
|
-
});
|
|
758
|
+
const response = await this.request.post(`${API_BASE}/users/sendSecurityCode`, { type });
|
|
823
759
|
return response.data;
|
|
824
760
|
}
|
|
825
761
|
catch (error) {
|
|
@@ -827,13 +763,6 @@ class Tropipay {
|
|
|
827
763
|
}
|
|
828
764
|
}
|
|
829
765
|
}
|
|
830
|
-
class ClientSideUtils {
|
|
831
|
-
constructor(tropipayInstance) {
|
|
832
|
-
throw Error(`Not implemented yet`);
|
|
833
|
-
}
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
const MAX_IMAGE_SIZE_MB = 1;
|
|
837
766
|
|
|
838
767
|
class ServerSideUtils {
|
|
839
768
|
tropipay;
|
|
@@ -860,23 +789,71 @@ class ServerSideUtils {
|
|
|
860
789
|
}
|
|
861
790
|
/**
|
|
862
791
|
* Checks if the provided base64 string represents a square image.
|
|
792
|
+
* Supports PNG and JPEG images (dimensions are read directly from
|
|
793
|
+
* the binary header, no DOM required).
|
|
863
794
|
*
|
|
864
795
|
* @param {string} base64String - The base64 string of the image
|
|
865
796
|
* @return {Promise<boolean>} A Promise that resolves to a boolean indicating whether the image is square
|
|
866
797
|
*/
|
|
867
798
|
static async isBase64ImageSquare(base64String) {
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
799
|
+
const dimensions = ServerSideUtils.getImageDimensions(base64String);
|
|
800
|
+
return dimensions.width === dimensions.height;
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Reads the width/height of a base64 encoded PNG or JPEG image
|
|
804
|
+
* from its binary header.
|
|
805
|
+
*
|
|
806
|
+
* @param {string} base64String - base64 image, with or without the data: prefix
|
|
807
|
+
* @return {{width: number, height: number}} the image dimensions
|
|
808
|
+
*/
|
|
809
|
+
static getImageDimensions(base64String) {
|
|
810
|
+
const base64Data = base64String.replace(/^data:image\/\w+;base64,/, "");
|
|
811
|
+
const buffer = Buffer.from(base64Data, "base64");
|
|
812
|
+
// PNG signature: 89 50 4E 47, IHDR width/height at offsets 16/20
|
|
813
|
+
if (buffer.length > 24 &&
|
|
814
|
+
buffer[0] === 0x89 &&
|
|
815
|
+
buffer[1] === 0x50 &&
|
|
816
|
+
buffer[2] === 0x4e &&
|
|
817
|
+
buffer[3] === 0x47) {
|
|
818
|
+
return {
|
|
819
|
+
width: buffer.readUInt32BE(16),
|
|
820
|
+
height: buffer.readUInt32BE(20),
|
|
877
821
|
};
|
|
878
|
-
|
|
879
|
-
|
|
822
|
+
}
|
|
823
|
+
// JPEG signature: FF D8. Scan segments for a SOFn marker with the frame size.
|
|
824
|
+
if (buffer.length > 4 && buffer[0] === 0xff && buffer[1] === 0xd8) {
|
|
825
|
+
let offset = 2;
|
|
826
|
+
while (offset + 9 < buffer.length) {
|
|
827
|
+
if (buffer[offset] !== 0xff) {
|
|
828
|
+
offset++;
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
const marker = buffer[offset + 1];
|
|
832
|
+
// 0xFF fill bytes may pad the stream before a marker
|
|
833
|
+
if (marker === 0xff) {
|
|
834
|
+
offset++;
|
|
835
|
+
continue;
|
|
836
|
+
}
|
|
837
|
+
// standalone markers (TEM, RST0-RST7) carry no length field
|
|
838
|
+
if (marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) {
|
|
839
|
+
offset += 2;
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
// SOF0-SOF15 markers except DHT (C4), JPG (C8) and DAC (CC)
|
|
843
|
+
if (marker >= 0xc0 &&
|
|
844
|
+
marker <= 0xcf &&
|
|
845
|
+
marker !== 0xc4 &&
|
|
846
|
+
marker !== 0xc8 &&
|
|
847
|
+
marker !== 0xcc) {
|
|
848
|
+
return {
|
|
849
|
+
height: buffer.readUInt16BE(offset + 5),
|
|
850
|
+
width: buffer.readUInt16BE(offset + 7),
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
offset += 2 + buffer.readUInt16BE(offset + 2);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
throw new Error("Unsupported image format: only PNG and JPEG are allowed");
|
|
880
857
|
}
|
|
881
858
|
/**
|
|
882
859
|
* Takes a local file path and returns a base64 representation of the file content.
|
|
@@ -885,7 +862,7 @@ class ServerSideUtils {
|
|
|
885
862
|
* @return {Promise<string>} a Promise that resolves to the base64 representation of the file content
|
|
886
863
|
*/
|
|
887
864
|
static async fileToBase64(filepath) {
|
|
888
|
-
const contents = await
|
|
865
|
+
const contents = await fs.readFile(filepath);
|
|
889
866
|
let base64content = contents.toString("base64");
|
|
890
867
|
const ext = filepath.split(".").pop();
|
|
891
868
|
return `data:image/${ext};base64,` + base64content;
|
|
@@ -897,7 +874,7 @@ class ServerSideUtils {
|
|
|
897
874
|
* @return {Promise<string>} the base64 representation of the file
|
|
898
875
|
*/
|
|
899
876
|
static async getBase64FromFileUrl(url) {
|
|
900
|
-
const response = await
|
|
877
|
+
const response = await axios.get(url, {
|
|
901
878
|
responseType: "arraybuffer",
|
|
902
879
|
maxRedirects: 5,
|
|
903
880
|
});
|
|
@@ -917,11 +894,10 @@ class ServerSideUtils {
|
|
|
917
894
|
console.error("Not a valid base64 image");
|
|
918
895
|
throw new Error("Not a valid base64 image");
|
|
919
896
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
throw new Error(`The image should be less than 2mb`);
|
|
897
|
+
const isSizeValid = base64Image.length * 0.75 <= MAX_IMAGE_SIZE_MB * 1024 * 1024;
|
|
898
|
+
if (!isSizeValid) {
|
|
899
|
+
console.error(`The image should be less than ${MAX_IMAGE_SIZE_MB}mb`);
|
|
900
|
+
throw new Error(`The image should be less than ${MAX_IMAGE_SIZE_MB}mb`);
|
|
925
901
|
}
|
|
926
902
|
// all is fine
|
|
927
903
|
return true;
|
|
@@ -933,6 +909,97 @@ class ServerSideUtils {
|
|
|
933
909
|
}
|
|
934
910
|
}
|
|
935
911
|
|
|
912
|
+
/**
|
|
913
|
+
* Payment reasons accepted in the `reasonId` field.
|
|
914
|
+
*/
|
|
915
|
+
exports.Reasons = void 0;
|
|
916
|
+
(function (Reasons) {
|
|
917
|
+
Reasons[Reasons["HOUSING_ARRANGEMENT"] = 1] = "HOUSING_ARRANGEMENT";
|
|
918
|
+
Reasons[Reasons["FINANCIAL_AID"] = 2] = "FINANCIAL_AID";
|
|
919
|
+
Reasons[Reasons["FAMILY_SUPPORT"] = 3] = "FAMILY_SUPPORT";
|
|
920
|
+
Reasons[Reasons["TRAVEL_FUND"] = 4] = "TRAVEL_FUND";
|
|
921
|
+
Reasons[Reasons["REAL_ESTATE_PURCHASE"] = 5] = "REAL_ESTATE_PURCHASE";
|
|
922
|
+
Reasons[Reasons["FURNITURE_PURCHASE"] = 6] = "FURNITURE_PURCHASE";
|
|
923
|
+
Reasons[Reasons["EDUCATION"] = 7] = "EDUCATION";
|
|
924
|
+
Reasons[Reasons["MEDICAL_EXPENSES"] = 8] = "MEDICAL_EXPENSES";
|
|
925
|
+
Reasons[Reasons["OTHER"] = 9] = "OTHER";
|
|
926
|
+
Reasons[Reasons["DEBT_PAYMENT"] = 10] = "DEBT_PAYMENT";
|
|
927
|
+
Reasons[Reasons["TOURISM"] = 11] = "TOURISM";
|
|
928
|
+
Reasons[Reasons["SELF_SHIPPING"] = 12] = "SELF_SHIPPING";
|
|
929
|
+
Reasons[Reasons["ACCOUNT_ACTIVATION"] = 13] = "ACCOUNT_ACTIVATION";
|
|
930
|
+
Reasons[Reasons["SPORTS_ACTIVITIES"] = 14] = "SPORTS_ACTIVITIES";
|
|
931
|
+
Reasons[Reasons["DONATION"] = 15] = "DONATION";
|
|
932
|
+
Reasons[Reasons["AFFILIATE_COMMISSION"] = 16] = "AFFILIATE_COMMISSION";
|
|
933
|
+
Reasons[Reasons["SALARY"] = 17] = "SALARY";
|
|
934
|
+
Reasons[Reasons["SAVINGS"] = 18] = "SAVINGS";
|
|
935
|
+
Reasons[Reasons["RENT_AND_LEASING"] = 19] = "RENT_AND_LEASING";
|
|
936
|
+
Reasons[Reasons["SHARED_EXPENSES"] = 20] = "SHARED_EXPENSES";
|
|
937
|
+
Reasons[Reasons["SERVICE_PAYMENT"] = 21] = "SERVICE_PAYMENT";
|
|
938
|
+
Reasons[Reasons["GIFT"] = 22] = "GIFT";
|
|
939
|
+
Reasons[Reasons["CRYPTOCURRENCY_PURCHASE"] = 23] = "CRYPTOCURRENCY_PURCHASE";
|
|
940
|
+
Reasons[Reasons["OPERATING_EXPENSES"] = 24] = "OPERATING_EXPENSES";
|
|
941
|
+
Reasons[Reasons["CURRENCY_EXCHANGE"] = 25] = "CURRENCY_EXCHANGE";
|
|
942
|
+
Reasons[Reasons["ACCOMMODATION"] = 26] = "ACCOMMODATION";
|
|
943
|
+
Reasons[Reasons["EQUIPMENT_PURCHASE"] = 27] = "EQUIPMENT_PURCHASE";
|
|
944
|
+
Reasons[Reasons["CONSULTING"] = 28] = "CONSULTING";
|
|
945
|
+
Reasons[Reasons["SOFTWARE_DEVELOPMENT"] = 29] = "SOFTWARE_DEVELOPMENT";
|
|
946
|
+
Reasons[Reasons["REFUND"] = 30] = "REFUND";
|
|
947
|
+
Reasons[Reasons["PACKAGE_DELIVERY"] = 31] = "PACKAGE_DELIVERY";
|
|
948
|
+
Reasons[Reasons["PERSONAL_EXPENSES"] = 32] = "PERSONAL_EXPENSES";
|
|
949
|
+
Reasons[Reasons["INVESTMENT"] = 33] = "INVESTMENT";
|
|
950
|
+
Reasons[Reasons["BILL_PAYMENT"] = 34] = "BILL_PAYMENT";
|
|
951
|
+
Reasons[Reasons["HOST_PAYMENT"] = 35] = "HOST_PAYMENT";
|
|
952
|
+
Reasons[Reasons["TRANSPORTATION"] = 36] = "TRANSPORTATION";
|
|
953
|
+
Reasons[Reasons["LOAN"] = 37] = "LOAN";
|
|
954
|
+
Reasons[Reasons["BONUS"] = 38] = "BONUS";
|
|
955
|
+
Reasons[Reasons["HALLOWEEN_REMITTANCE"] = 39] = "HALLOWEEN_REMITTANCE";
|
|
956
|
+
Reasons[Reasons["PLINK_REMITTANCE"] = 41] = "PLINK_REMITTANCE";
|
|
957
|
+
Reasons[Reasons["R1_2023"] = 78] = "R1_2023";
|
|
958
|
+
Reasons[Reasons["HAPPYWEEK"] = 79] = "HAPPYWEEK";
|
|
959
|
+
Reasons[Reasons["SENDING_YOU_A_KISS"] = 80] = "SENDING_YOU_A_KISS";
|
|
960
|
+
})(exports.Reasons || (exports.Reasons = {}));
|
|
961
|
+
|
|
962
|
+
const DepositAccountTypesList = {
|
|
963
|
+
/**
|
|
964
|
+
* Banco Metropolitano (Cuba) Bank Account
|
|
965
|
+
*/
|
|
966
|
+
BANMET_BANK_ACCOUNT: 0,
|
|
967
|
+
/**
|
|
968
|
+
* Banco Popular de Ahorro
|
|
969
|
+
*/
|
|
970
|
+
BPA_BANK_ACCOUNT: 1,
|
|
971
|
+
/**
|
|
972
|
+
* Banco de Credito y Comercio (Cuba) Bank Account
|
|
973
|
+
*/
|
|
974
|
+
BANDEC_BANK_ACCOUNT: 2,
|
|
975
|
+
/**
|
|
976
|
+
* Banco Metropilitano (Cuba) card
|
|
977
|
+
*/
|
|
978
|
+
BANMET_CARD: 3,
|
|
979
|
+
/**
|
|
980
|
+
* Banco Popular de Ahorro (Cuba) card
|
|
981
|
+
*/
|
|
982
|
+
BPA_CARD: 4,
|
|
983
|
+
/**
|
|
984
|
+
* Not available anymore
|
|
985
|
+
* @deprecated
|
|
986
|
+
*/
|
|
987
|
+
AIS_CUC_CARD: 5,
|
|
988
|
+
/**
|
|
989
|
+
* Not available
|
|
990
|
+
* @deprecated
|
|
991
|
+
*/
|
|
992
|
+
AIS_USD_CARD: 6,
|
|
993
|
+
/**
|
|
994
|
+
* For international bank accounts
|
|
995
|
+
*/
|
|
996
|
+
OTHER: 7,
|
|
997
|
+
/**
|
|
998
|
+
* Banco de Credito y comercio card
|
|
999
|
+
*/
|
|
1000
|
+
BANDEC_CARD: 8,
|
|
1001
|
+
};
|
|
1002
|
+
|
|
936
1003
|
const SERVER_MODE = "Development"; // Move the constant here
|
|
937
1004
|
|
|
938
1005
|
/**
|
|
@@ -943,7 +1010,6 @@ const SERVER_MODE = "Development"; // Move the constant here
|
|
|
943
1010
|
* Developed by Yosleivy Baez Acosta
|
|
944
1011
|
* GitHub: https://github.com/yosle/tropipayjs
|
|
945
1012
|
*
|
|
946
|
-
* @version 0.1.11
|
|
947
1013
|
* @license MIT
|
|
948
1014
|
*/
|
|
949
1015
|
if (typeof window !== "undefined") {
|
|
@@ -952,9 +1018,15 @@ if (typeof window !== "undefined") {
|
|
|
952
1018
|
throw new Error(err_msg);
|
|
953
1019
|
}
|
|
954
1020
|
|
|
955
|
-
exports.
|
|
1021
|
+
exports.API_BASE = API_BASE;
|
|
1022
|
+
exports.Accounts = Accounts;
|
|
1023
|
+
exports.DepositAccountTypesList = DepositAccountTypesList;
|
|
1024
|
+
exports.DepositAccounts = DepositAccounts;
|
|
956
1025
|
exports.MAX_IMAGE_SIZE_MB = MAX_IMAGE_SIZE_MB;
|
|
1026
|
+
exports.PaymentCard = PaymentCard;
|
|
957
1027
|
exports.SERVER_MODE = SERVER_MODE;
|
|
958
1028
|
exports.ServerSideUtils = ServerSideUtils;
|
|
1029
|
+
exports.Transfers = Transfers;
|
|
959
1030
|
exports.Tropipay = Tropipay;
|
|
1031
|
+
exports.TropipayHooks = TropipayHooks;
|
|
960
1032
|
//# sourceMappingURL=index.js.map
|