@garuhq/node 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to `@garuhq/node` are documented in this file. Format:
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning: [SemVer](https://semver.org/).
5
5
 
6
+ ## [0.3.0] — 2026-04-28
7
+
8
+ ### Added
9
+
10
+ - `products` resource on the `Garu` client.
11
+ - `products.list({ page, limit, search, tab })` — paginated listing of the
12
+ authenticated seller's products (`GET /api/products/seller`).
13
+ - `products.get(uuid)` — fetch a single product by UUID
14
+ (`GET /api/products/uuid/{uuid}`). The UUID is the same identifier
15
+ accepted by `charges.create({ productId })`, so `products.list` is
16
+ the discovery path before creating a charge.
17
+ - `Product`, `ProductList`, `ListProductsParams` types exported from the
18
+ package root.
19
+
6
20
  ## [0.1.1] — 2026-04-08
7
21
 
8
22
  ### Security
package/README.md CHANGED
@@ -1,15 +1,32 @@
1
+ <div align="center">
2
+
1
3
  # @garuhq/node
2
4
 
3
- Official Node.js / TypeScript SDK for the [Garu](https://garu.com.br) payment gateway.
5
+ The official Node.js / TypeScript SDK for the [Garu](https://garu.com.br) payment gateway.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@garuhq/node.svg)](https://www.npmjs.com/package/@garuhq/node)
8
+ [![CI](https://img.shields.io/github/actions/workflow/status/Garu-Pagamentos/garu-node/release.yml?label=CI)](https://github.com/Garu-Pagamentos/garu-node/actions)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
10
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg)](https://nodejs.org)
11
+
12
+ <p>
13
+ <a href="#quickstart">Quickstart</a> ·
14
+ <a href="#charges">Charges</a> ·
15
+ <a href="#customers">Customers</a> ·
16
+ <a href="#webhooks">Webhooks</a> ·
17
+ <a href="#error-handling">Errors</a>
18
+ </p>
19
+
20
+ </div>
4
21
 
5
- - **Typed end-to-end** — wire types are generated from the backend's OpenAPI spec, so the
6
- SDK can never drift from the API. Run `npm run generate` to refresh.
7
- - **LLM-optimized** every public method has a JSDoc `@example` so agents can autocomplete a
8
- working call from partial input.
9
- - **Tiny footprint** — one runtime dependency ([`openapi-fetch`](https://openapi-ts.dev/openapi-fetch/),
10
- ~4 KB). Node.js ≥ 18, native `fetch`, native `crypto`.
11
- - **Safe to retry** — automatic idempotency keys on every mutation, exponential backoff with
12
- full jitter, honors `Retry-After`.
22
+ ---
23
+
24
+ Brazilian payments (PIX, credit card, boleto) in a few lines of code.
25
+
26
+ - **Typed end-to-end** — wire types generated from the backend's OpenAPI spec; the SDK can never drift from the API.
27
+ - **Tiny footprint** — one runtime dependency ([`openapi-fetch`](https://openapi-ts.dev/openapi-fetch/), ~4 KB). Native `fetch`, native `crypto`.
28
+ - **Safe to retry** — automatic idempotency keys on every mutation, exponential backoff with full jitter, honors `Retry-After`.
29
+ - **LLM-friendly** every public method has JSDoc `@example` blocks for agent autocomplete.
13
30
  - **ESM + CJS** dual build.
14
31
 
15
32
  ## Install
@@ -22,7 +39,7 @@ pnpm add @garuhq/node
22
39
  yarn add @garuhq/node
23
40
  ```
24
41
 
25
- ## 60-second quickstart
42
+ ## Quickstart
26
43
 
27
44
  ```ts
28
45
  import { Garu } from '@garuhq/node';
@@ -37,53 +54,129 @@ const charge = await garu.charges.create({
37
54
  name: 'Maria Silva',
38
55
  email: 'maria@exemplo.com.br',
39
56
  document: '12345678909', // CPF, digits only
40
- phone: '11987654321'
41
- }
57
+ phone: '11987654321',
58
+ },
42
59
  });
43
60
 
44
61
  console.log(charge.id, charge.status);
45
62
  ```
46
63
 
47
- ## Authentication
64
+ ## Setup
48
65
 
49
- Get your API key from the [Garu dashboard](https://garu.com.br/inicio) → **API Keys**. Use
50
- `sk_test_…` for test mode and `sk_live_…` for production.
66
+ Get your API key from the [Garu dashboard](https://garu.com.br/inicio) → **API Keys**.
51
67
 
52
68
  ```ts
53
69
  const garu = new Garu({ apiKey: process.env.GARU_API_KEY });
54
70
  ```
55
71
 
56
- Public endpoints (`meta.get`, public checkout-style `charges.create`) also work without an
57
- API key.
72
+ > [!NOTE]
73
+ > Use `sk_test_…` for test mode and `sk_live_…` for production. Public endpoints like `meta.get` work without a key.
74
+
75
+ ## Configuration
58
76
 
59
- ## Surface
77
+ ```ts
78
+ const garu = new Garu({
79
+ apiKey: process.env.GARU_API_KEY,
80
+ timeoutMs: 30_000, // default
81
+ maxRetries: 2, // default (3 total attempts)
82
+ });
83
+ ```
60
84
 
61
- ### `garu.charges`
85
+ ## Charges
62
86
 
63
- | Method | What it does |
87
+ | Method | Description |
64
88
  | --------------------- | -------------------------------------------- |
65
89
  | `create(params)` | Create a PIX, credit-card, or boleto charge. |
90
+ | `list(params?)` | List charges with pagination and filters. |
66
91
  | `get(id)` | Fetch a single charge by ID. |
67
92
  | `refund(id, params?)` | Refund a charge fully or partially. |
68
93
 
69
- Every mutation automatically attaches an `X-Idempotency-Key` header (UUIDv4) unless you pass
70
- one via `params.idempotencyKey`. Safe to retry — the backend caches the first response for
71
- 24h.
94
+ ### Create a PIX charge
95
+
96
+ ```ts
97
+ const charge = await garu.charges.create({
98
+ productId: 'b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f',
99
+ paymentMethod: 'pix',
100
+ customer: {
101
+ name: 'Maria Silva',
102
+ email: 'maria@exemplo.com.br',
103
+ document: '12345678909',
104
+ phone: '11987654321',
105
+ },
106
+ });
107
+ ```
72
108
 
73
- ### `garu.meta`
109
+ ### Create a credit card charge
110
+
111
+ ```ts
112
+ const charge = await garu.charges.create({
113
+ productId: 'b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f',
114
+ paymentMethod: 'credit_card',
115
+ card: {
116
+ number: '4111111111111111',
117
+ holderName: 'MARIA SILVA',
118
+ expirationMonth: '12',
119
+ expirationYear: '2028',
120
+ cvv: '123',
121
+ },
122
+ customer: {
123
+ name: 'Maria Silva',
124
+ email: 'maria@exemplo.com.br',
125
+ document: '12345678909',
126
+ phone: '11987654321',
127
+ },
128
+ });
129
+ ```
130
+
131
+ ### List charges
132
+
133
+ ```ts
134
+ const { data, meta } = await garu.charges.list({ limit: 10 });
135
+ ```
136
+
137
+ ### Refund a charge
138
+
139
+ ```ts
140
+ await garu.charges.refund(4472, { amount: 1000 }); // partial refund (R$10.00)
141
+ ```
142
+
143
+ > [!TIP]
144
+ > Every mutation automatically attaches an `X-Idempotency-Key` header (UUIDv4) unless you provide one via `params.idempotencyKey`. Safe to retry — the backend caches the first response for 24h.
145
+
146
+ ## Customers
147
+
148
+ | Method | Description |
149
+ | ------------------------- | --------------------------------------------- |
150
+ | `create(params)` | Create a new customer. |
151
+ | `list(params?)` | List customers with pagination and search. |
152
+ | `get(id)` | Fetch a single customer by ID. |
153
+ | `update(id, params)` | Update a customer's profile. |
154
+ | `delete(id)` | Delete a customer. |
155
+
156
+ ```ts
157
+ const customer = await garu.customers.create({
158
+ name: 'Maria Silva',
159
+ email: 'maria@exemplo.com.br',
160
+ document: '12345678909',
161
+ phone: '11987654321',
162
+ personType: 'fisica',
163
+ });
164
+
165
+ const { data, meta } = await garu.customers.list({ search: 'maria', limit: 10 });
166
+ ```
167
+
168
+ ## Meta
169
+
170
+ Discover available payment methods and webhook events. No authentication required.
74
171
 
75
172
  ```ts
76
173
  const meta = await garu.meta.get();
77
174
  console.log(meta.version, meta.payment_methods, meta.webhook_events);
78
175
  ```
79
176
 
80
- Unauthenticated. Use this to discover which payment methods and webhook events are
81
- currently supported.
82
-
83
- ### `Garu.webhooks.verify`
177
+ ## Webhooks
84
178
 
85
- Verify an incoming webhook before trusting its body. Uses HMAC-SHA256 with constant-time
86
- comparison.
179
+ Verify incoming webhooks with HMAC-SHA256 and constant-time comparison.
87
180
 
88
181
  ```ts
89
182
  import express from 'express';
@@ -96,10 +189,9 @@ app.post('/webhooks/garu', express.raw({ type: 'application/json' }), (req, res)
96
189
  const { event } = Garu.webhooks.verify({
97
190
  payload: req.body, // raw Buffer — do NOT re-serialize parsed JSON
98
191
  signature: req.header('x-garu-signature') ?? '',
99
- secret: process.env.GARU_WEBHOOK_SECRET!
192
+ secret: process.env.GARU_WEBHOOK_SECRET!,
100
193
  });
101
194
 
102
- // handle event
103
195
  console.log('Received', event);
104
196
  res.sendStatus(200);
105
197
  } catch (err) {
@@ -109,16 +201,19 @@ app.post('/webhooks/garu', express.raw({ type: 'application/json' }), (req, res)
109
201
  });
110
202
  ```
111
203
 
112
- ## Errors
204
+ > [!IMPORTANT]
205
+ > Always pass the raw request body to `verify()`. Parsing and re-serializing JSON will break the signature check.
113
206
 
114
- Every error extends `GaruError` and has a stable `code`:
207
+ ## Error handling
208
+
209
+ Every error extends `GaruError`. API errors include `status`, `requestId`, and `body`.
115
210
 
116
211
  ```ts
117
212
  import {
118
213
  GaruAPIError,
119
214
  GaruNotFoundError,
120
215
  GaruRateLimitError,
121
- GaruValidationError
216
+ GaruValidationError,
122
217
  } from '@garuhq/node';
123
218
 
124
219
  try {
@@ -128,7 +223,7 @@ try {
128
223
  /* 404 */
129
224
  }
130
225
  if (err instanceof GaruValidationError) {
131
- /* 400/422 */
226
+ /* 400 / 422 */
132
227
  }
133
228
  if (err instanceof GaruRateLimitError) {
134
229
  console.log('Retry in', err.retryAfterSec, 'seconds');
@@ -139,23 +234,24 @@ try {
139
234
  }
140
235
  ```
141
236
 
237
+ | Error class | HTTP status |
238
+ | ----------------------------------- | ------------------ |
239
+ | `GaruAuthenticationError` | `401` |
240
+ | `GaruPermissionError` | `403` |
241
+ | `GaruNotFoundError` | `404` |
242
+ | `GaruValidationError` | `400` / `422` |
243
+ | `GaruRateLimitError` | `429` |
244
+ | `GaruServerError` | `5xx` |
245
+ | `GaruConnectionError` | Network failure |
246
+ | `GaruSignatureVerificationError` | Webhook mismatch |
247
+
142
248
  ## Retries
143
249
 
144
- The SDK retries idempotent requests automatically on connection errors, `408`, `429`, and
145
- `5xx` responses. Exponential backoff with full jitter. Honors `Retry-After`. Never retries
146
- `4xx` validation errors.
147
-
148
- ```ts
149
- const garu = new Garu({
150
- apiKey: process.env.GARU_API_KEY,
151
- timeoutMs: 30_000, // default
152
- maxRetries: 2 // default (so 3 total attempts)
153
- });
154
- ```
250
+ The SDK retries automatically on connection errors, `408`, `429`, and `5xx` responses. Exponential backoff with full jitter. Honors `Retry-After`. Never retries `4xx` validation errors.
155
251
 
156
252
  ## TypeScript
157
253
 
158
- Ships with full `.d.ts` and strict types. All public types are exported from the root:
254
+ Ships with full `.d.ts` and strict types. All public types are re-exported from the root:
159
255
 
160
256
  ```ts
161
257
  import type {
@@ -165,10 +261,14 @@ import type {
165
261
  Customer,
166
262
  CardInfo,
167
263
  PaymentMethod,
168
- MetaResponse
264
+ MetaResponse,
169
265
  } from '@garuhq/node';
170
266
  ```
171
267
 
268
+ ## Security
269
+
270
+ To report a vulnerability, **do not open a public issue**. See [SECURITY.md](SECURITY.md) for responsible disclosure instructions.
271
+
172
272
  ## License
173
273
 
174
- MIT.
274
+ MIT — see [LICENSE](LICENSE) for details.
package/dist/index.cjs CHANGED
@@ -337,7 +337,7 @@ var Customers = class {
337
337
  }
338
338
  http;
339
339
  /**
340
- * Create a customer and link it to the current seller.
340
+ * Register a customer for the current seller.
341
341
  *
342
342
  * @example
343
343
  * const customer = await garu.customers.create({
@@ -402,6 +402,30 @@ var Customers = class {
402
402
  }).then((r) => r)
403
403
  );
404
404
  }
405
+ /**
406
+ * Set or clear the per-seller billing email override.
407
+ *
408
+ * The override is sticky: it takes precedence over the per-seller last-used
409
+ * email and the global `customer.email` for outbound seller→customer emails,
410
+ * and is **never** auto-overwritten by subsequent payments or registrations.
411
+ *
412
+ * @example
413
+ * // Set
414
+ * await garu.customers.setBillingEmailOverride(42, {
415
+ * billingEmailOverride: 'cobrancas@empresa.com.br'
416
+ * });
417
+ *
418
+ * // Clear and fall back to the last-used email
419
+ * await garu.customers.setBillingEmailOverride(42, { billingEmailOverride: null });
420
+ */
421
+ async setBillingEmailOverride(id, params) {
422
+ return this.http.call(
423
+ (signal) => this.http.client.PATCH(`/api/customers/${id}/billing-email-override`, {
424
+ body: params,
425
+ signal
426
+ }).then((r) => r)
427
+ );
428
+ }
405
429
  /**
406
430
  * Remove a customer from the current seller.
407
431
  *
@@ -437,6 +461,48 @@ var Meta = class {
437
461
  );
438
462
  }
439
463
  };
464
+
465
+ // src/resources/products.ts
466
+ var Products = class {
467
+ constructor(http) {
468
+ this.http = http;
469
+ }
470
+ http;
471
+ /**
472
+ * List products for the authenticated seller, with pagination and search.
473
+ *
474
+ * @example
475
+ * const { data, meta } = await garu.products.list({ search: 'curso', limit: 10 });
476
+ */
477
+ async list(params = {}) {
478
+ const query = {};
479
+ if (params.page !== void 0) query.page = String(params.page);
480
+ if (params.limit !== void 0) query.limit = String(params.limit);
481
+ if (params.search) query.search = params.search;
482
+ if (params.tab) query.tab = params.tab;
483
+ const qs = new URLSearchParams(query).toString();
484
+ const url = `/api/products/seller${qs ? `?${qs}` : ""}`;
485
+ return this.http.call(
486
+ (signal) => this.http.client.GET(url, { signal }).then(
487
+ (r) => r
488
+ )
489
+ );
490
+ }
491
+ /**
492
+ * Fetch a single product by UUID — the same identifier used by
493
+ * `charges.create({ productId })`.
494
+ *
495
+ * @example
496
+ * const product = await garu.products.get('b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f');
497
+ */
498
+ async get(uuid) {
499
+ return this.http.call(
500
+ (signal) => this.http.client.GET(`/api/products/uuid/${uuid}`, { signal }).then(
501
+ (r) => r
502
+ )
503
+ );
504
+ }
505
+ };
440
506
  var webhooks = {
441
507
  verify(params) {
442
508
  const { signature, secret, payload } = params;
@@ -496,11 +562,12 @@ function parseSignatureHeader(header) {
496
562
  var DEFAULT_BASE_URL = "https://garu.com.br";
497
563
  var DEFAULT_TIMEOUT_MS = 3e4;
498
564
  var DEFAULT_MAX_RETRIES = 2;
499
- var SDK_VERSION = "0.2.0";
565
+ var SDK_VERSION = "0.3.0";
500
566
  var Garu = class {
501
567
  charges;
502
568
  customers;
503
569
  meta;
570
+ products;
504
571
  /**
505
572
  * Webhook helpers. Available both as an instance member and as a static —
506
573
  * `Garu.webhooks.verify(...)` works without constructing a client.
@@ -519,6 +586,7 @@ var Garu = class {
519
586
  this.charges = new Charges(http);
520
587
  this.customers = new Customers(http);
521
588
  this.meta = new Meta(http);
589
+ this.products = new Products(http);
522
590
  }
523
591
  };
524
592
 
@@ -534,5 +602,3 @@ exports.GaruServerError = GaruServerError;
534
602
  exports.GaruSignatureVerificationError = GaruSignatureVerificationError;
535
603
  exports.GaruValidationError = GaruValidationError;
536
604
  exports.webhooks = webhooks;
537
- //# sourceMappingURL=index.cjs.map
538
- //# sourceMappingURL=index.cjs.map
package/dist/index.d.cts CHANGED
@@ -219,8 +219,22 @@ interface CustomerRecord {
219
219
  state?: string | null;
220
220
  createdAt: string;
221
221
  updatedAt: string;
222
+ /**
223
+ * Resolved billing email used for outbound seller→customer emails:
224
+ * `billingEmailOverride ?? per-seller email ?? customer.email`.
225
+ */
226
+ billingEmail?: string;
227
+ /** True when a sticky `billingEmailOverride` is set for this seller. */
228
+ hasBillingEmailOverride?: boolean;
222
229
  [key: string]: unknown;
223
230
  }
231
+ interface SetBillingEmailOverrideParams {
232
+ /**
233
+ * Customer-controlled billing email. Pass `null` to clear and fall back to
234
+ * the per-seller last-used email or the global `customer.email`.
235
+ */
236
+ billingEmailOverride: string | null;
237
+ }
224
238
  type CustomerList = PaginatedList<CustomerRecord>;
225
239
  interface CreateCustomerParams {
226
240
  name: string;
@@ -259,6 +273,41 @@ interface ListCustomersParams {
259
273
  limit?: number;
260
274
  search?: string;
261
275
  }
276
+ interface Product {
277
+ id: number;
278
+ uuid: string;
279
+ name: string;
280
+ description: string;
281
+ image: string;
282
+ /** Price in centavos (BRL × 100). */
283
+ value: number;
284
+ sellerId: number;
285
+ sellerName?: string;
286
+ pix: boolean;
287
+ boleto: boolean;
288
+ creditCard: boolean;
289
+ installments: number[];
290
+ tags?: string[];
291
+ isSubscription?: boolean;
292
+ subscriptionType?: string;
293
+ unitLabel?: string;
294
+ comission?: string;
295
+ valueWithComission?: number;
296
+ returnUrl?: string;
297
+ returnUrlButtonText?: string;
298
+ createdAt: string;
299
+ updatedAt: string;
300
+ [key: string]: unknown;
301
+ }
302
+ type ProductList = PaginatedList<Product>;
303
+ interface ListProductsParams {
304
+ page?: number;
305
+ limit?: number;
306
+ /** Search by product name. */
307
+ search?: string;
308
+ /** Backend tab filter (e.g. `active`, `archived`). Backend default is used when omitted. */
309
+ tab?: string;
310
+ }
262
311
  interface MetaFeatures {
263
312
  subscriptions: boolean;
264
313
  checkout_sessions: boolean;
@@ -269,7 +318,7 @@ interface MetaFeatures {
269
318
  interface MetaResponse {
270
319
  name: string;
271
320
  version: string;
272
- environment: 'production' | 'staging' | 'development' | string;
321
+ environment: string;
273
322
  api_version: string;
274
323
  payment_methods: string[];
275
324
  currencies: string[];
@@ -371,7 +420,7 @@ declare class Customers {
371
420
  private readonly http;
372
421
  constructor(http: HttpClient);
373
422
  /**
374
- * Create a customer and link it to the current seller.
423
+ * Register a customer for the current seller.
375
424
  *
376
425
  * @example
377
426
  * const customer = await garu.customers.create({
@@ -404,6 +453,23 @@ declare class Customers {
404
453
  * const updated = await garu.customers.update(42, { name: 'Maria Santos' });
405
454
  */
406
455
  update(id: number, params: UpdateCustomerParams): Promise<CustomerRecord>;
456
+ /**
457
+ * Set or clear the per-seller billing email override.
458
+ *
459
+ * The override is sticky: it takes precedence over the per-seller last-used
460
+ * email and the global `customer.email` for outbound seller→customer emails,
461
+ * and is **never** auto-overwritten by subsequent payments or registrations.
462
+ *
463
+ * @example
464
+ * // Set
465
+ * await garu.customers.setBillingEmailOverride(42, {
466
+ * billingEmailOverride: 'cobrancas@empresa.com.br'
467
+ * });
468
+ *
469
+ * // Clear and fall back to the last-used email
470
+ * await garu.customers.setBillingEmailOverride(42, { billingEmailOverride: null });
471
+ */
472
+ setBillingEmailOverride(id: number, params: SetBillingEmailOverrideParams): Promise<CustomerRecord>;
407
473
  /**
408
474
  * Remove a customer from the current seller.
409
475
  *
@@ -434,6 +500,32 @@ declare class Meta {
434
500
  get(): Promise<MetaResponse>;
435
501
  }
436
502
 
503
+ /**
504
+ * Products — discover products available to charge.
505
+ *
506
+ * Products are scoped to the seller identified by the API key. The UUID
507
+ * returned here is the same identifier accepted by `charges.create({ productId })`.
508
+ */
509
+ declare class Products {
510
+ private readonly http;
511
+ constructor(http: HttpClient);
512
+ /**
513
+ * List products for the authenticated seller, with pagination and search.
514
+ *
515
+ * @example
516
+ * const { data, meta } = await garu.products.list({ search: 'curso', limit: 10 });
517
+ */
518
+ list(params?: ListProductsParams): Promise<ProductList>;
519
+ /**
520
+ * Fetch a single product by UUID — the same identifier used by
521
+ * `charges.create({ productId })`.
522
+ *
523
+ * @example
524
+ * const product = await garu.products.get('b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f');
525
+ */
526
+ get(uuid: string): Promise<Product>;
527
+ }
528
+
437
529
  interface GaruOptions {
438
530
  /**
439
531
  * Your Garu API key. `sk_live_…` for production, `sk_test_…` for test mode.
@@ -472,6 +564,7 @@ declare class Garu {
472
564
  readonly charges: Charges;
473
565
  readonly customers: Customers;
474
566
  readonly meta: Meta;
567
+ readonly products: Products;
475
568
  /**
476
569
  * Webhook helpers. Available both as an instance member and as a static —
477
570
  * `Garu.webhooks.verify(...)` works without constructing a client.
@@ -530,4 +623,4 @@ declare class GaruServerError extends GaruAPIError {
530
623
  constructor(message: string, status: number, requestId: string | null, body: unknown);
531
624
  }
532
625
 
533
- export { type CardInfo, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PaymentMethod, type RefundChargeParams, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
626
+ export { type CardInfo, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PaymentMethod, type Product, type ProductList, type RefundChargeParams, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
package/dist/index.d.ts CHANGED
@@ -219,8 +219,22 @@ interface CustomerRecord {
219
219
  state?: string | null;
220
220
  createdAt: string;
221
221
  updatedAt: string;
222
+ /**
223
+ * Resolved billing email used for outbound seller→customer emails:
224
+ * `billingEmailOverride ?? per-seller email ?? customer.email`.
225
+ */
226
+ billingEmail?: string;
227
+ /** True when a sticky `billingEmailOverride` is set for this seller. */
228
+ hasBillingEmailOverride?: boolean;
222
229
  [key: string]: unknown;
223
230
  }
231
+ interface SetBillingEmailOverrideParams {
232
+ /**
233
+ * Customer-controlled billing email. Pass `null` to clear and fall back to
234
+ * the per-seller last-used email or the global `customer.email`.
235
+ */
236
+ billingEmailOverride: string | null;
237
+ }
224
238
  type CustomerList = PaginatedList<CustomerRecord>;
225
239
  interface CreateCustomerParams {
226
240
  name: string;
@@ -259,6 +273,41 @@ interface ListCustomersParams {
259
273
  limit?: number;
260
274
  search?: string;
261
275
  }
276
+ interface Product {
277
+ id: number;
278
+ uuid: string;
279
+ name: string;
280
+ description: string;
281
+ image: string;
282
+ /** Price in centavos (BRL × 100). */
283
+ value: number;
284
+ sellerId: number;
285
+ sellerName?: string;
286
+ pix: boolean;
287
+ boleto: boolean;
288
+ creditCard: boolean;
289
+ installments: number[];
290
+ tags?: string[];
291
+ isSubscription?: boolean;
292
+ subscriptionType?: string;
293
+ unitLabel?: string;
294
+ comission?: string;
295
+ valueWithComission?: number;
296
+ returnUrl?: string;
297
+ returnUrlButtonText?: string;
298
+ createdAt: string;
299
+ updatedAt: string;
300
+ [key: string]: unknown;
301
+ }
302
+ type ProductList = PaginatedList<Product>;
303
+ interface ListProductsParams {
304
+ page?: number;
305
+ limit?: number;
306
+ /** Search by product name. */
307
+ search?: string;
308
+ /** Backend tab filter (e.g. `active`, `archived`). Backend default is used when omitted. */
309
+ tab?: string;
310
+ }
262
311
  interface MetaFeatures {
263
312
  subscriptions: boolean;
264
313
  checkout_sessions: boolean;
@@ -269,7 +318,7 @@ interface MetaFeatures {
269
318
  interface MetaResponse {
270
319
  name: string;
271
320
  version: string;
272
- environment: 'production' | 'staging' | 'development' | string;
321
+ environment: string;
273
322
  api_version: string;
274
323
  payment_methods: string[];
275
324
  currencies: string[];
@@ -371,7 +420,7 @@ declare class Customers {
371
420
  private readonly http;
372
421
  constructor(http: HttpClient);
373
422
  /**
374
- * Create a customer and link it to the current seller.
423
+ * Register a customer for the current seller.
375
424
  *
376
425
  * @example
377
426
  * const customer = await garu.customers.create({
@@ -404,6 +453,23 @@ declare class Customers {
404
453
  * const updated = await garu.customers.update(42, { name: 'Maria Santos' });
405
454
  */
406
455
  update(id: number, params: UpdateCustomerParams): Promise<CustomerRecord>;
456
+ /**
457
+ * Set or clear the per-seller billing email override.
458
+ *
459
+ * The override is sticky: it takes precedence over the per-seller last-used
460
+ * email and the global `customer.email` for outbound seller→customer emails,
461
+ * and is **never** auto-overwritten by subsequent payments or registrations.
462
+ *
463
+ * @example
464
+ * // Set
465
+ * await garu.customers.setBillingEmailOverride(42, {
466
+ * billingEmailOverride: 'cobrancas@empresa.com.br'
467
+ * });
468
+ *
469
+ * // Clear and fall back to the last-used email
470
+ * await garu.customers.setBillingEmailOverride(42, { billingEmailOverride: null });
471
+ */
472
+ setBillingEmailOverride(id: number, params: SetBillingEmailOverrideParams): Promise<CustomerRecord>;
407
473
  /**
408
474
  * Remove a customer from the current seller.
409
475
  *
@@ -434,6 +500,32 @@ declare class Meta {
434
500
  get(): Promise<MetaResponse>;
435
501
  }
436
502
 
503
+ /**
504
+ * Products — discover products available to charge.
505
+ *
506
+ * Products are scoped to the seller identified by the API key. The UUID
507
+ * returned here is the same identifier accepted by `charges.create({ productId })`.
508
+ */
509
+ declare class Products {
510
+ private readonly http;
511
+ constructor(http: HttpClient);
512
+ /**
513
+ * List products for the authenticated seller, with pagination and search.
514
+ *
515
+ * @example
516
+ * const { data, meta } = await garu.products.list({ search: 'curso', limit: 10 });
517
+ */
518
+ list(params?: ListProductsParams): Promise<ProductList>;
519
+ /**
520
+ * Fetch a single product by UUID — the same identifier used by
521
+ * `charges.create({ productId })`.
522
+ *
523
+ * @example
524
+ * const product = await garu.products.get('b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f');
525
+ */
526
+ get(uuid: string): Promise<Product>;
527
+ }
528
+
437
529
  interface GaruOptions {
438
530
  /**
439
531
  * Your Garu API key. `sk_live_…` for production, `sk_test_…` for test mode.
@@ -472,6 +564,7 @@ declare class Garu {
472
564
  readonly charges: Charges;
473
565
  readonly customers: Customers;
474
566
  readonly meta: Meta;
567
+ readonly products: Products;
475
568
  /**
476
569
  * Webhook helpers. Available both as an instance member and as a static —
477
570
  * `Garu.webhooks.verify(...)` works without constructing a client.
@@ -530,4 +623,4 @@ declare class GaruServerError extends GaruAPIError {
530
623
  constructor(message: string, status: number, requestId: string | null, body: unknown);
531
624
  }
532
625
 
533
- export { type CardInfo, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PaymentMethod, type RefundChargeParams, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
626
+ export { type CardInfo, type Charge, type ChargeList, type ChargeStatus, type CreateChargeParams, type CreateCustomerParams, type Customer, type CustomerList, type CustomerRecord, Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, type GaruErrorCode, GaruNotFoundError, type GaruOptions, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, type ListChargesParams, type ListCustomersParams, type ListProductsParams, type MetaFeatures, type MetaResponse, type PaginatedList, type PaymentMethod, type Product, type ProductList, type RefundChargeParams, type UpdateCustomerParams, type VerifiedWebhook, type VerifyWebhookParams, type WirePaymentMethodId, webhooks };
package/dist/index.js CHANGED
@@ -331,7 +331,7 @@ var Customers = class {
331
331
  }
332
332
  http;
333
333
  /**
334
- * Create a customer and link it to the current seller.
334
+ * Register a customer for the current seller.
335
335
  *
336
336
  * @example
337
337
  * const customer = await garu.customers.create({
@@ -396,6 +396,30 @@ var Customers = class {
396
396
  }).then((r) => r)
397
397
  );
398
398
  }
399
+ /**
400
+ * Set or clear the per-seller billing email override.
401
+ *
402
+ * The override is sticky: it takes precedence over the per-seller last-used
403
+ * email and the global `customer.email` for outbound seller→customer emails,
404
+ * and is **never** auto-overwritten by subsequent payments or registrations.
405
+ *
406
+ * @example
407
+ * // Set
408
+ * await garu.customers.setBillingEmailOverride(42, {
409
+ * billingEmailOverride: 'cobrancas@empresa.com.br'
410
+ * });
411
+ *
412
+ * // Clear and fall back to the last-used email
413
+ * await garu.customers.setBillingEmailOverride(42, { billingEmailOverride: null });
414
+ */
415
+ async setBillingEmailOverride(id, params) {
416
+ return this.http.call(
417
+ (signal) => this.http.client.PATCH(`/api/customers/${id}/billing-email-override`, {
418
+ body: params,
419
+ signal
420
+ }).then((r) => r)
421
+ );
422
+ }
399
423
  /**
400
424
  * Remove a customer from the current seller.
401
425
  *
@@ -431,6 +455,48 @@ var Meta = class {
431
455
  );
432
456
  }
433
457
  };
458
+
459
+ // src/resources/products.ts
460
+ var Products = class {
461
+ constructor(http) {
462
+ this.http = http;
463
+ }
464
+ http;
465
+ /**
466
+ * List products for the authenticated seller, with pagination and search.
467
+ *
468
+ * @example
469
+ * const { data, meta } = await garu.products.list({ search: 'curso', limit: 10 });
470
+ */
471
+ async list(params = {}) {
472
+ const query = {};
473
+ if (params.page !== void 0) query.page = String(params.page);
474
+ if (params.limit !== void 0) query.limit = String(params.limit);
475
+ if (params.search) query.search = params.search;
476
+ if (params.tab) query.tab = params.tab;
477
+ const qs = new URLSearchParams(query).toString();
478
+ const url = `/api/products/seller${qs ? `?${qs}` : ""}`;
479
+ return this.http.call(
480
+ (signal) => this.http.client.GET(url, { signal }).then(
481
+ (r) => r
482
+ )
483
+ );
484
+ }
485
+ /**
486
+ * Fetch a single product by UUID — the same identifier used by
487
+ * `charges.create({ productId })`.
488
+ *
489
+ * @example
490
+ * const product = await garu.products.get('b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f');
491
+ */
492
+ async get(uuid) {
493
+ return this.http.call(
494
+ (signal) => this.http.client.GET(`/api/products/uuid/${uuid}`, { signal }).then(
495
+ (r) => r
496
+ )
497
+ );
498
+ }
499
+ };
434
500
  var webhooks = {
435
501
  verify(params) {
436
502
  const { signature, secret, payload } = params;
@@ -490,11 +556,12 @@ function parseSignatureHeader(header) {
490
556
  var DEFAULT_BASE_URL = "https://garu.com.br";
491
557
  var DEFAULT_TIMEOUT_MS = 3e4;
492
558
  var DEFAULT_MAX_RETRIES = 2;
493
- var SDK_VERSION = "0.2.0";
559
+ var SDK_VERSION = "0.3.0";
494
560
  var Garu = class {
495
561
  charges;
496
562
  customers;
497
563
  meta;
564
+ products;
498
565
  /**
499
566
  * Webhook helpers. Available both as an instance member and as a static —
500
567
  * `Garu.webhooks.verify(...)` works without constructing a client.
@@ -513,9 +580,8 @@ var Garu = class {
513
580
  this.charges = new Charges(http);
514
581
  this.customers = new Customers(http);
515
582
  this.meta = new Meta(http);
583
+ this.products = new Products(http);
516
584
  }
517
585
  };
518
586
 
519
587
  export { Garu, GaruAPIError, GaruAuthenticationError, GaruConnectionError, GaruError, GaruNotFoundError, GaruPermissionError, GaruRateLimitError, GaruServerError, GaruSignatureVerificationError, GaruValidationError, webhooks };
520
- //# sourceMappingURL=index.js.map
521
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/node",
3
- "version": "0.2.0",
3
+ "version": "0.4.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",
@@ -46,7 +46,9 @@
46
46
  "typecheck": "tsc --noEmit",
47
47
  "test": "vitest run",
48
48
  "test:watch": "vitest",
49
- "generate": "curl -sf https://garu.com.br/api/swagger-json -o src/generated/openapi.json && openapi-typescript src/generated/openapi.json -o src/generated/schema.d.ts",
49
+ "generate:fetch": "curl -sf ${GARU_SPEC_URL:-https://garu.com.br/api/swagger-json} -o src/generated/openapi.json",
50
+ "generate:filter": "node scripts/filter-spec.mjs",
51
+ "generate": "npm run generate:fetch && npm run generate:filter && openapi-typescript src/generated/openapi-sdk.json -o src/generated/schema.d.ts",
50
52
  "prepublishOnly": "npm run typecheck && npm test && npm run build"
51
53
  },
52
54
  "devDependencies": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/idempotency.ts","../src/types.ts","../src/resources/charges.ts","../src/resources/customers.ts","../src/resources/meta.ts","../src/webhooks.ts","../src/client.ts"],"names":["createClient","randomUUID","createHmac","timingSafeEqual"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Error hierarchy for the Garu SDK.\n *\n * Every error has a stable `code` string so agents and typed clients can switch on it\n * without parsing messages. Non-2xx API responses are mapped to the most specific\n * subclass of `GaruAPIError` by {@link mapApiError}.\n */\n\nexport type GaruErrorCode =\n | 'authentication_error'\n | 'permission_error'\n | 'not_found'\n | 'validation_error'\n | 'rate_limited'\n | 'server_error'\n | 'api_error'\n | 'connection_error'\n | 'signature_verification_failed';\n\nexport class GaruError extends Error {\n public readonly code: GaruErrorCode;\n\n constructor(code: GaruErrorCode, message: string) {\n super(message);\n this.name = 'GaruError';\n this.code = code;\n }\n}\n\nexport class GaruConnectionError extends GaruError {\n public readonly connectionCause: unknown;\n constructor(message: string, connectionCause?: unknown) {\n super('connection_error', message);\n this.name = 'GaruConnectionError';\n this.connectionCause = connectionCause;\n }\n}\n\nexport class GaruSignatureVerificationError extends GaruError {\n constructor(message: string) {\n super('signature_verification_failed', message);\n this.name = 'GaruSignatureVerificationError';\n }\n}\n\nexport class GaruAPIError extends GaruError {\n public readonly status: number;\n public readonly requestId: string | null;\n public readonly body: unknown;\n\n constructor(\n code: GaruErrorCode,\n message: string,\n status: number,\n requestId: string | null,\n body: unknown\n ) {\n super(code, message);\n this.name = 'GaruAPIError';\n this.status = status;\n this.requestId = requestId;\n this.body = body;\n }\n}\n\nexport class GaruAuthenticationError extends GaruAPIError {\n constructor(message: string, status: number, requestId: string | null, body: unknown) {\n super('authentication_error', message, status, requestId, body);\n this.name = 'GaruAuthenticationError';\n }\n}\n\nexport class GaruPermissionError extends GaruAPIError {\n constructor(message: string, status: number, requestId: string | null, body: unknown) {\n super('permission_error', message, status, requestId, body);\n this.name = 'GaruPermissionError';\n }\n}\n\nexport class GaruNotFoundError extends GaruAPIError {\n constructor(message: string, status: number, requestId: string | null, body: unknown) {\n super('not_found', message, status, requestId, body);\n this.name = 'GaruNotFoundError';\n }\n}\n\nexport class GaruValidationError extends GaruAPIError {\n constructor(message: string, status: number, requestId: string | null, body: unknown) {\n super('validation_error', message, status, requestId, body);\n this.name = 'GaruValidationError';\n }\n}\n\nexport class GaruRateLimitError extends GaruAPIError {\n public readonly retryAfterSec: number | null;\n constructor(\n message: string,\n status: number,\n requestId: string | null,\n body: unknown,\n retryAfterSec: number | null\n ) {\n super('rate_limited', message, status, requestId, body);\n this.name = 'GaruRateLimitError';\n this.retryAfterSec = retryAfterSec;\n }\n}\n\nexport class GaruServerError extends GaruAPIError {\n constructor(message: string, status: number, requestId: string | null, body: unknown) {\n super('server_error', message, status, requestId, body);\n this.name = 'GaruServerError';\n }\n}\n\n/**\n * Map a non-2xx HTTP response to the most specific {@link GaruAPIError} subclass.\n */\nexport function mapApiError(\n status: number,\n body: unknown,\n requestId: string | null,\n retryAfterSec: number | null\n): GaruAPIError {\n const message = extractMessage(body) ?? `Garu API returned HTTP ${status}`;\n\n if (status === 401) return new GaruAuthenticationError(message, status, requestId, body);\n if (status === 403) return new GaruPermissionError(message, status, requestId, body);\n if (status === 404) return new GaruNotFoundError(message, status, requestId, body);\n if (status === 400 || status === 422) {\n return new GaruValidationError(message, status, requestId, body);\n }\n if (status === 429) {\n return new GaruRateLimitError(message, status, requestId, body, retryAfterSec);\n }\n if (status >= 500) return new GaruServerError(message, status, requestId, body);\n return new GaruAPIError('api_error', message, status, requestId, body);\n}\n\nfunction extractMessage(body: unknown): string | null {\n if (typeof body === 'string') return body;\n if (body && typeof body === 'object') {\n const m = (body as { message?: unknown }).message;\n if (typeof m === 'string') return m;\n if (Array.isArray(m) && m.every((x) => typeof x === 'string')) return m.join('; ');\n }\n return null;\n}\n","import createClient from 'openapi-fetch';\n\nimport { GaruConnectionError, mapApiError, type GaruAPIError } from './errors.js';\nimport type { paths } from './generated/schema.js';\n\nexport interface HttpClientConfig {\n baseUrl: string;\n apiKey?: string;\n timeoutMs: number;\n maxRetries: number;\n userAgent: string;\n /** Injectable for tests. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n}\n\nconst RETRYABLE_STATUSES = new Set([408, 429, 500, 502, 503, 504]);\n\n/** Typed openapi-fetch client keyed to the backend's OpenAPI paths. */\nexport type GaruOpenapiClient = ReturnType<typeof createClient<paths>>;\n\n/** Arg type for `HttpClient.call` — a thunk that issues one openapi-fetch request. */\nexport type OpenapiCallResult<T> = Promise<{\n data?: T;\n error?: unknown;\n response: Response;\n}>;\n\n/**\n * HttpClient wraps the generated `openapi-fetch` client with:\n * - retries (exponential backoff, full jitter, honors `Retry-After`)\n * - typed error mapping (non-2xx → {@link GaruAPIError} subclass)\n * - connection error wrapping\n * - Authorization + User-Agent injection\n *\n * Resources call {@link call} with a thunk that returns an openapi-fetch\n * `{ data, error, response }` tuple; the wrapper either returns `data` or\n * throws the mapped error.\n */\nexport class HttpClient {\n public readonly client: GaruOpenapiClient;\n private readonly cfg: HttpClientConfig;\n\n constructor(cfg: HttpClientConfig) {\n this.cfg = cfg;\n const fetchImpl = cfg.fetch ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new GaruConnectionError(\n 'No fetch implementation available. Node.js >= 18 is required.'\n );\n }\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'User-Agent': cfg.userAgent\n };\n if (cfg.apiKey) headers.Authorization = `Bearer ${cfg.apiKey}`;\n\n this.client = createClient<paths>({\n baseUrl: cfg.baseUrl.replace(/\\/+$/, ''),\n fetch: fetchImpl,\n headers\n });\n }\n\n /**\n * Issue one HTTP call against the typed client, with retries + error mapping.\n *\n * `fn` is invoked up to `maxRetries + 1` times. The timeout in `cfg.timeoutMs`\n * is enforced via `AbortController`.\n */\n async call<T>(fn: (signal: AbortSignal) => OpenapiCallResult<T>): Promise<T> {\n let lastError: GaruAPIError | GaruConnectionError | null = null;\n\n for (let attempt = 0; attempt <= this.cfg.maxRetries; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.cfg.timeoutMs);\n\n try {\n const { data, error, response } = await fn(controller.signal);\n clearTimeout(timer);\n\n if (response.ok) {\n return data as T;\n }\n\n const requestId = response.headers.get('x-request-id');\n const retryAfterSec = parseRetryAfter(response.headers.get('retry-after'));\n const apiError = mapApiError(response.status, error ?? null, requestId, retryAfterSec);\n lastError = apiError;\n\n if (!RETRYABLE_STATUSES.has(response.status) || attempt === this.cfg.maxRetries) {\n throw apiError;\n }\n\n await sleep(backoffDelay(attempt, retryAfterSec));\n continue;\n } catch (err) {\n clearTimeout(timer);\n\n if (isGaruApiError(err)) throw err;\n\n const connErr =\n err instanceof Error && err.name === 'AbortError'\n ? new GaruConnectionError(`Request timed out after ${this.cfg.timeoutMs}ms`, err)\n : new GaruConnectionError(err instanceof Error ? err.message : 'Network error', err);\n lastError = connErr;\n\n if (attempt === this.cfg.maxRetries) throw connErr;\n await sleep(backoffDelay(attempt, null));\n continue;\n }\n }\n\n // Unreachable — the loop always throws or returns on the final attempt.\n throw lastError ?? new GaruConnectionError('Request failed with no error captured');\n }\n}\n\nfunction isGaruApiError(err: unknown): boolean {\n return err instanceof Error && err.name.startsWith('Garu') && err.name.endsWith('Error');\n}\n\nfunction parseRetryAfter(value: string | null): number | null {\n if (!value) return null;\n const n = Number(value);\n return Number.isFinite(n) && n >= 0 ? n : null;\n}\n\n/**\n * Exponential backoff with full jitter. If the server returned `Retry-After`,\n * we honor it (with a small jitter).\n */\nfunction backoffDelay(attempt: number, retryAfterSec: number | null): number {\n if (retryAfterSec !== null) {\n return retryAfterSec * 1000 + Math.random() * 250;\n }\n const base = 500 * 2 ** attempt;\n const cap = 8000;\n return Math.min(cap, base) * Math.random();\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { randomUUID } from 'node:crypto';\n\n/**\n * Generate a UUIDv4 suitable for use as an `X-Idempotency-Key` header value.\n *\n * @example\n * const key = generateIdempotencyKey();\n * // '3b241101-e2bb-4255-8caf-4136c566a962'\n */\nexport function generateIdempotencyKey(): string {\n return randomUUID();\n}\n","/**\n * Public types for the Garu SDK.\n *\n * The wire-level types (`WireCreateTransactionRequest`, `WireMetaResponse`, ...)\n * are generated from the backend's OpenAPI spec and live in\n * `src/generated/schema.d.ts`. The friendly types in this file\n * (`CreateChargeParams`, `Customer`, `Charge`, ...) are hand-curated for\n * ergonomics — they rename `transactions` to `charges`, collapse wire enums\n * into readable unions, and mark only truly required fields as required.\n * The resource layer maps friendly → wire at the edge.\n */\n\nimport type { components } from './generated/schema.js';\n\nexport type WireCreateTransactionRequest = components['schemas']['CreateTransactionRequest'];\nexport type WireCustomerDto = components['schemas']['CustomerDto'];\nexport type WireCardInfoDto = components['schemas']['CardInfoDto'];\nexport type WireMetaResponse = components['schemas']['MetaResponse'];\n\nexport type PaymentMethod = 'pix' | 'credit_card' | 'boleto';\n\n/** Payment-method identifier as sent to the backend over the wire. */\nexport type WirePaymentMethodId = 'pix' | 'creditcard' | 'boleto';\n\nexport type ChargeStatus =\n | 'pending'\n | 'authorized'\n | 'paid'\n | 'failed'\n | 'refunded'\n | 'cancelled'\n | 'expired';\n\nexport interface Customer {\n /** Full legal name. 3–255 chars. */\n name: string;\n email: string;\n /** CPF (11 digits) or CNPJ (14 digits), digits only. */\n document: string;\n /** 10 or 11 digits with area code, no formatting. */\n phone: string;\n /** 8 digits, no hyphen. Optional. */\n zipCode?: string;\n street?: string;\n number?: string;\n complement?: string;\n neighborhood?: string;\n city?: string;\n /** 2-letter uppercase state code, e.g. `SP`. */\n state?: string;\n}\n\nexport interface CardInfo {\n /** 13–19 digits, no spaces or hyphens. */\n cardNumber: string;\n /** 3 or 4 digits. */\n cvv: string;\n /** `YYYY-MM`. */\n expirationDate: string;\n /** As printed on the card. */\n holderName: string;\n /** 1–12. */\n installments: number;\n}\n\nexport interface CreateChargeParams {\n /** Customer buying the product. */\n customer: Customer;\n /** UUID of the product being charged. */\n productId: string;\n /** Payment method. */\n paymentMethod: PaymentMethod;\n /** Required when `paymentMethod` is `credit_card`. */\n cardInfo?: CardInfo;\n /** Free-form metadata attached to the charge. */\n additionalInfo?: string;\n /** Original checkout link, if any. */\n link?: string | null;\n /** Associated affiliate ID, if any. */\n affiliateId?: number | null;\n /** Subscription price ID (`price_*`), for subscription charges only. */\n priceId?: string | null;\n /** Optional pre-created checkout session token. */\n checkoutSessionToken?: string;\n /**\n * Idempotency key. If omitted, the SDK generates a UUIDv4.\n * Keys are valid for 24h on the backend.\n */\n idempotencyKey?: string;\n}\n\nexport interface Charge {\n id: number;\n status: ChargeStatus;\n amount: number;\n paymentMethodId: WirePaymentMethodId;\n /** ISO-8601. */\n date: string;\n /** ISO-8601. */\n deadline?: string;\n /** Product this charge belongs to. */\n product?: { id: number; uuid?: string; name?: string };\n [key: string]: unknown;\n}\n\nexport interface RefundChargeParams {\n /** Partial refund in centavos. Omit for full refund. */\n amount?: number;\n /** Free-form reason stored on the refund. */\n reason?: string;\n idempotencyKey?: string;\n}\n\nexport interface ListChargesParams {\n /** Page number (1-based). Default: 1. */\n page?: number;\n /** Items per page (1–100). Default: 20. */\n limit?: number;\n /** Filter by status (e.g. `paid`, `pending`). */\n status?: string;\n /** Search by customer name, email, or document. */\n search?: string;\n /** Filter by payment method (`pix`, `creditcard`, `boleto`). */\n paymentMethod?: string;\n}\n\nexport interface PaginatedList<T> {\n data: T[];\n meta: {\n page: number;\n limit: number;\n total: number;\n totalPages: number;\n };\n}\n\nexport type ChargeList = PaginatedList<Charge>;\n\nexport interface CustomerRecord {\n id: number;\n name: string;\n email: string;\n document: string;\n phone: string;\n personType: string;\n zipCode?: string | null;\n street?: string | null;\n number?: string | null;\n complement?: string | null;\n neighborhood?: string | null;\n city?: string | null;\n state?: string | null;\n createdAt: string;\n updatedAt: string;\n [key: string]: unknown;\n}\n\nexport type CustomerList = PaginatedList<CustomerRecord>;\n\nexport interface CreateCustomerParams {\n name: string;\n email: string;\n /** CPF (11 digits) or CNPJ (14 digits), digits only. */\n document: string;\n /** 10 or 11 digits with area code. */\n phone: string;\n /** `fisica` or `juridica`. */\n personType: 'fisica' | 'juridica';\n zipCode?: string;\n street?: string;\n number?: string;\n complement?: string;\n neighborhood?: string;\n city?: string;\n /** 2-letter uppercase state code, e.g. `SP`. */\n state?: string;\n}\n\nexport interface UpdateCustomerParams {\n name?: string;\n email?: string;\n document?: string;\n phone?: string;\n personType?: 'fisica' | 'juridica';\n zipCode?: string;\n street?: string;\n number?: string;\n complement?: string;\n neighborhood?: string;\n city?: string;\n state?: string;\n}\n\nexport interface ListCustomersParams {\n page?: number;\n limit?: number;\n search?: string;\n}\n\nexport interface MetaFeatures {\n subscriptions: boolean;\n checkout_sessions: boolean;\n idempotency_keys: boolean;\n test_mode: boolean;\n webhooks: boolean;\n}\n\nexport interface MetaResponse {\n name: string;\n version: string;\n environment: 'production' | 'staging' | 'development' | string;\n api_version: string;\n payment_methods: string[];\n currencies: string[];\n billing_intervals: string[];\n webhook_events: string[];\n features: MetaFeatures;\n docs_url: string;\n dashboard_url: string;\n support_email: string;\n}\n\n/** Map the SDK's friendly `PaymentMethod` to the backend's wire value. */\nexport function toWirePaymentMethod(pm: PaymentMethod): WirePaymentMethodId {\n return pm === 'credit_card' ? 'creditcard' : pm;\n}\n","import type { HttpClient } from '../http.js';\nimport type { components } from '../generated/schema.js';\nimport { generateIdempotencyKey } from '../idempotency.js';\nimport {\n toWirePaymentMethod,\n type Charge,\n type ChargeList,\n type CreateChargeParams,\n type ListChargesParams,\n type RefundChargeParams\n} from '../types.js';\n\ntype CreateTransactionBody = components['schemas']['CreateTransactionRequest'];\n\n/**\n * Charges — the core of the Garu API.\n *\n * A charge represents a single payment attempt against a product. The SDK\n * surfaces charges under `garu.charges` even though the backend route is\n * `/api/transactions` — this matches Stripe convention and is the name every\n * other Garu surface (MCP, CLI, docs) uses.\n */\nexport class Charges {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a charge (PIX, credit card, or boleto).\n *\n * Automatically attaches an `X-Idempotency-Key` header — if you don't pass\n * `idempotencyKey`, the SDK generates a UUIDv4. Safe to retry: the backend\n * caches the first response for 24h.\n *\n * @example\n * // PIX charge\n * const charge = await garu.charges.create({\n * productId: 'b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f',\n * paymentMethod: 'pix',\n * customer: {\n * name: 'Maria Silva',\n * email: 'maria@exemplo.com.br',\n * document: '12345678909',\n * phone: '11987654321'\n * }\n * });\n * // charge.id, charge.status\n *\n * @example\n * // Credit card charge, 3 installments\n * const charge = await garu.charges.create({\n * productId: 'b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f',\n * paymentMethod: 'credit_card',\n * customer: { name: 'Maria Silva', email: 'maria@exemplo.com.br', document: '12345678909', phone: '11987654321' },\n * cardInfo: {\n * cardNumber: '4111111111111111',\n * cvv: '123',\n * expirationDate: '2030-12',\n * holderName: 'MARIA SILVA',\n * installments: 3\n * }\n * });\n */\n async create(params: CreateChargeParams): Promise<Charge> {\n const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();\n const body = this.buildCreateBody(params);\n\n return this.http.call<Charge>(\n (signal) =>\n this.http.client.POST('/api/transactions', {\n body,\n headers: { 'X-Idempotency-Key': idempotencyKey },\n signal\n }) as Promise<{ data?: Charge; error?: unknown; response: Response }>\n );\n }\n\n /**\n * List charges for the authenticated seller, with pagination and filters.\n *\n * @example\n * const { data, meta } = await garu.charges.list({ status: 'paid', limit: 10 });\n * // meta.total paid charges\n */\n async list(params: ListChargesParams = {}): Promise<ChargeList> {\n const query: Record<string, string> = {};\n if (params.page !== undefined) query.page = String(params.page);\n if (params.limit !== undefined) query.limit = String(params.limit);\n if (params.status) query.status = params.status;\n if (params.search) query.search = params.search;\n if (params.paymentMethod) query.paymentMethod = params.paymentMethod;\n\n const qs = new URLSearchParams(query).toString();\n const url = `/api/transactions${qs ? `?${qs}` : ''}`;\n\n return this.http.call<ChargeList>((signal) =>\n (this.http.client.GET as Function)(url, { signal }).then(\n (r: { data?: ChargeList; error?: unknown; response: Response }) => r\n )\n );\n }\n\n /**\n * Fetch a single charge by numeric ID.\n *\n * @example\n * const charge = await garu.charges.get(4472);\n * if (charge.status === 'paid') { ... }\n */\n async get(id: number): Promise<Charge> {\n return this.http.call<Charge>(\n (signal) =>\n this.http.client.GET('/api/transactions/{id}', {\n params: { path: { id } },\n signal\n }) as Promise<{ data?: Charge; error?: unknown; response: Response }>\n );\n }\n\n /**\n * Refund a charge — fully, or partially by passing `amount` in centavos.\n *\n * @example\n * // Full refund\n * await garu.charges.refund(4472);\n *\n * @example\n * // Partial refund of R$ 10,00\n * await garu.charges.refund(4472, { amount: 1000, reason: 'customer_request' });\n */\n async refund(id: number, params: RefundChargeParams = {}): Promise<Charge> {\n const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();\n const body: Record<string, unknown> = {};\n if (params.amount !== undefined) body.amount = params.amount;\n if (params.reason !== undefined) body.reason = params.reason;\n\n return this.http.call<Charge>(\n (signal) =>\n this.http.client.POST('/api/transactions/{id}/refund', {\n params: { path: { id } },\n body: body as never,\n headers: { 'X-Idempotency-Key': idempotencyKey },\n signal\n }) as Promise<{ data?: Charge; error?: unknown; response: Response }>\n );\n }\n\n private buildCreateBody(params: CreateChargeParams): CreateTransactionBody {\n const body: Record<string, unknown> = {\n customer: params.customer,\n productId: params.productId,\n paymentMethodId: toWirePaymentMethod(params.paymentMethod),\n link: params.link ?? null,\n affiliateId: params.affiliateId ?? null\n };\n if (params.additionalInfo !== undefined) body.additionalInfo = params.additionalInfo;\n if (params.priceId !== undefined) body.priceId = params.priceId;\n if (params.checkoutSessionToken !== undefined) {\n body.checkoutSessionToken = params.checkoutSessionToken;\n }\n if (params.cardInfo) body.CardInfo = params.cardInfo;\n return body as unknown as CreateTransactionBody;\n }\n}\n","import type { HttpClient } from '../http.js';\nimport type {\n CreateCustomerParams,\n CustomerList,\n CustomerRecord,\n ListCustomersParams,\n UpdateCustomerParams\n} from '../types.js';\n\n/**\n * Customers — manage your customer base.\n *\n * Customers are scoped to the seller identified by the API key. The backend\n * uses a junction table (`customer_seller_profile`) so the same person can\n * exist across multiple sellers without duplication.\n */\nexport class Customers {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a customer and link it to the current seller.\n *\n * @example\n * const customer = await garu.customers.create({\n * name: 'Maria Silva',\n * email: 'maria@exemplo.com.br',\n * document: '12345678909',\n * phone: '11987654321',\n * personType: 'fisica'\n * });\n */\n async create(params: CreateCustomerParams): Promise<CustomerRecord> {\n return this.http.call<CustomerRecord>((signal) =>\n (this.http.client.POST as Function)('/api/customers', {\n body: params,\n signal\n }).then((r: { data?: CustomerRecord; error?: unknown; response: Response }) => r)\n );\n }\n\n /**\n * List customers for the authenticated seller, with pagination and search.\n *\n * @example\n * const { data, meta } = await garu.customers.list({ search: 'maria', limit: 10 });\n */\n async list(params: ListCustomersParams = {}): Promise<CustomerList> {\n const query: Record<string, string> = {};\n if (params.page !== undefined) query.page = String(params.page);\n if (params.limit !== undefined) query.limit = String(params.limit);\n if (params.search) query.search = params.search;\n\n const qs = new URLSearchParams(query).toString();\n const url = `/api/customers${qs ? `?${qs}` : ''}`;\n\n return this.http.call<CustomerList>((signal) =>\n (this.http.client.GET as Function)(url, { signal }).then(\n (r: { data?: CustomerList; error?: unknown; response: Response }) => r\n )\n );\n }\n\n /**\n * Fetch a single customer by numeric ID.\n *\n * @example\n * const customer = await garu.customers.get(42);\n */\n async get(id: number): Promise<CustomerRecord> {\n return this.http.call<CustomerRecord>((signal) =>\n (this.http.client.GET as Function)(`/api/customers/${id}`, { signal }).then(\n (r: { data?: CustomerRecord; error?: unknown; response: Response }) => r\n )\n );\n }\n\n /**\n * Update a customer's profile for the current seller.\n *\n * @example\n * const updated = await garu.customers.update(42, { name: 'Maria Santos' });\n */\n async update(id: number, params: UpdateCustomerParams): Promise<CustomerRecord> {\n return this.http.call<CustomerRecord>((signal) =>\n (this.http.client.PUT as Function)(`/api/customers/${id}`, {\n body: params,\n signal\n }).then((r: { data?: CustomerRecord; error?: unknown; response: Response }) => r)\n );\n }\n\n /**\n * Remove a customer from the current seller.\n *\n * @example\n * await garu.customers.delete(42);\n */\n async delete(id: number): Promise<void> {\n await this.http.call<unknown>((signal) =>\n (this.http.client.DELETE as Function)(`/api/customers/${id}`, { signal }).then(\n (r: { data?: unknown; error?: unknown; response: Response }) => r\n )\n );\n }\n}\n","import type { HttpClient } from '../http.js';\nimport type { MetaResponse } from '../types.js';\n\n/**\n * Meta — capability introspection.\n *\n * Unauthenticated. Used by `garu doctor`, MCP tool `doctor`, and by SDK\n * consumers that want to know which payment methods and webhook events are\n * currently supported.\n */\nexport class Meta {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Fetch the API's current capability payload.\n *\n * @example\n * const meta = await garu.meta.get();\n * console.log(meta.version, meta.payment_methods);\n * if (meta.features.subscriptions) { ... }\n */\n async get(): Promise<MetaResponse> {\n return this.http.call<MetaResponse>(\n (signal) =>\n this.http.client.GET('/api/meta', { signal }) as Promise<{\n data?: MetaResponse;\n error?: unknown;\n response: Response;\n }>\n );\n }\n}\n","import { createHmac, timingSafeEqual } from 'node:crypto';\n\nimport { GaruSignatureVerificationError } from './errors.js';\n\nexport interface VerifyWebhookParams {\n /** Raw request body as received — do NOT re-serialize parsed JSON. */\n payload: string | Buffer;\n /** Value of the `X-Garu-Signature` header. Format: `t=<ts>,v1=<hex>`. */\n signature: string;\n /** The webhook endpoint's signing secret. */\n secret: string;\n /** Reject signatures older than this many seconds. Default: 300 (5 min). */\n toleranceSec?: number;\n /** Injectable for tests. Defaults to `Date.now()`. */\n now?: () => number;\n}\n\nexport interface VerifiedWebhook {\n /** Timestamp from the signature header, in seconds since epoch. */\n timestamp: number;\n /** Parsed JSON body. Throws {@link GaruSignatureVerificationError} if invalid JSON. */\n event: unknown;\n}\n\n/**\n * Webhook helpers.\n *\n * Garu signs outgoing webhooks with HMAC-SHA256 over `${timestamp}.${payload}`\n * and delivers the signature in the `X-Garu-Signature` header as `t=<ts>,v1=<hex>`.\n * This matches the format in the backend's `webhook-delivery.service.ts`.\n *\n * @example\n * // Express example\n * app.post('/webhooks/garu', express.raw({ type: 'application/json' }), (req, res) => {\n * try {\n * const { event } = Garu.webhooks.verify({\n * payload: req.body,\n * signature: req.header('x-garu-signature') ?? '',\n * secret: process.env.GARU_WEBHOOK_SECRET!\n * });\n * // handle event\n * res.sendStatus(200);\n * } catch (err) {\n * res.sendStatus(400);\n * }\n * });\n */\nexport const webhooks = {\n verify(params: VerifyWebhookParams): VerifiedWebhook {\n const { signature, secret, payload } = params;\n const toleranceSec = params.toleranceSec ?? 300;\n const now = params.now ?? Date.now;\n\n if (!signature || typeof signature !== 'string') {\n throw new GaruSignatureVerificationError('Missing or malformed X-Garu-Signature header');\n }\n\n const parts = parseSignatureHeader(signature);\n if (parts === null) {\n throw new GaruSignatureVerificationError(\n 'X-Garu-Signature header does not match expected format t=<ts>,v1=<hex>'\n );\n }\n\n const payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');\n const signedPayload = `${parts.timestamp}.${payloadStr}`;\n const expected = createHmac('sha256', secret).update(signedPayload).digest('hex');\n\n const expectedBuf = Buffer.from(expected, 'hex');\n const providedBuf = Buffer.from(parts.v1, 'hex');\n if (expectedBuf.length !== providedBuf.length || !timingSafeEqual(expectedBuf, providedBuf)) {\n throw new GaruSignatureVerificationError('Signature does not match computed HMAC');\n }\n\n const nowSec = Math.floor(now() / 1000);\n if (Math.abs(nowSec - parts.timestamp) > toleranceSec) {\n throw new GaruSignatureVerificationError(\n `Signature timestamp outside tolerance window (${toleranceSec}s)`\n );\n }\n\n let event: unknown;\n try {\n event = JSON.parse(payloadStr);\n } catch {\n throw new GaruSignatureVerificationError('Webhook payload is not valid JSON');\n }\n\n return { timestamp: parts.timestamp, event };\n }\n};\n\nfunction parseSignatureHeader(header: string): { timestamp: number; v1: string } | null {\n const fields: Record<string, string> = {};\n for (const part of header.split(',')) {\n const idx = part.indexOf('=');\n if (idx === -1) return null;\n const key = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (!key || !value) return null;\n fields[key] = value;\n }\n const t = fields.t;\n const v1 = fields.v1;\n if (!t || !v1) return null;\n const timestamp = Number(t);\n if (!Number.isFinite(timestamp) || !/^[a-f0-9]+$/i.test(v1)) return null;\n return { timestamp, v1 };\n}\n","import { HttpClient } from './http.js';\nimport { Charges } from './resources/charges.js';\nimport { Customers } from './resources/customers.js';\nimport { Meta } from './resources/meta.js';\nimport { webhooks } from './webhooks.js';\n\nexport interface GaruOptions {\n /**\n * Your Garu API key. `sk_live_…` for production, `sk_test_…` for test mode.\n * Optional — public endpoints (`meta.get`, public charge creation) work without one.\n */\n apiKey?: string;\n /** Override the API base URL. Default: `https://garu.com.br/api`. */\n baseUrl?: string;\n /** Per-request timeout in ms. Default: 30000. */\n timeoutMs?: number;\n /** Max retries on retryable errors (connection, 408, 429, 5xx). Default: 2. */\n maxRetries?: number;\n /** Injectable for tests. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_BASE_URL = 'https://garu.com.br';\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst SDK_VERSION = '0.2.0';\n\n/**\n * The Garu SDK client.\n *\n * @example\n * import { Garu } from '@garuhq/node';\n *\n * const garu = new Garu({ apiKey: process.env.GARU_API_KEY });\n *\n * const charge = await garu.charges.create({\n * productId: 'b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f',\n * paymentMethod: 'pix',\n * customer: {\n * name: 'Maria Silva',\n * email: 'maria@exemplo.com.br',\n * document: '12345678909',\n * phone: '11987654321'\n * }\n * });\n */\nexport class Garu {\n public readonly charges: Charges;\n public readonly customers: Customers;\n public readonly meta: Meta;\n\n /**\n * Webhook helpers. Available both as an instance member and as a static —\n * `Garu.webhooks.verify(...)` works without constructing a client.\n */\n public static readonly webhooks = webhooks;\n public readonly webhooks = webhooks;\n\n constructor(options: GaruOptions = {}) {\n const http = new HttpClient({\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\n apiKey: options.apiKey,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n userAgent: `garu-node/${SDK_VERSION}`,\n fetch: options.fetch\n });\n this.charges = new Charges(http);\n this.customers = new Customers(http);\n this.meta = new Meta(http);\n }\n}\n"]}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/idempotency.ts","../src/types.ts","../src/resources/charges.ts","../src/resources/customers.ts","../src/resources/meta.ts","../src/webhooks.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Error hierarchy for the Garu SDK.\n *\n * Every error has a stable `code` string so agents and typed clients can switch on it\n * without parsing messages. Non-2xx API responses are mapped to the most specific\n * subclass of `GaruAPIError` by {@link mapApiError}.\n */\n\nexport type GaruErrorCode =\n | 'authentication_error'\n | 'permission_error'\n | 'not_found'\n | 'validation_error'\n | 'rate_limited'\n | 'server_error'\n | 'api_error'\n | 'connection_error'\n | 'signature_verification_failed';\n\nexport class GaruError extends Error {\n public readonly code: GaruErrorCode;\n\n constructor(code: GaruErrorCode, message: string) {\n super(message);\n this.name = 'GaruError';\n this.code = code;\n }\n}\n\nexport class GaruConnectionError extends GaruError {\n public readonly connectionCause: unknown;\n constructor(message: string, connectionCause?: unknown) {\n super('connection_error', message);\n this.name = 'GaruConnectionError';\n this.connectionCause = connectionCause;\n }\n}\n\nexport class GaruSignatureVerificationError extends GaruError {\n constructor(message: string) {\n super('signature_verification_failed', message);\n this.name = 'GaruSignatureVerificationError';\n }\n}\n\nexport class GaruAPIError extends GaruError {\n public readonly status: number;\n public readonly requestId: string | null;\n public readonly body: unknown;\n\n constructor(\n code: GaruErrorCode,\n message: string,\n status: number,\n requestId: string | null,\n body: unknown\n ) {\n super(code, message);\n this.name = 'GaruAPIError';\n this.status = status;\n this.requestId = requestId;\n this.body = body;\n }\n}\n\nexport class GaruAuthenticationError extends GaruAPIError {\n constructor(message: string, status: number, requestId: string | null, body: unknown) {\n super('authentication_error', message, status, requestId, body);\n this.name = 'GaruAuthenticationError';\n }\n}\n\nexport class GaruPermissionError extends GaruAPIError {\n constructor(message: string, status: number, requestId: string | null, body: unknown) {\n super('permission_error', message, status, requestId, body);\n this.name = 'GaruPermissionError';\n }\n}\n\nexport class GaruNotFoundError extends GaruAPIError {\n constructor(message: string, status: number, requestId: string | null, body: unknown) {\n super('not_found', message, status, requestId, body);\n this.name = 'GaruNotFoundError';\n }\n}\n\nexport class GaruValidationError extends GaruAPIError {\n constructor(message: string, status: number, requestId: string | null, body: unknown) {\n super('validation_error', message, status, requestId, body);\n this.name = 'GaruValidationError';\n }\n}\n\nexport class GaruRateLimitError extends GaruAPIError {\n public readonly retryAfterSec: number | null;\n constructor(\n message: string,\n status: number,\n requestId: string | null,\n body: unknown,\n retryAfterSec: number | null\n ) {\n super('rate_limited', message, status, requestId, body);\n this.name = 'GaruRateLimitError';\n this.retryAfterSec = retryAfterSec;\n }\n}\n\nexport class GaruServerError extends GaruAPIError {\n constructor(message: string, status: number, requestId: string | null, body: unknown) {\n super('server_error', message, status, requestId, body);\n this.name = 'GaruServerError';\n }\n}\n\n/**\n * Map a non-2xx HTTP response to the most specific {@link GaruAPIError} subclass.\n */\nexport function mapApiError(\n status: number,\n body: unknown,\n requestId: string | null,\n retryAfterSec: number | null\n): GaruAPIError {\n const message = extractMessage(body) ?? `Garu API returned HTTP ${status}`;\n\n if (status === 401) return new GaruAuthenticationError(message, status, requestId, body);\n if (status === 403) return new GaruPermissionError(message, status, requestId, body);\n if (status === 404) return new GaruNotFoundError(message, status, requestId, body);\n if (status === 400 || status === 422) {\n return new GaruValidationError(message, status, requestId, body);\n }\n if (status === 429) {\n return new GaruRateLimitError(message, status, requestId, body, retryAfterSec);\n }\n if (status >= 500) return new GaruServerError(message, status, requestId, body);\n return new GaruAPIError('api_error', message, status, requestId, body);\n}\n\nfunction extractMessage(body: unknown): string | null {\n if (typeof body === 'string') return body;\n if (body && typeof body === 'object') {\n const m = (body as { message?: unknown }).message;\n if (typeof m === 'string') return m;\n if (Array.isArray(m) && m.every((x) => typeof x === 'string')) return m.join('; ');\n }\n return null;\n}\n","import createClient from 'openapi-fetch';\n\nimport { GaruConnectionError, mapApiError, type GaruAPIError } from './errors.js';\nimport type { paths } from './generated/schema.js';\n\nexport interface HttpClientConfig {\n baseUrl: string;\n apiKey?: string;\n timeoutMs: number;\n maxRetries: number;\n userAgent: string;\n /** Injectable for tests. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n}\n\nconst RETRYABLE_STATUSES = new Set([408, 429, 500, 502, 503, 504]);\n\n/** Typed openapi-fetch client keyed to the backend's OpenAPI paths. */\nexport type GaruOpenapiClient = ReturnType<typeof createClient<paths>>;\n\n/** Arg type for `HttpClient.call` — a thunk that issues one openapi-fetch request. */\nexport type OpenapiCallResult<T> = Promise<{\n data?: T;\n error?: unknown;\n response: Response;\n}>;\n\n/**\n * HttpClient wraps the generated `openapi-fetch` client with:\n * - retries (exponential backoff, full jitter, honors `Retry-After`)\n * - typed error mapping (non-2xx → {@link GaruAPIError} subclass)\n * - connection error wrapping\n * - Authorization + User-Agent injection\n *\n * Resources call {@link call} with a thunk that returns an openapi-fetch\n * `{ data, error, response }` tuple; the wrapper either returns `data` or\n * throws the mapped error.\n */\nexport class HttpClient {\n public readonly client: GaruOpenapiClient;\n private readonly cfg: HttpClientConfig;\n\n constructor(cfg: HttpClientConfig) {\n this.cfg = cfg;\n const fetchImpl = cfg.fetch ?? globalThis.fetch;\n if (!fetchImpl) {\n throw new GaruConnectionError(\n 'No fetch implementation available. Node.js >= 18 is required.'\n );\n }\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'User-Agent': cfg.userAgent\n };\n if (cfg.apiKey) headers.Authorization = `Bearer ${cfg.apiKey}`;\n\n this.client = createClient<paths>({\n baseUrl: cfg.baseUrl.replace(/\\/+$/, ''),\n fetch: fetchImpl,\n headers\n });\n }\n\n /**\n * Issue one HTTP call against the typed client, with retries + error mapping.\n *\n * `fn` is invoked up to `maxRetries + 1` times. The timeout in `cfg.timeoutMs`\n * is enforced via `AbortController`.\n */\n async call<T>(fn: (signal: AbortSignal) => OpenapiCallResult<T>): Promise<T> {\n let lastError: GaruAPIError | GaruConnectionError | null = null;\n\n for (let attempt = 0; attempt <= this.cfg.maxRetries; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.cfg.timeoutMs);\n\n try {\n const { data, error, response } = await fn(controller.signal);\n clearTimeout(timer);\n\n if (response.ok) {\n return data as T;\n }\n\n const requestId = response.headers.get('x-request-id');\n const retryAfterSec = parseRetryAfter(response.headers.get('retry-after'));\n const apiError = mapApiError(response.status, error ?? null, requestId, retryAfterSec);\n lastError = apiError;\n\n if (!RETRYABLE_STATUSES.has(response.status) || attempt === this.cfg.maxRetries) {\n throw apiError;\n }\n\n await sleep(backoffDelay(attempt, retryAfterSec));\n continue;\n } catch (err) {\n clearTimeout(timer);\n\n if (isGaruApiError(err)) throw err;\n\n const connErr =\n err instanceof Error && err.name === 'AbortError'\n ? new GaruConnectionError(`Request timed out after ${this.cfg.timeoutMs}ms`, err)\n : new GaruConnectionError(err instanceof Error ? err.message : 'Network error', err);\n lastError = connErr;\n\n if (attempt === this.cfg.maxRetries) throw connErr;\n await sleep(backoffDelay(attempt, null));\n continue;\n }\n }\n\n // Unreachable — the loop always throws or returns on the final attempt.\n throw lastError ?? new GaruConnectionError('Request failed with no error captured');\n }\n}\n\nfunction isGaruApiError(err: unknown): boolean {\n return err instanceof Error && err.name.startsWith('Garu') && err.name.endsWith('Error');\n}\n\nfunction parseRetryAfter(value: string | null): number | null {\n if (!value) return null;\n const n = Number(value);\n return Number.isFinite(n) && n >= 0 ? n : null;\n}\n\n/**\n * Exponential backoff with full jitter. If the server returned `Retry-After`,\n * we honor it (with a small jitter).\n */\nfunction backoffDelay(attempt: number, retryAfterSec: number | null): number {\n if (retryAfterSec !== null) {\n return retryAfterSec * 1000 + Math.random() * 250;\n }\n const base = 500 * 2 ** attempt;\n const cap = 8000;\n return Math.min(cap, base) * Math.random();\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { randomUUID } from 'node:crypto';\n\n/**\n * Generate a UUIDv4 suitable for use as an `X-Idempotency-Key` header value.\n *\n * @example\n * const key = generateIdempotencyKey();\n * // '3b241101-e2bb-4255-8caf-4136c566a962'\n */\nexport function generateIdempotencyKey(): string {\n return randomUUID();\n}\n","/**\n * Public types for the Garu SDK.\n *\n * The wire-level types (`WireCreateTransactionRequest`, `WireMetaResponse`, ...)\n * are generated from the backend's OpenAPI spec and live in\n * `src/generated/schema.d.ts`. The friendly types in this file\n * (`CreateChargeParams`, `Customer`, `Charge`, ...) are hand-curated for\n * ergonomics — they rename `transactions` to `charges`, collapse wire enums\n * into readable unions, and mark only truly required fields as required.\n * The resource layer maps friendly → wire at the edge.\n */\n\nimport type { components } from './generated/schema.js';\n\nexport type WireCreateTransactionRequest = components['schemas']['CreateTransactionRequest'];\nexport type WireCustomerDto = components['schemas']['CustomerDto'];\nexport type WireCardInfoDto = components['schemas']['CardInfoDto'];\nexport type WireMetaResponse = components['schemas']['MetaResponse'];\n\nexport type PaymentMethod = 'pix' | 'credit_card' | 'boleto';\n\n/** Payment-method identifier as sent to the backend over the wire. */\nexport type WirePaymentMethodId = 'pix' | 'creditcard' | 'boleto';\n\nexport type ChargeStatus =\n | 'pending'\n | 'authorized'\n | 'paid'\n | 'failed'\n | 'refunded'\n | 'cancelled'\n | 'expired';\n\nexport interface Customer {\n /** Full legal name. 3–255 chars. */\n name: string;\n email: string;\n /** CPF (11 digits) or CNPJ (14 digits), digits only. */\n document: string;\n /** 10 or 11 digits with area code, no formatting. */\n phone: string;\n /** 8 digits, no hyphen. Optional. */\n zipCode?: string;\n street?: string;\n number?: string;\n complement?: string;\n neighborhood?: string;\n city?: string;\n /** 2-letter uppercase state code, e.g. `SP`. */\n state?: string;\n}\n\nexport interface CardInfo {\n /** 13–19 digits, no spaces or hyphens. */\n cardNumber: string;\n /** 3 or 4 digits. */\n cvv: string;\n /** `YYYY-MM`. */\n expirationDate: string;\n /** As printed on the card. */\n holderName: string;\n /** 1–12. */\n installments: number;\n}\n\nexport interface CreateChargeParams {\n /** Customer buying the product. */\n customer: Customer;\n /** UUID of the product being charged. */\n productId: string;\n /** Payment method. */\n paymentMethod: PaymentMethod;\n /** Required when `paymentMethod` is `credit_card`. */\n cardInfo?: CardInfo;\n /** Free-form metadata attached to the charge. */\n additionalInfo?: string;\n /** Original checkout link, if any. */\n link?: string | null;\n /** Associated affiliate ID, if any. */\n affiliateId?: number | null;\n /** Subscription price ID (`price_*`), for subscription charges only. */\n priceId?: string | null;\n /** Optional pre-created checkout session token. */\n checkoutSessionToken?: string;\n /**\n * Idempotency key. If omitted, the SDK generates a UUIDv4.\n * Keys are valid for 24h on the backend.\n */\n idempotencyKey?: string;\n}\n\nexport interface Charge {\n id: number;\n status: ChargeStatus;\n amount: number;\n paymentMethodId: WirePaymentMethodId;\n /** ISO-8601. */\n date: string;\n /** ISO-8601. */\n deadline?: string;\n /** Product this charge belongs to. */\n product?: { id: number; uuid?: string; name?: string };\n [key: string]: unknown;\n}\n\nexport interface RefundChargeParams {\n /** Partial refund in centavos. Omit for full refund. */\n amount?: number;\n /** Free-form reason stored on the refund. */\n reason?: string;\n idempotencyKey?: string;\n}\n\nexport interface ListChargesParams {\n /** Page number (1-based). Default: 1. */\n page?: number;\n /** Items per page (1–100). Default: 20. */\n limit?: number;\n /** Filter by status (e.g. `paid`, `pending`). */\n status?: string;\n /** Search by customer name, email, or document. */\n search?: string;\n /** Filter by payment method (`pix`, `creditcard`, `boleto`). */\n paymentMethod?: string;\n}\n\nexport interface PaginatedList<T> {\n data: T[];\n meta: {\n page: number;\n limit: number;\n total: number;\n totalPages: number;\n };\n}\n\nexport type ChargeList = PaginatedList<Charge>;\n\nexport interface CustomerRecord {\n id: number;\n name: string;\n email: string;\n document: string;\n phone: string;\n personType: string;\n zipCode?: string | null;\n street?: string | null;\n number?: string | null;\n complement?: string | null;\n neighborhood?: string | null;\n city?: string | null;\n state?: string | null;\n createdAt: string;\n updatedAt: string;\n [key: string]: unknown;\n}\n\nexport type CustomerList = PaginatedList<CustomerRecord>;\n\nexport interface CreateCustomerParams {\n name: string;\n email: string;\n /** CPF (11 digits) or CNPJ (14 digits), digits only. */\n document: string;\n /** 10 or 11 digits with area code. */\n phone: string;\n /** `fisica` or `juridica`. */\n personType: 'fisica' | 'juridica';\n zipCode?: string;\n street?: string;\n number?: string;\n complement?: string;\n neighborhood?: string;\n city?: string;\n /** 2-letter uppercase state code, e.g. `SP`. */\n state?: string;\n}\n\nexport interface UpdateCustomerParams {\n name?: string;\n email?: string;\n document?: string;\n phone?: string;\n personType?: 'fisica' | 'juridica';\n zipCode?: string;\n street?: string;\n number?: string;\n complement?: string;\n neighborhood?: string;\n city?: string;\n state?: string;\n}\n\nexport interface ListCustomersParams {\n page?: number;\n limit?: number;\n search?: string;\n}\n\nexport interface MetaFeatures {\n subscriptions: boolean;\n checkout_sessions: boolean;\n idempotency_keys: boolean;\n test_mode: boolean;\n webhooks: boolean;\n}\n\nexport interface MetaResponse {\n name: string;\n version: string;\n environment: 'production' | 'staging' | 'development' | string;\n api_version: string;\n payment_methods: string[];\n currencies: string[];\n billing_intervals: string[];\n webhook_events: string[];\n features: MetaFeatures;\n docs_url: string;\n dashboard_url: string;\n support_email: string;\n}\n\n/** Map the SDK's friendly `PaymentMethod` to the backend's wire value. */\nexport function toWirePaymentMethod(pm: PaymentMethod): WirePaymentMethodId {\n return pm === 'credit_card' ? 'creditcard' : pm;\n}\n","import type { HttpClient } from '../http.js';\nimport type { components } from '../generated/schema.js';\nimport { generateIdempotencyKey } from '../idempotency.js';\nimport {\n toWirePaymentMethod,\n type Charge,\n type ChargeList,\n type CreateChargeParams,\n type ListChargesParams,\n type RefundChargeParams\n} from '../types.js';\n\ntype CreateTransactionBody = components['schemas']['CreateTransactionRequest'];\n\n/**\n * Charges — the core of the Garu API.\n *\n * A charge represents a single payment attempt against a product. The SDK\n * surfaces charges under `garu.charges` even though the backend route is\n * `/api/transactions` — this matches Stripe convention and is the name every\n * other Garu surface (MCP, CLI, docs) uses.\n */\nexport class Charges {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a charge (PIX, credit card, or boleto).\n *\n * Automatically attaches an `X-Idempotency-Key` header — if you don't pass\n * `idempotencyKey`, the SDK generates a UUIDv4. Safe to retry: the backend\n * caches the first response for 24h.\n *\n * @example\n * // PIX charge\n * const charge = await garu.charges.create({\n * productId: 'b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f',\n * paymentMethod: 'pix',\n * customer: {\n * name: 'Maria Silva',\n * email: 'maria@exemplo.com.br',\n * document: '12345678909',\n * phone: '11987654321'\n * }\n * });\n * // charge.id, charge.status\n *\n * @example\n * // Credit card charge, 3 installments\n * const charge = await garu.charges.create({\n * productId: 'b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f',\n * paymentMethod: 'credit_card',\n * customer: { name: 'Maria Silva', email: 'maria@exemplo.com.br', document: '12345678909', phone: '11987654321' },\n * cardInfo: {\n * cardNumber: '4111111111111111',\n * cvv: '123',\n * expirationDate: '2030-12',\n * holderName: 'MARIA SILVA',\n * installments: 3\n * }\n * });\n */\n async create(params: CreateChargeParams): Promise<Charge> {\n const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();\n const body = this.buildCreateBody(params);\n\n return this.http.call<Charge>(\n (signal) =>\n this.http.client.POST('/api/transactions', {\n body,\n headers: { 'X-Idempotency-Key': idempotencyKey },\n signal\n }) as Promise<{ data?: Charge; error?: unknown; response: Response }>\n );\n }\n\n /**\n * List charges for the authenticated seller, with pagination and filters.\n *\n * @example\n * const { data, meta } = await garu.charges.list({ status: 'paid', limit: 10 });\n * // meta.total paid charges\n */\n async list(params: ListChargesParams = {}): Promise<ChargeList> {\n const query: Record<string, string> = {};\n if (params.page !== undefined) query.page = String(params.page);\n if (params.limit !== undefined) query.limit = String(params.limit);\n if (params.status) query.status = params.status;\n if (params.search) query.search = params.search;\n if (params.paymentMethod) query.paymentMethod = params.paymentMethod;\n\n const qs = new URLSearchParams(query).toString();\n const url = `/api/transactions${qs ? `?${qs}` : ''}`;\n\n return this.http.call<ChargeList>((signal) =>\n (this.http.client.GET as Function)(url, { signal }).then(\n (r: { data?: ChargeList; error?: unknown; response: Response }) => r\n )\n );\n }\n\n /**\n * Fetch a single charge by numeric ID.\n *\n * @example\n * const charge = await garu.charges.get(4472);\n * if (charge.status === 'paid') { ... }\n */\n async get(id: number): Promise<Charge> {\n return this.http.call<Charge>(\n (signal) =>\n this.http.client.GET('/api/transactions/{id}', {\n params: { path: { id } },\n signal\n }) as Promise<{ data?: Charge; error?: unknown; response: Response }>\n );\n }\n\n /**\n * Refund a charge — fully, or partially by passing `amount` in centavos.\n *\n * @example\n * // Full refund\n * await garu.charges.refund(4472);\n *\n * @example\n * // Partial refund of R$ 10,00\n * await garu.charges.refund(4472, { amount: 1000, reason: 'customer_request' });\n */\n async refund(id: number, params: RefundChargeParams = {}): Promise<Charge> {\n const idempotencyKey = params.idempotencyKey ?? generateIdempotencyKey();\n const body: Record<string, unknown> = {};\n if (params.amount !== undefined) body.amount = params.amount;\n if (params.reason !== undefined) body.reason = params.reason;\n\n return this.http.call<Charge>(\n (signal) =>\n this.http.client.POST('/api/transactions/{id}/refund', {\n params: { path: { id } },\n body: body as never,\n headers: { 'X-Idempotency-Key': idempotencyKey },\n signal\n }) as Promise<{ data?: Charge; error?: unknown; response: Response }>\n );\n }\n\n private buildCreateBody(params: CreateChargeParams): CreateTransactionBody {\n const body: Record<string, unknown> = {\n customer: params.customer,\n productId: params.productId,\n paymentMethodId: toWirePaymentMethod(params.paymentMethod),\n link: params.link ?? null,\n affiliateId: params.affiliateId ?? null\n };\n if (params.additionalInfo !== undefined) body.additionalInfo = params.additionalInfo;\n if (params.priceId !== undefined) body.priceId = params.priceId;\n if (params.checkoutSessionToken !== undefined) {\n body.checkoutSessionToken = params.checkoutSessionToken;\n }\n if (params.cardInfo) body.CardInfo = params.cardInfo;\n return body as unknown as CreateTransactionBody;\n }\n}\n","import type { HttpClient } from '../http.js';\nimport type {\n CreateCustomerParams,\n CustomerList,\n CustomerRecord,\n ListCustomersParams,\n UpdateCustomerParams\n} from '../types.js';\n\n/**\n * Customers — manage your customer base.\n *\n * Customers are scoped to the seller identified by the API key. The backend\n * uses a junction table (`customer_seller_profile`) so the same person can\n * exist across multiple sellers without duplication.\n */\nexport class Customers {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create a customer and link it to the current seller.\n *\n * @example\n * const customer = await garu.customers.create({\n * name: 'Maria Silva',\n * email: 'maria@exemplo.com.br',\n * document: '12345678909',\n * phone: '11987654321',\n * personType: 'fisica'\n * });\n */\n async create(params: CreateCustomerParams): Promise<CustomerRecord> {\n return this.http.call<CustomerRecord>((signal) =>\n (this.http.client.POST as Function)('/api/customers', {\n body: params,\n signal\n }).then((r: { data?: CustomerRecord; error?: unknown; response: Response }) => r)\n );\n }\n\n /**\n * List customers for the authenticated seller, with pagination and search.\n *\n * @example\n * const { data, meta } = await garu.customers.list({ search: 'maria', limit: 10 });\n */\n async list(params: ListCustomersParams = {}): Promise<CustomerList> {\n const query: Record<string, string> = {};\n if (params.page !== undefined) query.page = String(params.page);\n if (params.limit !== undefined) query.limit = String(params.limit);\n if (params.search) query.search = params.search;\n\n const qs = new URLSearchParams(query).toString();\n const url = `/api/customers${qs ? `?${qs}` : ''}`;\n\n return this.http.call<CustomerList>((signal) =>\n (this.http.client.GET as Function)(url, { signal }).then(\n (r: { data?: CustomerList; error?: unknown; response: Response }) => r\n )\n );\n }\n\n /**\n * Fetch a single customer by numeric ID.\n *\n * @example\n * const customer = await garu.customers.get(42);\n */\n async get(id: number): Promise<CustomerRecord> {\n return this.http.call<CustomerRecord>((signal) =>\n (this.http.client.GET as Function)(`/api/customers/${id}`, { signal }).then(\n (r: { data?: CustomerRecord; error?: unknown; response: Response }) => r\n )\n );\n }\n\n /**\n * Update a customer's profile for the current seller.\n *\n * @example\n * const updated = await garu.customers.update(42, { name: 'Maria Santos' });\n */\n async update(id: number, params: UpdateCustomerParams): Promise<CustomerRecord> {\n return this.http.call<CustomerRecord>((signal) =>\n (this.http.client.PUT as Function)(`/api/customers/${id}`, {\n body: params,\n signal\n }).then((r: { data?: CustomerRecord; error?: unknown; response: Response }) => r)\n );\n }\n\n /**\n * Remove a customer from the current seller.\n *\n * @example\n * await garu.customers.delete(42);\n */\n async delete(id: number): Promise<void> {\n await this.http.call<unknown>((signal) =>\n (this.http.client.DELETE as Function)(`/api/customers/${id}`, { signal }).then(\n (r: { data?: unknown; error?: unknown; response: Response }) => r\n )\n );\n }\n}\n","import type { HttpClient } from '../http.js';\nimport type { MetaResponse } from '../types.js';\n\n/**\n * Meta — capability introspection.\n *\n * Unauthenticated. Used by `garu doctor`, MCP tool `doctor`, and by SDK\n * consumers that want to know which payment methods and webhook events are\n * currently supported.\n */\nexport class Meta {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Fetch the API's current capability payload.\n *\n * @example\n * const meta = await garu.meta.get();\n * console.log(meta.version, meta.payment_methods);\n * if (meta.features.subscriptions) { ... }\n */\n async get(): Promise<MetaResponse> {\n return this.http.call<MetaResponse>(\n (signal) =>\n this.http.client.GET('/api/meta', { signal }) as Promise<{\n data?: MetaResponse;\n error?: unknown;\n response: Response;\n }>\n );\n }\n}\n","import { createHmac, timingSafeEqual } from 'node:crypto';\n\nimport { GaruSignatureVerificationError } from './errors.js';\n\nexport interface VerifyWebhookParams {\n /** Raw request body as received — do NOT re-serialize parsed JSON. */\n payload: string | Buffer;\n /** Value of the `X-Garu-Signature` header. Format: `t=<ts>,v1=<hex>`. */\n signature: string;\n /** The webhook endpoint's signing secret. */\n secret: string;\n /** Reject signatures older than this many seconds. Default: 300 (5 min). */\n toleranceSec?: number;\n /** Injectable for tests. Defaults to `Date.now()`. */\n now?: () => number;\n}\n\nexport interface VerifiedWebhook {\n /** Timestamp from the signature header, in seconds since epoch. */\n timestamp: number;\n /** Parsed JSON body. Throws {@link GaruSignatureVerificationError} if invalid JSON. */\n event: unknown;\n}\n\n/**\n * Webhook helpers.\n *\n * Garu signs outgoing webhooks with HMAC-SHA256 over `${timestamp}.${payload}`\n * and delivers the signature in the `X-Garu-Signature` header as `t=<ts>,v1=<hex>`.\n * This matches the format in the backend's `webhook-delivery.service.ts`.\n *\n * @example\n * // Express example\n * app.post('/webhooks/garu', express.raw({ type: 'application/json' }), (req, res) => {\n * try {\n * const { event } = Garu.webhooks.verify({\n * payload: req.body,\n * signature: req.header('x-garu-signature') ?? '',\n * secret: process.env.GARU_WEBHOOK_SECRET!\n * });\n * // handle event\n * res.sendStatus(200);\n * } catch (err) {\n * res.sendStatus(400);\n * }\n * });\n */\nexport const webhooks = {\n verify(params: VerifyWebhookParams): VerifiedWebhook {\n const { signature, secret, payload } = params;\n const toleranceSec = params.toleranceSec ?? 300;\n const now = params.now ?? Date.now;\n\n if (!signature || typeof signature !== 'string') {\n throw new GaruSignatureVerificationError('Missing or malformed X-Garu-Signature header');\n }\n\n const parts = parseSignatureHeader(signature);\n if (parts === null) {\n throw new GaruSignatureVerificationError(\n 'X-Garu-Signature header does not match expected format t=<ts>,v1=<hex>'\n );\n }\n\n const payloadStr = typeof payload === 'string' ? payload : payload.toString('utf8');\n const signedPayload = `${parts.timestamp}.${payloadStr}`;\n const expected = createHmac('sha256', secret).update(signedPayload).digest('hex');\n\n const expectedBuf = Buffer.from(expected, 'hex');\n const providedBuf = Buffer.from(parts.v1, 'hex');\n if (expectedBuf.length !== providedBuf.length || !timingSafeEqual(expectedBuf, providedBuf)) {\n throw new GaruSignatureVerificationError('Signature does not match computed HMAC');\n }\n\n const nowSec = Math.floor(now() / 1000);\n if (Math.abs(nowSec - parts.timestamp) > toleranceSec) {\n throw new GaruSignatureVerificationError(\n `Signature timestamp outside tolerance window (${toleranceSec}s)`\n );\n }\n\n let event: unknown;\n try {\n event = JSON.parse(payloadStr);\n } catch {\n throw new GaruSignatureVerificationError('Webhook payload is not valid JSON');\n }\n\n return { timestamp: parts.timestamp, event };\n }\n};\n\nfunction parseSignatureHeader(header: string): { timestamp: number; v1: string } | null {\n const fields: Record<string, string> = {};\n for (const part of header.split(',')) {\n const idx = part.indexOf('=');\n if (idx === -1) return null;\n const key = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (!key || !value) return null;\n fields[key] = value;\n }\n const t = fields.t;\n const v1 = fields.v1;\n if (!t || !v1) return null;\n const timestamp = Number(t);\n if (!Number.isFinite(timestamp) || !/^[a-f0-9]+$/i.test(v1)) return null;\n return { timestamp, v1 };\n}\n","import { HttpClient } from './http.js';\nimport { Charges } from './resources/charges.js';\nimport { Customers } from './resources/customers.js';\nimport { Meta } from './resources/meta.js';\nimport { webhooks } from './webhooks.js';\n\nexport interface GaruOptions {\n /**\n * Your Garu API key. `sk_live_…` for production, `sk_test_…` for test mode.\n * Optional — public endpoints (`meta.get`, public charge creation) work without one.\n */\n apiKey?: string;\n /** Override the API base URL. Default: `https://garu.com.br/api`. */\n baseUrl?: string;\n /** Per-request timeout in ms. Default: 30000. */\n timeoutMs?: number;\n /** Max retries on retryable errors (connection, 408, 429, 5xx). Default: 2. */\n maxRetries?: number;\n /** Injectable for tests. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n}\n\nconst DEFAULT_BASE_URL = 'https://garu.com.br';\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_RETRIES = 2;\nconst SDK_VERSION = '0.2.0';\n\n/**\n * The Garu SDK client.\n *\n * @example\n * import { Garu } from '@garuhq/node';\n *\n * const garu = new Garu({ apiKey: process.env.GARU_API_KEY });\n *\n * const charge = await garu.charges.create({\n * productId: 'b3f2c1e8-6e4a-4b9f-9d1c-2a1f6c3d4e5f',\n * paymentMethod: 'pix',\n * customer: {\n * name: 'Maria Silva',\n * email: 'maria@exemplo.com.br',\n * document: '12345678909',\n * phone: '11987654321'\n * }\n * });\n */\nexport class Garu {\n public readonly charges: Charges;\n public readonly customers: Customers;\n public readonly meta: Meta;\n\n /**\n * Webhook helpers. Available both as an instance member and as a static —\n * `Garu.webhooks.verify(...)` works without constructing a client.\n */\n public static readonly webhooks = webhooks;\n public readonly webhooks = webhooks;\n\n constructor(options: GaruOptions = {}) {\n const http = new HttpClient({\n baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,\n apiKey: options.apiKey,\n timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n userAgent: `garu-node/${SDK_VERSION}`,\n fetch: options.fetch\n });\n this.charges = new Charges(http);\n this.customers = new Customers(http);\n this.meta = new Meta(http);\n }\n}\n"]}