@bloque/payments 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +535 -0
- package/dist/client.d.ts +15 -0
- package/dist/errors/bloque-error.d.ts +18 -0
- package/dist/http/http-client.d.ts +35 -0
- package/dist/index.cjs +312 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +278 -0
- package/dist/resources/base.d.ts +5 -0
- package/dist/resources/checkout.d.ts +7 -0
- package/dist/resources/payment.d.ts +33 -0
- package/dist/types/checkout.d.ts +173 -0
- package/dist/types/common.d.ts +12 -0
- package/dist/types/customer.d.ts +12 -0
- package/package.json +55 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
Bloque: ()=>Bloque
|
|
28
|
+
});
|
|
29
|
+
var package_namespaceObject = JSON.parse('{"UU":"@bloque/payments","rE":"0.0.1"}');
|
|
30
|
+
class BloqueError extends Error {
|
|
31
|
+
constructor(message){
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = 'BloqueError';
|
|
34
|
+
Object.setPrototypeOf(this, BloqueError.prototype);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
class APIError extends BloqueError {
|
|
38
|
+
status;
|
|
39
|
+
code;
|
|
40
|
+
constructor(message, status, code){
|
|
41
|
+
super(message), this.status = status, this.code = code;
|
|
42
|
+
this.name = 'APIError';
|
|
43
|
+
Object.setPrototypeOf(this, APIError.prototype);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
class AuthenticationError extends APIError {
|
|
47
|
+
constructor(message, code){
|
|
48
|
+
super(message, 401, code);
|
|
49
|
+
this.name = 'AuthenticationError';
|
|
50
|
+
Object.setPrototypeOf(this, AuthenticationError.prototype);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
class RateLimitError extends APIError {
|
|
54
|
+
constructor(message, code){
|
|
55
|
+
super(message, 429, code);
|
|
56
|
+
this.name = 'RateLimitError';
|
|
57
|
+
Object.setPrototypeOf(this, RateLimitError.prototype);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const SDK_NAME = package_namespaceObject.UU;
|
|
61
|
+
const SDK_VERSION = package_namespaceObject.rE;
|
|
62
|
+
class HttpClient {
|
|
63
|
+
baseURL;
|
|
64
|
+
apiKey;
|
|
65
|
+
timeout;
|
|
66
|
+
maxRetries;
|
|
67
|
+
userAgent;
|
|
68
|
+
constructor(config){
|
|
69
|
+
this.baseURL = config.baseURL;
|
|
70
|
+
this.apiKey = config.apiKey;
|
|
71
|
+
this.timeout = config.timeout ?? 10000;
|
|
72
|
+
this.maxRetries = config.maxRetries ?? 2;
|
|
73
|
+
this.userAgent = `${SDK_NAME}/${SDK_VERSION}`;
|
|
74
|
+
}
|
|
75
|
+
async request(options) {
|
|
76
|
+
const url = this.buildURL(options.path, options.params);
|
|
77
|
+
const headers = this.buildHeaders(options.headers, options.idempotencyKey);
|
|
78
|
+
let lastError;
|
|
79
|
+
for(let attempt = 0; attempt <= this.maxRetries; attempt++)try {
|
|
80
|
+
const controller = new AbortController();
|
|
81
|
+
const timeoutId = setTimeout(()=>controller.abort(), this.timeout);
|
|
82
|
+
const response = await fetch(url, {
|
|
83
|
+
method: options.method,
|
|
84
|
+
headers,
|
|
85
|
+
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
86
|
+
signal: controller.signal
|
|
87
|
+
});
|
|
88
|
+
clearTimeout(timeoutId);
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
const error = await this.parseError(response);
|
|
91
|
+
this.isRetryableHttpStatus(response.status);
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
if (204 === response.status) return;
|
|
95
|
+
return await response.json();
|
|
96
|
+
} catch (error) {
|
|
97
|
+
lastError = error;
|
|
98
|
+
if (!this.isRetryableError(error)) throw error;
|
|
99
|
+
if (attempt === this.maxRetries) break;
|
|
100
|
+
await this.sleep(this.backoff(attempt));
|
|
101
|
+
}
|
|
102
|
+
throw lastError ?? new BloqueError('Request failed after retries');
|
|
103
|
+
}
|
|
104
|
+
buildURL(path, params) {
|
|
105
|
+
const url = new URL(path, this.baseURL);
|
|
106
|
+
if (params) {
|
|
107
|
+
for (const [key, value] of Object.entries(params))if (null != value) url.searchParams.append(key, String(value));
|
|
108
|
+
}
|
|
109
|
+
return url.toString();
|
|
110
|
+
}
|
|
111
|
+
buildHeaders(customHeaders, idempotencyKey) {
|
|
112
|
+
return {
|
|
113
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
114
|
+
'Content-Type': 'application/json',
|
|
115
|
+
'User-Agent': this.userAgent,
|
|
116
|
+
...idempotencyKey ? {
|
|
117
|
+
'Idempotency-Key': idempotencyKey
|
|
118
|
+
} : {},
|
|
119
|
+
...customHeaders
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
async parseError(response) {
|
|
123
|
+
let payload;
|
|
124
|
+
try {
|
|
125
|
+
payload = await response.json();
|
|
126
|
+
} catch {
|
|
127
|
+
payload = {
|
|
128
|
+
message: response.statusText
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const message = payload.message || 'Request failed';
|
|
132
|
+
const code = payload.code;
|
|
133
|
+
switch(response.status){
|
|
134
|
+
case 401:
|
|
135
|
+
return new AuthenticationError(message, code);
|
|
136
|
+
case 429:
|
|
137
|
+
return new RateLimitError(message, code);
|
|
138
|
+
case 400:
|
|
139
|
+
case 404:
|
|
140
|
+
case 409:
|
|
141
|
+
case 422:
|
|
142
|
+
return new APIError(message, response.status, code);
|
|
143
|
+
default:
|
|
144
|
+
return new APIError(message, response.status, code);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
isRetryableHttpStatus(status) {
|
|
148
|
+
return status >= 500 || 429 === status;
|
|
149
|
+
}
|
|
150
|
+
isRetryableError(error) {
|
|
151
|
+
if (error instanceof AuthenticationError || error instanceof APIError || error instanceof BloqueError) return false;
|
|
152
|
+
if (error instanceof RateLimitError) return true;
|
|
153
|
+
error instanceof DOMException && error.name;
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
backoff(attempt) {
|
|
157
|
+
const base = 300;
|
|
158
|
+
const max = 5000;
|
|
159
|
+
return Math.min(base * 2 ** attempt, max);
|
|
160
|
+
}
|
|
161
|
+
sleep(ms) {
|
|
162
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
163
|
+
}
|
|
164
|
+
get(path, params) {
|
|
165
|
+
return this.request({
|
|
166
|
+
method: 'GET',
|
|
167
|
+
path,
|
|
168
|
+
params
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
post(path, body, options) {
|
|
172
|
+
return this.request({
|
|
173
|
+
method: 'POST',
|
|
174
|
+
path,
|
|
175
|
+
body,
|
|
176
|
+
idempotencyKey: options?.idempotencyKey
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
patch(path, body) {
|
|
180
|
+
return this.request({
|
|
181
|
+
method: 'PATCH',
|
|
182
|
+
path,
|
|
183
|
+
body
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
delete(path) {
|
|
187
|
+
return this.request({
|
|
188
|
+
method: 'DELETE',
|
|
189
|
+
path
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
class BaseResource {
|
|
194
|
+
http;
|
|
195
|
+
constructor(http){
|
|
196
|
+
this.http = http;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
class CheckoutResource extends BaseResource {
|
|
200
|
+
async create(params) {
|
|
201
|
+
const items = params.items.map((item)=>({
|
|
202
|
+
name: item.name,
|
|
203
|
+
price: item.amount.toString(),
|
|
204
|
+
units: item.quantity,
|
|
205
|
+
image_url: item.image_url
|
|
206
|
+
}));
|
|
207
|
+
const payload = {
|
|
208
|
+
name: params.name,
|
|
209
|
+
description: params.description,
|
|
210
|
+
asset: 'dUSD/6',
|
|
211
|
+
payment_type: 'shopping_cart',
|
|
212
|
+
image_url: params.image_url,
|
|
213
|
+
items: items,
|
|
214
|
+
redirect_url: params.success_url,
|
|
215
|
+
expires_at: params.expires_at,
|
|
216
|
+
metadata: params.metadata
|
|
217
|
+
};
|
|
218
|
+
const response = await this.http.post('/checkout', payload);
|
|
219
|
+
return {
|
|
220
|
+
id: response.payment.urn,
|
|
221
|
+
object: 'checkout',
|
|
222
|
+
url: response.payment.url,
|
|
223
|
+
status: response.payment.summary.status,
|
|
224
|
+
amount_total: response.payment.price,
|
|
225
|
+
amount_subtotal: response.payment.price,
|
|
226
|
+
currency: 'USD',
|
|
227
|
+
items: params.items,
|
|
228
|
+
created_at: response.payment.created_at,
|
|
229
|
+
updated_at: response.payment.updated_at,
|
|
230
|
+
expires_at: response.payment.expires_at,
|
|
231
|
+
metadata: response.payment.metadata
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
async retrieve(checkoutId) {
|
|
235
|
+
return this.http.get(`/checkout/${checkoutId}`);
|
|
236
|
+
}
|
|
237
|
+
async cancel(checkoutId) {
|
|
238
|
+
return this.http.post(`/checkout/${checkoutId}/cancel`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
class PaymentResource extends BaseResource {
|
|
242
|
+
async create(params) {
|
|
243
|
+
const paymentPayload = this.buildPaymentPayload(params.payment);
|
|
244
|
+
const paymentResponse = await this.http.post(`/checkout/${params.checkoutId}/pay/${params.payment.type}`, paymentPayload);
|
|
245
|
+
return paymentResponse;
|
|
246
|
+
}
|
|
247
|
+
buildPaymentPayload(payment) {
|
|
248
|
+
switch(payment.type){
|
|
249
|
+
case 'card':
|
|
250
|
+
return this.buildCardPayload(payment.data);
|
|
251
|
+
case 'pse':
|
|
252
|
+
return this.buildPSEPayload(payment.data);
|
|
253
|
+
case 'cash':
|
|
254
|
+
return this.buildCashPayload(payment.data);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
buildCardPayload(data) {
|
|
258
|
+
return {
|
|
259
|
+
customer_email: data.email || '',
|
|
260
|
+
number: data.cardNumber,
|
|
261
|
+
cvc: data.cvv,
|
|
262
|
+
exp_month: data.expiryMonth,
|
|
263
|
+
exp_year: data.expiryYear,
|
|
264
|
+
card_holder: data.cardholderName
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
buildPSEPayload(data) {
|
|
268
|
+
return {
|
|
269
|
+
customer_email: data.email,
|
|
270
|
+
person_type: data.personType,
|
|
271
|
+
document_type: data.documentType,
|
|
272
|
+
document_number: data.documentNumber,
|
|
273
|
+
bank_code: data.bankCode
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
buildCashPayload(data) {
|
|
277
|
+
return {
|
|
278
|
+
customer_email: data.email,
|
|
279
|
+
document_type: data.documentType,
|
|
280
|
+
document_number: data.documentNumber,
|
|
281
|
+
full_name: data.fullName
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
class Bloque {
|
|
286
|
+
#httpClient;
|
|
287
|
+
#config;
|
|
288
|
+
checkout;
|
|
289
|
+
payments;
|
|
290
|
+
constructor(config){
|
|
291
|
+
if (!config.apiKey) throw new Error('API key is required');
|
|
292
|
+
this.#config = config;
|
|
293
|
+
this.#httpClient = new HttpClient({
|
|
294
|
+
baseURL: 'https: //api.bloque.app/api/payments',
|
|
295
|
+
apiKey: this.#config.apiKey,
|
|
296
|
+
timeout: this.#config.timeout,
|
|
297
|
+
maxRetries: this.#config.maxRetries
|
|
298
|
+
});
|
|
299
|
+
this.initializeResources();
|
|
300
|
+
}
|
|
301
|
+
initializeResources() {
|
|
302
|
+
this.checkout = new CheckoutResource(this.#httpClient);
|
|
303
|
+
this.payments = new PaymentResource(this.#httpClient);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
exports.Bloque = __webpack_exports__.Bloque;
|
|
307
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
308
|
+
"Bloque"
|
|
309
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
310
|
+
Object.defineProperty(exports, '__esModule', {
|
|
311
|
+
value: true
|
|
312
|
+
});
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
var package_namespaceObject = JSON.parse('{"UU":"@bloque/payments","rE":"0.0.1"}');
|
|
2
|
+
class BloqueError extends Error {
|
|
3
|
+
constructor(message){
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = 'BloqueError';
|
|
6
|
+
Object.setPrototypeOf(this, BloqueError.prototype);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
class APIError extends BloqueError {
|
|
10
|
+
status;
|
|
11
|
+
code;
|
|
12
|
+
constructor(message, status, code){
|
|
13
|
+
super(message), this.status = status, this.code = code;
|
|
14
|
+
this.name = 'APIError';
|
|
15
|
+
Object.setPrototypeOf(this, APIError.prototype);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
class AuthenticationError extends APIError {
|
|
19
|
+
constructor(message, code){
|
|
20
|
+
super(message, 401, code);
|
|
21
|
+
this.name = 'AuthenticationError';
|
|
22
|
+
Object.setPrototypeOf(this, AuthenticationError.prototype);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
class RateLimitError extends APIError {
|
|
26
|
+
constructor(message, code){
|
|
27
|
+
super(message, 429, code);
|
|
28
|
+
this.name = 'RateLimitError';
|
|
29
|
+
Object.setPrototypeOf(this, RateLimitError.prototype);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const SDK_NAME = package_namespaceObject.UU;
|
|
33
|
+
const SDK_VERSION = package_namespaceObject.rE;
|
|
34
|
+
class HttpClient {
|
|
35
|
+
baseURL;
|
|
36
|
+
apiKey;
|
|
37
|
+
timeout;
|
|
38
|
+
maxRetries;
|
|
39
|
+
userAgent;
|
|
40
|
+
constructor(config){
|
|
41
|
+
this.baseURL = config.baseURL;
|
|
42
|
+
this.apiKey = config.apiKey;
|
|
43
|
+
this.timeout = config.timeout ?? 10000;
|
|
44
|
+
this.maxRetries = config.maxRetries ?? 2;
|
|
45
|
+
this.userAgent = `${SDK_NAME}/${SDK_VERSION}`;
|
|
46
|
+
}
|
|
47
|
+
async request(options) {
|
|
48
|
+
const url = this.buildURL(options.path, options.params);
|
|
49
|
+
const headers = this.buildHeaders(options.headers, options.idempotencyKey);
|
|
50
|
+
let lastError;
|
|
51
|
+
for(let attempt = 0; attempt <= this.maxRetries; attempt++)try {
|
|
52
|
+
const controller = new AbortController();
|
|
53
|
+
const timeoutId = setTimeout(()=>controller.abort(), this.timeout);
|
|
54
|
+
const response = await fetch(url, {
|
|
55
|
+
method: options.method,
|
|
56
|
+
headers,
|
|
57
|
+
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
58
|
+
signal: controller.signal
|
|
59
|
+
});
|
|
60
|
+
clearTimeout(timeoutId);
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
const error = await this.parseError(response);
|
|
63
|
+
this.isRetryableHttpStatus(response.status);
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
if (204 === response.status) return;
|
|
67
|
+
return await response.json();
|
|
68
|
+
} catch (error) {
|
|
69
|
+
lastError = error;
|
|
70
|
+
if (!this.isRetryableError(error)) throw error;
|
|
71
|
+
if (attempt === this.maxRetries) break;
|
|
72
|
+
await this.sleep(this.backoff(attempt));
|
|
73
|
+
}
|
|
74
|
+
throw lastError ?? new BloqueError('Request failed after retries');
|
|
75
|
+
}
|
|
76
|
+
buildURL(path, params) {
|
|
77
|
+
const url = new URL(path, this.baseURL);
|
|
78
|
+
if (params) {
|
|
79
|
+
for (const [key, value] of Object.entries(params))if (null != value) url.searchParams.append(key, String(value));
|
|
80
|
+
}
|
|
81
|
+
return url.toString();
|
|
82
|
+
}
|
|
83
|
+
buildHeaders(customHeaders, idempotencyKey) {
|
|
84
|
+
return {
|
|
85
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
86
|
+
'Content-Type': 'application/json',
|
|
87
|
+
'User-Agent': this.userAgent,
|
|
88
|
+
...idempotencyKey ? {
|
|
89
|
+
'Idempotency-Key': idempotencyKey
|
|
90
|
+
} : {},
|
|
91
|
+
...customHeaders
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async parseError(response) {
|
|
95
|
+
let payload;
|
|
96
|
+
try {
|
|
97
|
+
payload = await response.json();
|
|
98
|
+
} catch {
|
|
99
|
+
payload = {
|
|
100
|
+
message: response.statusText
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const message = payload.message || 'Request failed';
|
|
104
|
+
const code = payload.code;
|
|
105
|
+
switch(response.status){
|
|
106
|
+
case 401:
|
|
107
|
+
return new AuthenticationError(message, code);
|
|
108
|
+
case 429:
|
|
109
|
+
return new RateLimitError(message, code);
|
|
110
|
+
case 400:
|
|
111
|
+
case 404:
|
|
112
|
+
case 409:
|
|
113
|
+
case 422:
|
|
114
|
+
return new APIError(message, response.status, code);
|
|
115
|
+
default:
|
|
116
|
+
return new APIError(message, response.status, code);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
isRetryableHttpStatus(status) {
|
|
120
|
+
return status >= 500 || 429 === status;
|
|
121
|
+
}
|
|
122
|
+
isRetryableError(error) {
|
|
123
|
+
if (error instanceof AuthenticationError || error instanceof APIError || error instanceof BloqueError) return false;
|
|
124
|
+
if (error instanceof RateLimitError) return true;
|
|
125
|
+
error instanceof DOMException && error.name;
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
backoff(attempt) {
|
|
129
|
+
const base = 300;
|
|
130
|
+
const max = 5000;
|
|
131
|
+
return Math.min(base * 2 ** attempt, max);
|
|
132
|
+
}
|
|
133
|
+
sleep(ms) {
|
|
134
|
+
return new Promise((resolve)=>setTimeout(resolve, ms));
|
|
135
|
+
}
|
|
136
|
+
get(path, params) {
|
|
137
|
+
return this.request({
|
|
138
|
+
method: 'GET',
|
|
139
|
+
path,
|
|
140
|
+
params
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
post(path, body, options) {
|
|
144
|
+
return this.request({
|
|
145
|
+
method: 'POST',
|
|
146
|
+
path,
|
|
147
|
+
body,
|
|
148
|
+
idempotencyKey: options?.idempotencyKey
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
patch(path, body) {
|
|
152
|
+
return this.request({
|
|
153
|
+
method: 'PATCH',
|
|
154
|
+
path,
|
|
155
|
+
body
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
delete(path) {
|
|
159
|
+
return this.request({
|
|
160
|
+
method: 'DELETE',
|
|
161
|
+
path
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
class BaseResource {
|
|
166
|
+
http;
|
|
167
|
+
constructor(http){
|
|
168
|
+
this.http = http;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
class CheckoutResource extends BaseResource {
|
|
172
|
+
async create(params) {
|
|
173
|
+
const items = params.items.map((item)=>({
|
|
174
|
+
name: item.name,
|
|
175
|
+
price: item.amount.toString(),
|
|
176
|
+
units: item.quantity,
|
|
177
|
+
image_url: item.image_url
|
|
178
|
+
}));
|
|
179
|
+
const payload = {
|
|
180
|
+
name: params.name,
|
|
181
|
+
description: params.description,
|
|
182
|
+
asset: 'dUSD/6',
|
|
183
|
+
payment_type: 'shopping_cart',
|
|
184
|
+
image_url: params.image_url,
|
|
185
|
+
items: items,
|
|
186
|
+
redirect_url: params.success_url,
|
|
187
|
+
expires_at: params.expires_at,
|
|
188
|
+
metadata: params.metadata
|
|
189
|
+
};
|
|
190
|
+
const response = await this.http.post('/checkout', payload);
|
|
191
|
+
return {
|
|
192
|
+
id: response.payment.urn,
|
|
193
|
+
object: 'checkout',
|
|
194
|
+
url: response.payment.url,
|
|
195
|
+
status: response.payment.summary.status,
|
|
196
|
+
amount_total: response.payment.price,
|
|
197
|
+
amount_subtotal: response.payment.price,
|
|
198
|
+
currency: 'USD',
|
|
199
|
+
items: params.items,
|
|
200
|
+
created_at: response.payment.created_at,
|
|
201
|
+
updated_at: response.payment.updated_at,
|
|
202
|
+
expires_at: response.payment.expires_at,
|
|
203
|
+
metadata: response.payment.metadata
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
async retrieve(checkoutId) {
|
|
207
|
+
return this.http.get(`/checkout/${checkoutId}`);
|
|
208
|
+
}
|
|
209
|
+
async cancel(checkoutId) {
|
|
210
|
+
return this.http.post(`/checkout/${checkoutId}/cancel`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
class PaymentResource extends BaseResource {
|
|
214
|
+
async create(params) {
|
|
215
|
+
const paymentPayload = this.buildPaymentPayload(params.payment);
|
|
216
|
+
const paymentResponse = await this.http.post(`/checkout/${params.checkoutId}/pay/${params.payment.type}`, paymentPayload);
|
|
217
|
+
return paymentResponse;
|
|
218
|
+
}
|
|
219
|
+
buildPaymentPayload(payment) {
|
|
220
|
+
switch(payment.type){
|
|
221
|
+
case 'card':
|
|
222
|
+
return this.buildCardPayload(payment.data);
|
|
223
|
+
case 'pse':
|
|
224
|
+
return this.buildPSEPayload(payment.data);
|
|
225
|
+
case 'cash':
|
|
226
|
+
return this.buildCashPayload(payment.data);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
buildCardPayload(data) {
|
|
230
|
+
return {
|
|
231
|
+
customer_email: data.email || '',
|
|
232
|
+
number: data.cardNumber,
|
|
233
|
+
cvc: data.cvv,
|
|
234
|
+
exp_month: data.expiryMonth,
|
|
235
|
+
exp_year: data.expiryYear,
|
|
236
|
+
card_holder: data.cardholderName
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
buildPSEPayload(data) {
|
|
240
|
+
return {
|
|
241
|
+
customer_email: data.email,
|
|
242
|
+
person_type: data.personType,
|
|
243
|
+
document_type: data.documentType,
|
|
244
|
+
document_number: data.documentNumber,
|
|
245
|
+
bank_code: data.bankCode
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
buildCashPayload(data) {
|
|
249
|
+
return {
|
|
250
|
+
customer_email: data.email,
|
|
251
|
+
document_type: data.documentType,
|
|
252
|
+
document_number: data.documentNumber,
|
|
253
|
+
full_name: data.fullName
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
class Bloque {
|
|
258
|
+
#httpClient;
|
|
259
|
+
#config;
|
|
260
|
+
checkout;
|
|
261
|
+
payments;
|
|
262
|
+
constructor(config){
|
|
263
|
+
if (!config.apiKey) throw new Error('API key is required');
|
|
264
|
+
this.#config = config;
|
|
265
|
+
this.#httpClient = new HttpClient({
|
|
266
|
+
baseURL: 'https: //api.bloque.app/api/payments',
|
|
267
|
+
apiKey: this.#config.apiKey,
|
|
268
|
+
timeout: this.#config.timeout,
|
|
269
|
+
maxRetries: this.#config.maxRetries
|
|
270
|
+
});
|
|
271
|
+
this.initializeResources();
|
|
272
|
+
}
|
|
273
|
+
initializeResources() {
|
|
274
|
+
this.checkout = new CheckoutResource(this.#httpClient);
|
|
275
|
+
this.payments = new PaymentResource(this.#httpClient);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
export { Bloque };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Checkout, CheckoutParams } from '../types/checkout';
|
|
2
|
+
import { BaseResource } from './base';
|
|
3
|
+
export declare class CheckoutResource extends BaseResource {
|
|
4
|
+
create(params: CheckoutParams): Promise<Checkout>;
|
|
5
|
+
retrieve(checkoutId: string): Promise<Checkout>;
|
|
6
|
+
cancel(checkoutId: string): Promise<Checkout>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { CreatePaymentParams, PaymentResponse } from '@bloque/payments-core';
|
|
2
|
+
import { BaseResource } from './base';
|
|
3
|
+
export declare class PaymentResource extends BaseResource {
|
|
4
|
+
/**
|
|
5
|
+
* Create a payment for an existing checkout session
|
|
6
|
+
*
|
|
7
|
+
* @param params - Checkout ID and payment data
|
|
8
|
+
* @returns Payment response
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const payment = await bloque.payments.create({
|
|
13
|
+
* checkoutId: 'checkout_abc123',
|
|
14
|
+
* payment: {
|
|
15
|
+
* type: 'card',
|
|
16
|
+
* data: {
|
|
17
|
+
* cardNumber: '4111111111111111',
|
|
18
|
+
* cardholderName: 'John Doe',
|
|
19
|
+
* expiryMonth: '12',
|
|
20
|
+
* expiryYear: '2025',
|
|
21
|
+
* cvv: '123',
|
|
22
|
+
* email: 'john@example.com'
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
create(params: CreatePaymentParams): Promise<PaymentResponse>;
|
|
29
|
+
private buildPaymentPayload;
|
|
30
|
+
private buildCardPayload;
|
|
31
|
+
private buildPSEPayload;
|
|
32
|
+
private buildCashPayload;
|
|
33
|
+
}
|