@garuhq/cli 0.6.0 → 0.7.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 +29 -0
- package/dist/index.cjs +207 -25
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,35 @@
|
|
|
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.7.0] — 2026-05-31
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- **Pix Automático** (BACEN auto-debit recurring Pix) across the CLI.
|
|
11
|
+
- `garu scheduled-charges create --methods pix_automatic` — schedule a
|
|
12
|
+
Pix Automático recurring series. The CLI validates locally that
|
|
13
|
+
`pix_automatic` is paired with `--type=recurring` **and** a
|
|
14
|
+
`--product-id`, returning an `invalid_input` error before any network
|
|
15
|
+
round-trip if either is missing.
|
|
16
|
+
- `garu products` — a new command group wrapping the SDK's product
|
|
17
|
+
write surface:
|
|
18
|
+
- `garu products create --name <name> [...]` — create a product.
|
|
19
|
+
- `garu products update <id> [...]` — partial update by numeric id or
|
|
20
|
+
UUID; only the flags you pass are changed.
|
|
21
|
+
- Both accept `--pix-automatic` / `--no-pix-automatic` to toggle Pix
|
|
22
|
+
Automático on the product's subscription checkout, alongside
|
|
23
|
+
`--pix`, `--boleto`, `--credit-card`, `--value` (centavos),
|
|
24
|
+
`--installments`, `--subscription`, and related fields.
|
|
25
|
+
- `garu --help` now includes an end-to-end **Pix Automático recurring
|
|
26
|
+
subscription** recipe (create the product, then schedule the
|
|
27
|
+
recurring charge).
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- `@garuhq/node` SDK bumped to 0.15.0 for `pix_automatic` on scheduled
|
|
32
|
+
charges, the `pixAutomatic` product field, and the new
|
|
33
|
+
`products.create()` / `products.update()` methods.
|
|
34
|
+
|
|
6
35
|
## [0.6.0] — 2026-05-25
|
|
7
36
|
|
|
8
37
|
### Added
|
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.
|
|
18
|
+
var CLI_VERSION = "0.7.0";
|
|
19
19
|
var CliError = class extends Error {
|
|
20
20
|
code;
|
|
21
21
|
exitCode;
|
|
@@ -476,7 +476,7 @@ async function logoutCommand(opts = {}) {
|
|
|
476
476
|
return { cleared: opts.profile };
|
|
477
477
|
}
|
|
478
478
|
|
|
479
|
-
// src/commands/
|
|
479
|
+
// src/commands/products.ts
|
|
480
480
|
async function getClient2(opts) {
|
|
481
481
|
if (opts.garu) return opts.garu;
|
|
482
482
|
const auth = await resolveAuth({
|
|
@@ -488,6 +488,73 @@ async function getClient2(opts) {
|
|
|
488
488
|
...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {}
|
|
489
489
|
});
|
|
490
490
|
}
|
|
491
|
+
function buildProductBody(opts) {
|
|
492
|
+
const body = {};
|
|
493
|
+
if (opts.name !== void 0) body.name = opts.name;
|
|
494
|
+
if (opts.value !== void 0) body.value = opts.value;
|
|
495
|
+
if (opts.description !== void 0) body.description = opts.description;
|
|
496
|
+
if (opts.image !== void 0) body.image = opts.image;
|
|
497
|
+
if (opts.tags !== void 0) body.tags = opts.tags;
|
|
498
|
+
if (opts.pix !== void 0) body.pix = opts.pix;
|
|
499
|
+
if (opts.boleto !== void 0) body.boleto = opts.boleto;
|
|
500
|
+
if (opts.creditCard !== void 0) body.creditCard = opts.creditCard;
|
|
501
|
+
if (opts.pixAutomatic !== void 0) body.pixAutomatic = opts.pixAutomatic;
|
|
502
|
+
if (opts.installments !== void 0) body.installments = opts.installments;
|
|
503
|
+
if (opts.isSubscription !== void 0) body.isSubscription = opts.isSubscription;
|
|
504
|
+
if (opts.subscriptionType !== void 0) body.subscriptionType = opts.subscriptionType;
|
|
505
|
+
if (opts.unitLabel !== void 0) body.unitLabel = opts.unitLabel;
|
|
506
|
+
if (opts.returnUrl !== void 0) body.returnUrl = opts.returnUrl;
|
|
507
|
+
if (opts.returnUrlButtonText !== void 0) body.returnUrlButtonText = opts.returnUrlButtonText;
|
|
508
|
+
return body;
|
|
509
|
+
}
|
|
510
|
+
async function productsCreateCommand(opts) {
|
|
511
|
+
const garu = await getClient2(opts);
|
|
512
|
+
const params = { ...buildProductBody(opts), name: opts.name };
|
|
513
|
+
const product = await garu.products.create(params);
|
|
514
|
+
printSuccess(`Created product ${product.uuid ?? product.id}`, opts);
|
|
515
|
+
printResult(product, { ...opts, prettyPrint: prettyProduct });
|
|
516
|
+
return product;
|
|
517
|
+
}
|
|
518
|
+
async function productsUpdateCommand(opts) {
|
|
519
|
+
const body = buildProductBody(opts);
|
|
520
|
+
if (Object.keys(body).length === 0) {
|
|
521
|
+
throw new CliError("invalid_input", "Nothing to update \u2014 pass at least one field to change.");
|
|
522
|
+
}
|
|
523
|
+
const garu = await getClient2(opts);
|
|
524
|
+
const product = await garu.products.update(opts.id, body);
|
|
525
|
+
printSuccess(`Updated product ${product.uuid ?? product.id}`, opts);
|
|
526
|
+
printResult(product, { ...opts, prettyPrint: prettyProduct });
|
|
527
|
+
return product;
|
|
528
|
+
}
|
|
529
|
+
function prettyProduct(p) {
|
|
530
|
+
const methods = [
|
|
531
|
+
p.pix ? "pix" : null,
|
|
532
|
+
p.boleto ? "boleto" : null,
|
|
533
|
+
p.creditCard ? "card" : null,
|
|
534
|
+
p.pixAutomatic ? "pix_automatic" : null
|
|
535
|
+
].filter(Boolean).join(", ");
|
|
536
|
+
const lines = [
|
|
537
|
+
`Product ${p.uuid ?? p.id}`,
|
|
538
|
+
` name: ${p.name}`,
|
|
539
|
+
` value: ${p.value} (centavos)`,
|
|
540
|
+
` methods: ${methods || "(none)"}`
|
|
541
|
+
];
|
|
542
|
+
if (p.description) lines.push(` description: ${p.description}`);
|
|
543
|
+
return lines.join("\n");
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// src/commands/scheduled-charges.ts
|
|
547
|
+
async function getClient3(opts) {
|
|
548
|
+
if (opts.garu) return opts.garu;
|
|
549
|
+
const auth = await resolveAuth({
|
|
550
|
+
...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
|
|
551
|
+
...opts.profile !== void 0 ? { profile: opts.profile } : {}
|
|
552
|
+
});
|
|
553
|
+
return createGaruClient({
|
|
554
|
+
auth,
|
|
555
|
+
...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {}
|
|
556
|
+
});
|
|
557
|
+
}
|
|
491
558
|
function buildRecurrence(opts) {
|
|
492
559
|
if (opts.recurrenceInterval === void 0) return void 0;
|
|
493
560
|
const recurrence = { interval: opts.recurrenceInterval };
|
|
@@ -497,8 +564,24 @@ function buildRecurrence(opts) {
|
|
|
497
564
|
if (opts.recurrenceEndsOn !== void 0) recurrence.endsOn = opts.recurrenceEndsOn;
|
|
498
565
|
return recurrence;
|
|
499
566
|
}
|
|
567
|
+
function assertPixAutomaticRequirements(opts) {
|
|
568
|
+
if (!opts.methods.includes("pix_automatic")) return;
|
|
569
|
+
if (opts.type !== "recurring") {
|
|
570
|
+
throw new CliError(
|
|
571
|
+
"invalid_input",
|
|
572
|
+
`--methods pix_automatic requires --type=recurring (Pix Autom\xE1tico is auto-debit recurring; got '${opts.type}')`
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
if (opts.productId === void 0) {
|
|
576
|
+
throw new CliError(
|
|
577
|
+
"invalid_input",
|
|
578
|
+
"--methods pix_automatic requires --product-id (Pix Autom\xE1tico must be enabled on a product)"
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
500
582
|
async function scheduledChargesCreateCommand(opts) {
|
|
501
|
-
|
|
583
|
+
assertPixAutomaticRequirements(opts);
|
|
584
|
+
const garu = await getClient3(opts);
|
|
502
585
|
const params = {
|
|
503
586
|
customerId: opts.customerId,
|
|
504
587
|
amount: opts.amount,
|
|
@@ -520,7 +603,7 @@ async function scheduledChargesCreateCommand(opts) {
|
|
|
520
603
|
return charge;
|
|
521
604
|
}
|
|
522
605
|
async function scheduledChargesListCommand(opts) {
|
|
523
|
-
const garu = await
|
|
606
|
+
const garu = await getClient3(opts);
|
|
524
607
|
const params = {};
|
|
525
608
|
if (opts.page !== void 0) params.page = opts.page;
|
|
526
609
|
if (opts.limit !== void 0) params.limit = opts.limit;
|
|
@@ -537,13 +620,13 @@ async function scheduledChargesListCommand(opts) {
|
|
|
537
620
|
return result;
|
|
538
621
|
}
|
|
539
622
|
async function scheduledChargesGetCommand(opts) {
|
|
540
|
-
const garu = await
|
|
623
|
+
const garu = await getClient3(opts);
|
|
541
624
|
const detail = await garu.scheduledCharges.get(opts.id);
|
|
542
625
|
printResult(detail, { ...opts, prettyPrint: prettyScheduledChargeDetail });
|
|
543
626
|
return detail;
|
|
544
627
|
}
|
|
545
628
|
async function scheduledChargesPostponeCommand(opts) {
|
|
546
|
-
const garu = await
|
|
629
|
+
const garu = await getClient3(opts);
|
|
547
630
|
const params = { newDueDate: opts.newDueDate };
|
|
548
631
|
if (opts.reason !== void 0) params.reason = opts.reason;
|
|
549
632
|
const charge = await garu.scheduledCharges.postpone(opts.id, params);
|
|
@@ -551,7 +634,7 @@ async function scheduledChargesPostponeCommand(opts) {
|
|
|
551
634
|
return charge;
|
|
552
635
|
}
|
|
553
636
|
async function scheduledChargesPauseCommand(opts) {
|
|
554
|
-
const garu = await
|
|
637
|
+
const garu = await getClient3(opts);
|
|
555
638
|
const params = {};
|
|
556
639
|
if (opts.reason !== void 0) params.reason = opts.reason;
|
|
557
640
|
const charge = await garu.scheduledCharges.pause(opts.id, params);
|
|
@@ -559,13 +642,13 @@ async function scheduledChargesPauseCommand(opts) {
|
|
|
559
642
|
return charge;
|
|
560
643
|
}
|
|
561
644
|
async function scheduledChargesResumeCommand(opts) {
|
|
562
|
-
const garu = await
|
|
645
|
+
const garu = await getClient3(opts);
|
|
563
646
|
const charge = await garu.scheduledCharges.resume(opts.id);
|
|
564
647
|
printResult(charge, { ...opts, prettyPrint: prettyScheduledCharge });
|
|
565
648
|
return charge;
|
|
566
649
|
}
|
|
567
650
|
async function scheduledChargesMarkPaidCommand(opts) {
|
|
568
|
-
const garu = await
|
|
651
|
+
const garu = await getClient3(opts);
|
|
569
652
|
const params = { paymentDate: opts.paymentDate };
|
|
570
653
|
if (opts.externalReference !== void 0) params.externalReference = opts.externalReference;
|
|
571
654
|
if (opts.cycleNumber !== void 0) params.cycleNumber = opts.cycleNumber;
|
|
@@ -574,7 +657,7 @@ async function scheduledChargesMarkPaidCommand(opts) {
|
|
|
574
657
|
return charge;
|
|
575
658
|
}
|
|
576
659
|
async function scheduledChargesCancelRecurrenceCommand(opts) {
|
|
577
|
-
const garu = await
|
|
660
|
+
const garu = await getClient3(opts);
|
|
578
661
|
const params = {};
|
|
579
662
|
if (opts.reason !== void 0) params.reason = opts.reason;
|
|
580
663
|
const charge = await garu.scheduledCharges.cancelRecurrence(opts.id, params);
|
|
@@ -582,14 +665,14 @@ async function scheduledChargesCancelRecurrenceCommand(opts) {
|
|
|
582
665
|
return charge;
|
|
583
666
|
}
|
|
584
667
|
async function scheduledChargesCancelAtPeriodEndCommand(opts) {
|
|
585
|
-
const garu = await
|
|
668
|
+
const garu = await getClient3(opts);
|
|
586
669
|
const params = { enabled: opts.enabled };
|
|
587
670
|
const charge = await garu.scheduledCharges.setCancelAtPeriodEnd(opts.id, params);
|
|
588
671
|
printResult(charge, { ...opts, prettyPrint: prettyScheduledCharge });
|
|
589
672
|
return charge;
|
|
590
673
|
}
|
|
591
674
|
async function scheduledChargesChangePaymentMethodCommand(opts) {
|
|
592
|
-
const garu = await
|
|
675
|
+
const garu = await getClient3(opts);
|
|
593
676
|
const params = {
|
|
594
677
|
paymentMethodId: opts.paymentMethodId
|
|
595
678
|
};
|
|
@@ -598,13 +681,13 @@ async function scheduledChargesChangePaymentMethodCommand(opts) {
|
|
|
598
681
|
return charge;
|
|
599
682
|
}
|
|
600
683
|
async function scheduledChargesClearPaymentMethodCommand(opts) {
|
|
601
|
-
const garu = await
|
|
684
|
+
const garu = await getClient3(opts);
|
|
602
685
|
const charge = await garu.scheduledCharges.clearPaymentMethod(opts.id);
|
|
603
686
|
printResult(charge, { ...opts, prettyPrint: prettyScheduledCharge });
|
|
604
687
|
return charge;
|
|
605
688
|
}
|
|
606
689
|
async function scheduledChargesAttemptsCommand(opts) {
|
|
607
|
-
const garu = await
|
|
690
|
+
const garu = await getClient3(opts);
|
|
608
691
|
const params = {};
|
|
609
692
|
if (opts.page !== void 0) params.page = opts.page;
|
|
610
693
|
if (opts.limit !== void 0) params.limit = opts.limit;
|
|
@@ -614,7 +697,7 @@ async function scheduledChargesAttemptsCommand(opts) {
|
|
|
614
697
|
return result;
|
|
615
698
|
}
|
|
616
699
|
async function scheduledChargesChargeNowCommand(opts) {
|
|
617
|
-
const garu = await
|
|
700
|
+
const garu = await getClient3(opts);
|
|
618
701
|
const result = await garu.scheduledCharges.chargeNow(opts.id);
|
|
619
702
|
printResult(result, { ...opts, prettyPrint: prettyChargeNow });
|
|
620
703
|
if (result.outcome === "failed" || result.outcome === "not_sent") {
|
|
@@ -678,7 +761,7 @@ function prettyChargeNow(result) {
|
|
|
678
761
|
if (result.reason) lines.push(` reason: ${result.reason}`);
|
|
679
762
|
return lines.join("\n");
|
|
680
763
|
}
|
|
681
|
-
async function
|
|
764
|
+
async function getClient4(opts) {
|
|
682
765
|
if (opts.garu) return opts.garu;
|
|
683
766
|
const auth = await resolveAuth({
|
|
684
767
|
...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
|
|
@@ -690,7 +773,7 @@ async function getClient3(opts) {
|
|
|
690
773
|
});
|
|
691
774
|
}
|
|
692
775
|
async function webhooksEventsListCommand(opts) {
|
|
693
|
-
const garu = await
|
|
776
|
+
const garu = await getClient4(opts);
|
|
694
777
|
const params = {};
|
|
695
778
|
if (opts.page !== void 0) params.page = opts.page;
|
|
696
779
|
if (opts.limit !== void 0) params.limit = opts.limit;
|
|
@@ -702,19 +785,19 @@ async function webhooksEventsListCommand(opts) {
|
|
|
702
785
|
return result;
|
|
703
786
|
}
|
|
704
787
|
async function webhooksEventsGetCommand(opts) {
|
|
705
|
-
const garu = await
|
|
788
|
+
const garu = await getClient4(opts);
|
|
706
789
|
const event = await garu.webhookEvents.get(opts.id);
|
|
707
790
|
printResult(event, { ...opts, prettyPrint: prettyWebhookEvent });
|
|
708
791
|
return event;
|
|
709
792
|
}
|
|
710
793
|
async function webhooksEventsRetryCommand(opts) {
|
|
711
|
-
const garu = await
|
|
794
|
+
const garu = await getClient4(opts);
|
|
712
795
|
const event = await garu.webhookEvents.retry(opts.id);
|
|
713
796
|
printResult(event, { ...opts, prettyPrint: prettyWebhookEvent });
|
|
714
797
|
return event;
|
|
715
798
|
}
|
|
716
799
|
async function webhooksEventsResendCommand(opts) {
|
|
717
|
-
const garu = await
|
|
800
|
+
const garu = await getClient4(opts);
|
|
718
801
|
const clone = await garu.webhookEvents.resend(opts.id);
|
|
719
802
|
printSuccess(`Resent event ${opts.id} \u2192 new event ${clone.id}`, opts);
|
|
720
803
|
printResult(clone, { ...opts, prettyPrint: prettyWebhookEvent });
|
|
@@ -782,9 +865,17 @@ function parseScheduledChargeType(raw) {
|
|
|
782
865
|
if (raw === "one_time" || raw === "recurring") return raw;
|
|
783
866
|
throw new CliError("invalid_input", `--type must be 'one_time' or 'recurring' (got '${raw}')`);
|
|
784
867
|
}
|
|
785
|
-
var SCHEDULED_PAYMENT_METHODS = [
|
|
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
|
+
}
|
|
786
877
|
function parseScheduledPaymentMethods(raw) {
|
|
787
|
-
const parts = raw
|
|
878
|
+
const parts = parseCsvList(raw);
|
|
788
879
|
if (parts.length === 0) {
|
|
789
880
|
throw new CliError(
|
|
790
881
|
"invalid_input",
|
|
@@ -846,6 +937,14 @@ function parseIntInRange(raw, label, min, max) {
|
|
|
846
937
|
}
|
|
847
938
|
return n;
|
|
848
939
|
}
|
|
940
|
+
function parseNonNegativeInt(raw, label) {
|
|
941
|
+
const trimmed = raw.trim();
|
|
942
|
+
const n = Number.parseInt(trimmed, 10);
|
|
943
|
+
if (!Number.isFinite(n) || String(n) !== trimmed || n < 0) {
|
|
944
|
+
throw new CliError("invalid_input", `${label} must be a non-negative integer (got '${raw}')`);
|
|
945
|
+
}
|
|
946
|
+
return n;
|
|
947
|
+
}
|
|
849
948
|
function parseAmountBrl(raw) {
|
|
850
949
|
const n = Number(raw);
|
|
851
950
|
if (!Number.isFinite(n) || n <= 0) {
|
|
@@ -872,7 +971,28 @@ function parseMetadata(raw) {
|
|
|
872
971
|
// src/index.ts
|
|
873
972
|
function buildCli() {
|
|
874
973
|
const program = new commander.Command();
|
|
875
|
-
program.name("garu").description("Command-line interface for the Garu payment gateway.").version(CLI_VERSION, "-v, --version").addOption(new commander.Option("--api-key <key>", "Garu API key (overrides env and credentials file)")).addOption(new commander.Option("-p, --profile <name>", "credentials profile name")).addOption(new commander.Option("--json", "emit strict JSON on stdout (forced in pipes)")).addOption(new commander.Option("-q, --quiet", "suppress status output; only print results and errors")).showHelpAfterError()
|
|
974
|
+
program.name("garu").description("Command-line interface for the Garu payment gateway.").version(CLI_VERSION, "-v, --version").addOption(new commander.Option("--api-key <key>", "Garu API key (overrides env and credentials file)")).addOption(new commander.Option("-p, --profile <name>", "credentials profile name")).addOption(new commander.Option("--json", "emit strict JSON on stdout (forced in pipes)")).addOption(new commander.Option("-q, --quiet", "suppress status output; only print results and errors")).showHelpAfterError().addHelpText(
|
|
975
|
+
"after",
|
|
976
|
+
`
|
|
977
|
+
Recipes:
|
|
978
|
+
Pix Autom\xE1tico recurring subscription (end-to-end):
|
|
979
|
+
|
|
980
|
+
# 1. Create a product with Pix Autom\xE1tico enabled
|
|
981
|
+
garu products create \\
|
|
982
|
+
--name "Plano Mensal" --value 4990 \\
|
|
983
|
+
--pix --credit-card --pix-automatic \\
|
|
984
|
+
--subscription --subscription-type monthly
|
|
985
|
+
|
|
986
|
+
# 2. Schedule the recurring auto-debit charge for that product.
|
|
987
|
+
# pix_automatic requires --type=recurring and --product-id.
|
|
988
|
+
garu scheduled-charges create \\
|
|
989
|
+
--customer-id 42 --product-id 456 \\
|
|
990
|
+
--amount 49.90 --type recurring \\
|
|
991
|
+
--due-date 2026-06-15 \\
|
|
992
|
+
--methods pix_automatic \\
|
|
993
|
+
--recurrence-interval monthly
|
|
994
|
+
`
|
|
995
|
+
);
|
|
876
996
|
program.command("login").description("Save a Garu API key to the credentials file").option("--api-key <key>", "pre-supply the key instead of prompting").option("-p, --profile <name>", "profile name to store under", "default").action(async (cmdOpts) => {
|
|
877
997
|
const base = toCommandOptions(program);
|
|
878
998
|
await loginCommand({
|
|
@@ -954,9 +1074,9 @@ function buildCli() {
|
|
|
954
1074
|
"--customer-id <n>",
|
|
955
1075
|
"customer id",
|
|
956
1076
|
(v) => parsePositiveIntId(v, "--customer-id")
|
|
957
|
-
).requiredOption("--amount <brl>", "decimal BRL amount, e.g. 297.50").requiredOption("--type <type>", "one_time | recurring").requiredOption("--due-date <yyyy-mm-dd>", "first due date in S\xE3o Paulo time").requiredOption("--methods <list>", "comma-separated: pix,boleto,card").option(
|
|
1077
|
+
).requiredOption("--amount <brl>", "decimal BRL amount, e.g. 297.50").requiredOption("--type <type>", "one_time | recurring").requiredOption("--due-date <yyyy-mm-dd>", "first due date in S\xE3o Paulo time").requiredOption("--methods <list>", "comma-separated: pix,boleto,card,pix_automatic").option(
|
|
958
1078
|
"--product-id <n>",
|
|
959
|
-
"product id (required when methods includes card)",
|
|
1079
|
+
"product id (required when methods includes card or pix_automatic)",
|
|
960
1080
|
(v) => parsePositiveIntId(v, "--product-id")
|
|
961
1081
|
).option("--description <text>", "charge description").option("--recurrence-interval <interval>", "recurring cadence: weekly|monthly|yearly|\u2026").option(
|
|
962
1082
|
"--recurrence-interval-count <n>",
|
|
@@ -1163,6 +1283,68 @@ function buildCli() {
|
|
|
1163
1283
|
id: parsePositiveIntId(id, "Webhook event ID")
|
|
1164
1284
|
}).catch((err) => printErrorAndExit(err, base));
|
|
1165
1285
|
});
|
|
1286
|
+
const products = program.command("products").description("Create and update products");
|
|
1287
|
+
products.command("create").description("Create a product").requiredOption("--name <name>", "product name").option(
|
|
1288
|
+
"--value <centavos>",
|
|
1289
|
+
"price in centavos (BRL \xD7 100)",
|
|
1290
|
+
(v) => parseNonNegativeInt(v, "--value")
|
|
1291
|
+
).option("--description <text>", "product description").option("--image <url>", "HTTPS URL of the product cover image").option("--tags <list>", "comma-separated tags", parseCsvList).option("--pix", "accept PIX").option("--no-pix", "do not accept PIX").option("--boleto", "accept boleto").option("--no-boleto", "do not accept boleto").option("--credit-card", "accept credit card").option("--no-credit-card", "do not accept credit card").option("--pix-automatic", "expose Pix Autom\xE1tico on the subscription checkout").option("--no-pix-automatic", "do not expose Pix Autom\xE1tico").option(
|
|
1292
|
+
"--installments <n>",
|
|
1293
|
+
"max credit-card installments",
|
|
1294
|
+
(v) => parsePositiveIntId(v, "--installments")
|
|
1295
|
+
).option("--subscription", "mark the product as a subscription").option("--no-subscription", "mark the product as one-time").option("--subscription-type <type>", "subscription cadence, e.g. monthly").option("--unit-label <label>", "unit label shown on the checkout").option("--return-url <url>", "post-purchase redirect URL").option("--return-url-button-text <text>", "label for the return-URL button").action(async (cmdOpts) => {
|
|
1296
|
+
const base = toCommandOptions(program);
|
|
1297
|
+
await productsCreateCommand({
|
|
1298
|
+
...base,
|
|
1299
|
+
name: cmdOpts.name,
|
|
1300
|
+
value: cmdOpts.value,
|
|
1301
|
+
description: cmdOpts.description,
|
|
1302
|
+
image: cmdOpts.image,
|
|
1303
|
+
tags: cmdOpts.tags,
|
|
1304
|
+
pix: cmdOpts.pix,
|
|
1305
|
+
boleto: cmdOpts.boleto,
|
|
1306
|
+
creditCard: cmdOpts.creditCard,
|
|
1307
|
+
pixAutomatic: cmdOpts.pixAutomatic,
|
|
1308
|
+
installments: cmdOpts.installments,
|
|
1309
|
+
isSubscription: cmdOpts.subscription,
|
|
1310
|
+
subscriptionType: cmdOpts.subscriptionType,
|
|
1311
|
+
unitLabel: cmdOpts.unitLabel,
|
|
1312
|
+
returnUrl: cmdOpts.returnUrl,
|
|
1313
|
+
returnUrlButtonText: cmdOpts.returnUrlButtonText
|
|
1314
|
+
}).catch((err) => printErrorAndExit(err, base));
|
|
1315
|
+
});
|
|
1316
|
+
products.command("update <id>").description(
|
|
1317
|
+
"Update a product (partial \u2014 only the flags you pass change). <id> is the numeric id or UUID"
|
|
1318
|
+
).option("--name <name>", "product name").option(
|
|
1319
|
+
"--value <centavos>",
|
|
1320
|
+
"price in centavos (BRL \xD7 100)",
|
|
1321
|
+
(v) => parseNonNegativeInt(v, "--value")
|
|
1322
|
+
).option("--description <text>", "product description").option("--image <url>", "HTTPS URL of the product cover image").option("--tags <list>", "comma-separated tags", parseCsvList).option("--pix", "accept PIX").option("--no-pix", "do not accept PIX").option("--boleto", "accept boleto").option("--no-boleto", "do not accept boleto").option("--credit-card", "accept credit card").option("--no-credit-card", "do not accept credit card").option("--pix-automatic", "expose Pix Autom\xE1tico on the subscription checkout").option("--no-pix-automatic", "do not expose Pix Autom\xE1tico").option(
|
|
1323
|
+
"--installments <n>",
|
|
1324
|
+
"max credit-card installments",
|
|
1325
|
+
(v) => parsePositiveIntId(v, "--installments")
|
|
1326
|
+
).option("--subscription", "mark the product as a subscription").option("--no-subscription", "mark the product as one-time").option("--subscription-type <type>", "subscription cadence, e.g. monthly").option("--unit-label <label>", "unit label shown on the checkout").option("--return-url <url>", "post-purchase redirect URL").option("--return-url-button-text <text>", "label for the return-URL button").action(async (id, cmdOpts) => {
|
|
1327
|
+
const base = toCommandOptions(program);
|
|
1328
|
+
await productsUpdateCommand({
|
|
1329
|
+
...base,
|
|
1330
|
+
id,
|
|
1331
|
+
name: cmdOpts.name,
|
|
1332
|
+
value: cmdOpts.value,
|
|
1333
|
+
description: cmdOpts.description,
|
|
1334
|
+
image: cmdOpts.image,
|
|
1335
|
+
tags: cmdOpts.tags,
|
|
1336
|
+
pix: cmdOpts.pix,
|
|
1337
|
+
boleto: cmdOpts.boleto,
|
|
1338
|
+
creditCard: cmdOpts.creditCard,
|
|
1339
|
+
pixAutomatic: cmdOpts.pixAutomatic,
|
|
1340
|
+
installments: cmdOpts.installments,
|
|
1341
|
+
isSubscription: cmdOpts.subscription,
|
|
1342
|
+
subscriptionType: cmdOpts.subscriptionType,
|
|
1343
|
+
unitLabel: cmdOpts.unitLabel,
|
|
1344
|
+
returnUrl: cmdOpts.returnUrl,
|
|
1345
|
+
returnUrlButtonText: cmdOpts.returnUrlButtonText
|
|
1346
|
+
}).catch((err) => printErrorAndExit(err, base));
|
|
1347
|
+
});
|
|
1166
1348
|
program.command("doctor").description("Environment diagnostic").action(async () => {
|
|
1167
1349
|
const base = toCommandOptions(program);
|
|
1168
1350
|
await doctorCommand(base).catch((err) => printErrorAndExit(err, base));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@garuhq/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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": "0.
|
|
49
|
+
"@garuhq/node": "0.15.0",
|
|
50
50
|
"@inquirer/prompts": "8.4.1",
|
|
51
51
|
"commander": "12.0.0",
|
|
52
52
|
"picocolors": "1.0.0",
|