@garuhq/cli 0.9.0 → 0.11.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,39 @@
3
3
  All notable changes to `@garuhq/cli` 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.11.0] — 2026-08-22
7
+
8
+ ### Changed
9
+
10
+ - **`garu webhooks events` now targets `/api/v1/webhook-events`, uuid-keyed.**
11
+ `get`, `retry`, and `resend` take a `<uuid>` positional argument instead of
12
+ a numeric id. `list` output now reports `count`/`totalCount`/`totalPages`
13
+ instead of a `page`/`total` counter, and every row/detail view prints the
14
+ event's `uuid`.
15
+ - **`@garuhq/node` bumped to `3.0.0`.** Breaking for `garu.webhookEvents.*`
16
+ (see that package's changelog).
17
+
18
+ ### Breaking
19
+
20
+ - `garu webhooks events get <id>` / `retry <id>` / `resend <id>` now expect
21
+ a `uuid`, not a numeric id. Run `garu webhooks events list` to read the
22
+ `uuid` of the event you want to act on.
23
+
24
+ ## [0.10.0] — 2026-08-22
25
+
26
+ ### Added
27
+
28
+ - **`garu customers` — manage your customer base.** `create`, `list`, `get`,
29
+ `update`, `set-billing-email`, `clear-billing-email`, `delete`. Backed by
30
+ the new `/api/v1/customers`, keyed on `uuid`.
31
+
32
+ ### Changed
33
+
34
+ - **`@garuhq/node` bumped to `2.0.0`.** Breaking for `garu.customers.*` (see
35
+ that package's changelog); does not affect any other `garu-cli` command —
36
+ `customers` is a new command group in this release, so nothing here
37
+ changes behavior.
38
+
6
39
  ## [0.9.0] — 2026-08-21
7
40
 
8
41
  ### Added
@@ -42,7 +75,7 @@ All notable changes to `@garuhq/cli` are documented in this file. Format:
42
75
  `.expiresAt` (was `.date` / `.deadline`), and a new `charge.chargedTotal`
43
76
  field (what was actually charged, vs. `.amount`, the product's base
44
77
  price). `charges list`'s response shape is now `{ data, count, totalCount,
45
- totalPages }` (was `{ data, meta }`).
78
+ totalPages }` (was `{ data, meta }`).
46
79
 
47
80
  ## [0.8.0] — 2026-07-18
48
81
 
package/README.md CHANGED
@@ -402,6 +402,43 @@ garu refund-requests reject a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
402
402
 
403
403
  ---
404
404
 
405
+ ### `garu customers create`
406
+
407
+ Register a customer for the current seller. Registering the same `document`
408
+ twice attaches your profile to the existing global customer instead of
409
+ erroring — safe to call once per seller per person.
410
+
411
+ ```bash
412
+ garu customers create \
413
+ --name "Maria Silva" --email maria@exemplo.com.br \
414
+ --document 12345678909 --phone 11987654321 \
415
+ --person-type fisica
416
+ ```
417
+
418
+ | Flag | Description |
419
+ | ----------------------- | ---------------------------------------------- |
420
+ | `--name <name>` | Customer name (required) |
421
+ | `--email <email>` | Customer email (required) |
422
+ | `--document <document>` | CPF (11 digits) or CNPJ (14 digits) (required) |
423
+ | `--phone <phone>` | Phone with area code, 10-11 digits (required) |
424
+ | `--person-type <type>` | `fisica` or `juridica` (required) |
425
+ | `--zip-code <cep>` etc. | Address fields (all optional) |
426
+
427
+ ---
428
+
429
+ ### `garu customers` — other subcommands
430
+
431
+ | Command | Description |
432
+ | ------------------------------------------ | ---------------------------------------------------------------- |
433
+ | `list [--page --limit --search --status]` | List customers (`--status overdue` filters to at-risk customers) |
434
+ | `get <uuid>` | Fetch a single customer |
435
+ | `update <uuid> [...]` | Partial update — same flags as `create`, all optional |
436
+ | `set-billing-email <uuid> --email <email>` | Set the sticky per-seller billing-email override |
437
+ | `clear-billing-email <uuid>` | Clear the override, falling back to the last-used email |
438
+ | `delete <uuid>` | Unlink the customer from the current seller |
439
+
440
+ ---
441
+
405
442
  ### `garu doctor`
406
443
 
407
444
  Run environment diagnostics. Verifies your CLI version, API connectivity, credentials, and detects AI agent integrations.
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.9.0";
18
+ var CLI_VERSION = "0.11.0";
19
19
  var CliError = class extends Error {
20
20
  code;
21
21
  exitCode;
@@ -251,6 +251,13 @@ function parsePaymentMethod(raw) {
251
251
  function toChargePaymentMethod(type) {
252
252
  return type === "credit_card" ? "creditCard" : type;
253
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
+ }
254
261
  function parseChargePaymentMethodFilter(raw) {
255
262
  return toChargePaymentMethod(parsePaymentMethod(raw));
256
263
  }
@@ -523,6 +530,108 @@ function prettyCharge(charge) {
523
530
  lines.push(` refund: ${charge.refund.amount} (${charge.refund.reason ?? "no reason"})`);
524
531
  return lines.join("\n");
525
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)" : ""}`
632
+ ];
633
+ return lines.join("\n");
634
+ }
526
635
  async function doctorCommand(opts = {}) {
527
636
  const home = opts.home ?? os.homedir();
528
637
  const cwd = opts.cwd ?? process.cwd();
@@ -617,7 +726,7 @@ function prettyDoctor(r) {
617
726
  }
618
727
 
619
728
  // src/commands/installment-plans.ts
620
- async function getClient2(opts) {
729
+ async function getClient3(opts) {
621
730
  if (opts.garu) return opts.garu;
622
731
  const auth = await resolveAuth({
623
732
  ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
@@ -629,7 +738,7 @@ async function getClient2(opts) {
629
738
  });
630
739
  }
631
740
  async function installmentPlansCreateCommand(opts) {
632
- const garu = await getClient2(opts);
741
+ const garu = await getClient3(opts);
633
742
  const params = {
634
743
  productId: opts.productId,
635
744
  customerId: opts.customerId,
@@ -643,7 +752,7 @@ async function installmentPlansCreateCommand(opts) {
643
752
  return plan;
644
753
  }
645
754
  async function installmentPlansListCommand(opts) {
646
- const garu = await getClient2(opts);
755
+ const garu = await getClient3(opts);
647
756
  const params = {};
648
757
  if (opts.page !== void 0) params.page = opts.page;
649
758
  if (opts.limit !== void 0) params.limit = opts.limit;
@@ -659,19 +768,19 @@ async function installmentPlansListCommand(opts) {
659
768
  return result;
660
769
  }
661
770
  async function installmentPlansGetCommand(opts) {
662
- const garu = await getClient2(opts);
771
+ const garu = await getClient3(opts);
663
772
  const plan = await garu.installmentPlans.get(opts.uuid);
664
773
  printResult(plan, { ...opts, prettyPrint: prettyInstallmentPlanDetail });
665
774
  return plan;
666
775
  }
667
776
  async function installmentPlansReissueCommand(opts) {
668
- const garu = await getClient2(opts);
777
+ const garu = await getClient3(opts);
669
778
  const result = await garu.installmentPlans.reissueInstallment(opts.uuid, opts.number);
670
779
  printResult(result, { ...opts, prettyPrint: prettyReissueResult });
671
780
  return result;
672
781
  }
673
782
  async function installmentPlansPostponeCommand(opts) {
674
- const garu = await getClient2(opts);
783
+ const garu = await getClient3(opts);
675
784
  const params = { newDueDate: opts.newDueDate };
676
785
  const installment = await garu.installmentPlans.postponeInstallment(
677
786
  opts.uuid,
@@ -682,13 +791,13 @@ async function installmentPlansPostponeCommand(opts) {
682
791
  return installment;
683
792
  }
684
793
  async function installmentPlansMarkPaidCommand(opts) {
685
- const garu = await getClient2(opts);
794
+ const garu = await getClient3(opts);
686
795
  const installment = await garu.installmentPlans.markInstallmentPaid(opts.uuid, opts.number);
687
796
  printResult(installment, { ...opts, prettyPrint: prettyInstallment });
688
797
  return installment;
689
798
  }
690
799
  async function installmentPlansCancelCommand(opts) {
691
- const garu = await getClient2(opts);
800
+ const garu = await getClient3(opts);
692
801
  const params = {};
693
802
  if (opts.note !== void 0) params.note = opts.note;
694
803
  const plan = await garu.installmentPlans.cancel(opts.uuid, params);
@@ -696,7 +805,7 @@ async function installmentPlansCancelCommand(opts) {
696
805
  return plan;
697
806
  }
698
807
  async function installmentPlansRequestRefundCommand(opts) {
699
- const garu = await getClient2(opts);
808
+ const garu = await getClient3(opts);
700
809
  const params = {};
701
810
  if (opts.amount !== void 0) params.amount = opts.amount;
702
811
  if (opts.reason !== void 0) params.reason = opts.reason;
@@ -808,7 +917,7 @@ async function logoutCommand(opts = {}) {
808
917
  }
809
918
 
810
919
  // src/commands/products.ts
811
- async function getClient3(opts) {
920
+ async function getClient4(opts) {
812
921
  if (opts.garu) return opts.garu;
813
922
  const auth = await resolveAuth({
814
923
  ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
@@ -839,7 +948,7 @@ function buildProductBody(opts) {
839
948
  return body;
840
949
  }
841
950
  async function productsCreateCommand(opts) {
842
- const garu = await getClient3(opts);
951
+ const garu = await getClient4(opts);
843
952
  const params = { ...buildProductBody(opts), name: opts.name };
844
953
  const product = await garu.products.create(params);
845
954
  printSuccess(`Created product ${product.uuid ?? product.id}`, opts);
@@ -851,7 +960,7 @@ async function productsUpdateCommand(opts) {
851
960
  if (Object.keys(body).length === 0) {
852
961
  throw new CliError("invalid_input", "Nothing to update \u2014 pass at least one field to change.");
853
962
  }
854
- const garu = await getClient3(opts);
963
+ const garu = await getClient4(opts);
855
964
  const product = await garu.products.update(opts.id, body);
856
965
  printSuccess(`Updated product ${product.uuid ?? product.id}`, opts);
857
966
  printResult(product, { ...opts, prettyPrint: prettyProduct });
@@ -875,7 +984,7 @@ function prettyProduct(p) {
875
984
  }
876
985
 
877
986
  // src/commands/refund-requests.ts
878
- async function getClient4(opts) {
987
+ async function getClient5(opts) {
879
988
  if (opts.garu) return opts.garu;
880
989
  const auth = await resolveAuth({
881
990
  ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
@@ -887,7 +996,7 @@ async function getClient4(opts) {
887
996
  });
888
997
  }
889
998
  async function refundRequestsListCommand(opts) {
890
- const garu = await getClient4(opts);
999
+ const garu = await getClient5(opts);
891
1000
  const params = {};
892
1001
  if (opts.page !== void 0) params.page = opts.page;
893
1002
  if (opts.limit !== void 0) params.limit = opts.limit;
@@ -901,13 +1010,13 @@ async function refundRequestsListCommand(opts) {
901
1010
  return result;
902
1011
  }
903
1012
  async function refundRequestsGetCommand(opts) {
904
- const garu = await getClient4(opts);
1013
+ const garu = await getClient5(opts);
905
1014
  const request = await garu.refundRequests.get(opts.uuid);
906
1015
  printResult(request, { ...opts, prettyPrint: prettyRefundRequest2 });
907
1016
  return request;
908
1017
  }
909
1018
  async function refundRequestsConfirmCommand(opts) {
910
- const garu = await getClient4(opts);
1019
+ const garu = await getClient5(opts);
911
1020
  const params = {};
912
1021
  if (opts.note !== void 0) params.note = opts.note;
913
1022
  const request = await garu.refundRequests.confirm(opts.uuid, params);
@@ -915,7 +1024,7 @@ async function refundRequestsConfirmCommand(opts) {
915
1024
  return request;
916
1025
  }
917
1026
  async function refundRequestsRejectCommand(opts) {
918
- const garu = await getClient4(opts);
1027
+ const garu = await getClient5(opts);
919
1028
  const params = {};
920
1029
  if (opts.note !== void 0) params.note = opts.note;
921
1030
  const request = await garu.refundRequests.reject(opts.uuid, params);
@@ -941,7 +1050,7 @@ function prettyRefundRequest2(r) {
941
1050
  }
942
1051
 
943
1052
  // src/commands/scheduled-charges.ts
944
- async function getClient5(opts) {
1053
+ async function getClient6(opts) {
945
1054
  if (opts.garu) return opts.garu;
946
1055
  const auth = await resolveAuth({
947
1056
  ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
@@ -978,7 +1087,7 @@ function assertPixAutomaticRequirements(opts) {
978
1087
  }
979
1088
  async function scheduledChargesCreateCommand(opts) {
980
1089
  assertPixAutomaticRequirements(opts);
981
- const garu = await getClient5(opts);
1090
+ const garu = await getClient6(opts);
982
1091
  const params = {
983
1092
  customerId: opts.customerId,
984
1093
  amount: opts.amount,
@@ -1000,7 +1109,7 @@ async function scheduledChargesCreateCommand(opts) {
1000
1109
  return charge;
1001
1110
  }
1002
1111
  async function scheduledChargesListCommand(opts) {
1003
- const garu = await getClient5(opts);
1112
+ const garu = await getClient6(opts);
1004
1113
  const params = {};
1005
1114
  if (opts.page !== void 0) params.page = opts.page;
1006
1115
  if (opts.limit !== void 0) params.limit = opts.limit;
@@ -1017,13 +1126,13 @@ async function scheduledChargesListCommand(opts) {
1017
1126
  return result;
1018
1127
  }
1019
1128
  async function scheduledChargesGetCommand(opts) {
1020
- const garu = await getClient5(opts);
1129
+ const garu = await getClient6(opts);
1021
1130
  const detail = await garu.scheduledCharges.get(opts.id);
1022
1131
  printResult(detail, { ...opts, prettyPrint: prettyScheduledChargeDetail });
1023
1132
  return detail;
1024
1133
  }
1025
1134
  async function scheduledChargesPostponeCommand(opts) {
1026
- const garu = await getClient5(opts);
1135
+ const garu = await getClient6(opts);
1027
1136
  const params = { newDueDate: opts.newDueDate };
1028
1137
  if (opts.reason !== void 0) params.reason = opts.reason;
1029
1138
  const charge = await garu.scheduledCharges.postpone(opts.id, params);
@@ -1031,7 +1140,7 @@ async function scheduledChargesPostponeCommand(opts) {
1031
1140
  return charge;
1032
1141
  }
1033
1142
  async function scheduledChargesPauseCommand(opts) {
1034
- const garu = await getClient5(opts);
1143
+ const garu = await getClient6(opts);
1035
1144
  const params = {};
1036
1145
  if (opts.reason !== void 0) params.reason = opts.reason;
1037
1146
  const charge = await garu.scheduledCharges.pause(opts.id, params);
@@ -1039,13 +1148,13 @@ async function scheduledChargesPauseCommand(opts) {
1039
1148
  return charge;
1040
1149
  }
1041
1150
  async function scheduledChargesResumeCommand(opts) {
1042
- const garu = await getClient5(opts);
1151
+ const garu = await getClient6(opts);
1043
1152
  const charge = await garu.scheduledCharges.resume(opts.id);
1044
1153
  printResult(charge, { ...opts, prettyPrint: prettyScheduledCharge });
1045
1154
  return charge;
1046
1155
  }
1047
1156
  async function scheduledChargesMarkPaidCommand(opts) {
1048
- const garu = await getClient5(opts);
1157
+ const garu = await getClient6(opts);
1049
1158
  const params = { paymentDate: opts.paymentDate };
1050
1159
  if (opts.externalReference !== void 0) params.externalReference = opts.externalReference;
1051
1160
  if (opts.cycleNumber !== void 0) params.cycleNumber = opts.cycleNumber;
@@ -1054,7 +1163,7 @@ async function scheduledChargesMarkPaidCommand(opts) {
1054
1163
  return charge;
1055
1164
  }
1056
1165
  async function scheduledChargesCancelRecurrenceCommand(opts) {
1057
- const garu = await getClient5(opts);
1166
+ const garu = await getClient6(opts);
1058
1167
  const params = {};
1059
1168
  if (opts.reason !== void 0) params.reason = opts.reason;
1060
1169
  const charge = await garu.scheduledCharges.cancelRecurrence(opts.id, params);
@@ -1062,14 +1171,14 @@ async function scheduledChargesCancelRecurrenceCommand(opts) {
1062
1171
  return charge;
1063
1172
  }
1064
1173
  async function scheduledChargesCancelAtPeriodEndCommand(opts) {
1065
- const garu = await getClient5(opts);
1174
+ const garu = await getClient6(opts);
1066
1175
  const params = { enabled: opts.enabled };
1067
1176
  const charge = await garu.scheduledCharges.setCancelAtPeriodEnd(opts.id, params);
1068
1177
  printResult(charge, { ...opts, prettyPrint: prettyScheduledCharge });
1069
1178
  return charge;
1070
1179
  }
1071
1180
  async function scheduledChargesChangePaymentMethodCommand(opts) {
1072
- const garu = await getClient5(opts);
1181
+ const garu = await getClient6(opts);
1073
1182
  const params = {
1074
1183
  paymentMethodId: opts.paymentMethodId
1075
1184
  };
@@ -1078,13 +1187,13 @@ async function scheduledChargesChangePaymentMethodCommand(opts) {
1078
1187
  return charge;
1079
1188
  }
1080
1189
  async function scheduledChargesClearPaymentMethodCommand(opts) {
1081
- const garu = await getClient5(opts);
1190
+ const garu = await getClient6(opts);
1082
1191
  const charge = await garu.scheduledCharges.clearPaymentMethod(opts.id);
1083
1192
  printResult(charge, { ...opts, prettyPrint: prettyScheduledCharge });
1084
1193
  return charge;
1085
1194
  }
1086
1195
  async function scheduledChargesAttemptsCommand(opts) {
1087
- const garu = await getClient5(opts);
1196
+ const garu = await getClient6(opts);
1088
1197
  const params = {};
1089
1198
  if (opts.page !== void 0) params.page = opts.page;
1090
1199
  if (opts.limit !== void 0) params.limit = opts.limit;
@@ -1094,7 +1203,7 @@ async function scheduledChargesAttemptsCommand(opts) {
1094
1203
  return result;
1095
1204
  }
1096
1205
  async function scheduledChargesChargeNowCommand(opts) {
1097
- const garu = await getClient5(opts);
1206
+ const garu = await getClient6(opts);
1098
1207
  const result = await garu.scheduledCharges.chargeNow(opts.id);
1099
1208
  printResult(result, { ...opts, prettyPrint: prettyChargeNow });
1100
1209
  if (result.outcome === "failed" || result.outcome === "not_sent") {
@@ -1158,7 +1267,7 @@ function prettyChargeNow(result) {
1158
1267
  if (result.reason) lines.push(` reason: ${result.reason}`);
1159
1268
  return lines.join("\n");
1160
1269
  }
1161
- async function getClient6(opts) {
1270
+ async function getClient7(opts) {
1162
1271
  if (opts.garu) return opts.garu;
1163
1272
  const auth = await resolveAuth({
1164
1273
  ...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
@@ -1170,7 +1279,7 @@ async function getClient6(opts) {
1170
1279
  });
1171
1280
  }
1172
1281
  async function webhooksEventsListCommand(opts) {
1173
- const garu = await getClient6(opts);
1282
+ const garu = await getClient7(opts);
1174
1283
  const params = {};
1175
1284
  if (opts.page !== void 0) params.page = opts.page;
1176
1285
  if (opts.limit !== void 0) params.limit = opts.limit;
@@ -1182,21 +1291,21 @@ async function webhooksEventsListCommand(opts) {
1182
1291
  return result;
1183
1292
  }
1184
1293
  async function webhooksEventsGetCommand(opts) {
1185
- const garu = await getClient6(opts);
1186
- const event = await garu.webhookEvents.get(opts.id);
1294
+ const garu = await getClient7(opts);
1295
+ const event = await garu.webhookEvents.get(opts.uuid);
1187
1296
  printResult(event, { ...opts, prettyPrint: prettyWebhookEvent });
1188
1297
  return event;
1189
1298
  }
1190
1299
  async function webhooksEventsRetryCommand(opts) {
1191
- const garu = await getClient6(opts);
1192
- const event = await garu.webhookEvents.retry(opts.id);
1300
+ const garu = await getClient7(opts);
1301
+ const event = await garu.webhookEvents.retry(opts.uuid);
1193
1302
  printResult(event, { ...opts, prettyPrint: prettyWebhookEvent });
1194
1303
  return event;
1195
1304
  }
1196
1305
  async function webhooksEventsResendCommand(opts) {
1197
- const garu = await getClient6(opts);
1198
- const clone = await garu.webhookEvents.resend(opts.id);
1199
- printSuccess(`Resent event ${opts.id} \u2192 new event ${clone.id}`, opts);
1306
+ const garu = await getClient7(opts);
1307
+ const clone = await garu.webhookEvents.resend(opts.uuid);
1308
+ printSuccess(`Resent event ${opts.uuid} \u2192 new event ${clone.uuid}`, opts);
1200
1309
  printResult(clone, { ...opts, prettyPrint: prettyWebhookEvent });
1201
1310
  return clone;
1202
1311
  }
@@ -1207,18 +1316,16 @@ function statusBadge(status) {
1207
1316
  return pc__default.default.yellow(padded);
1208
1317
  }
1209
1318
  function prettyWebhookEventList(list) {
1210
- if (list.data.length === 0) {
1211
- return `No webhook events found (page ${list.meta.page}/${list.meta.totalPages || 1})`;
1212
- }
1213
- const header = `Webhook events (page ${list.meta.page}/${list.meta.totalPages || "?"}, ${list.meta.total} total)`;
1319
+ if (list.data.length === 0) return "No webhook events found";
1320
+ const header = `Webhook events (${list.count} of ${list.totalCount} total, ${list.totalPages} page(s))`;
1214
1321
  const rows = list.data.map(
1215
- (e) => ` ${String(e.id).padStart(8)} ${statusBadge(e.status)} attempts=${String(e.attempts).padStart(2)} ${e.eventType.padEnd(38)} ${e.createdAt}`
1322
+ (e) => ` ${e.uuid} ${statusBadge(e.status)} attempts=${String(e.attempts).padStart(2)} ${e.eventType.padEnd(38)} ${e.createdAt}`
1216
1323
  );
1217
1324
  return [header, ...rows].join("\n");
1218
1325
  }
1219
1326
  function prettyWebhookEvent(event) {
1220
1327
  const lines = [
1221
- `Webhook event ${event.id}`,
1328
+ `Webhook event ${event.uuid}`,
1222
1329
  ` status: ${statusBadge(event.status)}`,
1223
1330
  ` eventType: ${event.eventType}`,
1224
1331
  ` attempts: ${event.attempts}`,
@@ -1530,31 +1637,105 @@ Recipes:
1530
1637
  }).catch((err) => printErrorAndExit(err, base));
1531
1638
  }
1532
1639
  );
1533
- events.command("get <id>").description("Fetch a single webhook event by ID").action(async (id) => {
1640
+ events.command("get <uuid>").description("Fetch a single webhook event by uuid").action(async (uuid) => {
1641
+ const base = toCommandOptions(program);
1642
+ await webhooksEventsGetCommand({ ...base, uuid }).catch(
1643
+ (err) => printErrorAndExit(err, base)
1644
+ );
1645
+ });
1646
+ events.command("retry <uuid>").description(
1647
+ "[deprecated: prefer `resend`] Re-deliver a webhook event in place (resets the original row to pending and triggers an immediate attempt; destroys the prior failure record)"
1648
+ ).action(async (uuid) => {
1649
+ const base = toCommandOptions(program);
1650
+ await webhooksEventsRetryCommand({ ...base, uuid }).catch(
1651
+ (err) => printErrorAndExit(err, base)
1652
+ );
1653
+ });
1654
+ events.command("resend <uuid>").description(
1655
+ "Re-deliver a webhook event by cloning it (audit-trail preserving: original row is untouched, clone gets a new uuid and points back via manualResendOf)"
1656
+ ).action(async (uuid) => {
1657
+ const base = toCommandOptions(program);
1658
+ await webhooksEventsResendCommand({ ...base, uuid }).catch(
1659
+ (err) => printErrorAndExit(err, base)
1660
+ );
1661
+ });
1662
+ const customers = program.command("customers").description("Manage your customer base");
1663
+ 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) => {
1664
+ const base = toCommandOptions(program);
1665
+ await customersCreateCommand({
1666
+ ...base,
1667
+ name: cmdOpts.name,
1668
+ email: cmdOpts.email,
1669
+ document: cmdOpts.document,
1670
+ phone: cmdOpts.phone,
1671
+ personType: parsePersonType(cmdOpts.personType),
1672
+ zipCode: cmdOpts.zipCode,
1673
+ street: cmdOpts.street,
1674
+ number: cmdOpts.number,
1675
+ complement: cmdOpts.complement,
1676
+ neighborhood: cmdOpts.neighborhood,
1677
+ city: cmdOpts.city,
1678
+ state: cmdOpts.state
1679
+ }).catch((err) => printErrorAndExit(err, base));
1680
+ });
1681
+ 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(
1682
+ "--status <status>",
1683
+ "'overdue' returns customers with at least one overdue scheduled charge"
1684
+ ).action(
1685
+ async (cmdOpts) => {
1686
+ const base = toCommandOptions(program);
1687
+ await customersListCommand({
1688
+ ...base,
1689
+ page: cmdOpts.page,
1690
+ limit: cmdOpts.limit,
1691
+ search: cmdOpts.search,
1692
+ status: cmdOpts.status === "overdue" ? "overdue" : void 0
1693
+ }).catch((err) => printErrorAndExit(err, base));
1694
+ }
1695
+ );
1696
+ customers.command("get <uuid>").description("Fetch a single customer by uuid").action(async (uuid) => {
1697
+ const base = toCommandOptions(program);
1698
+ await customersGetCommand({ ...base, uuid }).catch((err) => printErrorAndExit(err, base));
1699
+ });
1700
+ 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) => {
1534
1701
  const base = toCommandOptions(program);
1535
- await webhooksEventsGetCommand({
1702
+ await customersUpdateCommand({
1536
1703
  ...base,
1537
- id: parsePositiveIntId(id, "Webhook event ID")
1704
+ uuid,
1705
+ name: cmdOpts.name,
1706
+ email: cmdOpts.email,
1707
+ phone: cmdOpts.phone,
1708
+ document: cmdOpts.document,
1709
+ personType: cmdOpts.personType ? parsePersonType(cmdOpts.personType) : void 0,
1710
+ zipCode: cmdOpts.zipCode,
1711
+ street: cmdOpts.street,
1712
+ number: cmdOpts.number,
1713
+ complement: cmdOpts.complement,
1714
+ neighborhood: cmdOpts.neighborhood,
1715
+ city: cmdOpts.city,
1716
+ state: cmdOpts.state
1538
1717
  }).catch((err) => printErrorAndExit(err, base));
1539
1718
  });
1540
- events.command("retry <id>").description(
1541
- "[deprecated: prefer `resend`] Re-deliver a webhook event in place (resets the original row to pending and triggers an immediate attempt; destroys the prior failure record)"
1542
- ).action(async (id) => {
1719
+ 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) => {
1543
1720
  const base = toCommandOptions(program);
1544
- await webhooksEventsRetryCommand({
1721
+ await customersSetBillingEmailOverrideCommand({
1545
1722
  ...base,
1546
- id: parsePositiveIntId(id, "Webhook event ID")
1723
+ uuid,
1724
+ billingEmailOverride: cmdOpts.email
1547
1725
  }).catch((err) => printErrorAndExit(err, base));
1548
1726
  });
1549
- events.command("resend <id>").description(
1550
- "Re-deliver a webhook event by cloning it (audit-trail preserving: original row is untouched, clone gets a new id and points back via manualResendOf)"
1551
- ).action(async (id) => {
1727
+ customers.command("clear-billing-email <uuid>").description("Clear the billing-email override, falling back to the last-used email").action(async (uuid) => {
1552
1728
  const base = toCommandOptions(program);
1553
- await webhooksEventsResendCommand({
1729
+ await customersSetBillingEmailOverrideCommand({
1554
1730
  ...base,
1555
- id: parsePositiveIntId(id, "Webhook event ID")
1731
+ uuid,
1732
+ billingEmailOverride: null
1556
1733
  }).catch((err) => printErrorAndExit(err, base));
1557
1734
  });
1735
+ customers.command("delete <uuid>").description("Remove a customer from the current seller (unlinks your profile only)").action(async (uuid) => {
1736
+ const base = toCommandOptions(program);
1737
+ await customersDeleteCommand({ ...base, uuid }).catch((err) => printErrorAndExit(err, base));
1738
+ });
1558
1739
  const installmentPlans = program.command("installment-plans").description("Sell a product as boleto parcelado (carn\xEA) and manage its installments");
1559
1740
  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(
1560
1741
  "--customer-id <n>",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garuhq/cli",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Official command-line interface for the Garu payment gateway.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://garu.com.br",
@@ -46,7 +46,7 @@
46
46
  "prepublishOnly": "npm run check:version-sync && npm run typecheck && npm test && npm run build"
47
47
  },
48
48
  "dependencies": {
49
- "@garuhq/node": "1.1.0",
49
+ "@garuhq/node": "3.0.0",
50
50
  "@inquirer/prompts": "8.4.1",
51
51
  "commander": "12.0.0",
52
52
  "picocolors": "1.0.0",