@garuhq/node 0.15.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -186,11 +186,6 @@ function generateIdempotencyKey() {
186
186
  return randomUUID();
187
187
  }
188
188
 
189
- // src/types.ts
190
- function toWirePaymentMethod(pm) {
191
- return pm === "credit_card" ? "creditcard" : pm;
192
- }
193
-
194
189
  // src/resources/charges.ts
195
190
  var Charges = class {
196
191
  constructor(http) {
@@ -198,16 +193,16 @@ var Charges = class {
198
193
  }
199
194
  http;
200
195
  /**
201
- * Create a charge (PIX, credit card, or boleto).
196
+ * Create a charge (PIX, boleto, or credit card).
202
197
  *
203
- * Automatically attaches an `X-Idempotency-Key` header — if you don't pass
204
- * `idempotencyKey`, the SDK generates a UUIDv4. Safe to retry: the backend
205
- * caches the first response for 24h.
198
+ * Attaches an `X-Idempotency-Key` header automatically — if you don't pass
199
+ * `idempotencyKey`, the SDK generates a UUIDv4. Safe to retry: the same key
200
+ * returns the original charge for 24h.
206
201
  *
207
202
  * @example
208
- * // PIX charge
203
+ * // PIX — render charge.pix.code as a QR in your own checkout
209
204
  * const charge = await garu.charges.create({
210
- * productId: 'b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f',
205
+ * productId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
211
206
  * paymentMethod: 'pix',
212
207
  * customer: {
213
208
  * name: 'Maria Silva',
@@ -216,111 +211,109 @@ var Charges = class {
216
211
  * phone: '11987654321'
217
212
  * }
218
213
  * });
219
- * // charge.id, charge.status
214
+ * console.log(charge.uuid, charge.pix?.code);
220
215
  *
221
216
  * @example
222
- * // Credit card charge, 3 installments
217
+ * // Credit card, 2 installments. Server-to-server only (PCI scope).
223
218
  * const charge = await garu.charges.create({
224
- * productId: 'b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f',
225
- * paymentMethod: 'credit_card',
219
+ * productId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
220
+ * paymentMethod: 'creditCard',
226
221
  * customer: { name: 'Maria Silva', email: 'maria@exemplo.com.br', document: '12345678909', phone: '11987654321' },
227
- * cardInfo: {
228
- * cardNumber: '4111111111111111',
229
- * cvv: '123',
230
- * expirationDate: '2030-12',
222
+ * card: {
223
+ * number: '4111111111111111',
231
224
  * holderName: 'MARIA SILVA',
232
- * installments: 3
225
+ * expirationDate: '2030-12',
226
+ * cvv: '123',
227
+ * installments: 2
233
228
  * }
234
229
  * });
230
+ * // charge.amount is the base price; charge.chargedTotal is what was charged.
235
231
  */
236
232
  async create(params) {
237
233
  const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
238
- const body = this.buildCreateBody(params);
239
- return this.http.call(
240
- (signal) => this.http.client.POST("/api/transactions", {
241
- body,
242
- headers: { "X-Idempotency-Key": idempotencyKey },
243
- signal
244
- })
245
- );
234
+ const body = {
235
+ productId: params.productId,
236
+ paymentMethod: params.paymentMethod,
237
+ customer: params.customer
238
+ };
239
+ if (params.card) body.card = params.card;
240
+ if (params.checkoutSessionToken) body.checkoutSessionToken = params.checkoutSessionToken;
241
+ if (params.additionalInfo !== void 0) body.additionalInfo = params.additionalInfo;
242
+ return this.post("/api/v1/charges", body, { "X-Idempotency-Key": idempotencyKey });
246
243
  }
247
244
  /**
248
- * List charges for the authenticated seller, with pagination and filters.
245
+ * Retrieve a charge by uuid.
249
246
  *
250
247
  * @example
251
- * const { data, meta } = await garu.charges.list({ status: 'paid', limit: 10 });
252
- * // meta.total paid charges
248
+ * const charge = await garu.charges.retrieve('6f1c9b2e-4a7d-4f0b-9a3e-1d2c3b4a5e6f');
249
+ * if (charge.status === 'paid') fulfil(charge);
250
+ */
251
+ async retrieve(uuid) {
252
+ return this.get(`/api/v1/charges/${encodeURIComponent(uuid)}`);
253
+ }
254
+ /**
255
+ * List charges for the authenticated account, newest first by default.
256
+ *
257
+ * @example
258
+ * const { data, totalCount } = await garu.charges.list({ status: 'paid', limit: 50 });
259
+ * console.log(`${data.length} of ${totalCount} paid charges`);
253
260
  */
254
261
  async list(params = {}) {
255
262
  const query = {};
256
263
  if (params.page !== void 0) query.page = String(params.page);
257
264
  if (params.limit !== void 0) query.limit = String(params.limit);
258
265
  if (params.status) query.status = params.status;
259
- if (params.search) query.search = params.search;
260
266
  if (params.paymentMethod) query.paymentMethod = params.paymentMethod;
267
+ if (params.productId) query.productId = params.productId;
268
+ if (params.createdAfter) query.createdAfter = params.createdAfter;
269
+ if (params.createdBefore) query.createdBefore = params.createdBefore;
270
+ if (params.search) query.search = params.search;
271
+ if (params.sort) query.sort = params.sort;
261
272
  const qs = new URLSearchParams(query).toString();
262
- const url = `/api/transactions${qs ? `?${qs}` : ""}`;
263
- return this.http.call(
264
- (signal) => this.http.client.GET(url, { signal }).then(
265
- (r) => r
266
- )
267
- );
273
+ return this.get(`/api/v1/charges${qs ? `?${qs}` : ""}`);
268
274
  }
269
275
  /**
270
- * Fetch a single charge by numeric ID.
276
+ * Refund a charge, fully or partially. `amount` is in reais.
277
+ *
278
+ * For a Pix Automático charge the refund is a devolução: it returns with the
279
+ * charge in `refund_pending`, reaching `refunded` only once the transfer
280
+ * settles.
271
281
  *
272
282
  * @example
273
- * const charge = await garu.charges.get(4472);
274
- * if (charge.status === 'paid') { ... }
283
+ * await garu.charges.refund('6f1c9b2e-...'); // full
284
+ * await garu.charges.refund('6f1c9b2e-...', { amount: 10.0 }); // R$10,00
275
285
  */
276
- async get(id) {
277
- return this.http.call(
278
- (signal) => this.http.client.GET("/api/transactions/{id}", {
279
- params: { path: { id } },
280
- signal
281
- })
282
- );
286
+ async refund(uuid, params = {}) {
287
+ const body = {};
288
+ if (params.amount !== void 0) body.amount = params.amount;
289
+ if (params.reason !== void 0) body.reason = params.reason;
290
+ return this.post(`/api/v1/charges/${encodeURIComponent(uuid)}/refund`, body);
283
291
  }
284
292
  /**
285
- * Refund a charge — fully, or partially by passing `amount` in centavos.
293
+ * Cancel an unpaid charge.
286
294
  *
287
295
  * @example
288
- * // Full refund
289
- * await garu.charges.refund(4472);
290
- *
291
- * @example
292
- * // Partial refund of R$ 10,00
293
- * await garu.charges.refund(4472, { amount: 1000, reason: 'customer_request' });
296
+ * const { canceled } = await garu.charges.cancel('6f1c9b2e-...');
294
297
  */
295
- async refund(id, params = {}) {
296
- const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();
297
- const body = {};
298
- if (params.amount !== void 0) body.amount = params.amount;
299
- if (params.reason !== void 0) body.reason = params.reason;
298
+ async cancel(uuid) {
300
299
  return this.http.call(
301
- (signal) => this.http.client.POST("/api/transactions/{id}/refund", {
302
- params: { path: { id } },
303
- body,
304
- headers: { "X-Idempotency-Key": idempotencyKey },
305
- signal
306
- })
300
+ (signal) => this.http.client.DELETE(
301
+ `/api/v1/charges/${encodeURIComponent(uuid)}`,
302
+ { signal }
303
+ )
307
304
  );
308
305
  }
309
- buildCreateBody(params) {
310
- const body = {
311
- customer: params.customer,
312
- productId: params.productId,
313
- paymentMethodId: toWirePaymentMethod(params.paymentMethod),
314
- link: params.link ?? null,
315
- affiliateId: params.affiliateId ?? null
316
- };
317
- if (params.additionalInfo !== void 0) body.additionalInfo = params.additionalInfo;
318
- if (params.priceId !== void 0) body.priceId = params.priceId;
319
- if (params.checkoutSessionToken !== void 0) {
320
- body.checkoutSessionToken = params.checkoutSessionToken;
321
- }
322
- if (params.cardInfo) body.CardInfo = params.cardInfo;
323
- return body;
306
+ // v1 charge routes are not in the generated OpenAPI schema (it is regenerated
307
+ // from a live deploy), so these use the client's untyped path.
308
+ get(url) {
309
+ return this.http.call(
310
+ (signal) => this.http.client.GET(url, { signal })
311
+ );
312
+ }
313
+ post(url, body, headers) {
314
+ return this.http.call(
315
+ (signal) => this.http.client.POST(url, { body, headers, signal })
316
+ );
324
317
  }
325
318
  };
326
319
 
@@ -475,7 +468,7 @@ var ProductPortalConfigResource = class {
475
468
  async get(productId) {
476
469
  return this.http.call(
477
470
  (signal) => this.http.client.GET(
478
- `/api/products/${encodeURIComponent(String(productId))}/portal-config`,
471
+ `/api/v1/products/${encodeURIComponent(String(productId))}/portal-config`,
479
472
  {
480
473
  signal
481
474
  }
@@ -498,7 +491,7 @@ var ProductPortalConfigResource = class {
498
491
  async set(productId, params) {
499
492
  return this.http.call(
500
493
  (signal) => this.http.client.POST(
501
- `/api/products/${encodeURIComponent(String(productId))}/portal-config`,
494
+ `/api/v1/products/${encodeURIComponent(String(productId))}/portal-config`,
502
495
  {
503
496
  body: params,
504
497
  signal
@@ -510,7 +503,7 @@ var ProductPortalConfigResource = class {
510
503
  async patch(productId, params) {
511
504
  return this.http.call(
512
505
  (signal) => this.http.client.PATCH(
513
- `/api/products/${encodeURIComponent(String(productId))}/portal-config`,
506
+ `/api/v1/products/${encodeURIComponent(String(productId))}/portal-config`,
514
507
  {
515
508
  body: params,
516
509
  signal
@@ -529,7 +522,7 @@ var ProductPortalConfigResource = class {
529
522
  async clear(productId) {
530
523
  return this.http.call(
531
524
  (signal) => this.http.client.DELETE(
532
- `/api/products/${encodeURIComponent(String(productId))}/portal-config`,
525
+ `/api/v1/products/${encodeURIComponent(String(productId))}/portal-config`,
533
526
  {
534
527
  body: {},
535
528
  signal
@@ -550,16 +543,15 @@ var Products = class {
550
543
  * List products for the authenticated seller, with pagination and search.
551
544
  *
552
545
  * @example
553
- * const { data, meta } = await garu.products.list({ search: 'curso', limit: 10 });
546
+ * const { data, totalCount } = await garu.products.list({ search: 'curso', limit: 10 });
554
547
  */
555
548
  async list(params = {}) {
556
549
  const query = {};
557
550
  if (params.page !== void 0) query.page = String(params.page);
558
551
  if (params.limit !== void 0) query.limit = String(params.limit);
559
552
  if (params.search) query.search = params.search;
560
- if (params.tab) query.tab = params.tab;
561
553
  const qs = new URLSearchParams(query).toString();
562
- const url = `/api/products/seller${qs ? `?${qs}` : ""}`;
554
+ const url = `/api/v1/products${qs ? `?${qs}` : ""}`;
563
555
  return this.http.call(
564
556
  (signal) => this.http.client.GET(url, { signal }).then(
565
557
  (r) => r
@@ -575,7 +567,7 @@ var Products = class {
575
567
  */
576
568
  async get(uuid) {
577
569
  return this.http.call(
578
- (signal) => this.http.client.GET(`/api/products/uuid/${uuid}`, { signal }).then(
570
+ (signal) => this.http.client.GET(`/api/v1/products/${uuid}`, { signal }).then(
579
571
  (r) => r
580
572
  )
581
573
  );
@@ -593,7 +585,7 @@ var Products = class {
593
585
  * @example
594
586
  * const product = await garu.products.create({
595
587
  * name: 'Plano Mensal',
596
- * value: 4990, // R$ 49,90 in centavos
588
+ * value: 49.90, // R$ 49,90 in reais (decimal BRL), NOT centavos
597
589
  * description: 'Acesso completo à plataforma',
598
590
  * pix: true,
599
591
  * creditCard: true,
@@ -606,7 +598,7 @@ var Products = class {
606
598
  const { idempotencyKey, ...body } = params;
607
599
  const key = idempotencyKey ?? generateIdempotencyKey();
608
600
  return this.http.call(
609
- (signal) => this.http.client.POST("/api/products", {
601
+ (signal) => this.http.client.POST("/api/v1/products", {
610
602
  body,
611
603
  headers: { "X-Idempotency-Key": key },
612
604
  signal
@@ -617,19 +609,19 @@ var Products = class {
617
609
  * Update a product (partial PATCH — only the fields you pass are changed).
618
610
  * Returns the updated product.
619
611
  *
620
- * `id` accepts the numeric id or the product UUID the same identifiers
621
- * accepted elsewhere on the `/api/products/:id` path (see
612
+ * `id` accepts the product UUID (recommended) or the legacy numeric id
613
+ * both resolve on the `/api/v1/products/:id` path (see
622
614
  * {@link ProductPortalConfigResource}).
623
615
  *
624
616
  * @example
625
617
  * const updated = await garu.products.update('b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f', {
626
- * value: 5990,
618
+ * value: 59.90, // reais (decimal BRL), NOT centavos
627
619
  * pixAutomatic: true // turn on Pix Automático for this product
628
620
  * });
629
621
  */
630
622
  async update(id, params) {
631
623
  return this.http.call(
632
- (signal) => this.http.client.PATCH(`/api/products/${encodeURIComponent(String(id))}`, {
624
+ (signal) => this.http.client.PATCH(`/api/v1/products/${encodeURIComponent(String(id))}`, {
633
625
  body: params,
634
626
  signal
635
627
  }).then((r) => r)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/node",
3
- "version": "0.15.0",
3
+ "version": "1.0.0",
4
4
  "description": "Official Node.js / TypeScript SDK for the Garu payment gateway.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://garu.com.br",