@pague-dev/sdk-node 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/dist/index.cjs +265 -0
- package/dist/index.d.cts +437 -0
- package/dist/index.d.mts +437 -0
- package/dist/index.mjs +263 -0
- package/package.json +52 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
//#region src/charges/interfaces/charge.interface.d.ts
|
|
2
|
+
type ChargeStatus = 'active' | 'expired' | 'disabled' | 'paid';
|
|
3
|
+
type PaymentMethod = 'pix' | 'credit_card' | 'boleto';
|
|
4
|
+
type NotificationType = 'email';
|
|
5
|
+
interface Charge {
|
|
6
|
+
id: string;
|
|
7
|
+
projectId: string;
|
|
8
|
+
customerId?: string;
|
|
9
|
+
name: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
amount: number;
|
|
12
|
+
currency: string;
|
|
13
|
+
status: ChargeStatus;
|
|
14
|
+
slug: string;
|
|
15
|
+
url: string;
|
|
16
|
+
paymentMethods: PaymentMethod[];
|
|
17
|
+
maxInstallments?: number;
|
|
18
|
+
notifications: NotificationType[];
|
|
19
|
+
allowCoupons: boolean;
|
|
20
|
+
expiresAt?: string;
|
|
21
|
+
paymentsCount: number;
|
|
22
|
+
totalCollected: number;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
updatedAt?: string;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/interfaces.d.ts
|
|
28
|
+
type Response<T> = {
|
|
29
|
+
data: T;
|
|
30
|
+
error: null;
|
|
31
|
+
} | {
|
|
32
|
+
data: null;
|
|
33
|
+
error: ErrorResponse;
|
|
34
|
+
};
|
|
35
|
+
interface ErrorResponse {
|
|
36
|
+
statusCode: number | null;
|
|
37
|
+
error: string;
|
|
38
|
+
message: string;
|
|
39
|
+
details?: Record<string, unknown>;
|
|
40
|
+
timestamp?: string;
|
|
41
|
+
traceId?: string;
|
|
42
|
+
}
|
|
43
|
+
interface PaginatedResponse<T> {
|
|
44
|
+
items: T[];
|
|
45
|
+
total: number;
|
|
46
|
+
page: number;
|
|
47
|
+
limit: number;
|
|
48
|
+
totalPages: number;
|
|
49
|
+
}
|
|
50
|
+
interface PaginationOptions {
|
|
51
|
+
page?: number;
|
|
52
|
+
limit?: number;
|
|
53
|
+
}
|
|
54
|
+
interface GetOptions {
|
|
55
|
+
query?: Record<string, unknown>;
|
|
56
|
+
}
|
|
57
|
+
interface PostOptions {
|
|
58
|
+
query?: Record<string, unknown>;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/charges/interfaces/create-charge.interface.d.ts
|
|
62
|
+
interface CreateChargeOptions {
|
|
63
|
+
projectId: string;
|
|
64
|
+
name: string;
|
|
65
|
+
description?: string;
|
|
66
|
+
amount: number;
|
|
67
|
+
paymentMethods: PaymentMethod[];
|
|
68
|
+
expiresAt?: string;
|
|
69
|
+
customerId?: string;
|
|
70
|
+
}
|
|
71
|
+
type CreateChargeResponse = Response<Charge>;
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/charges/interfaces/get-charge.interface.d.ts
|
|
74
|
+
type GetChargeResponse = Response<Charge>;
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/charges/interfaces/list-charges.interface.d.ts
|
|
77
|
+
interface ListChargesOptions extends PaginationOptions {
|
|
78
|
+
search?: string;
|
|
79
|
+
status?: ChargeStatus;
|
|
80
|
+
projectId?: string;
|
|
81
|
+
}
|
|
82
|
+
type ListChargesResponse = Response<PaginatedResponse<Charge>>;
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/customers/interfaces/customer.interface.d.ts
|
|
85
|
+
type DocumentType = 'cpf' | 'cnpj';
|
|
86
|
+
interface Customer {
|
|
87
|
+
id: string;
|
|
88
|
+
name: string;
|
|
89
|
+
email?: string;
|
|
90
|
+
phone?: string;
|
|
91
|
+
documentType: DocumentType;
|
|
92
|
+
document: string;
|
|
93
|
+
createdAt: string;
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/customers/interfaces/create-customer.interface.d.ts
|
|
97
|
+
interface CreateCustomerOptions {
|
|
98
|
+
name: string;
|
|
99
|
+
document: string;
|
|
100
|
+
email?: string;
|
|
101
|
+
phone?: string;
|
|
102
|
+
}
|
|
103
|
+
type CreateCustomerResponse = Response<Customer>;
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/customers/interfaces/list-customers.interface.d.ts
|
|
106
|
+
interface ListCustomersOptions extends PaginationOptions {
|
|
107
|
+
search?: string;
|
|
108
|
+
}
|
|
109
|
+
type ListCustomersResponse = Response<PaginatedResponse<Customer>>;
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/common/base-resource.d.ts
|
|
112
|
+
/**
|
|
113
|
+
* Base class for API resources that follow CRUD patterns.
|
|
114
|
+
* Provides common create, list, and get operations.
|
|
115
|
+
*/
|
|
116
|
+
declare abstract class BaseResource<TEntity, TCreateOptions = never, TListOptions extends object = object> {
|
|
117
|
+
protected readonly pdev: Pdev;
|
|
118
|
+
protected abstract readonly endpoint: string;
|
|
119
|
+
constructor(pdev: Pdev);
|
|
120
|
+
/**
|
|
121
|
+
* Create a new entity
|
|
122
|
+
*/
|
|
123
|
+
create(options: TCreateOptions): Promise<Response<TEntity>>;
|
|
124
|
+
/**
|
|
125
|
+
* List entities with pagination
|
|
126
|
+
*/
|
|
127
|
+
list(options?: TListOptions): Promise<Response<PaginatedResponse<TEntity>>>;
|
|
128
|
+
/**
|
|
129
|
+
* Get a single entity by ID
|
|
130
|
+
*/
|
|
131
|
+
get(id: string): Promise<Response<TEntity>>;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Base class for resources that only support create operations
|
|
135
|
+
*/
|
|
136
|
+
declare abstract class CreateOnlyResource<TEntity, TCreateOptions> {
|
|
137
|
+
protected readonly pdev: Pdev;
|
|
138
|
+
protected abstract readonly endpoint: string;
|
|
139
|
+
constructor(pdev: Pdev);
|
|
140
|
+
create(options: TCreateOptions): Promise<Response<TEntity>>;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Base class for resources that only support get operations
|
|
144
|
+
*/
|
|
145
|
+
declare abstract class GetOnlyResource<TEntity> {
|
|
146
|
+
protected readonly pdev: Pdev;
|
|
147
|
+
protected abstract readonly endpoint: string;
|
|
148
|
+
constructor(pdev: Pdev);
|
|
149
|
+
get(id: string): Promise<Response<TEntity>>;
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/charges/charges.d.ts
|
|
153
|
+
declare class Charges extends BaseResource<Charge, CreateChargeOptions, ListChargesOptions> {
|
|
154
|
+
protected readonly endpoint = "/charges";
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/customers/customers.d.ts
|
|
158
|
+
declare class Customers extends BaseResource<Customer, CreateCustomerOptions, ListCustomersOptions> {
|
|
159
|
+
protected readonly endpoint = "/customers";
|
|
160
|
+
}
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/pix/interfaces/pix.interface.d.ts
|
|
163
|
+
type PixStatus = 'pending' | 'completed' | 'failed' | 'cancelled';
|
|
164
|
+
interface PixCharge {
|
|
165
|
+
id: string;
|
|
166
|
+
status: PixStatus;
|
|
167
|
+
amount: number;
|
|
168
|
+
currency: string;
|
|
169
|
+
pixCopyPaste: string;
|
|
170
|
+
expiresAt: string;
|
|
171
|
+
externalReference?: string;
|
|
172
|
+
customerId?: string;
|
|
173
|
+
createdAt: string;
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
//#region src/pix/interfaces/create-pix.interface.d.ts
|
|
177
|
+
interface CreatePixCustomer {
|
|
178
|
+
name: string;
|
|
179
|
+
document: string;
|
|
180
|
+
email?: string;
|
|
181
|
+
phone?: string;
|
|
182
|
+
}
|
|
183
|
+
interface CreatePixOptions {
|
|
184
|
+
amount: number;
|
|
185
|
+
description?: string;
|
|
186
|
+
customerId?: string;
|
|
187
|
+
customer?: CreatePixCustomer;
|
|
188
|
+
projectId?: string;
|
|
189
|
+
expiresIn?: number;
|
|
190
|
+
externalReference?: string;
|
|
191
|
+
metadata?: Record<string, unknown>;
|
|
192
|
+
}
|
|
193
|
+
type CreatePixResponse = Response<PixCharge>;
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region src/pix/pix.d.ts
|
|
196
|
+
declare class Pix extends CreateOnlyResource<PixCharge, CreatePixOptions> {
|
|
197
|
+
protected readonly endpoint = "/pix";
|
|
198
|
+
}
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region src/projects/interfaces/project.interface.d.ts
|
|
201
|
+
interface Project {
|
|
202
|
+
id: string;
|
|
203
|
+
name: string;
|
|
204
|
+
description?: string;
|
|
205
|
+
color: string;
|
|
206
|
+
logoUrl?: string;
|
|
207
|
+
createdAt: string;
|
|
208
|
+
}
|
|
209
|
+
//#endregion
|
|
210
|
+
//#region src/projects/interfaces/create-project.interface.d.ts
|
|
211
|
+
interface CreateProjectOptions {
|
|
212
|
+
name: string;
|
|
213
|
+
description?: string;
|
|
214
|
+
color: string;
|
|
215
|
+
logoUrl?: string;
|
|
216
|
+
}
|
|
217
|
+
type CreateProjectResponse = Response<Project>;
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region src/projects/interfaces/list-projects.interface.d.ts
|
|
220
|
+
type SortBy = 'createdAt' | 'updatedAt' | 'name';
|
|
221
|
+
type SortOrder = 'asc' | 'desc';
|
|
222
|
+
interface ListProjectsOptions extends PaginationOptions {
|
|
223
|
+
sortBy?: SortBy;
|
|
224
|
+
sortOrder?: SortOrder;
|
|
225
|
+
}
|
|
226
|
+
type ListProjectsResponse = Response<PaginatedResponse<Project>>;
|
|
227
|
+
//#endregion
|
|
228
|
+
//#region src/projects/projects.d.ts
|
|
229
|
+
declare class Projects extends BaseResource<Project, CreateProjectOptions, ListProjectsOptions> {
|
|
230
|
+
protected readonly endpoint = "/projects";
|
|
231
|
+
}
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region src/transactions/interfaces/transaction.interface.d.ts
|
|
234
|
+
type TransactionStatus = 'pending' | 'completed' | 'failed' | 'cancelled';
|
|
235
|
+
type TransactionType = 'payment' | 'fee' | 'refund' | 'chargeback' | 'withdrawal';
|
|
236
|
+
type TransactionPaymentMethod = 'pix' | 'credit_card' | 'boleto';
|
|
237
|
+
interface Transaction {
|
|
238
|
+
id: string;
|
|
239
|
+
status: TransactionStatus;
|
|
240
|
+
type: TransactionType;
|
|
241
|
+
paymentMethod: TransactionPaymentMethod;
|
|
242
|
+
amount: number;
|
|
243
|
+
currency: string;
|
|
244
|
+
description?: string;
|
|
245
|
+
externalReference?: string;
|
|
246
|
+
customerId?: string;
|
|
247
|
+
projectId?: string;
|
|
248
|
+
metadata?: Record<string, unknown>;
|
|
249
|
+
pixCopyPaste?: string;
|
|
250
|
+
expiresAt?: string;
|
|
251
|
+
paidAt?: string;
|
|
252
|
+
createdAt: string;
|
|
253
|
+
updatedAt?: string;
|
|
254
|
+
}
|
|
255
|
+
//#endregion
|
|
256
|
+
//#region src/transactions/interfaces/get-transaction.interface.d.ts
|
|
257
|
+
type GetTransactionResponse = Response<Transaction>;
|
|
258
|
+
//#endregion
|
|
259
|
+
//#region src/transactions/transactions.d.ts
|
|
260
|
+
declare class Transactions extends GetOnlyResource<Transaction> {
|
|
261
|
+
protected readonly endpoint = "/transactions";
|
|
262
|
+
}
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region src/pdev.d.ts
|
|
265
|
+
declare class Pdev {
|
|
266
|
+
readonly key: string;
|
|
267
|
+
private readonly baseUrl;
|
|
268
|
+
private readonly headers;
|
|
269
|
+
readonly pix: Pix;
|
|
270
|
+
readonly customers: Customers;
|
|
271
|
+
readonly projects: Projects;
|
|
272
|
+
readonly charges: Charges;
|
|
273
|
+
readonly transactions: Transactions;
|
|
274
|
+
constructor(key?: string);
|
|
275
|
+
post<T>(path: string, body?: unknown, options?: PostOptions): Promise<Response<T>>;
|
|
276
|
+
get<T>(path: string, options?: GetOptions): Promise<Response<T>>;
|
|
277
|
+
private buildUrl;
|
|
278
|
+
private fetchRequest;
|
|
279
|
+
}
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/webhooks/interfaces.d.ts
|
|
282
|
+
/**
|
|
283
|
+
* Available webhook event types
|
|
284
|
+
*/
|
|
285
|
+
type WebhookEventType = 'payment_completed' | 'payment_failed' | 'refund_completed';
|
|
286
|
+
/**
|
|
287
|
+
* Base webhook payload structure
|
|
288
|
+
*/
|
|
289
|
+
interface WebhookPayload<T extends WebhookEventType, D> {
|
|
290
|
+
/** Type of event that triggered the webhook */
|
|
291
|
+
event: T;
|
|
292
|
+
/** Unique event identifier (typically the transaction ID) */
|
|
293
|
+
eventId: string;
|
|
294
|
+
/** ISO 8601 formatted timestamp of when the event occurred */
|
|
295
|
+
timestamp: string;
|
|
296
|
+
/** Event-specific data */
|
|
297
|
+
data: D;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Data payload for payment_completed event
|
|
301
|
+
*/
|
|
302
|
+
interface PaymentCompletedData {
|
|
303
|
+
/** Transaction identifier */
|
|
304
|
+
transactionId: string;
|
|
305
|
+
/** Payment amount */
|
|
306
|
+
amount: number;
|
|
307
|
+
/** Platform fees charged */
|
|
308
|
+
feeAmount: number;
|
|
309
|
+
/** Amount received after fees (amount - feeAmount) */
|
|
310
|
+
netAmount: number;
|
|
311
|
+
/** Currency code (e.g., "BRL") */
|
|
312
|
+
currency: string;
|
|
313
|
+
/** Payment method used (e.g., "pix") */
|
|
314
|
+
paymentMethod: string;
|
|
315
|
+
/** Payment status */
|
|
316
|
+
status: 'completed';
|
|
317
|
+
/** ISO 8601 timestamp of when payment was completed */
|
|
318
|
+
completedAt: string;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Data payload for payment_failed event
|
|
322
|
+
*/
|
|
323
|
+
interface PaymentFailedData {
|
|
324
|
+
/** Transaction identifier */
|
|
325
|
+
transactionId: string;
|
|
326
|
+
/** Payment amount */
|
|
327
|
+
amount: number;
|
|
328
|
+
/** Currency code (e.g., "BRL") */
|
|
329
|
+
currency: string;
|
|
330
|
+
/** Payment method used (e.g., "pix") */
|
|
331
|
+
paymentMethod: string;
|
|
332
|
+
/** Payment status */
|
|
333
|
+
status: 'failed';
|
|
334
|
+
/** ISO 8601 timestamp of when payment failed */
|
|
335
|
+
failedAt: string;
|
|
336
|
+
/** Reason for failure (e.g., "expired", "insufficient_funds") */
|
|
337
|
+
failureReason: string;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Data payload for refund_completed event
|
|
341
|
+
*/
|
|
342
|
+
interface RefundCompletedData {
|
|
343
|
+
/** Refund transaction identifier */
|
|
344
|
+
refundTransactionId: string;
|
|
345
|
+
/** Original payment transaction ID that was refunded */
|
|
346
|
+
originalTransactionId: string;
|
|
347
|
+
/** Refunded amount */
|
|
348
|
+
amount: number;
|
|
349
|
+
/** Fees (typically 0 for refunds) */
|
|
350
|
+
feeAmount: number;
|
|
351
|
+
/** Currency code (e.g., "BRL") */
|
|
352
|
+
currency: string;
|
|
353
|
+
/** Refund status */
|
|
354
|
+
status: 'completed';
|
|
355
|
+
/** ISO 8601 timestamp of when refund was completed */
|
|
356
|
+
refundedAt: string;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Payment completed webhook event
|
|
360
|
+
*/
|
|
361
|
+
type PaymentCompletedEvent = WebhookPayload<'payment_completed', PaymentCompletedData>;
|
|
362
|
+
/**
|
|
363
|
+
* Payment failed webhook event
|
|
364
|
+
*/
|
|
365
|
+
type PaymentFailedEvent = WebhookPayload<'payment_failed', PaymentFailedData>;
|
|
366
|
+
/**
|
|
367
|
+
* Refund completed webhook event
|
|
368
|
+
*/
|
|
369
|
+
type RefundCompletedEvent = WebhookPayload<'refund_completed', RefundCompletedData>;
|
|
370
|
+
/**
|
|
371
|
+
* Union type of all possible webhook events
|
|
372
|
+
*/
|
|
373
|
+
type WebhookEvent = PaymentCompletedEvent | PaymentFailedEvent | RefundCompletedEvent;
|
|
374
|
+
/**
|
|
375
|
+
* Webhook headers sent with each request
|
|
376
|
+
*/
|
|
377
|
+
interface WebhookHeaders {
|
|
378
|
+
/** HMAC-SHA256 signature of the payload */
|
|
379
|
+
'x-webhook-signature': string;
|
|
380
|
+
/** Unix timestamp in milliseconds when webhook was sent */
|
|
381
|
+
'x-webhook-timestamp': string;
|
|
382
|
+
/** Content type (always application/json) */
|
|
383
|
+
'content-type': string;
|
|
384
|
+
}
|
|
385
|
+
//#endregion
|
|
386
|
+
//#region src/webhooks/verify.d.ts
|
|
387
|
+
/**
|
|
388
|
+
* Parses a webhook payload and returns a type-safe WebhookEvent.
|
|
389
|
+
* Returns null if the payload is invalid.
|
|
390
|
+
*
|
|
391
|
+
* @param payload - The raw request body as a string
|
|
392
|
+
* @returns Parsed WebhookEvent or null if invalid
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```typescript
|
|
396
|
+
* import { parseWebhook } from 'pague-dev';
|
|
397
|
+
*
|
|
398
|
+
* app.post('/webhook', (req, res) => {
|
|
399
|
+
* // 1. Verify signature first (implement using your framework)
|
|
400
|
+
* // const isValid = verifySignature(req.body, req.headers['x-webhook-signature'], secret);
|
|
401
|
+
*
|
|
402
|
+
* // 2. Parse the webhook payload
|
|
403
|
+
* const event = parseWebhook(req.body);
|
|
404
|
+
*
|
|
405
|
+
* if (!event) {
|
|
406
|
+
* return res.status(400).send('Invalid webhook payload');
|
|
407
|
+
* }
|
|
408
|
+
*
|
|
409
|
+
* // 3. Handle the event with full type safety
|
|
410
|
+
* switch (event.event) {
|
|
411
|
+
* case 'payment_completed':
|
|
412
|
+
* // event.data is PaymentCompletedData
|
|
413
|
+
* console.log('Payment completed:', event.data.transactionId);
|
|
414
|
+
* console.log('Amount:', event.data.amount);
|
|
415
|
+
* console.log('Net amount:', event.data.netAmount);
|
|
416
|
+
* break;
|
|
417
|
+
*
|
|
418
|
+
* case 'payment_failed':
|
|
419
|
+
* // event.data is PaymentFailedData
|
|
420
|
+
* console.log('Payment failed:', event.data.transactionId);
|
|
421
|
+
* console.log('Reason:', event.data.failureReason);
|
|
422
|
+
* break;
|
|
423
|
+
*
|
|
424
|
+
* case 'refund_completed':
|
|
425
|
+
* // event.data is RefundCompletedData
|
|
426
|
+
* console.log('Refund completed:', event.data.refundTransactionId);
|
|
427
|
+
* console.log('Original transaction:', event.data.originalTransactionId);
|
|
428
|
+
* break;
|
|
429
|
+
* }
|
|
430
|
+
*
|
|
431
|
+
* res.status(200).send('OK');
|
|
432
|
+
* });
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
declare function parseWebhook(payload: string): WebhookEvent | null;
|
|
436
|
+
//#endregion
|
|
437
|
+
export { Charge, ChargeStatus, CreateChargeOptions, CreateChargeResponse, CreateCustomerOptions, CreateCustomerResponse, CreatePixCustomer, CreatePixOptions, CreatePixResponse, CreateProjectOptions, CreateProjectResponse, Customer, DocumentType, type ErrorResponse, GetChargeResponse, GetTransactionResponse, ListChargesOptions, ListChargesResponse, ListCustomersOptions, ListCustomersResponse, ListProjectsOptions, ListProjectsResponse, NotificationType, type PaginatedResponse, type PaginationOptions, PaymentCompletedData, PaymentCompletedEvent, PaymentFailedData, PaymentFailedEvent, PaymentMethod, Pdev, PixCharge, PixStatus, Project, RefundCompletedData, RefundCompletedEvent, type Response, SortBy, SortOrder, Transaction, TransactionPaymentMethod, TransactionStatus, TransactionType, WebhookEvent, WebhookEventType, WebhookHeaders, WebhookPayload, parseWebhook };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
//#region src/common/utils/build-pagination-query.ts
|
|
2
|
+
function buildPaginationQuery(options) {
|
|
3
|
+
const searchParams = new URLSearchParams();
|
|
4
|
+
for (const [key, value] of Object.entries(options)) if (value !== void 0 && value !== null) searchParams.set(key, String(value));
|
|
5
|
+
return searchParams.toString();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/common/base-resource.ts
|
|
10
|
+
/**
|
|
11
|
+
* Base class for API resources that follow CRUD patterns.
|
|
12
|
+
* Provides common create, list, and get operations.
|
|
13
|
+
*/
|
|
14
|
+
var BaseResource = class {
|
|
15
|
+
constructor(pdev) {
|
|
16
|
+
this.pdev = pdev;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a new entity
|
|
20
|
+
*/
|
|
21
|
+
async create(options) {
|
|
22
|
+
return this.pdev.post(this.endpoint, options);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* List entities with pagination
|
|
26
|
+
*/
|
|
27
|
+
async list(options = {}) {
|
|
28
|
+
const queryString = buildPaginationQuery(options);
|
|
29
|
+
const path = queryString ? `${this.endpoint}?${queryString}` : this.endpoint;
|
|
30
|
+
return this.pdev.get(path);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get a single entity by ID
|
|
34
|
+
*/
|
|
35
|
+
async get(id) {
|
|
36
|
+
return this.pdev.get(`${this.endpoint}/${id}`);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Base class for resources that only support create operations
|
|
41
|
+
*/
|
|
42
|
+
var CreateOnlyResource = class {
|
|
43
|
+
constructor(pdev) {
|
|
44
|
+
this.pdev = pdev;
|
|
45
|
+
}
|
|
46
|
+
async create(options) {
|
|
47
|
+
return this.pdev.post(this.endpoint, options);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Base class for resources that only support get operations
|
|
52
|
+
*/
|
|
53
|
+
var GetOnlyResource = class {
|
|
54
|
+
constructor(pdev) {
|
|
55
|
+
this.pdev = pdev;
|
|
56
|
+
}
|
|
57
|
+
async get(id) {
|
|
58
|
+
return this.pdev.get(`${this.endpoint}/${id}`);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/charges/charges.ts
|
|
64
|
+
var Charges = class extends BaseResource {
|
|
65
|
+
endpoint = "/charges";
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/config.ts
|
|
70
|
+
const config = { baseUrl: "https://api.pague.dev/v1" };
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/customers/customers.ts
|
|
74
|
+
var Customers = class extends BaseResource {
|
|
75
|
+
endpoint = "/customers";
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/pix/pix.ts
|
|
80
|
+
var Pix = class extends CreateOnlyResource {
|
|
81
|
+
endpoint = "/pix";
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/projects/projects.ts
|
|
86
|
+
var Projects = class extends BaseResource {
|
|
87
|
+
endpoint = "/projects";
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/transactions/transactions.ts
|
|
92
|
+
var Transactions = class extends GetOnlyResource {
|
|
93
|
+
endpoint = "/transactions";
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/pdev.ts
|
|
98
|
+
var Pdev = class {
|
|
99
|
+
key;
|
|
100
|
+
baseUrl;
|
|
101
|
+
headers;
|
|
102
|
+
pix;
|
|
103
|
+
customers;
|
|
104
|
+
projects;
|
|
105
|
+
charges;
|
|
106
|
+
transactions;
|
|
107
|
+
constructor(key) {
|
|
108
|
+
if (!key) {
|
|
109
|
+
if (typeof process !== "undefined" && process.env) this.key = process.env.PDEV_API_KEY || "";
|
|
110
|
+
else this.key = "";
|
|
111
|
+
if (!this.key) throw new Error("Missing API key. Pass it to the constructor `new Pdev(\"pd_live_xxx\")` or set the PDEV_API_KEY environment variable.");
|
|
112
|
+
} else this.key = key;
|
|
113
|
+
this.baseUrl = config.baseUrl;
|
|
114
|
+
this.headers = new Headers({
|
|
115
|
+
"X-API-Key": this.key,
|
|
116
|
+
"Content-Type": "application/json"
|
|
117
|
+
});
|
|
118
|
+
this.pix = new Pix(this);
|
|
119
|
+
this.customers = new Customers(this);
|
|
120
|
+
this.projects = new Projects(this);
|
|
121
|
+
this.charges = new Charges(this);
|
|
122
|
+
this.transactions = new Transactions(this);
|
|
123
|
+
}
|
|
124
|
+
async post(path, body, options = {}) {
|
|
125
|
+
const url = this.buildUrl(path, options.query);
|
|
126
|
+
return this.fetchRequest(url, {
|
|
127
|
+
method: "POST",
|
|
128
|
+
headers: this.headers,
|
|
129
|
+
body: body ? JSON.stringify(body) : void 0
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
async get(path, options = {}) {
|
|
133
|
+
const url = this.buildUrl(path, options.query);
|
|
134
|
+
return this.fetchRequest(url, {
|
|
135
|
+
method: "GET",
|
|
136
|
+
headers: this.headers
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
buildUrl(path, query) {
|
|
140
|
+
let url = `${this.baseUrl}${path}`;
|
|
141
|
+
if (query) {
|
|
142
|
+
const searchParams = new URLSearchParams();
|
|
143
|
+
for (const [key, value] of Object.entries(query)) if (value !== void 0 && value !== null) searchParams.set(key, String(value));
|
|
144
|
+
const queryString = searchParams.toString();
|
|
145
|
+
if (queryString) url += `?${queryString}`;
|
|
146
|
+
}
|
|
147
|
+
return url;
|
|
148
|
+
}
|
|
149
|
+
async fetchRequest(url, options) {
|
|
150
|
+
try {
|
|
151
|
+
const response = await fetch(url, options);
|
|
152
|
+
if (!response.ok) try {
|
|
153
|
+
const rawError = await response.text();
|
|
154
|
+
return {
|
|
155
|
+
data: null,
|
|
156
|
+
error: JSON.parse(rawError)
|
|
157
|
+
};
|
|
158
|
+
} catch {
|
|
159
|
+
return {
|
|
160
|
+
data: null,
|
|
161
|
+
error: {
|
|
162
|
+
statusCode: response.status,
|
|
163
|
+
error: "UnknownError",
|
|
164
|
+
message: "An unexpected error occurred"
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
data: await response.json(),
|
|
170
|
+
error: null
|
|
171
|
+
};
|
|
172
|
+
} catch {
|
|
173
|
+
return {
|
|
174
|
+
data: null,
|
|
175
|
+
error: {
|
|
176
|
+
statusCode: null,
|
|
177
|
+
error: "NetworkError",
|
|
178
|
+
message: "Unable to fetch data. The request could not be resolved."
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/webhooks/verify.ts
|
|
187
|
+
/**
|
|
188
|
+
* Type guard to check if an event is a valid WebhookEvent
|
|
189
|
+
*/
|
|
190
|
+
function isValidWebhookEvent(event) {
|
|
191
|
+
if (typeof event !== "object" || event === null) return false;
|
|
192
|
+
const obj = event;
|
|
193
|
+
if (typeof obj.event !== "string") return false;
|
|
194
|
+
if (typeof obj.eventId !== "string") return false;
|
|
195
|
+
if (typeof obj.timestamp !== "string") return false;
|
|
196
|
+
if (typeof obj.data !== "object" || obj.data === null) return false;
|
|
197
|
+
return [
|
|
198
|
+
"payment_completed",
|
|
199
|
+
"payment_failed",
|
|
200
|
+
"refund_completed"
|
|
201
|
+
].includes(obj.event);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Parses a webhook payload and returns a type-safe WebhookEvent.
|
|
205
|
+
* Returns null if the payload is invalid.
|
|
206
|
+
*
|
|
207
|
+
* @param payload - The raw request body as a string
|
|
208
|
+
* @returns Parsed WebhookEvent or null if invalid
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* import { parseWebhook } from 'pague-dev';
|
|
213
|
+
*
|
|
214
|
+
* app.post('/webhook', (req, res) => {
|
|
215
|
+
* // 1. Verify signature first (implement using your framework)
|
|
216
|
+
* // const isValid = verifySignature(req.body, req.headers['x-webhook-signature'], secret);
|
|
217
|
+
*
|
|
218
|
+
* // 2. Parse the webhook payload
|
|
219
|
+
* const event = parseWebhook(req.body);
|
|
220
|
+
*
|
|
221
|
+
* if (!event) {
|
|
222
|
+
* return res.status(400).send('Invalid webhook payload');
|
|
223
|
+
* }
|
|
224
|
+
*
|
|
225
|
+
* // 3. Handle the event with full type safety
|
|
226
|
+
* switch (event.event) {
|
|
227
|
+
* case 'payment_completed':
|
|
228
|
+
* // event.data is PaymentCompletedData
|
|
229
|
+
* console.log('Payment completed:', event.data.transactionId);
|
|
230
|
+
* console.log('Amount:', event.data.amount);
|
|
231
|
+
* console.log('Net amount:', event.data.netAmount);
|
|
232
|
+
* break;
|
|
233
|
+
*
|
|
234
|
+
* case 'payment_failed':
|
|
235
|
+
* // event.data is PaymentFailedData
|
|
236
|
+
* console.log('Payment failed:', event.data.transactionId);
|
|
237
|
+
* console.log('Reason:', event.data.failureReason);
|
|
238
|
+
* break;
|
|
239
|
+
*
|
|
240
|
+
* case 'refund_completed':
|
|
241
|
+
* // event.data is RefundCompletedData
|
|
242
|
+
* console.log('Refund completed:', event.data.refundTransactionId);
|
|
243
|
+
* console.log('Original transaction:', event.data.originalTransactionId);
|
|
244
|
+
* break;
|
|
245
|
+
* }
|
|
246
|
+
*
|
|
247
|
+
* res.status(200).send('OK');
|
|
248
|
+
* });
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
function parseWebhook(payload) {
|
|
252
|
+
let parsed;
|
|
253
|
+
try {
|
|
254
|
+
parsed = JSON.parse(payload);
|
|
255
|
+
} catch {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
if (!isValidWebhookEvent(parsed)) return null;
|
|
259
|
+
return parsed;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
//#endregion
|
|
263
|
+
export { Pdev, parseWebhook };
|