@garuhq/cli 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -15,7 +15,7 @@ var pc__default = /*#__PURE__*/_interopDefault(pc);
15
15
  // src/index.ts
16
16
 
17
17
  // src/version.ts
18
- var CLI_VERSION = "0.8.0";
18
+ var CLI_VERSION = "0.10.0";
19
19
  var CliError = class extends Error {
20
20
  code;
21
21
  exitCode;
@@ -233,6 +233,192 @@ function createGaruClient(opts) {
233
233
  });
234
234
  }
235
235
 
236
+ // src/lib/parse.ts
237
+ function parsePositiveIntId(raw, label) {
238
+ const id = Number.parseInt(raw, 10);
239
+ if (!Number.isFinite(id) || id <= 0) {
240
+ throw new CliError("invalid_input", `${label} must be a positive integer (got '${raw}')`);
241
+ }
242
+ return id;
243
+ }
244
+ function parsePaymentMethod(raw) {
245
+ if (raw === "pix" || raw === "credit_card" || raw === "boleto") return raw;
246
+ throw new CliError(
247
+ "invalid_input",
248
+ `--type must be 'pix', 'credit_card', or 'boleto' (got '${raw}')`
249
+ );
250
+ }
251
+ function toChargePaymentMethod(type) {
252
+ return type === "credit_card" ? "creditCard" : type;
253
+ }
254
+ function parsePersonType(raw) {
255
+ if (raw === "fisica" || raw === "juridica") return raw;
256
+ throw new CliError(
257
+ "invalid_input",
258
+ `--person-type must be 'fisica' or 'juridica' (got '${raw}')`
259
+ );
260
+ }
261
+ function parseChargePaymentMethodFilter(raw) {
262
+ return toChargePaymentMethod(parsePaymentMethod(raw));
263
+ }
264
+ var CHARGE_STATUSES = [
265
+ "pending",
266
+ "authorized",
267
+ "paid",
268
+ "failed",
269
+ "expired",
270
+ "canceled",
271
+ "refund_pending",
272
+ "refunded",
273
+ "chargeback"
274
+ ];
275
+ function parseChargeStatus(raw) {
276
+ if (CHARGE_STATUSES.includes(raw)) return raw;
277
+ throw new CliError(
278
+ "invalid_input",
279
+ `--status must be one of ${CHARGE_STATUSES.join(", ")} (got '${raw}')`
280
+ );
281
+ }
282
+ var INSTALLMENT_PLAN_STATUSES = [
283
+ "pending_activation",
284
+ "active",
285
+ "completed",
286
+ "defaulted",
287
+ "canceled",
288
+ "refunded"
289
+ ];
290
+ function parseInstallmentPlanStatus(raw) {
291
+ if (INSTALLMENT_PLAN_STATUSES.includes(raw)) return raw;
292
+ throw new CliError(
293
+ "invalid_input",
294
+ `--status must be one of ${INSTALLMENT_PLAN_STATUSES.join(", ")} (got '${raw}')`
295
+ );
296
+ }
297
+ var REFUND_REQUEST_STATUSES = ["pending", "confirmed", "rejected"];
298
+ function parseRefundRequestStatus(raw) {
299
+ if (REFUND_REQUEST_STATUSES.includes(raw)) return raw;
300
+ throw new CliError(
301
+ "invalid_input",
302
+ `--status must be one of ${REFUND_REQUEST_STATUSES.join(", ")} (got '${raw}')`
303
+ );
304
+ }
305
+ function parseWebhookEventStatus(raw) {
306
+ if (raw === "pending" || raw === "success" || raw === "failed") return raw;
307
+ throw new CliError(
308
+ "invalid_input",
309
+ `--status must be 'pending', 'success', or 'failed' (got '${raw}')`
310
+ );
311
+ }
312
+ function parseScheduledChargeType(raw) {
313
+ if (raw === "one_time" || raw === "recurring") return raw;
314
+ throw new CliError("invalid_input", `--type must be 'one_time' or 'recurring' (got '${raw}')`);
315
+ }
316
+ var SCHEDULED_PAYMENT_METHODS = [
317
+ "pix",
318
+ "boleto",
319
+ "card",
320
+ "pix_automatic"
321
+ ];
322
+ function parseCsvList(raw) {
323
+ return raw.split(",").map((s) => s.trim()).filter(Boolean);
324
+ }
325
+ function parseScheduledPaymentMethods(raw) {
326
+ const parts = parseCsvList(raw);
327
+ if (parts.length === 0) {
328
+ throw new CliError(
329
+ "invalid_input",
330
+ `--methods must list at least one of: ${SCHEDULED_PAYMENT_METHODS.join(", ")}`
331
+ );
332
+ }
333
+ for (const p of parts) {
334
+ if (!SCHEDULED_PAYMENT_METHODS.includes(p)) {
335
+ throw new CliError(
336
+ "invalid_input",
337
+ `--methods entries must be one of ${SCHEDULED_PAYMENT_METHODS.join(", ")} (got '${p}')`
338
+ );
339
+ }
340
+ }
341
+ return parts;
342
+ }
343
+ var RECURRENCE_INTERVALS = [
344
+ "weekly",
345
+ "biweekly",
346
+ "monthly",
347
+ "bimonthly",
348
+ "quarterly",
349
+ "biannual",
350
+ "yearly"
351
+ ];
352
+ function parseRecurrenceInterval(raw) {
353
+ if (RECURRENCE_INTERVALS.includes(raw)) return raw;
354
+ throw new CliError(
355
+ "invalid_input",
356
+ `--recurrence-interval must be one of ${RECURRENCE_INTERVALS.join(", ")} (got '${raw}')`
357
+ );
358
+ }
359
+ var SCHEDULED_CHARGE_STATUSES = [
360
+ "scheduled",
361
+ "due_today",
362
+ "overdue",
363
+ "paid",
364
+ "paused",
365
+ "canceled",
366
+ "trial",
367
+ "pending_tokenization",
368
+ "recurrence_canceled"
369
+ ];
370
+ function parseScheduledChargeStatus(raw) {
371
+ if (SCHEDULED_CHARGE_STATUSES.includes(raw)) return raw;
372
+ throw new CliError(
373
+ "invalid_input",
374
+ `--status must be one of ${SCHEDULED_CHARGE_STATUSES.join(", ")} (got '${raw}')`
375
+ );
376
+ }
377
+ function parseIntInRange(raw, label, min, max) {
378
+ const trimmed = raw.trim();
379
+ const n = Number.parseInt(trimmed, 10);
380
+ if (!Number.isFinite(n) || String(n) !== trimmed || n < min || n > max) {
381
+ throw new CliError(
382
+ "invalid_input",
383
+ `${label} must be an integer between ${min} and ${max} (got '${raw}')`
384
+ );
385
+ }
386
+ return n;
387
+ }
388
+ function parseNonNegativeBrl(raw, label) {
389
+ const trimmed = raw.trim();
390
+ const n = Number(trimmed);
391
+ if (trimmed === "" || !Number.isFinite(n) || n < 0) {
392
+ throw new CliError(
393
+ "invalid_input",
394
+ `${label} must be a non-negative amount in BRL/reais, e.g. 49.90 (got '${raw}')`
395
+ );
396
+ }
397
+ return n;
398
+ }
399
+ function parseAmountBrl(raw) {
400
+ const n = Number(raw);
401
+ if (!Number.isFinite(n) || n <= 0) {
402
+ throw new CliError(
403
+ "invalid_input",
404
+ `--amount must be a positive decimal in BRL, e.g. 297.50 (got '${raw}')`
405
+ );
406
+ }
407
+ return n;
408
+ }
409
+ function parseMetadata(raw) {
410
+ let parsed;
411
+ try {
412
+ parsed = JSON.parse(raw);
413
+ } catch {
414
+ throw new CliError("invalid_input", `--metadata must be valid JSON (got '${raw}')`);
415
+ }
416
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
417
+ throw new CliError("invalid_input", `--metadata must be a JSON object`);
418
+ }
419
+ return parsed;
420
+ }
421
+
236
422
  // src/commands/charges.ts
237
423
  async function getClient(opts) {
238
424
  if (opts.garu) return opts.garu;
@@ -275,8 +461,9 @@ async function chargesCreateCommand(opts) {
275
461
  assertCardFieldsPresent(opts);
276
462
  charge = await garu.charges.create({
277
463
  ...base,
278
- cardInfo: {
279
- cardNumber: opts.cardNumber,
464
+ paymentMethod: toChargePaymentMethod(opts.type),
465
+ card: {
466
+ number: opts.cardNumber,
280
467
  cvv: opts.cardCvv,
281
468
  expirationDate: opts.cardExpiration,
282
469
  holderName: opts.cardHolder,
@@ -284,14 +471,17 @@ async function chargesCreateCommand(opts) {
284
471
  }
285
472
  });
286
473
  } else {
287
- charge = await garu.charges.create(base);
474
+ charge = await garu.charges.create({
475
+ ...base,
476
+ paymentMethod: toChargePaymentMethod(opts.type)
477
+ });
288
478
  }
289
479
  printResult(charge, { ...opts, prettyPrint: prettyCharge });
290
480
  return charge;
291
481
  }
292
482
  async function chargesGetCommand(opts) {
293
483
  const garu = await getClient(opts);
294
- const charge = await garu.charges.get(opts.id);
484
+ const charge = await garu.charges.retrieve(opts.id);
295
485
  printResult(charge, { ...opts, prettyPrint: prettyCharge });
296
486
  return charge;
297
487
  }
@@ -300,7 +490,6 @@ async function chargesRefundCommand(opts) {
300
490
  const params = {};
301
491
  if (opts.amount !== void 0) params.amount = opts.amount;
302
492
  if (opts.reason !== void 0) params.reason = opts.reason;
303
- if (opts.idempotencyKey !== void 0) params.idempotencyKey = opts.idempotencyKey;
304
493
  const charge = await garu.charges.refund(opts.id, params);
305
494
  printResult(charge, { ...opts, prettyPrint: prettyCharge });
306
495
  return charge;
@@ -319,23 +508,128 @@ async function chargesListCommand(opts) {
319
508
  }
320
509
  function prettyChargeList(list) {
321
510
  if (list.data.length === 0) {
322
- return `No charges found (page ${list.meta.page}/${list.meta.totalPages || 1})`;
511
+ return "No charges found";
323
512
  }
324
- const header = `Charges (page ${list.meta.page}/${list.meta.totalPages || "?"}, ${list.meta.total} total)`;
513
+ const header = `Charges (${list.count} of ${list.totalCount} total, ${list.totalPages} page(s))`;
325
514
  const rows = list.data.map(
326
- (c) => ` ${String(c.id).padStart(6)} ${String(c.status).padEnd(14)} ${c.paymentMethodId?.padEnd(10) ?? ""} ${c.date}`
515
+ (c) => ` ${c.uuid} ${String(c.status).padEnd(14)} ${c.paymentMethod.padEnd(10)} ${c.createdAt}`
327
516
  );
328
517
  return [header, ...rows].join("\n");
329
518
  }
330
519
  function prettyCharge(charge) {
331
520
  const lines = [
332
- `Charge ${charge.id}`,
333
- ` status: ${charge.status}`,
334
- ` amount: ${charge.amount}`,
335
- ` method: ${charge.paymentMethodId}`,
336
- ` date: ${charge.date}`
521
+ `Charge ${charge.uuid}`,
522
+ ` status: ${charge.status}`,
523
+ ` amount: ${charge.amount}`,
524
+ ` chargedTotal: ${charge.chargedTotal}`,
525
+ ` method: ${charge.paymentMethod}`,
526
+ ` createdAt: ${charge.createdAt}`
527
+ ];
528
+ if (charge.expiresAt) lines.push(` expiresAt: ${charge.expiresAt}`);
529
+ if (charge.refund)
530
+ lines.push(` refund: ${charge.refund.amount} (${charge.refund.reason ?? "no reason"})`);
531
+ return lines.join("\n");
532
+ }
533
+
534
+ // src/commands/customers.ts
535
+ async function getClient2(opts) {
536
+ if (opts.garu) return opts.garu;
537
+ const auth = await resolveAuth({
538
+ ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
539
+ ...opts.profile !== void 0 ? { profile: opts.profile } : {}
540
+ });
541
+ return createGaruClient({
542
+ auth,
543
+ ...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {}
544
+ });
545
+ }
546
+ async function customersCreateCommand(opts) {
547
+ const garu = await getClient2(opts);
548
+ const params = {
549
+ name: opts.name,
550
+ email: opts.email,
551
+ document: opts.document,
552
+ phone: opts.phone,
553
+ personType: opts.personType
554
+ };
555
+ if (opts.zipCode !== void 0) params.zipCode = opts.zipCode;
556
+ if (opts.street !== void 0) params.street = opts.street;
557
+ if (opts.number !== void 0) params.number = opts.number;
558
+ if (opts.complement !== void 0) params.complement = opts.complement;
559
+ if (opts.neighborhood !== void 0) params.neighborhood = opts.neighborhood;
560
+ if (opts.city !== void 0) params.city = opts.city;
561
+ if (opts.state !== void 0) params.state = opts.state;
562
+ const customer = await garu.customers.create(params);
563
+ printResult(customer, { ...opts, prettyPrint: prettyCustomer });
564
+ return customer;
565
+ }
566
+ async function customersListCommand(opts) {
567
+ const garu = await getClient2(opts);
568
+ const params = {};
569
+ if (opts.page !== void 0) params.page = opts.page;
570
+ if (opts.limit !== void 0) params.limit = opts.limit;
571
+ if (opts.search !== void 0) params.search = opts.search;
572
+ if (opts.status !== void 0) params.status = opts.status;
573
+ const result = await garu.customers.list(params);
574
+ printResult(result, { ...opts, prettyPrint: prettyCustomerList });
575
+ return result;
576
+ }
577
+ async function customersGetCommand(opts) {
578
+ const garu = await getClient2(opts);
579
+ const customer = await garu.customers.get(opts.uuid);
580
+ printResult(customer, { ...opts, prettyPrint: prettyCustomer });
581
+ return customer;
582
+ }
583
+ async function customersUpdateCommand(opts) {
584
+ const garu = await getClient2(opts);
585
+ const params = {};
586
+ if (opts.name !== void 0) params.name = opts.name;
587
+ if (opts.email !== void 0) params.email = opts.email;
588
+ if (opts.phone !== void 0) params.phone = opts.phone;
589
+ if (opts.document !== void 0) params.document = opts.document;
590
+ if (opts.personType !== void 0) params.personType = opts.personType;
591
+ if (opts.zipCode !== void 0) params.zipCode = opts.zipCode;
592
+ if (opts.street !== void 0) params.street = opts.street;
593
+ if (opts.number !== void 0) params.number = opts.number;
594
+ if (opts.complement !== void 0) params.complement = opts.complement;
595
+ if (opts.neighborhood !== void 0) params.neighborhood = opts.neighborhood;
596
+ if (opts.city !== void 0) params.city = opts.city;
597
+ if (opts.state !== void 0) params.state = opts.state;
598
+ const customer = await garu.customers.update(opts.uuid, params);
599
+ printResult(customer, { ...opts, prettyPrint: prettyCustomer });
600
+ return customer;
601
+ }
602
+ async function customersSetBillingEmailOverrideCommand(opts) {
603
+ const garu = await getClient2(opts);
604
+ const params = {
605
+ billingEmailOverride: opts.billingEmailOverride
606
+ };
607
+ const customer = await garu.customers.setBillingEmailOverride(opts.uuid, params);
608
+ printResult(customer, { ...opts, prettyPrint: prettyCustomer });
609
+ return customer;
610
+ }
611
+ async function customersDeleteCommand(opts) {
612
+ const garu = await getClient2(opts);
613
+ const result = await garu.customers.delete(opts.uuid);
614
+ printResult(result, { ...opts });
615
+ return result;
616
+ }
617
+ function prettyCustomerList(list) {
618
+ if (list.data.length === 0) return "No customers found";
619
+ const header = `Customers (${list.count} of ${list.totalCount} total, ${list.totalPages} page(s))`;
620
+ const rows = list.data.map((c) => ` ${c.uuid} ${c.name.padEnd(30)} ${c.email}`);
621
+ return [header, ...rows].join("\n");
622
+ }
623
+ function prettyCustomer(c) {
624
+ const lines = [
625
+ `Customer ${c.uuid}`,
626
+ ` name: ${c.name}`,
627
+ ` email: ${c.email}`,
628
+ ` phone: ${c.phone}`,
629
+ ` document: ${c.document}`,
630
+ ` personType: ${c.personType}`,
631
+ ` billingEmail: ${c.billingEmail}${c.hasBillingEmailOverride ? " (override)" : ""}`
337
632
  ];
338
- if (charge.deadline) lines.push(` deadline: ${charge.deadline}`);
339
633
  return lines.join("\n");
340
634
  }
341
635
  async function doctorCommand(opts = {}) {
@@ -430,6 +724,152 @@ function prettyDoctor(r) {
430
724
  ].filter((l) => l !== void 0);
431
725
  return lines.join("\n");
432
726
  }
727
+
728
+ // src/commands/installment-plans.ts
729
+ async function getClient3(opts) {
730
+ if (opts.garu) return opts.garu;
731
+ const auth = await resolveAuth({
732
+ ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
733
+ ...opts.profile !== void 0 ? { profile: opts.profile } : {}
734
+ });
735
+ return createGaruClient({
736
+ auth,
737
+ ...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {}
738
+ });
739
+ }
740
+ async function installmentPlansCreateCommand(opts) {
741
+ const garu = await getClient3(opts);
742
+ const params = {
743
+ productId: opts.productId,
744
+ customerId: opts.customerId,
745
+ installments: opts.installments
746
+ };
747
+ if (opts.firstDueDate !== void 0) params.firstDueDate = opts.firstDueDate;
748
+ if (opts.affiliateId !== void 0) params.affiliateId = opts.affiliateId;
749
+ if (opts.idempotencyKey !== void 0) params.idempotencyKey = opts.idempotencyKey;
750
+ const plan = await garu.installmentPlans.create(params);
751
+ printResult(plan, { ...opts, prettyPrint: prettyInstallmentPlan });
752
+ return plan;
753
+ }
754
+ async function installmentPlansListCommand(opts) {
755
+ const garu = await getClient3(opts);
756
+ const params = {};
757
+ if (opts.page !== void 0) params.page = opts.page;
758
+ if (opts.limit !== void 0) params.limit = opts.limit;
759
+ if (opts.customerId !== void 0) params.customerId = opts.customerId;
760
+ if (opts.productId !== void 0) params.productId = opts.productId;
761
+ if (opts.dueFrom !== void 0) params.dueFrom = opts.dueFrom;
762
+ if (opts.dueTo !== void 0) params.dueTo = opts.dueTo;
763
+ if (opts.status !== void 0 && opts.status.length > 0) {
764
+ params.status = opts.status.length === 1 ? opts.status[0] : opts.status;
765
+ }
766
+ const result = await garu.installmentPlans.list(params);
767
+ printResult(result, { ...opts, prettyPrint: prettyInstallmentPlanList });
768
+ return result;
769
+ }
770
+ async function installmentPlansGetCommand(opts) {
771
+ const garu = await getClient3(opts);
772
+ const plan = await garu.installmentPlans.get(opts.uuid);
773
+ printResult(plan, { ...opts, prettyPrint: prettyInstallmentPlanDetail });
774
+ return plan;
775
+ }
776
+ async function installmentPlansReissueCommand(opts) {
777
+ const garu = await getClient3(opts);
778
+ const result = await garu.installmentPlans.reissueInstallment(opts.uuid, opts.number);
779
+ printResult(result, { ...opts, prettyPrint: prettyReissueResult });
780
+ return result;
781
+ }
782
+ async function installmentPlansPostponeCommand(opts) {
783
+ const garu = await getClient3(opts);
784
+ const params = { newDueDate: opts.newDueDate };
785
+ const installment = await garu.installmentPlans.postponeInstallment(
786
+ opts.uuid,
787
+ opts.number,
788
+ params
789
+ );
790
+ printResult(installment, { ...opts, prettyPrint: prettyInstallment });
791
+ return installment;
792
+ }
793
+ async function installmentPlansMarkPaidCommand(opts) {
794
+ const garu = await getClient3(opts);
795
+ const installment = await garu.installmentPlans.markInstallmentPaid(opts.uuid, opts.number);
796
+ printResult(installment, { ...opts, prettyPrint: prettyInstallment });
797
+ return installment;
798
+ }
799
+ async function installmentPlansCancelCommand(opts) {
800
+ const garu = await getClient3(opts);
801
+ const params = {};
802
+ if (opts.note !== void 0) params.note = opts.note;
803
+ const plan = await garu.installmentPlans.cancel(opts.uuid, params);
804
+ printResult(plan, { ...opts, prettyPrint: prettyInstallmentPlan });
805
+ return plan;
806
+ }
807
+ async function installmentPlansRequestRefundCommand(opts) {
808
+ const garu = await getClient3(opts);
809
+ const params = {};
810
+ if (opts.amount !== void 0) params.amount = opts.amount;
811
+ if (opts.reason !== void 0) params.reason = opts.reason;
812
+ const request = await garu.installmentPlans.requestRefund(opts.uuid, params);
813
+ printResult(request, { ...opts, prettyPrint: prettyRefundRequest });
814
+ return request;
815
+ }
816
+ function prettyInstallmentPlan(p) {
817
+ const lines = [
818
+ `Installment plan ${p.uuid}`,
819
+ ` status: ${p.status}`,
820
+ ` installments: ${p.installmentsPaid}/${p.installments} paid`,
821
+ ` baseValue: ${p.baseValue}`,
822
+ ` installmentAmount: ${p.installmentAmount}`,
823
+ ` totalScheduled: ${p.totalScheduled}`,
824
+ ` totalCollected: ${p.totalCollected}`,
825
+ ` firstDueDate: ${p.firstDueDate}`
826
+ ];
827
+ if (p.product) lines.push(` product: ${p.product.name} (${p.product.uuid})`);
828
+ if (p.customer) lines.push(` customer: ${p.customer.name} <${p.customer.email}>`);
829
+ return lines.join("\n");
830
+ }
831
+ function prettyInstallmentPlanDetail(p) {
832
+ const lines = [prettyInstallmentPlan(p)];
833
+ if (p.installmentsDetail && p.installmentsDetail.length > 0) {
834
+ lines.push(" installments:");
835
+ for (const i of p.installmentsDetail) {
836
+ lines.push(
837
+ ` #${i.number} ${i.status.padEnd(10)} ${String(i.amount).padStart(10)} due ${i.dueDate}${i.paidAt ? ` paid ${i.paidAt}` : ""}`
838
+ );
839
+ }
840
+ }
841
+ return lines.join("\n");
842
+ }
843
+ function prettyInstallmentPlanList(list) {
844
+ if (list.data.length === 0) return "No installment plans found";
845
+ const header = `Installment plans (${list.count} of ${list.totalCount} total, ${list.totalPages} page(s))`;
846
+ const rows = list.data.map(
847
+ (p) => ` ${p.uuid} ${p.status.padEnd(18)} ${p.installmentsPaid}/${p.installments} paid ${p.firstDueDate}`
848
+ );
849
+ return [header, ...rows].join("\n");
850
+ }
851
+ function prettyInstallment(i) {
852
+ const lines = [
853
+ `Installment #${i.number}`,
854
+ ` status: ${i.status}`,
855
+ ` amount: ${i.amount}`,
856
+ ` dueDate: ${i.dueDate}`
857
+ ];
858
+ if (i.paidAt) lines.push(` paidAt: ${i.paidAt}`);
859
+ if (i.boleto) lines.push(` boleto: ${i.boleto.barcodeLine}`);
860
+ return lines.join("\n");
861
+ }
862
+ function prettyReissueResult(result) {
863
+ const lines = [`Reissue: ${result.status}`];
864
+ if (result.reason) lines.push(` reason: ${result.reason}`);
865
+ if (result.installment) lines.push(prettyInstallment(result.installment));
866
+ return lines.join("\n");
867
+ }
868
+ function prettyRefundRequest(r) {
869
+ const lines = [`Refund request ${r.uuid}`, ` status: ${r.status}`, ` amount: ${r.amount}`];
870
+ if (r.reason) lines.push(` reason: ${r.reason}`);
871
+ return lines.join("\n");
872
+ }
433
873
  async function loginCommand(opts = {}) {
434
874
  const profile = opts.profile ?? "default";
435
875
  const apiKey = opts.apiKey ?? await import('@inquirer/prompts').then(
@@ -477,7 +917,7 @@ async function logoutCommand(opts = {}) {
477
917
  }
478
918
 
479
919
  // src/commands/products.ts
480
- async function getClient2(opts) {
920
+ async function getClient4(opts) {
481
921
  if (opts.garu) return opts.garu;
482
922
  const auth = await resolveAuth({
483
923
  ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
@@ -508,7 +948,7 @@ function buildProductBody(opts) {
508
948
  return body;
509
949
  }
510
950
  async function productsCreateCommand(opts) {
511
- const garu = await getClient2(opts);
951
+ const garu = await getClient4(opts);
512
952
  const params = { ...buildProductBody(opts), name: opts.name };
513
953
  const product = await garu.products.create(params);
514
954
  printSuccess(`Created product ${product.uuid ?? product.id}`, opts);
@@ -520,7 +960,7 @@ async function productsUpdateCommand(opts) {
520
960
  if (Object.keys(body).length === 0) {
521
961
  throw new CliError("invalid_input", "Nothing to update \u2014 pass at least one field to change.");
522
962
  }
523
- const garu = await getClient2(opts);
963
+ const garu = await getClient4(opts);
524
964
  const product = await garu.products.update(opts.id, body);
525
965
  printSuccess(`Updated product ${product.uuid ?? product.id}`, opts);
526
966
  printResult(product, { ...opts, prettyPrint: prettyProduct });
@@ -543,8 +983,74 @@ function prettyProduct(p) {
543
983
  return lines.join("\n");
544
984
  }
545
985
 
986
+ // src/commands/refund-requests.ts
987
+ async function getClient5(opts) {
988
+ if (opts.garu) return opts.garu;
989
+ const auth = await resolveAuth({
990
+ ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
991
+ ...opts.profile !== void 0 ? { profile: opts.profile } : {}
992
+ });
993
+ return createGaruClient({
994
+ auth,
995
+ ...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {}
996
+ });
997
+ }
998
+ async function refundRequestsListCommand(opts) {
999
+ const garu = await getClient5(opts);
1000
+ const params = {};
1001
+ if (opts.page !== void 0) params.page = opts.page;
1002
+ if (opts.limit !== void 0) params.limit = opts.limit;
1003
+ if (opts.planId !== void 0) params.planId = opts.planId;
1004
+ if (opts.chargeId !== void 0) params.chargeId = opts.chargeId;
1005
+ if (opts.status !== void 0 && opts.status.length > 0) {
1006
+ params.status = opts.status.length === 1 ? opts.status[0] : opts.status;
1007
+ }
1008
+ const result = await garu.refundRequests.list(params);
1009
+ printResult(result, { ...opts, prettyPrint: prettyRefundRequestList });
1010
+ return result;
1011
+ }
1012
+ async function refundRequestsGetCommand(opts) {
1013
+ const garu = await getClient5(opts);
1014
+ const request = await garu.refundRequests.get(opts.uuid);
1015
+ printResult(request, { ...opts, prettyPrint: prettyRefundRequest2 });
1016
+ return request;
1017
+ }
1018
+ async function refundRequestsConfirmCommand(opts) {
1019
+ const garu = await getClient5(opts);
1020
+ const params = {};
1021
+ if (opts.note !== void 0) params.note = opts.note;
1022
+ const request = await garu.refundRequests.confirm(opts.uuid, params);
1023
+ printResult(request, { ...opts, prettyPrint: prettyRefundRequest2 });
1024
+ return request;
1025
+ }
1026
+ async function refundRequestsRejectCommand(opts) {
1027
+ const garu = await getClient5(opts);
1028
+ const params = {};
1029
+ if (opts.note !== void 0) params.note = opts.note;
1030
+ const request = await garu.refundRequests.reject(opts.uuid, params);
1031
+ printResult(request, { ...opts, prettyPrint: prettyRefundRequest2 });
1032
+ return request;
1033
+ }
1034
+ function prettyRefundRequestList(list) {
1035
+ if (list.data.length === 0) return "No refund requests found";
1036
+ const header = `Refund requests (${list.count} of ${list.totalCount} total, ${list.totalPages} page(s))`;
1037
+ const rows = list.data.map(
1038
+ (r) => ` ${r.uuid} ${r.status.padEnd(10)} ${String(r.amount).padStart(10)} ${r.installmentPlanId ?? r.chargeId ?? ""}`
1039
+ );
1040
+ return [header, ...rows].join("\n");
1041
+ }
1042
+ function prettyRefundRequest2(r) {
1043
+ const lines = [`Refund request ${r.uuid}`, ` status: ${r.status}`, ` amount: ${r.amount}`];
1044
+ if (r.reason) lines.push(` reason: ${r.reason}`);
1045
+ if (r.installmentPlanId) lines.push(` installmentPlan: ${r.installmentPlanId}`);
1046
+ if (r.chargeId) lines.push(` charge: ${r.chargeId}`);
1047
+ if (r.resolvedAt) lines.push(` resolvedAt: ${r.resolvedAt}`);
1048
+ if (r.sellerNote) lines.push(` sellerNote: ${r.sellerNote}`);
1049
+ return lines.join("\n");
1050
+ }
1051
+
546
1052
  // src/commands/scheduled-charges.ts
547
- async function getClient3(opts) {
1053
+ async function getClient6(opts) {
548
1054
  if (opts.garu) return opts.garu;
549
1055
  const auth = await resolveAuth({
550
1056
  ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
@@ -581,7 +1087,7 @@ function assertPixAutomaticRequirements(opts) {
581
1087
  }
582
1088
  async function scheduledChargesCreateCommand(opts) {
583
1089
  assertPixAutomaticRequirements(opts);
584
- const garu = await getClient3(opts);
1090
+ const garu = await getClient6(opts);
585
1091
  const params = {
586
1092
  customerId: opts.customerId,
587
1093
  amount: opts.amount,
@@ -603,7 +1109,7 @@ async function scheduledChargesCreateCommand(opts) {
603
1109
  return charge;
604
1110
  }
605
1111
  async function scheduledChargesListCommand(opts) {
606
- const garu = await getClient3(opts);
1112
+ const garu = await getClient6(opts);
607
1113
  const params = {};
608
1114
  if (opts.page !== void 0) params.page = opts.page;
609
1115
  if (opts.limit !== void 0) params.limit = opts.limit;
@@ -620,13 +1126,13 @@ async function scheduledChargesListCommand(opts) {
620
1126
  return result;
621
1127
  }
622
1128
  async function scheduledChargesGetCommand(opts) {
623
- const garu = await getClient3(opts);
1129
+ const garu = await getClient6(opts);
624
1130
  const detail = await garu.scheduledCharges.get(opts.id);
625
1131
  printResult(detail, { ...opts, prettyPrint: prettyScheduledChargeDetail });
626
1132
  return detail;
627
1133
  }
628
1134
  async function scheduledChargesPostponeCommand(opts) {
629
- const garu = await getClient3(opts);
1135
+ const garu = await getClient6(opts);
630
1136
  const params = { newDueDate: opts.newDueDate };
631
1137
  if (opts.reason !== void 0) params.reason = opts.reason;
632
1138
  const charge = await garu.scheduledCharges.postpone(opts.id, params);
@@ -634,7 +1140,7 @@ async function scheduledChargesPostponeCommand(opts) {
634
1140
  return charge;
635
1141
  }
636
1142
  async function scheduledChargesPauseCommand(opts) {
637
- const garu = await getClient3(opts);
1143
+ const garu = await getClient6(opts);
638
1144
  const params = {};
639
1145
  if (opts.reason !== void 0) params.reason = opts.reason;
640
1146
  const charge = await garu.scheduledCharges.pause(opts.id, params);
@@ -642,13 +1148,13 @@ async function scheduledChargesPauseCommand(opts) {
642
1148
  return charge;
643
1149
  }
644
1150
  async function scheduledChargesResumeCommand(opts) {
645
- const garu = await getClient3(opts);
1151
+ const garu = await getClient6(opts);
646
1152
  const charge = await garu.scheduledCharges.resume(opts.id);
647
1153
  printResult(charge, { ...opts, prettyPrint: prettyScheduledCharge });
648
1154
  return charge;
649
1155
  }
650
1156
  async function scheduledChargesMarkPaidCommand(opts) {
651
- const garu = await getClient3(opts);
1157
+ const garu = await getClient6(opts);
652
1158
  const params = { paymentDate: opts.paymentDate };
653
1159
  if (opts.externalReference !== void 0) params.externalReference = opts.externalReference;
654
1160
  if (opts.cycleNumber !== void 0) params.cycleNumber = opts.cycleNumber;
@@ -657,7 +1163,7 @@ async function scheduledChargesMarkPaidCommand(opts) {
657
1163
  return charge;
658
1164
  }
659
1165
  async function scheduledChargesCancelRecurrenceCommand(opts) {
660
- const garu = await getClient3(opts);
1166
+ const garu = await getClient6(opts);
661
1167
  const params = {};
662
1168
  if (opts.reason !== void 0) params.reason = opts.reason;
663
1169
  const charge = await garu.scheduledCharges.cancelRecurrence(opts.id, params);
@@ -665,14 +1171,14 @@ async function scheduledChargesCancelRecurrenceCommand(opts) {
665
1171
  return charge;
666
1172
  }
667
1173
  async function scheduledChargesCancelAtPeriodEndCommand(opts) {
668
- const garu = await getClient3(opts);
1174
+ const garu = await getClient6(opts);
669
1175
  const params = { enabled: opts.enabled };
670
1176
  const charge = await garu.scheduledCharges.setCancelAtPeriodEnd(opts.id, params);
671
1177
  printResult(charge, { ...opts, prettyPrint: prettyScheduledCharge });
672
1178
  return charge;
673
1179
  }
674
1180
  async function scheduledChargesChangePaymentMethodCommand(opts) {
675
- const garu = await getClient3(opts);
1181
+ const garu = await getClient6(opts);
676
1182
  const params = {
677
1183
  paymentMethodId: opts.paymentMethodId
678
1184
  };
@@ -681,13 +1187,13 @@ async function scheduledChargesChangePaymentMethodCommand(opts) {
681
1187
  return charge;
682
1188
  }
683
1189
  async function scheduledChargesClearPaymentMethodCommand(opts) {
684
- const garu = await getClient3(opts);
1190
+ const garu = await getClient6(opts);
685
1191
  const charge = await garu.scheduledCharges.clearPaymentMethod(opts.id);
686
1192
  printResult(charge, { ...opts, prettyPrint: prettyScheduledCharge });
687
1193
  return charge;
688
1194
  }
689
1195
  async function scheduledChargesAttemptsCommand(opts) {
690
- const garu = await getClient3(opts);
1196
+ const garu = await getClient6(opts);
691
1197
  const params = {};
692
1198
  if (opts.page !== void 0) params.page = opts.page;
693
1199
  if (opts.limit !== void 0) params.limit = opts.limit;
@@ -697,7 +1203,7 @@ async function scheduledChargesAttemptsCommand(opts) {
697
1203
  return result;
698
1204
  }
699
1205
  async function scheduledChargesChargeNowCommand(opts) {
700
- const garu = await getClient3(opts);
1206
+ const garu = await getClient6(opts);
701
1207
  const result = await garu.scheduledCharges.chargeNow(opts.id);
702
1208
  printResult(result, { ...opts, prettyPrint: prettyChargeNow });
703
1209
  if (result.outcome === "failed" || result.outcome === "not_sent") {
@@ -761,7 +1267,7 @@ function prettyChargeNow(result) {
761
1267
  if (result.reason) lines.push(` reason: ${result.reason}`);
762
1268
  return lines.join("\n");
763
1269
  }
764
- async function getClient4(opts) {
1270
+ async function getClient7(opts) {
765
1271
  if (opts.garu) return opts.garu;
766
1272
  const auth = await resolveAuth({
767
1273
  ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
@@ -773,7 +1279,7 @@ async function getClient4(opts) {
773
1279
  });
774
1280
  }
775
1281
  async function webhooksEventsListCommand(opts) {
776
- const garu = await getClient4(opts);
1282
+ const garu = await getClient7(opts);
777
1283
  const params = {};
778
1284
  if (opts.page !== void 0) params.page = opts.page;
779
1285
  if (opts.limit !== void 0) params.limit = opts.limit;
@@ -785,19 +1291,19 @@ async function webhooksEventsListCommand(opts) {
785
1291
  return result;
786
1292
  }
787
1293
  async function webhooksEventsGetCommand(opts) {
788
- const garu = await getClient4(opts);
1294
+ const garu = await getClient7(opts);
789
1295
  const event = await garu.webhookEvents.get(opts.id);
790
1296
  printResult(event, { ...opts, prettyPrint: prettyWebhookEvent });
791
1297
  return event;
792
1298
  }
793
1299
  async function webhooksEventsRetryCommand(opts) {
794
- const garu = await getClient4(opts);
1300
+ const garu = await getClient7(opts);
795
1301
  const event = await garu.webhookEvents.retry(opts.id);
796
1302
  printResult(event, { ...opts, prettyPrint: prettyWebhookEvent });
797
1303
  return event;
798
1304
  }
799
1305
  async function webhooksEventsResendCommand(opts) {
800
- const garu = await getClient4(opts);
1306
+ const garu = await getClient7(opts);
801
1307
  const clone = await garu.webhookEvents.resend(opts.id);
802
1308
  printSuccess(`Resent event ${opts.id} \u2192 new event ${clone.id}`, opts);
803
1309
  printResult(clone, { ...opts, prettyPrint: prettyWebhookEvent });
@@ -839,138 +1345,6 @@ function prettyWebhookEvent(event) {
839
1345
  return lines.join("\n");
840
1346
  }
841
1347
 
842
- // src/lib/parse.ts
843
- function parsePositiveIntId(raw, label) {
844
- const id = Number.parseInt(raw, 10);
845
- if (!Number.isFinite(id) || id <= 0) {
846
- throw new CliError("invalid_input", `${label} must be a positive integer (got '${raw}')`);
847
- }
848
- return id;
849
- }
850
- function parsePaymentMethod(raw) {
851
- if (raw === "pix" || raw === "credit_card" || raw === "boleto") return raw;
852
- throw new CliError(
853
- "invalid_input",
854
- `--type must be 'pix', 'credit_card', or 'boleto' (got '${raw}')`
855
- );
856
- }
857
- function parseWebhookEventStatus(raw) {
858
- if (raw === "pending" || raw === "success" || raw === "failed") return raw;
859
- throw new CliError(
860
- "invalid_input",
861
- `--status must be 'pending', 'success', or 'failed' (got '${raw}')`
862
- );
863
- }
864
- function parseScheduledChargeType(raw) {
865
- if (raw === "one_time" || raw === "recurring") return raw;
866
- throw new CliError("invalid_input", `--type must be 'one_time' or 'recurring' (got '${raw}')`);
867
- }
868
- var SCHEDULED_PAYMENT_METHODS = [
869
- "pix",
870
- "boleto",
871
- "card",
872
- "pix_automatic"
873
- ];
874
- function parseCsvList(raw) {
875
- return raw.split(",").map((s) => s.trim()).filter(Boolean);
876
- }
877
- function parseScheduledPaymentMethods(raw) {
878
- const parts = parseCsvList(raw);
879
- if (parts.length === 0) {
880
- throw new CliError(
881
- "invalid_input",
882
- `--methods must list at least one of: ${SCHEDULED_PAYMENT_METHODS.join(", ")}`
883
- );
884
- }
885
- for (const p of parts) {
886
- if (!SCHEDULED_PAYMENT_METHODS.includes(p)) {
887
- throw new CliError(
888
- "invalid_input",
889
- `--methods entries must be one of ${SCHEDULED_PAYMENT_METHODS.join(", ")} (got '${p}')`
890
- );
891
- }
892
- }
893
- return parts;
894
- }
895
- var RECURRENCE_INTERVALS = [
896
- "weekly",
897
- "biweekly",
898
- "monthly",
899
- "bimonthly",
900
- "quarterly",
901
- "biannual",
902
- "yearly"
903
- ];
904
- function parseRecurrenceInterval(raw) {
905
- if (RECURRENCE_INTERVALS.includes(raw)) return raw;
906
- throw new CliError(
907
- "invalid_input",
908
- `--recurrence-interval must be one of ${RECURRENCE_INTERVALS.join(", ")} (got '${raw}')`
909
- );
910
- }
911
- var SCHEDULED_CHARGE_STATUSES = [
912
- "scheduled",
913
- "due_today",
914
- "overdue",
915
- "paid",
916
- "paused",
917
- "canceled",
918
- "trial",
919
- "pending_tokenization",
920
- "recurrence_canceled"
921
- ];
922
- function parseScheduledChargeStatus(raw) {
923
- if (SCHEDULED_CHARGE_STATUSES.includes(raw)) return raw;
924
- throw new CliError(
925
- "invalid_input",
926
- `--status must be one of ${SCHEDULED_CHARGE_STATUSES.join(", ")} (got '${raw}')`
927
- );
928
- }
929
- function parseIntInRange(raw, label, min, max) {
930
- const trimmed = raw.trim();
931
- const n = Number.parseInt(trimmed, 10);
932
- if (!Number.isFinite(n) || String(n) !== trimmed || n < min || n > max) {
933
- throw new CliError(
934
- "invalid_input",
935
- `${label} must be an integer between ${min} and ${max} (got '${raw}')`
936
- );
937
- }
938
- return n;
939
- }
940
- function parseNonNegativeBrl(raw, label) {
941
- const trimmed = raw.trim();
942
- const n = Number(trimmed);
943
- if (trimmed === "" || !Number.isFinite(n) || n < 0) {
944
- throw new CliError(
945
- "invalid_input",
946
- `${label} must be a non-negative amount in BRL/reais, e.g. 49.90 (got '${raw}')`
947
- );
948
- }
949
- return n;
950
- }
951
- function parseAmountBrl(raw) {
952
- const n = Number(raw);
953
- if (!Number.isFinite(n) || n <= 0) {
954
- throw new CliError(
955
- "invalid_input",
956
- `--amount must be a positive decimal in BRL, e.g. 297.50 (got '${raw}')`
957
- );
958
- }
959
- return n;
960
- }
961
- function parseMetadata(raw) {
962
- let parsed;
963
- try {
964
- parsed = JSON.parse(raw);
965
- } catch {
966
- throw new CliError("invalid_input", `--metadata must be valid JSON (got '${raw}')`);
967
- }
968
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
969
- throw new CliError("invalid_input", `--metadata must be a JSON object`);
970
- }
971
- return parsed;
972
- }
973
-
974
1348
  // src/index.ts
975
1349
  function buildCli() {
976
1350
  const program = new commander.Command();
@@ -1021,16 +1395,19 @@ Recipes:
1021
1395
  );
1022
1396
  });
1023
1397
  const charges = program.command("charges").description("Create, fetch, and refund charges");
1024
- charges.command("list").description("List charges with pagination and filters").option("--page <n>", "page number (1-based)", (v) => parseInt(v, 10)).option("--limit <n>", "items per page (1-100)", (v) => parseInt(v, 10)).option("--status <status>", "filter by status (e.g. paid, pending)").option("--search <query>", "search by customer name, email, or document").option("--payment-method <method>", "filter: pix, creditcard, boleto").action(
1398
+ charges.command("list").description("List charges with pagination and filters").option("--page <n>", "page number (1-based)", (v) => parseInt(v, 10)).option("--limit <n>", "items per page (1-100)", (v) => parseInt(v, 10)).option(
1399
+ "--status <status>",
1400
+ "filter by status: pending, authorized, paid, failed, expired, canceled, refund_pending, refunded, chargeback"
1401
+ ).option("--search <query>", "search by customer name, email, or document").option("--payment-method <method>", "filter: pix, credit_card, boleto").action(
1025
1402
  async (cmdOpts) => {
1026
1403
  const base = toCommandOptions(program);
1027
1404
  await chargesListCommand({
1028
1405
  ...base,
1029
1406
  page: cmdOpts.page,
1030
1407
  limit: cmdOpts.limit,
1031
- status: cmdOpts.status,
1408
+ status: cmdOpts.status ? parseChargeStatus(cmdOpts.status) : void 0,
1032
1409
  search: cmdOpts.search,
1033
- paymentMethod: cmdOpts.paymentMethod
1410
+ paymentMethod: cmdOpts.paymentMethod ? parseChargePaymentMethodFilter(cmdOpts.paymentMethod) : void 0
1034
1411
  }).catch((err) => printErrorAndExit(err, base));
1035
1412
  }
1036
1413
  );
@@ -1056,20 +1433,21 @@ Recipes:
1056
1433
  idempotencyKey: cmdOpts.idempotencyKey
1057
1434
  }).catch((err) => printErrorAndExit(err, base));
1058
1435
  });
1059
- charges.command("get <id>").description("Fetch a single charge by ID").action(async (id) => {
1436
+ charges.command("get <id>").description("Fetch a single charge by its uuid").action(async (id) => {
1060
1437
  const base = toCommandOptions(program);
1061
- await chargesGetCommand({ ...base, id: parsePositiveIntId(id, "Charge ID") }).catch(
1062
- (err) => printErrorAndExit(err, base)
1063
- );
1438
+ await chargesGetCommand({ ...base, id }).catch((err) => printErrorAndExit(err, base));
1064
1439
  });
1065
- charges.command("refund <id>").description("Refund a charge (full or partial)").option("--amount <centavos>", "partial refund amount in centavos", (v) => parseInt(v, 10)).option("--reason <text>", "optional refund reason").option("--idempotency-key <key>", "idempotency key (auto-generated if omitted)").action(async (id, cmdOpts) => {
1440
+ charges.command("refund <id>").description("Refund a charge by its uuid (full or partial)").option(
1441
+ "--amount <reais>",
1442
+ "partial refund amount in decimal BRL, e.g. 10.00",
1443
+ (v) => parseNonNegativeBrl(v, "--amount")
1444
+ ).option("--reason <text>", "optional refund reason").action(async (id, cmdOpts) => {
1066
1445
  const base = toCommandOptions(program);
1067
1446
  await chargesRefundCommand({
1068
1447
  ...base,
1069
- id: parsePositiveIntId(id, "Charge ID"),
1448
+ id,
1070
1449
  amount: cmdOpts.amount,
1071
- reason: cmdOpts.reason,
1072
- idempotencyKey: cmdOpts.idempotencyKey
1450
+ reason: cmdOpts.reason
1073
1451
  }).catch((err) => printErrorAndExit(err, base));
1074
1452
  });
1075
1453
  const scheduled = program.command("scheduled-charges").description("Schedule, inspect, and act on future-dated charges");
@@ -1286,6 +1664,221 @@ Recipes:
1286
1664
  id: parsePositiveIntId(id, "Webhook event ID")
1287
1665
  }).catch((err) => printErrorAndExit(err, base));
1288
1666
  });
1667
+ const customers = program.command("customers").description("Manage your customer base");
1668
+ customers.command("create").description("Register a customer for the current seller (dedup by document)").requiredOption("--name <name>", "customer name").requiredOption("--email <email>", "customer email").requiredOption("--document <document>", "CPF (11 digits) or CNPJ (14 digits), digits only").requiredOption("--phone <phone>", "phone with area code, 10-11 digits").requiredOption("--person-type <type>", "'fisica' or 'juridica'").option("--zip-code <cep>", "ZIP code, 8 digits").option("--street <street>", "street address").option("--number <number>", "address number").option("--complement <text>", "address complement").option("--neighborhood <text>", "neighborhood").option("--city <city>", "city").option("--state <uf>", "2-letter state code, e.g. SP").action(async (cmdOpts) => {
1669
+ const base = toCommandOptions(program);
1670
+ await customersCreateCommand({
1671
+ ...base,
1672
+ name: cmdOpts.name,
1673
+ email: cmdOpts.email,
1674
+ document: cmdOpts.document,
1675
+ phone: cmdOpts.phone,
1676
+ personType: parsePersonType(cmdOpts.personType),
1677
+ zipCode: cmdOpts.zipCode,
1678
+ street: cmdOpts.street,
1679
+ number: cmdOpts.number,
1680
+ complement: cmdOpts.complement,
1681
+ neighborhood: cmdOpts.neighborhood,
1682
+ city: cmdOpts.city,
1683
+ state: cmdOpts.state
1684
+ }).catch((err) => printErrorAndExit(err, base));
1685
+ });
1686
+ customers.command("list").description("List customers with pagination and search").option("--page <n>", "page number (1-based)", (v) => parseInt(v, 10)).option("--limit <n>", "items per page (1-100)", (v) => parseInt(v, 10)).option("--search <query>", "search by name, email, or document").option(
1687
+ "--status <status>",
1688
+ "'overdue' returns customers with at least one overdue scheduled charge"
1689
+ ).action(
1690
+ async (cmdOpts) => {
1691
+ const base = toCommandOptions(program);
1692
+ await customersListCommand({
1693
+ ...base,
1694
+ page: cmdOpts.page,
1695
+ limit: cmdOpts.limit,
1696
+ search: cmdOpts.search,
1697
+ status: cmdOpts.status === "overdue" ? "overdue" : void 0
1698
+ }).catch((err) => printErrorAndExit(err, base));
1699
+ }
1700
+ );
1701
+ customers.command("get <uuid>").description("Fetch a single customer by uuid").action(async (uuid) => {
1702
+ const base = toCommandOptions(program);
1703
+ await customersGetCommand({ ...base, uuid }).catch((err) => printErrorAndExit(err, base));
1704
+ });
1705
+ customers.command("update <uuid>").description("Partially update a customer (only the flags you pass change)").option("--name <name>", "customer name").option("--email <email>", "customer email").option("--phone <phone>", "phone with area code, 10-11 digits").option("--document <document>", "CPF (11 digits) or CNPJ (14 digits), digits only").option("--person-type <type>", "'fisica' or 'juridica'").option("--zip-code <cep>", "ZIP code, 8 digits").option("--street <street>", "street address").option("--number <number>", "address number").option("--complement <text>", "address complement").option("--neighborhood <text>", "neighborhood").option("--city <city>", "city").option("--state <uf>", "2-letter state code, e.g. SP").action(async (uuid, cmdOpts) => {
1706
+ const base = toCommandOptions(program);
1707
+ await customersUpdateCommand({
1708
+ ...base,
1709
+ uuid,
1710
+ name: cmdOpts.name,
1711
+ email: cmdOpts.email,
1712
+ phone: cmdOpts.phone,
1713
+ document: cmdOpts.document,
1714
+ personType: cmdOpts.personType ? parsePersonType(cmdOpts.personType) : void 0,
1715
+ zipCode: cmdOpts.zipCode,
1716
+ street: cmdOpts.street,
1717
+ number: cmdOpts.number,
1718
+ complement: cmdOpts.complement,
1719
+ neighborhood: cmdOpts.neighborhood,
1720
+ city: cmdOpts.city,
1721
+ state: cmdOpts.state
1722
+ }).catch((err) => printErrorAndExit(err, base));
1723
+ });
1724
+ customers.command("set-billing-email <uuid>").description("Set the sticky per-seller billing-email override").requiredOption("--email <email>", "the billing email to set").action(async (uuid, cmdOpts) => {
1725
+ const base = toCommandOptions(program);
1726
+ await customersSetBillingEmailOverrideCommand({
1727
+ ...base,
1728
+ uuid,
1729
+ billingEmailOverride: cmdOpts.email
1730
+ }).catch((err) => printErrorAndExit(err, base));
1731
+ });
1732
+ customers.command("clear-billing-email <uuid>").description("Clear the billing-email override, falling back to the last-used email").action(async (uuid) => {
1733
+ const base = toCommandOptions(program);
1734
+ await customersSetBillingEmailOverrideCommand({
1735
+ ...base,
1736
+ uuid,
1737
+ billingEmailOverride: null
1738
+ }).catch((err) => printErrorAndExit(err, base));
1739
+ });
1740
+ customers.command("delete <uuid>").description("Remove a customer from the current seller (unlinks your profile only)").action(async (uuid) => {
1741
+ const base = toCommandOptions(program);
1742
+ await customersDeleteCommand({ ...base, uuid }).catch((err) => printErrorAndExit(err, base));
1743
+ });
1744
+ const installmentPlans = program.command("installment-plans").description("Sell a product as boleto parcelado (carn\xEA) and manage its installments");
1745
+ installmentPlans.command("create").description("Sell a product as a carn\xEA (installments of boleto slips)").requiredOption("--product-id <uuid>", "product uuid (must have boleto parcelado enabled)").requiredOption(
1746
+ "--customer-id <n>",
1747
+ "customer id",
1748
+ (v) => parsePositiveIntId(v, "--customer-id")
1749
+ ).requiredOption(
1750
+ "--installments <n>",
1751
+ "2-12 installments",
1752
+ (v) => parseIntInRange(v, "--installments", 2, 12)
1753
+ ).option("--first-due-date <yyyy-mm-dd>", "first installment due date (default: today)").option(
1754
+ "--affiliate-id <n>",
1755
+ "attribute the sale to this affiliate (fixed for the whole plan)",
1756
+ (v) => parsePositiveIntId(v, "--affiliate-id")
1757
+ ).option("--idempotency-key <key>", "idempotency key (auto-generated if omitted)").action(async (cmdOpts) => {
1758
+ const base = toCommandOptions(program);
1759
+ await installmentPlansCreateCommand({
1760
+ ...base,
1761
+ productId: cmdOpts.productId,
1762
+ customerId: cmdOpts.customerId,
1763
+ installments: cmdOpts.installments,
1764
+ firstDueDate: cmdOpts.firstDueDate,
1765
+ affiliateId: cmdOpts.affiliateId,
1766
+ idempotencyKey: cmdOpts.idempotencyKey
1767
+ }).catch((err) => printErrorAndExit(err, base));
1768
+ });
1769
+ installmentPlans.command("list").description("List installment plans (carn\xEAs) with pagination and filters").option("--page <n>", "page number (1-based)", (v) => parseInt(v, 10)).option("--limit <n>", "items per page (1-100)", (v) => parseInt(v, 10)).option(
1770
+ "--customer-id <n>",
1771
+ "filter by customer id",
1772
+ (v) => parsePositiveIntId(v, "--customer-id")
1773
+ ).option("--product-id <uuid>", "filter by product uuid").option(
1774
+ "--status <status>",
1775
+ "filter by status (repeatable)",
1776
+ (val, acc) => acc.concat(val),
1777
+ []
1778
+ ).option("--due-from <yyyy-mm-dd>", "lower bound for the first installment due date").option("--due-to <yyyy-mm-dd>", "upper bound for the first installment due date").action(
1779
+ async (cmdOpts) => {
1780
+ const base = toCommandOptions(program);
1781
+ await installmentPlansListCommand({
1782
+ ...base,
1783
+ page: cmdOpts.page,
1784
+ limit: cmdOpts.limit,
1785
+ customerId: cmdOpts.customerId,
1786
+ productId: cmdOpts.productId,
1787
+ status: cmdOpts.status.length > 0 ? cmdOpts.status.map(parseInstallmentPlanStatus) : void 0,
1788
+ dueFrom: cmdOpts.dueFrom,
1789
+ dueTo: cmdOpts.dueTo
1790
+ }).catch((err) => printErrorAndExit(err, base));
1791
+ }
1792
+ );
1793
+ installmentPlans.command("get <uuid>").description("Fetch a carn\xEA with every installment: due date, status, barcode and PDF").action(async (uuid) => {
1794
+ const base = toCommandOptions(program);
1795
+ await installmentPlansGetCommand({ ...base, uuid }).catch(
1796
+ (err) => printErrorAndExit(err, base)
1797
+ );
1798
+ });
1799
+ installmentPlans.command("reissue <uuid> <number>").description("Issue a segunda via for one installment once its slip has expired").action(async (uuid, number) => {
1800
+ const base = toCommandOptions(program);
1801
+ await installmentPlansReissueCommand({
1802
+ ...base,
1803
+ uuid,
1804
+ number: parsePositiveIntId(number, "installment number")
1805
+ }).catch((err) => printErrorAndExit(err, base));
1806
+ });
1807
+ installmentPlans.command("postpone <uuid> <number>").description("Move one installment to a later due date (its siblings keep theirs)").requiredOption("--new-due-date <yyyy-mm-dd>", "new due date for this installment").action(async (uuid, number, cmdOpts) => {
1808
+ const base = toCommandOptions(program);
1809
+ await installmentPlansPostponeCommand({
1810
+ ...base,
1811
+ uuid,
1812
+ number: parsePositiveIntId(number, "installment number"),
1813
+ newDueDate: cmdOpts.newDueDate
1814
+ }).catch((err) => printErrorAndExit(err, base));
1815
+ });
1816
+ installmentPlans.command("mark-paid <uuid> <number>").description("Record an installment as paid when the buyer paid but the webhook never arrived").action(async (uuid, number) => {
1817
+ const base = toCommandOptions(program);
1818
+ await installmentPlansMarkPaidCommand({
1819
+ ...base,
1820
+ uuid,
1821
+ number: parsePositiveIntId(number, "installment number")
1822
+ }).catch((err) => printErrorAndExit(err, base));
1823
+ });
1824
+ installmentPlans.command("cancel <uuid>").description("Cancel a carn\xEA \u2014 stops emission/reminders and cancels open provider slips").option("--note <text>", "optional note recorded on the plan").action(async (uuid, cmdOpts) => {
1825
+ const base = toCommandOptions(program);
1826
+ await installmentPlansCancelCommand({ ...base, uuid, note: cmdOpts.note }).catch(
1827
+ (err) => printErrorAndExit(err, base)
1828
+ );
1829
+ });
1830
+ installmentPlans.command("request-refund <uuid>").description(
1831
+ "Ask for a carn\xEA to be refunded (Garu records the request; transfer the money yourself, then confirm with `garu refund-requests confirm`)"
1832
+ ).option(
1833
+ "--amount <reais>",
1834
+ "defaults to everything the carn\xEA has collected",
1835
+ (v) => parseNonNegativeBrl(v, "--amount")
1836
+ ).option("--reason <text>", "optional reason").action(async (uuid, cmdOpts) => {
1837
+ const base = toCommandOptions(program);
1838
+ await installmentPlansRequestRefundCommand({
1839
+ ...base,
1840
+ uuid,
1841
+ amount: cmdOpts.amount,
1842
+ reason: cmdOpts.reason
1843
+ }).catch((err) => printErrorAndExit(err, base));
1844
+ });
1845
+ const refundRequests = program.command("refund-requests").description("Inspect and resolve refund requests (carn\xEA and Pix/boleto)");
1846
+ refundRequests.command("list").description("List refund requests with pagination and filters").option("--page <n>", "page number (1-based)", (v) => parseInt(v, 10)).option("--limit <n>", "items per page (1-100)", (v) => parseInt(v, 10)).option("--plan-id <uuid>", "filter by carn\xEA uuid").option("--charge-id <uuid>", "filter by charge uuid (Pix/boleto)").option(
1847
+ "--status <status>",
1848
+ "filter by status (repeatable): pending, confirmed, rejected",
1849
+ (val, acc) => acc.concat(val),
1850
+ []
1851
+ ).action(
1852
+ async (cmdOpts) => {
1853
+ const base = toCommandOptions(program);
1854
+ await refundRequestsListCommand({
1855
+ ...base,
1856
+ page: cmdOpts.page,
1857
+ limit: cmdOpts.limit,
1858
+ planId: cmdOpts.planId,
1859
+ chargeId: cmdOpts.chargeId,
1860
+ status: cmdOpts.status.length > 0 ? cmdOpts.status.map(parseRefundRequestStatus) : void 0
1861
+ }).catch((err) => printErrorAndExit(err, base));
1862
+ }
1863
+ );
1864
+ refundRequests.command("get <uuid>").description("Fetch a single refund request").action(async (uuid) => {
1865
+ const base = toCommandOptions(program);
1866
+ await refundRequestsGetCommand({ ...base, uuid }).catch(
1867
+ (err) => printErrorAndExit(err, base)
1868
+ );
1869
+ });
1870
+ refundRequests.command("confirm <uuid>").description("Record that you transferred the money back \u2014 call this AFTER the transfer").option("--note <text>", "optional note, e.g. a bank reference").action(async (uuid, cmdOpts) => {
1871
+ const base = toCommandOptions(program);
1872
+ await refundRequestsConfirmCommand({ ...base, uuid, note: cmdOpts.note }).catch(
1873
+ (err) => printErrorAndExit(err, base)
1874
+ );
1875
+ });
1876
+ refundRequests.command("reject <uuid>").description("Decline the request \u2014 the carn\xEA or charge is left untouched").option("--note <text>", "optional note explaining the rejection").action(async (uuid, cmdOpts) => {
1877
+ const base = toCommandOptions(program);
1878
+ await refundRequestsRejectCommand({ ...base, uuid, note: cmdOpts.note }).catch(
1879
+ (err) => printErrorAndExit(err, base)
1880
+ );
1881
+ });
1289
1882
  const products = program.command("products").description("Create and update products");
1290
1883
  products.command("create").description("Create a product").requiredOption("--name <name>", "product name").option(
1291
1884
  "--value <reais>",