@garuhq/cli 0.1.1 → 0.1.2
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 +57 -0
- package/dist/index.cjs +106 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,63 @@
|
|
|
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.1.2] — 2026-04-08
|
|
7
|
+
|
|
8
|
+
Post-review batch — addresses all findings from an internal code review.
|
|
9
|
+
|
|
10
|
+
### Security
|
|
11
|
+
|
|
12
|
+
- **`install.sh` now verifies binaries against `SHA256SUMS.txt`.** The installer
|
|
13
|
+
downloads the checksum file from the same release, grep's the expected hash
|
|
14
|
+
for the target asset, and fails the install if the binary has been tampered
|
|
15
|
+
with. Supports both `sha256sum` (Linux) and `shasum -a 256` (macOS).
|
|
16
|
+
- **Credentials file path now uses `node:path`'s `dirname`** instead of a
|
|
17
|
+
`lastIndexOf('/')` slice, fixing `garu login` on Windows (`npm i -g @garuhq/cli`).
|
|
18
|
+
- Upgrade dev dependencies to clear `npm audit` findings:
|
|
19
|
+
- `vitest` 1.5.0 → 4.1.3 (closes critical vitest RCE advisory)
|
|
20
|
+
- `tsup` 8.0.2 → 8.5.1, `tsx` 4.7.2 → 4.21.0
|
|
21
|
+
- `@inquirer/prompts` 5.0.2 → 8.4.1 (clears the `tmp` symlink chain)
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **`garu login` no longer claims to validate the API key.** The prompt now
|
|
26
|
+
says "Checking connectivity to Garu..." instead of "Validating key with
|
|
27
|
+
Garu..." — a key that passes the `sk_(live|test)_...` regex will still be
|
|
28
|
+
saved even if the backend would reject it. A real authenticated probe lands
|
|
29
|
+
once the backend exposes `GET /api/v1/me`.
|
|
30
|
+
- **`garu logout --profile <name>` now deletes the credentials file** when the
|
|
31
|
+
removed profile was the last one, instead of leaving an orphaned
|
|
32
|
+
`activeProfile` pointing at nothing.
|
|
33
|
+
- **SDK errors are now classified via `instanceof GaruError`** instead of
|
|
34
|
+
`.name.startsWith('Garu')` duck-typing.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- Removed non-null assertions on credit-card fields in `charges create`;
|
|
39
|
+
replaced with a type-guard assertion so the TypeScript narrowing is
|
|
40
|
+
compile-time enforced.
|
|
41
|
+
- Collapsed `globalsToOutput` + `globalFlagsToCommandOptions` into one
|
|
42
|
+
`toCommandOptions` helper. `src/index.ts` is ~25 lines shorter.
|
|
43
|
+
- Removed unused `cliUserAgent()` dead code from `src/lib/client.ts`.
|
|
44
|
+
|
|
45
|
+
### Infrastructure
|
|
46
|
+
|
|
47
|
+
- **All third-party GitHub Actions are now SHA-pinned** in both `ci.yml` and
|
|
48
|
+
`release.yml`: `actions/checkout`, `actions/setup-node`,
|
|
49
|
+
`actions/upload-artifact`, `actions/download-artifact`, `oven-sh/setup-bun`,
|
|
50
|
+
`ludeeus/action-shellcheck`. Human-readable version as trailing comment.
|
|
51
|
+
- **Release workflow asserts `package.json .version == $TAG_NAME`** before
|
|
52
|
+
publishing to npm. Mismatched tags fail fast with a clear error instead of
|
|
53
|
+
hitting `npm publish` with a stale version.
|
|
54
|
+
|
|
55
|
+
### Tests
|
|
56
|
+
|
|
57
|
+
- Added 6 new tests for `logoutCommand` covering: removing the last profile
|
|
58
|
+
deletes the file, removing a non-active profile preserves the active one,
|
|
59
|
+
removing the active profile elects a remaining profile, and the not-found
|
|
60
|
+
error path.
|
|
61
|
+
- Total: 42 tests across 6 files (previously 36 across 5).
|
|
62
|
+
|
|
6
63
|
## [0.1.1] — 2026-04-08
|
|
7
64
|
|
|
8
65
|
### Fixed
|
package/dist/index.cjs
CHANGED
|
@@ -4,10 +4,9 @@ var commander = require('commander');
|
|
|
4
4
|
var os = require('os');
|
|
5
5
|
var path = require('path');
|
|
6
6
|
var promises = require('fs/promises');
|
|
7
|
-
var pc = require('picocolors');
|
|
8
7
|
var node = require('@garuhq/node');
|
|
8
|
+
var pc = require('picocolors');
|
|
9
9
|
var fs = require('fs');
|
|
10
|
-
var prompts = require('@inquirer/prompts');
|
|
11
10
|
|
|
12
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
12
|
|
|
@@ -16,9 +15,7 @@ var pc__default = /*#__PURE__*/_interopDefault(pc);
|
|
|
16
15
|
// src/index.ts
|
|
17
16
|
|
|
18
17
|
// src/version.ts
|
|
19
|
-
var CLI_VERSION = "0.1.
|
|
20
|
-
|
|
21
|
-
// src/lib/errors.ts
|
|
18
|
+
var CLI_VERSION = "0.1.2";
|
|
22
19
|
var CliError = class extends Error {
|
|
23
20
|
code;
|
|
24
21
|
exitCode;
|
|
@@ -30,16 +27,11 @@ var CliError = class extends Error {
|
|
|
30
27
|
}
|
|
31
28
|
};
|
|
32
29
|
function toCliError(err) {
|
|
33
|
-
if (err instanceof CliError)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const e = err;
|
|
37
|
-
if (typeof e.name === "string" && e.name.startsWith("Garu")) {
|
|
38
|
-
return new CliError(mapSdkCodeToCliCode(e.code), e.message ?? "Request failed", 1);
|
|
39
|
-
}
|
|
30
|
+
if (err instanceof CliError) return err;
|
|
31
|
+
if (err instanceof node.GaruError) {
|
|
32
|
+
return new CliError(mapSdkCodeToCliCode(err.code), err.message, 1);
|
|
40
33
|
}
|
|
41
|
-
if (err instanceof Error)
|
|
42
|
-
return new CliError("unknown_error", err.message);
|
|
34
|
+
if (err instanceof Error) return new CliError("unknown_error", err.message);
|
|
43
35
|
return new CliError("unknown_error", String(err));
|
|
44
36
|
}
|
|
45
37
|
function mapSdkCodeToCliCode(sdkCode) {
|
|
@@ -71,8 +63,7 @@ var DEFAULT_FILE = {
|
|
|
71
63
|
profiles: {}
|
|
72
64
|
};
|
|
73
65
|
function credentialsPath(env = process.env) {
|
|
74
|
-
if (env.GARU_CREDENTIALS_PATH)
|
|
75
|
-
return env.GARU_CREDENTIALS_PATH;
|
|
66
|
+
if (env.GARU_CREDENTIALS_PATH) return env.GARU_CREDENTIALS_PATH;
|
|
76
67
|
const base = env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
|
|
77
68
|
return path.join(base, "garu", "credentials.json");
|
|
78
69
|
}
|
|
@@ -93,18 +84,16 @@ async function loadCredentials(env = process.env) {
|
|
|
93
84
|
}
|
|
94
85
|
}
|
|
95
86
|
async function saveCredentials(file, env = process.env) {
|
|
96
|
-
const path = credentialsPath(env);
|
|
97
|
-
|
|
98
|
-
await promises.
|
|
99
|
-
await promises.writeFile(path, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
|
|
87
|
+
const path$1 = credentialsPath(env);
|
|
88
|
+
await promises.mkdir(path.dirname(path$1), { recursive: true, mode: 448 });
|
|
89
|
+
await promises.writeFile(path$1, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
|
|
100
90
|
}
|
|
101
91
|
async function deleteCredentials(env = process.env) {
|
|
102
92
|
const path = credentialsPath(env);
|
|
103
93
|
try {
|
|
104
94
|
await promises.rm(path);
|
|
105
95
|
} catch (err) {
|
|
106
|
-
if (err.code !== "ENOENT")
|
|
107
|
-
throw err;
|
|
96
|
+
if (err.code !== "ENOENT") throw err;
|
|
108
97
|
}
|
|
109
98
|
}
|
|
110
99
|
function upsertProfile(file, name, profile) {
|
|
@@ -123,8 +112,7 @@ async function credentialsFileMode(env = process.env) {
|
|
|
123
112
|
}
|
|
124
113
|
}
|
|
125
114
|
function normalize(raw) {
|
|
126
|
-
if (!raw || typeof raw !== "object")
|
|
127
|
-
return { ...DEFAULT_FILE };
|
|
115
|
+
if (!raw || typeof raw !== "object") return { ...DEFAULT_FILE };
|
|
128
116
|
const obj = raw;
|
|
129
117
|
return {
|
|
130
118
|
version: 1,
|
|
@@ -133,8 +121,7 @@ function normalize(raw) {
|
|
|
133
121
|
};
|
|
134
122
|
}
|
|
135
123
|
function resolveMode(opts = {}, stdout = process.stdout) {
|
|
136
|
-
if (opts.mode)
|
|
137
|
-
return opts.mode;
|
|
124
|
+
if (opts.mode) return opts.mode;
|
|
138
125
|
return stdout.isTTY ? "pretty" : "json";
|
|
139
126
|
}
|
|
140
127
|
function printResult(value, opts = {}) {
|
|
@@ -153,18 +140,14 @@ function printResult(value, opts = {}) {
|
|
|
153
140
|
`);
|
|
154
141
|
}
|
|
155
142
|
function printStatus(message, opts = {}) {
|
|
156
|
-
if (opts.quiet)
|
|
157
|
-
|
|
158
|
-
if (resolveMode(opts) === "json")
|
|
159
|
-
return;
|
|
143
|
+
if (opts.quiet) return;
|
|
144
|
+
if (resolveMode(opts) === "json") return;
|
|
160
145
|
process.stderr.write(`${pc__default.default.dim("\u2192")} ${message}
|
|
161
146
|
`);
|
|
162
147
|
}
|
|
163
148
|
function printSuccess(message, opts = {}) {
|
|
164
|
-
if (opts.quiet)
|
|
165
|
-
|
|
166
|
-
if (resolveMode(opts) === "json")
|
|
167
|
-
return;
|
|
149
|
+
if (opts.quiet) return;
|
|
150
|
+
if (resolveMode(opts) === "json") return;
|
|
168
151
|
process.stderr.write(`${pc__default.default.green("\u2713")} ${message}
|
|
169
152
|
`);
|
|
170
153
|
}
|
|
@@ -223,8 +206,7 @@ async function resolveAuthOptional(opts = {}) {
|
|
|
223
206
|
try {
|
|
224
207
|
return await resolveAuth(opts);
|
|
225
208
|
} catch (err) {
|
|
226
|
-
if (err instanceof CliError && err.code === "auth_error")
|
|
227
|
-
return null;
|
|
209
|
+
if (err instanceof CliError && err.code === "auth_error") return null;
|
|
228
210
|
throw err;
|
|
229
211
|
}
|
|
230
212
|
}
|
|
@@ -237,8 +219,7 @@ function createGaruClient(opts) {
|
|
|
237
219
|
|
|
238
220
|
// src/commands/charges.ts
|
|
239
221
|
async function getClient(opts) {
|
|
240
|
-
if (opts.garu)
|
|
241
|
-
return opts.garu;
|
|
222
|
+
if (opts.garu) return opts.garu;
|
|
242
223
|
const auth = await resolveAuth({
|
|
243
224
|
...opts.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
|
|
244
225
|
...opts.profile !== void 0 ? { profile: opts.profile } : {}
|
|
@@ -248,8 +229,17 @@ async function getClient(opts) {
|
|
|
248
229
|
...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {}
|
|
249
230
|
});
|
|
250
231
|
}
|
|
232
|
+
function assertCardFieldsPresent(opts) {
|
|
233
|
+
const missing = [];
|
|
234
|
+
if (!opts.cardNumber) missing.push("--card-number");
|
|
235
|
+
if (!opts.cardCvv) missing.push("--card-cvv");
|
|
236
|
+
if (!opts.cardExpiration) missing.push("--card-expiration");
|
|
237
|
+
if (!opts.cardHolder) missing.push("--card-holder");
|
|
238
|
+
if (missing.length) {
|
|
239
|
+
throw new CliError("invalid_input", `Credit-card charges require: ${missing.join(", ")}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
251
242
|
async function chargesCreateCommand(opts) {
|
|
252
|
-
validateCreate(opts);
|
|
253
243
|
const garu = await getClient(opts);
|
|
254
244
|
const customer = {
|
|
255
245
|
name: opts.customerName,
|
|
@@ -257,13 +247,18 @@ async function chargesCreateCommand(opts) {
|
|
|
257
247
|
document: opts.customerDocument,
|
|
258
248
|
phone: opts.customerPhone
|
|
259
249
|
};
|
|
260
|
-
const
|
|
250
|
+
const base = {
|
|
261
251
|
productId: opts.productId,
|
|
262
252
|
paymentMethod: opts.type,
|
|
263
253
|
customer,
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
254
|
+
additionalInfo: opts.additionalInfo,
|
|
255
|
+
idempotencyKey: opts.idempotencyKey
|
|
256
|
+
};
|
|
257
|
+
let charge;
|
|
258
|
+
if (opts.type === "credit_card") {
|
|
259
|
+
assertCardFieldsPresent(opts);
|
|
260
|
+
charge = await garu.charges.create({
|
|
261
|
+
...base,
|
|
267
262
|
cardInfo: {
|
|
268
263
|
cardNumber: opts.cardNumber,
|
|
269
264
|
cvv: opts.cardCvv,
|
|
@@ -271,8 +266,10 @@ async function chargesCreateCommand(opts) {
|
|
|
271
266
|
holderName: opts.cardHolder,
|
|
272
267
|
installments: opts.installments ?? 1
|
|
273
268
|
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
269
|
+
});
|
|
270
|
+
} else {
|
|
271
|
+
charge = await garu.charges.create(base);
|
|
272
|
+
}
|
|
276
273
|
printResult(charge, { ...opts, prettyPrint: prettyCharge });
|
|
277
274
|
return charge;
|
|
278
275
|
}
|
|
@@ -285,32 +282,13 @@ async function chargesGetCommand(opts) {
|
|
|
285
282
|
async function chargesRefundCommand(opts) {
|
|
286
283
|
const garu = await getClient(opts);
|
|
287
284
|
const params = {};
|
|
288
|
-
if (opts.amount !== void 0)
|
|
289
|
-
|
|
290
|
-
if (opts.
|
|
291
|
-
params.reason = opts.reason;
|
|
292
|
-
if (opts.idempotencyKey !== void 0)
|
|
293
|
-
params.idempotencyKey = opts.idempotencyKey;
|
|
285
|
+
if (opts.amount !== void 0) params.amount = opts.amount;
|
|
286
|
+
if (opts.reason !== void 0) params.reason = opts.reason;
|
|
287
|
+
if (opts.idempotencyKey !== void 0) params.idempotencyKey = opts.idempotencyKey;
|
|
294
288
|
const charge = await garu.charges.refund(opts.id, params);
|
|
295
289
|
printResult(charge, { ...opts, prettyPrint: prettyCharge });
|
|
296
290
|
return charge;
|
|
297
291
|
}
|
|
298
|
-
function validateCreate(opts) {
|
|
299
|
-
if (opts.type === "credit_card") {
|
|
300
|
-
const missing = [];
|
|
301
|
-
if (!opts.cardNumber)
|
|
302
|
-
missing.push("--card-number");
|
|
303
|
-
if (!opts.cardCvv)
|
|
304
|
-
missing.push("--card-cvv");
|
|
305
|
-
if (!opts.cardExpiration)
|
|
306
|
-
missing.push("--card-expiration");
|
|
307
|
-
if (!opts.cardHolder)
|
|
308
|
-
missing.push("--card-holder");
|
|
309
|
-
if (missing.length) {
|
|
310
|
-
throw new CliError("invalid_input", `Credit-card charges require: ${missing.join(", ")}`);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
292
|
function prettyCharge(charge) {
|
|
315
293
|
const lines = [
|
|
316
294
|
`Charge ${charge.id}`,
|
|
@@ -319,8 +297,7 @@ function prettyCharge(charge) {
|
|
|
319
297
|
` method: ${charge.paymentMethodId}`,
|
|
320
298
|
` date: ${charge.date}`
|
|
321
299
|
];
|
|
322
|
-
if (charge.deadline)
|
|
323
|
-
lines.push(` deadline: ${charge.deadline}`);
|
|
300
|
+
if (charge.deadline) lines.push(` deadline: ${charge.deadline}`);
|
|
324
301
|
return lines.join("\n");
|
|
325
302
|
}
|
|
326
303
|
async function doctorCommand(opts = {}) {
|
|
@@ -349,8 +326,7 @@ async function reportCredentials(opts) {
|
|
|
349
326
|
return { path, source: "none" };
|
|
350
327
|
}
|
|
351
328
|
const out = { path, source: resolved.source };
|
|
352
|
-
if (resolved.profile)
|
|
353
|
-
out.profile = resolved.profile;
|
|
329
|
+
if (resolved.profile) out.profile = resolved.profile;
|
|
354
330
|
if (resolved.source === "file") {
|
|
355
331
|
const mode = await credentialsFileMode();
|
|
356
332
|
if (mode !== null) {
|
|
@@ -418,20 +394,19 @@ function prettyDoctor(r) {
|
|
|
418
394
|
}
|
|
419
395
|
async function loginCommand(opts = {}) {
|
|
420
396
|
const profile = opts.profile ?? "default";
|
|
421
|
-
const apiKey = opts.apiKey ?? await prompts.
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
397
|
+
const apiKey = opts.apiKey ?? await import('@inquirer/prompts').then(
|
|
398
|
+
({ password }) => password({
|
|
399
|
+
message: "Paste your Garu API key (sk_live_... or sk_test_...)",
|
|
400
|
+
mask: "*"
|
|
401
|
+
})
|
|
402
|
+
).catch(() => {
|
|
425
403
|
throw new CliError("user_cancelled", "Login cancelled.");
|
|
426
404
|
});
|
|
427
405
|
if (!apiKey || !/^sk_(live|test)_[A-Za-z0-9_]+$/.test(apiKey)) {
|
|
428
406
|
throw new CliError("invalid_input", "API key must look like `sk_live_...` or `sk_test_...`.");
|
|
429
407
|
}
|
|
430
|
-
printStatus("
|
|
431
|
-
const garu = new node.Garu({
|
|
432
|
-
apiKey,
|
|
433
|
-
...opts.baseUrl !== void 0 ? { baseUrl: opts.baseUrl } : {}
|
|
434
|
-
});
|
|
408
|
+
printStatus("Checking connectivity to Garu...", opts);
|
|
409
|
+
const garu = new node.Garu({ apiKey, baseUrl: opts.baseUrl });
|
|
435
410
|
await garu.meta.get();
|
|
436
411
|
const file = await loadCredentials();
|
|
437
412
|
const updated = upsertProfile(file, profile, { apiKey });
|
|
@@ -452,7 +427,12 @@ async function logoutCommand(opts = {}) {
|
|
|
452
427
|
throw new CliError("not_found", `Profile '${opts.profile}' not found.`);
|
|
453
428
|
}
|
|
454
429
|
const { [opts.profile]: _removed, ...rest } = file.profiles;
|
|
455
|
-
|
|
430
|
+
if (Object.keys(rest).length === 0) {
|
|
431
|
+
await deleteCredentials();
|
|
432
|
+
printSuccess(`Profile '${opts.profile}' removed (credentials file deleted).`, opts);
|
|
433
|
+
return { cleared: opts.profile };
|
|
434
|
+
}
|
|
435
|
+
const nextActive = file.activeProfile === opts.profile ? Object.keys(rest)[0] : file.activeProfile;
|
|
456
436
|
await saveCredentials({ ...file, activeProfile: nextActive, profiles: rest });
|
|
457
437
|
printSuccess(`Profile '${opts.profile}' removed.`, opts);
|
|
458
438
|
return { cleared: opts.profile };
|
|
@@ -461,27 +441,29 @@ async function logoutCommand(opts = {}) {
|
|
|
461
441
|
// src/index.ts
|
|
462
442
|
function buildCli() {
|
|
463
443
|
const program = new commander.Command();
|
|
464
|
-
program.name("garu").description("Command-line interface for the Garu payment gateway.").version(
|
|
444
|
+
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();
|
|
465
445
|
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) => {
|
|
466
|
-
const
|
|
446
|
+
const base = toCommandOptions(program);
|
|
467
447
|
await loginCommand({
|
|
468
|
-
|
|
448
|
+
apiKey: cmdOpts.apiKey,
|
|
469
449
|
profile: cmdOpts.profile,
|
|
470
|
-
|
|
471
|
-
|
|
450
|
+
mode: base.mode,
|
|
451
|
+
quiet: base.quiet
|
|
452
|
+
}).catch((err) => printErrorAndExit(err, base));
|
|
472
453
|
});
|
|
473
454
|
program.command("logout").description("Remove saved credentials").option("-p, --profile <name>", "only remove this profile instead of the whole file").action(async (cmdOpts) => {
|
|
474
|
-
const
|
|
455
|
+
const base = toCommandOptions(program);
|
|
475
456
|
await logoutCommand({
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
457
|
+
profile: cmdOpts.profile,
|
|
458
|
+
mode: base.mode,
|
|
459
|
+
quiet: base.quiet
|
|
460
|
+
}).catch((err) => printErrorAndExit(err, base));
|
|
479
461
|
});
|
|
480
462
|
const auth = program.command("auth").description("Manage credentials profiles");
|
|
481
463
|
auth.command("switch <profile>").description("Set the active credentials profile").action(async (profile) => {
|
|
482
|
-
const
|
|
483
|
-
await authSwitchCommand({ profile,
|
|
484
|
-
(err) => printErrorAndExit(err,
|
|
464
|
+
const base = toCommandOptions(program);
|
|
465
|
+
await authSwitchCommand({ profile, mode: base.mode, quiet: base.quiet }).catch(
|
|
466
|
+
(err) => printErrorAndExit(err, base)
|
|
485
467
|
);
|
|
486
468
|
});
|
|
487
469
|
const charges = program.command("charges").description("Create, fetch, and refund charges");
|
|
@@ -489,76 +471,57 @@ function buildCli() {
|
|
|
489
471
|
"--customer-document <document>",
|
|
490
472
|
"CPF (11 digits) or CNPJ (14 digits), digits only"
|
|
491
473
|
).requiredOption("--customer-phone <phone>", "customer phone with area code, digits only").option("--card-number <number>", "credit-card number (required for credit_card)").option("--card-cvv <cvv>", "credit-card CVV").option("--card-expiration <yyyy-mm>", "credit-card expiration date (YYYY-MM)").option("--card-holder <name>", "credit-card holder name").option("--installments <n>", "number of installments (1-12)", (v) => parseInt(v, 10), 1).option("--additional-info <text>", "free-form metadata attached to the charge").option("--idempotency-key <key>", "idempotency key (auto-generated if omitted)").action(async (cmdOpts) => {
|
|
492
|
-
const
|
|
493
|
-
const type = parsePaymentMethod(cmdOpts.type);
|
|
474
|
+
const base = toCommandOptions(program);
|
|
494
475
|
await chargesCreateCommand({
|
|
495
|
-
|
|
476
|
+
...base,
|
|
477
|
+
type: parsePaymentMethod(cmdOpts.type),
|
|
496
478
|
productId: cmdOpts.productId,
|
|
497
479
|
customerName: cmdOpts.customerName,
|
|
498
480
|
customerEmail: cmdOpts.customerEmail,
|
|
499
481
|
customerDocument: cmdOpts.customerDocument,
|
|
500
482
|
customerPhone: cmdOpts.customerPhone,
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
}).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));
|
|
483
|
+
cardNumber: cmdOpts.cardNumber,
|
|
484
|
+
cardCvv: cmdOpts.cardCvv,
|
|
485
|
+
cardExpiration: cmdOpts.cardExpiration,
|
|
486
|
+
cardHolder: cmdOpts.cardHolder,
|
|
487
|
+
installments: cmdOpts.installments,
|
|
488
|
+
additionalInfo: cmdOpts.additionalInfo,
|
|
489
|
+
idempotencyKey: cmdOpts.idempotencyKey
|
|
490
|
+
}).catch((err) => printErrorAndExit(err, base));
|
|
510
491
|
});
|
|
511
492
|
charges.command("get <id>").description("Fetch a single charge by ID").action(async (id) => {
|
|
512
|
-
const
|
|
513
|
-
await chargesGetCommand({
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
}).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));
|
|
493
|
+
const base = toCommandOptions(program);
|
|
494
|
+
await chargesGetCommand({ ...base, id: parseId(id) }).catch(
|
|
495
|
+
(err) => printErrorAndExit(err, base)
|
|
496
|
+
);
|
|
517
497
|
});
|
|
518
498
|
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) => {
|
|
519
|
-
const
|
|
499
|
+
const base = toCommandOptions(program);
|
|
520
500
|
await chargesRefundCommand({
|
|
501
|
+
...base,
|
|
521
502
|
id: parseId(id),
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
}).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));
|
|
503
|
+
amount: cmdOpts.amount,
|
|
504
|
+
reason: cmdOpts.reason,
|
|
505
|
+
idempotencyKey: cmdOpts.idempotencyKey
|
|
506
|
+
}).catch((err) => printErrorAndExit(err, base));
|
|
527
507
|
});
|
|
528
508
|
program.command("doctor").description("Environment diagnostic").action(async () => {
|
|
529
|
-
const
|
|
530
|
-
await doctorCommand(
|
|
531
|
-
...globalFlagsToCommandOptions(globals)
|
|
532
|
-
}).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));
|
|
509
|
+
const base = toCommandOptions(program);
|
|
510
|
+
await doctorCommand(base).catch((err) => printErrorAndExit(err, base));
|
|
533
511
|
});
|
|
534
512
|
return program;
|
|
535
513
|
}
|
|
536
|
-
function
|
|
537
|
-
|
|
538
|
-
}
|
|
539
|
-
function globalsToOutput(globals) {
|
|
514
|
+
function toCommandOptions(program) {
|
|
515
|
+
const g = program.opts();
|
|
540
516
|
const out = {};
|
|
541
|
-
if (
|
|
542
|
-
|
|
543
|
-
if (
|
|
544
|
-
|
|
545
|
-
return out;
|
|
546
|
-
}
|
|
547
|
-
function globalFlagsToCommandOptions(globals) {
|
|
548
|
-
const out = {};
|
|
549
|
-
if (globals.apiKey)
|
|
550
|
-
out.apiKey = globals.apiKey;
|
|
551
|
-
if (globals.profile)
|
|
552
|
-
out.profile = globals.profile;
|
|
553
|
-
if (globals.json)
|
|
554
|
-
out.mode = "json";
|
|
555
|
-
if (globals.quiet)
|
|
556
|
-
out.quiet = true;
|
|
517
|
+
if (g.apiKey) out.apiKey = g.apiKey;
|
|
518
|
+
if (g.profile) out.profile = g.profile;
|
|
519
|
+
if (g.json) out.mode = "json";
|
|
520
|
+
if (g.quiet) out.quiet = true;
|
|
557
521
|
return out;
|
|
558
522
|
}
|
|
559
523
|
function parsePaymentMethod(raw) {
|
|
560
|
-
if (raw === "pix" || raw === "credit_card" || raw === "boleto")
|
|
561
|
-
return raw;
|
|
524
|
+
if (raw === "pix" || raw === "credit_card" || raw === "boleto") return raw;
|
|
562
525
|
throw new CliError(
|
|
563
526
|
"invalid_input",
|
|
564
527
|
`--type must be 'pix', 'credit_card', or 'boleto' (got '${raw}')`
|
|
@@ -571,9 +534,6 @@ function parseId(raw) {
|
|
|
571
534
|
}
|
|
572
535
|
return id;
|
|
573
536
|
}
|
|
574
|
-
function getVersion() {
|
|
575
|
-
return CLI_VERSION;
|
|
576
|
-
}
|
|
577
537
|
async function main(argv = process.argv) {
|
|
578
538
|
const program = buildCli();
|
|
579
539
|
await program.parseAsync(argv);
|
|
@@ -582,5 +542,5 @@ main().catch((err) => printErrorAndExit(err));
|
|
|
582
542
|
|
|
583
543
|
exports.buildCli = buildCli;
|
|
584
544
|
exports.main = main;
|
|
585
|
-
//# sourceMappingURL=
|
|
545
|
+
//# sourceMappingURL=index.cjs.map
|
|
586
546
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/version.ts","../src/lib/credentials.ts","../src/lib/errors.ts","../src/lib/output.ts","../src/commands/auth-switch.ts","../src/lib/auth.ts","../src/lib/client.ts","../src/commands/charges.ts","../src/commands/doctor.ts","../src/commands/login.ts","../src/commands/logout.ts"],"names":["homedir","join","Garu"],"mappings":"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","sourcesContent":["import { Command, Option } from 'commander';\n\nimport { CLI_VERSION } from './version.js';\nimport { authSwitchCommand } from './commands/auth-switch.js';\nimport {\n chargesCreateCommand,\n chargesGetCommand,\n chargesRefundCommand\n} from './commands/charges.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { loginCommand } from './commands/login.js';\nimport { logoutCommand } from './commands/logout.js';\nimport type { PaymentMethod } from '@garuhq/node';\nimport { CliError } from './lib/errors.js';\nimport { printErrorAndExit, type OutputMode } from './lib/output.js';\n\ninterface GlobalFlags {\n apiKey?: string;\n profile?: string;\n json?: boolean;\n quiet?: boolean;\n}\n\n/** Build the top-level command tree. Exposed so tests can exercise the router. */\nexport function buildCli(): Command {\n const program = new Command();\n\n program\n .name('garu')\n .description('Command-line interface for the Garu payment gateway.')\n .version(getVersion(), '-v, --version')\n .addOption(new Option('--api-key <key>', 'Garu API key (overrides env and credentials file)'))\n .addOption(new Option('-p, --profile <name>', 'credentials profile name'))\n .addOption(new Option('--json', 'emit strict JSON on stdout (forced in pipes)'))\n .addOption(new Option('-q, --quiet', 'suppress status output; only print results and errors'))\n .showHelpAfterError();\n\n // login\n program\n .command('login')\n .description('Save a Garu API key to the credentials file')\n .option('--api-key <key>', 'pre-supply the key instead of prompting')\n .option('-p, --profile <name>', 'profile name to store under', 'default')\n .action(async (cmdOpts: { apiKey?: string; profile: string }) => {\n const globals = getGlobals(program);\n await loginCommand({\n ...(cmdOpts.apiKey !== undefined ? { apiKey: cmdOpts.apiKey } : {}),\n profile: cmdOpts.profile,\n ...globalsToOutput(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n // logout\n program\n .command('logout')\n .description('Remove saved credentials')\n .option('-p, --profile <name>', 'only remove this profile instead of the whole file')\n .action(async (cmdOpts: { profile?: string }) => {\n const globals = getGlobals(program);\n await logoutCommand({\n ...(cmdOpts.profile !== undefined ? { profile: cmdOpts.profile } : {}),\n ...globalsToOutput(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n // auth switch\n const auth = program.command('auth').description('Manage credentials profiles');\n auth\n .command('switch <profile>')\n .description('Set the active credentials profile')\n .action(async (profile: string) => {\n const globals = getGlobals(program);\n await authSwitchCommand({ profile, ...globalsToOutput(globals) }).catch((err) =>\n printErrorAndExit(err, globalsToOutput(globals))\n );\n });\n\n // charges\n const charges = program.command('charges').description('Create, fetch, and refund charges');\n\n charges\n .command('create')\n .description('Create a charge (PIX, credit card, or boleto)')\n .requiredOption('--type <type>', 'payment method: pix | credit_card | boleto')\n .requiredOption('--product-id <uuid>', 'product UUID')\n .requiredOption('--customer-name <name>', 'customer full name')\n .requiredOption('--customer-email <email>', 'customer email')\n .requiredOption(\n '--customer-document <document>',\n 'CPF (11 digits) or CNPJ (14 digits), digits only'\n )\n .requiredOption('--customer-phone <phone>', 'customer phone with area code, digits only')\n .option('--card-number <number>', 'credit-card number (required for credit_card)')\n .option('--card-cvv <cvv>', 'credit-card CVV')\n .option('--card-expiration <yyyy-mm>', 'credit-card expiration date (YYYY-MM)')\n .option('--card-holder <name>', 'credit-card holder name')\n .option('--installments <n>', 'number of installments (1-12)', (v) => parseInt(v, 10), 1)\n .option('--additional-info <text>', 'free-form metadata attached to the charge')\n .option('--idempotency-key <key>', 'idempotency key (auto-generated if omitted)')\n .action(async (cmdOpts) => {\n const globals = getGlobals(program);\n const type = parsePaymentMethod(cmdOpts.type);\n await chargesCreateCommand({\n type,\n productId: cmdOpts.productId,\n customerName: cmdOpts.customerName,\n customerEmail: cmdOpts.customerEmail,\n customerDocument: cmdOpts.customerDocument,\n customerPhone: cmdOpts.customerPhone,\n ...(cmdOpts.cardNumber !== undefined ? { cardNumber: cmdOpts.cardNumber } : {}),\n ...(cmdOpts.cardCvv !== undefined ? { cardCvv: cmdOpts.cardCvv } : {}),\n ...(cmdOpts.cardExpiration !== undefined ? { cardExpiration: cmdOpts.cardExpiration } : {}),\n ...(cmdOpts.cardHolder !== undefined ? { cardHolder: cmdOpts.cardHolder } : {}),\n ...(cmdOpts.installments !== undefined ? { installments: cmdOpts.installments } : {}),\n ...(cmdOpts.additionalInfo !== undefined ? { additionalInfo: cmdOpts.additionalInfo } : {}),\n ...(cmdOpts.idempotencyKey !== undefined ? { idempotencyKey: cmdOpts.idempotencyKey } : {}),\n ...globalFlagsToCommandOptions(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n charges\n .command('get <id>')\n .description('Fetch a single charge by ID')\n .action(async (id: string) => {\n const globals = getGlobals(program);\n await chargesGetCommand({\n id: parseId(id),\n ...globalFlagsToCommandOptions(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n charges\n .command('refund <id>')\n .description('Refund a charge (full or partial)')\n .option('--amount <centavos>', 'partial refund amount in centavos', (v) => parseInt(v, 10))\n .option('--reason <text>', 'optional refund reason')\n .option('--idempotency-key <key>', 'idempotency key (auto-generated if omitted)')\n .action(async (id: string, cmdOpts) => {\n const globals = getGlobals(program);\n await chargesRefundCommand({\n id: parseId(id),\n ...(cmdOpts.amount !== undefined ? { amount: cmdOpts.amount } : {}),\n ...(cmdOpts.reason !== undefined ? { reason: cmdOpts.reason } : {}),\n ...(cmdOpts.idempotencyKey !== undefined ? { idempotencyKey: cmdOpts.idempotencyKey } : {}),\n ...globalFlagsToCommandOptions(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n // doctor\n program\n .command('doctor')\n .description('Environment diagnostic')\n .action(async () => {\n const globals = getGlobals(program);\n await doctorCommand({\n ...globalFlagsToCommandOptions(globals)\n }).catch((err) => printErrorAndExit(err, globalsToOutput(globals)));\n });\n\n return program;\n}\n\nfunction getGlobals(program: Command): GlobalFlags {\n return program.opts<GlobalFlags>();\n}\n\nfunction globalsToOutput(globals: GlobalFlags): { mode?: OutputMode; quiet?: boolean } {\n const out: { mode?: OutputMode; quiet?: boolean } = {};\n if (globals.json) out.mode = 'json';\n if (globals.quiet) out.quiet = true;\n return out;\n}\n\nfunction globalFlagsToCommandOptions(globals: GlobalFlags): {\n apiKey?: string;\n profile?: string;\n mode?: OutputMode;\n quiet?: boolean;\n} {\n const out: { apiKey?: string; profile?: string; mode?: OutputMode; quiet?: boolean } = {};\n if (globals.apiKey) out.apiKey = globals.apiKey;\n if (globals.profile) out.profile = globals.profile;\n if (globals.json) out.mode = 'json';\n if (globals.quiet) out.quiet = true;\n return out;\n}\n\nfunction parsePaymentMethod(raw: string): PaymentMethod {\n if (raw === 'pix' || raw === 'credit_card' || raw === 'boleto') return raw;\n throw new CliError(\n 'invalid_input',\n `--type must be 'pix', 'credit_card', or 'boleto' (got '${raw}')`\n );\n}\n\nfunction parseId(raw: string): number {\n const id = Number.parseInt(raw, 10);\n if (!Number.isFinite(id) || id <= 0) {\n throw new CliError('invalid_input', `Charge ID must be a positive integer (got '${raw}')`);\n }\n return id;\n}\n\nfunction getVersion(): string {\n return CLI_VERSION;\n}\n\n/** Main entry invoked by `bin/garu.js` and `src/index.ts` when run directly. */\nexport async function main(argv: string[] = process.argv): Promise<void> {\n const program = buildCli();\n await program.parseAsync(argv);\n}\n\n// This module is only ever loaded as the CLI entry point — either through the\n// `bin/garu.cjs` shim for npm installs or as the compiled binary produced by\n// `bun build --compile`. No test imports `src/index.ts`, so it's safe to call\n// `main()` unconditionally at module load time.\nmain().catch((err) => printErrorAndExit(err));\n","/**\n * CLI version.\n *\n * Kept as a plain string so `bun build --compile` can inline it at compile time\n * and the resulting binary has no runtime dependency on `package.json`.\n * The release workflow bumps this in lockstep with `package.json` on `v*` tags.\n */\nexport const CLI_VERSION = '0.1.1';\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { mkdir, readFile, writeFile, rm, stat } from 'node:fs/promises';\n\nimport { CliError } from './errors.js';\n\nexport interface CredentialProfile {\n apiKey: string;\n /** Optional seller ID to render in `garu doctor` output. */\n sellerId?: number;\n /** Human-readable label for multi-profile setups. */\n label?: string;\n}\n\nexport interface CredentialsFile {\n version: 1;\n activeProfile: string;\n profiles: Record<string, CredentialProfile>;\n}\n\nconst DEFAULT_FILE: CredentialsFile = {\n version: 1,\n activeProfile: 'default',\n profiles: {}\n};\n\n/**\n * Resolve the credentials file path.\n *\n * Honors `$XDG_CONFIG_HOME` per the XDG base-dir spec, falling back to\n * `~/.config/garu/credentials.json`. Override with `$GARU_CREDENTIALS_PATH`\n * (primarily for tests).\n */\nexport function credentialsPath(env: NodeJS.ProcessEnv = process.env): string {\n if (env.GARU_CREDENTIALS_PATH) return env.GARU_CREDENTIALS_PATH;\n const base = env.XDG_CONFIG_HOME || join(homedir(), '.config');\n return join(base, 'garu', 'credentials.json');\n}\n\n/** Read the credentials file. Returns the default (empty) file if it doesn't exist. */\nexport async function loadCredentials(\n env: NodeJS.ProcessEnv = process.env\n): Promise<CredentialsFile> {\n const path = credentialsPath(env);\n try {\n const raw = await readFile(path, 'utf8');\n const parsed = JSON.parse(raw);\n return normalize(parsed);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { ...DEFAULT_FILE };\n }\n throw new CliError(\n 'invalid_input',\n `Failed to read credentials at ${path}: ${(err as Error).message}`\n );\n }\n}\n\n/**\n * Write the credentials file atomically with tight file-mode (0600) and\n * directory-mode (0700).\n */\nexport async function saveCredentials(\n file: CredentialsFile,\n env: NodeJS.ProcessEnv = process.env\n): Promise<void> {\n const path = credentialsPath(env);\n const dir = path.slice(0, path.lastIndexOf('/'));\n await mkdir(dir, { recursive: true, mode: 0o700 });\n await writeFile(path, JSON.stringify(file, null, 2) + '\\n', { mode: 0o600 });\n}\n\n/** Delete the credentials file. No-op if it doesn't exist. */\nexport async function deleteCredentials(env: NodeJS.ProcessEnv = process.env): Promise<void> {\n const path = credentialsPath(env);\n try {\n await rm(path);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n}\n\n/** Add or replace a profile and set it active. */\nexport function upsertProfile(\n file: CredentialsFile,\n name: string,\n profile: CredentialProfile\n): CredentialsFile {\n return {\n ...file,\n activeProfile: name,\n profiles: { ...file.profiles, [name]: profile }\n };\n}\n\n/** Check whether the credentials file has the expected 0600 mode. Returns null on any error. */\nexport async function credentialsFileMode(\n env: NodeJS.ProcessEnv = process.env\n): Promise<number | null> {\n try {\n const s = await stat(credentialsPath(env));\n return s.mode & 0o777;\n } catch {\n return null;\n }\n}\n\nfunction normalize(raw: unknown): CredentialsFile {\n if (!raw || typeof raw !== 'object') return { ...DEFAULT_FILE };\n const obj = raw as Partial<CredentialsFile>;\n return {\n version: 1,\n activeProfile: obj.activeProfile ?? 'default',\n profiles: obj.profiles && typeof obj.profiles === 'object' ? obj.profiles : {}\n };\n}\n","/**\n * CLI error model. All user-visible failures flow through these types so that\n * the output layer can render them consistently — pretty with a red prefix in\n * TTY mode, strict `{\"error\":{\"code\",\"message\"}}` on stdout + exit 1 in JSON mode.\n */\n\nexport type CliErrorCode =\n | 'auth_error'\n | 'not_found'\n | 'validation_error'\n | 'rate_limited'\n | 'server_error'\n | 'connection_error'\n | 'signature_verification_failed'\n | 'user_cancelled'\n | 'invalid_input'\n | 'unknown_error';\n\nexport class CliError extends Error {\n public readonly code: CliErrorCode;\n public readonly exitCode: number;\n\n constructor(code: CliErrorCode, message: string, exitCode = 1) {\n super(message);\n this.name = 'CliError';\n this.code = code;\n this.exitCode = exitCode;\n }\n}\n\n/** Wrap an unknown thrown value as a {@link CliError}. */\nexport function toCliError(err: unknown): CliError {\n if (err instanceof CliError) return err;\n // Duck-type the SDK's GaruError — avoids importing the SDK class hierarchy\n // just for instanceof checks, and keeps this module dependency-free.\n if (err && typeof err === 'object' && 'name' in err && 'code' in err) {\n const e = err as { name: string; code: string; message?: string };\n if (typeof e.name === 'string' && e.name.startsWith('Garu')) {\n return new CliError(mapSdkCodeToCliCode(e.code), e.message ?? 'Request failed', 1);\n }\n }\n if (err instanceof Error) return new CliError('unknown_error', err.message);\n return new CliError('unknown_error', String(err));\n}\n\nfunction mapSdkCodeToCliCode(sdkCode: string): CliErrorCode {\n switch (sdkCode) {\n case 'authentication_error':\n case 'permission_error':\n return 'auth_error';\n case 'not_found':\n return 'not_found';\n case 'validation_error':\n return 'validation_error';\n case 'rate_limited':\n return 'rate_limited';\n case 'server_error':\n return 'server_error';\n case 'connection_error':\n return 'connection_error';\n case 'signature_verification_failed':\n return 'signature_verification_failed';\n default:\n return 'unknown_error';\n }\n}\n","import pc from 'picocolors';\n\nimport { CliError, toCliError } from './errors.js';\n\nexport type OutputMode = 'pretty' | 'json';\n\nexport interface OutputOptions {\n /** Force a mode. If omitted, auto-detect from TTY. */\n mode?: OutputMode;\n /** Passed by `--quiet`; suppresses everything except errors and the final value. */\n quiet?: boolean;\n}\n\n/**\n * Resolve the output mode. Rules:\n * - Explicit `--json` (or `opts.mode === 'json'`) wins.\n * - Non-TTY stdout (pipe, CI) → `json`.\n * - Everything else → `pretty`.\n */\nexport function resolveMode(\n opts: OutputOptions = {},\n stdout: NodeJS.WriteStream = process.stdout\n): OutputMode {\n if (opts.mode) return opts.mode;\n return stdout.isTTY ? 'pretty' : 'json';\n}\n\n/**\n * Print a successful command result. In JSON mode the full object is written\n * to stdout with a trailing newline. In pretty mode the caller's `prettyPrint`\n * fallback (if provided) is used; otherwise the JSON is indented.\n */\nexport function printResult<T>(\n value: T,\n opts: OutputOptions & { prettyPrint?: (value: T) => string } = {}\n): void {\n const mode = resolveMode(opts);\n if (mode === 'json') {\n process.stdout.write(`${JSON.stringify(value)}\\n`);\n return;\n }\n if (opts.prettyPrint) {\n process.stdout.write(`${opts.prettyPrint(value)}\\n`);\n return;\n }\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\n/** Print a short status line — suppressed in JSON mode and when `--quiet`. */\nexport function printStatus(message: string, opts: OutputOptions = {}): void {\n if (opts.quiet) return;\n if (resolveMode(opts) === 'json') return;\n process.stderr.write(`${pc.dim('→')} ${message}\\n`);\n}\n\n/** Print a success line — suppressed in JSON mode and when `--quiet`. */\nexport function printSuccess(message: string, opts: OutputOptions = {}): void {\n if (opts.quiet) return;\n if (resolveMode(opts) === 'json') return;\n process.stderr.write(`${pc.green('✓')} ${message}\\n`);\n}\n\n/**\n * Print an error and exit with the appropriate code. Always uses the\n * CLI-standard shape `{\"error\":{\"code\",\"message\"}}` on stdout in JSON mode,\n * or a red `Error:` line on stderr in pretty mode.\n */\nexport function printErrorAndExit(err: unknown, opts: OutputOptions = {}): never {\n const cliErr: CliError = toCliError(err);\n const payload = { error: { code: cliErr.code, message: cliErr.message } };\n\n if (resolveMode(opts) === 'json') {\n process.stdout.write(`${JSON.stringify(payload)}\\n`);\n } else {\n process.stderr.write(`${pc.red('Error:')} ${cliErr.message}\\n`);\n if (cliErr.code !== 'unknown_error') {\n process.stderr.write(`${pc.dim(` code: ${cliErr.code}`)}\\n`);\n }\n }\n process.exit(cliErr.exitCode);\n}\n","import { loadCredentials, saveCredentials } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface AuthSwitchOptions extends OutputOptions {\n profile: string;\n}\n\nexport async function authSwitchCommand(\n opts: AuthSwitchOptions\n): Promise<{ activeProfile: string }> {\n const file = await loadCredentials();\n if (!file.profiles[opts.profile]) {\n const available = Object.keys(file.profiles).join(', ') || '(none)';\n throw new CliError('not_found', `Profile '${opts.profile}' not found. Available: ${available}`);\n }\n\n await saveCredentials({ ...file, activeProfile: opts.profile });\n printSuccess(`Active profile set to '${opts.profile}'.`, opts);\n return { activeProfile: opts.profile };\n}\n","import { loadCredentials, type CredentialProfile } from './credentials.js';\nimport { CliError } from './errors.js';\n\nexport interface ResolvedAuth {\n apiKey: string;\n /** Where the key came from, for `doctor` and debug output. */\n source: 'flag' | 'env' | 'file';\n /** Profile name if resolved from file; undefined otherwise. */\n profile?: string;\n fileProfile?: CredentialProfile;\n}\n\nexport interface ResolveAuthOptions {\n /** `--api-key` flag value. Highest precedence. */\n apiKey?: string;\n /** `--profile` flag value. When set, reads that profile instead of the active one. */\n profile?: string;\n env?: NodeJS.ProcessEnv;\n}\n\n/**\n * Resolve the API key following SPEC §7 auth priority:\n *\n * 1. `--api-key` flag\n * 2. `GARU_API_KEY` environment variable\n * 3. credentials file active profile (or profile selected with `--profile`)\n *\n * Throws {@link CliError} with code `auth_error` if no key is found. Never logs.\n */\nexport async function resolveAuth(opts: ResolveAuthOptions = {}): Promise<ResolvedAuth> {\n const env = opts.env ?? process.env;\n\n if (opts.apiKey) {\n return { apiKey: opts.apiKey, source: 'flag' };\n }\n\n if (env.GARU_API_KEY) {\n return { apiKey: env.GARU_API_KEY, source: 'env' };\n }\n\n const file = await loadCredentials(env);\n const profileName = opts.profile ?? file.activeProfile;\n const profile = file.profiles[profileName];\n if (profile && profile.apiKey) {\n return {\n apiKey: profile.apiKey,\n source: 'file',\n profile: profileName,\n fileProfile: profile\n };\n }\n\n throw new CliError('auth_error', 'No API key found. Run `garu login` or set GARU_API_KEY.');\n}\n\n/**\n * Same as {@link resolveAuth} but returns `null` instead of throwing when no\n * credentials are available. Used by `garu doctor`.\n */\nexport async function resolveAuthOptional(\n opts: ResolveAuthOptions = {}\n): Promise<ResolvedAuth | null> {\n try {\n return await resolveAuth(opts);\n } catch (err) {\n if (err instanceof CliError && err.code === 'auth_error') return null;\n throw err;\n }\n}\n","import { Garu } from '@garuhq/node';\n\nimport type { ResolvedAuth } from './auth.js';\nimport { CLI_VERSION } from '../version.js';\n\nexport interface GaruClientOptions {\n auth: ResolvedAuth;\n baseUrl?: string;\n}\n\n/**\n * Construct a `Garu` SDK instance from resolved auth.\n *\n * The CLI dogfoods `@garuhq/node` — every HTTP call flows through the SDK we\n * shipped in Chunk 3. This keeps retries, idempotency, and error mapping\n * consistent between the CLI, MCP server, and any user-written integration.\n */\nexport function createGaruClient(opts: GaruClientOptions): Garu {\n return new Garu({\n apiKey: opts.auth.apiKey,\n baseUrl: opts.baseUrl\n });\n}\n\n/** User-Agent used for CLI requests. Surfaces the CLI version in backend logs. */\nexport function cliUserAgent(): string {\n return `garu-cli/${CLI_VERSION}`;\n}\n","import type { Charge, Customer, Garu, PaymentMethod, RefundChargeParams } from '@garuhq/node';\n\nimport { resolveAuth } from '../lib/auth.js';\nimport { createGaruClient } from '../lib/client.js';\nimport { CliError } from '../lib/errors.js';\nimport { printResult, type OutputOptions } from '../lib/output.js';\n\nexport interface ChargesGlobalOptions extends OutputOptions {\n apiKey?: string;\n profile?: string;\n baseUrl?: string;\n /** Injectable for tests — bypass auth resolution + SDK construction. */\n garu?: Garu;\n}\n\nexport interface ChargesCreateOptions extends ChargesGlobalOptions {\n type: PaymentMethod;\n productId: string;\n customerName: string;\n customerEmail: string;\n customerDocument: string;\n customerPhone: string;\n cardNumber?: string;\n cardCvv?: string;\n cardExpiration?: string;\n cardHolder?: string;\n installments?: number;\n idempotencyKey?: string;\n additionalInfo?: string;\n}\n\nexport interface ChargesByIdOptions extends ChargesGlobalOptions {\n id: number;\n}\n\nexport interface ChargesRefundOptions extends ChargesByIdOptions {\n /** Amount in centavos. Omit for full refund. */\n amount?: number;\n reason?: string;\n idempotencyKey?: string;\n}\n\nasync function getClient(opts: ChargesGlobalOptions): Promise<Garu> {\n if (opts.garu) return opts.garu;\n const auth = await resolveAuth({\n ...(opts.apiKey !== undefined ? { apiKey: opts.apiKey } : {}),\n ...(opts.profile !== undefined ? { profile: opts.profile } : {})\n });\n return createGaruClient({\n auth,\n ...(opts.baseUrl !== undefined ? { baseUrl: opts.baseUrl } : {})\n });\n}\n\nexport async function chargesCreateCommand(opts: ChargesCreateOptions): Promise<Charge> {\n validateCreate(opts);\n const garu = await getClient(opts);\n\n const customer: Customer = {\n name: opts.customerName,\n email: opts.customerEmail,\n document: opts.customerDocument,\n phone: opts.customerPhone\n };\n\n const charge = await garu.charges.create({\n productId: opts.productId,\n paymentMethod: opts.type,\n customer,\n ...(opts.additionalInfo !== undefined ? { additionalInfo: opts.additionalInfo } : {}),\n ...(opts.idempotencyKey !== undefined ? { idempotencyKey: opts.idempotencyKey } : {}),\n ...(opts.type === 'credit_card' && opts.cardNumber\n ? {\n cardInfo: {\n cardNumber: opts.cardNumber,\n cvv: opts.cardCvv!,\n expirationDate: opts.cardExpiration!,\n holderName: opts.cardHolder!,\n installments: opts.installments ?? 1\n }\n }\n : {})\n });\n\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nexport async function chargesGetCommand(opts: ChargesByIdOptions): Promise<Charge> {\n const garu = await getClient(opts);\n const charge = await garu.charges.get(opts.id);\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nexport async function chargesRefundCommand(opts: ChargesRefundOptions): Promise<Charge> {\n const garu = await getClient(opts);\n const params: RefundChargeParams = {};\n if (opts.amount !== undefined) params.amount = opts.amount;\n if (opts.reason !== undefined) params.reason = opts.reason;\n if (opts.idempotencyKey !== undefined) params.idempotencyKey = opts.idempotencyKey;\n const charge = await garu.charges.refund(opts.id, params);\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nfunction validateCreate(opts: ChargesCreateOptions): void {\n if (opts.type === 'credit_card') {\n const missing: string[] = [];\n if (!opts.cardNumber) missing.push('--card-number');\n if (!opts.cardCvv) missing.push('--card-cvv');\n if (!opts.cardExpiration) missing.push('--card-expiration');\n if (!opts.cardHolder) missing.push('--card-holder');\n if (missing.length) {\n throw new CliError('invalid_input', `Credit-card charges require: ${missing.join(', ')}`);\n }\n }\n}\n\nfunction prettyCharge(charge: Charge): string {\n const lines = [\n `Charge ${charge.id}`,\n ` status: ${charge.status}`,\n ` amount: ${charge.amount}`,\n ` method: ${charge.paymentMethodId}`,\n ` date: ${charge.date}`\n ];\n if (charge.deadline) lines.push(` deadline: ${charge.deadline}`);\n return lines.join('\\n');\n}\n","import { existsSync } from 'node:fs';\nimport { homedir, platform } from 'node:os';\nimport { join } from 'node:path';\n\nimport { Garu } from '@garuhq/node';\n\nimport { resolveAuthOptional } from '../lib/auth.js';\nimport { credentialsFileMode, credentialsPath } from '../lib/credentials.js';\nimport { printResult, type OutputOptions } from '../lib/output.js';\nimport { CLI_VERSION } from '../version.js';\n\nexport interface DoctorReport {\n cli: { version: string };\n api: { reachable: boolean; url: string; version?: string; error?: string };\n credentials: {\n path: string;\n source: 'flag' | 'env' | 'file' | 'none';\n profile?: string;\n fileMode?: string;\n warning?: string;\n };\n agents: {\n claudeCode: boolean;\n cursor: boolean;\n codex: boolean;\n windsurf: boolean;\n claudeDesktop: boolean;\n vscodeMcpInCwd: boolean;\n };\n}\n\nexport interface DoctorOptions extends OutputOptions {\n apiKey?: string;\n profile?: string;\n baseUrl?: string;\n /** Injectable for tests — bypass the real HTTP call. */\n garu?: Garu;\n /** Injectable HOME, for tests. */\n home?: string;\n /** Injectable cwd, for tests. */\n cwd?: string;\n /** Injectable platform, for tests. */\n platform?: NodeJS.Platform;\n}\n\n/**\n * Run a full environment diagnostic.\n *\n * Never throws on expected failures — bad auth, unreachable API, missing\n * credentials all become structured report fields. Only genuinely unexpected\n * errors (programming bugs) bubble up.\n */\nexport async function doctorCommand(opts: DoctorOptions = {}): Promise<DoctorReport> {\n const home = opts.home ?? homedir();\n const cwd = opts.cwd ?? process.cwd();\n const plat = opts.platform ?? platform();\n\n const credentials = await reportCredentials(opts);\n const api = await reportApi(opts);\n const agents = detectAgents(home, cwd, plat);\n\n const report: DoctorReport = {\n cli: { version: CLI_VERSION },\n api,\n credentials,\n agents\n };\n\n printResult(report, { ...opts, prettyPrint: prettyDoctor });\n return report;\n}\n\nasync function reportCredentials(opts: DoctorOptions): Promise<DoctorReport['credentials']> {\n const path = credentialsPath();\n const resolved = await resolveAuthOptional({\n ...(opts.apiKey !== undefined ? { apiKey: opts.apiKey } : {}),\n ...(opts.profile !== undefined ? { profile: opts.profile } : {})\n });\n\n if (!resolved) {\n return { path, source: 'none' };\n }\n\n const out: DoctorReport['credentials'] = { path, source: resolved.source };\n if (resolved.profile) out.profile = resolved.profile;\n\n if (resolved.source === 'file') {\n const mode = await credentialsFileMode();\n if (mode !== null) {\n out.fileMode = `0${mode.toString(8)}`;\n if (mode !== 0o600) {\n out.warning = `credentials file mode is 0${mode.toString(8)}; expected 0600`;\n }\n }\n }\n\n return out;\n}\n\nasync function reportApi(opts: DoctorOptions): Promise<DoctorReport['api']> {\n const url = opts.baseUrl ?? 'https://garu.com.br';\n const garu =\n opts.garu ??\n new Garu({\n ...(opts.baseUrl !== undefined ? { baseUrl: opts.baseUrl } : {})\n });\n\n try {\n const meta = await garu.meta.get();\n return { reachable: true, url, version: meta.version };\n } catch (err) {\n return {\n reachable: false,\n url,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n}\n\nfunction detectAgents(home: string, cwd: string, plat: NodeJS.Platform): DoctorReport['agents'] {\n return {\n claudeCode: existsSync(join(home, '.claude')),\n cursor: existsSync(join(home, '.cursor')),\n codex: existsSync(join(home, '.codex')),\n windsurf: existsSync(join(home, '.windsurf')),\n claudeDesktop: existsSync(claudeDesktopConfigPath(home, plat)),\n vscodeMcpInCwd: existsSync(join(cwd, '.vscode', 'mcp.json'))\n };\n}\n\nfunction claudeDesktopConfigPath(home: string, plat: NodeJS.Platform): string {\n if (plat === 'darwin') {\n return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');\n }\n if (plat === 'win32') {\n return join(home, 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json');\n }\n return join(home, '.config', 'Claude', 'claude_desktop_config.json');\n}\n\nfunction prettyDoctor(r: DoctorReport): string {\n const check = (ok: boolean) => (ok ? 'yes' : 'no ');\n const lines = [\n `CLI: garu ${r.cli.version}`,\n `API: ${r.api.reachable ? `reachable (${r.api.url}, backend ${r.api.version ?? '?'})` : `unreachable (${r.api.url})`}`,\n r.api.error ? ` ${r.api.error}` : undefined,\n `Credentials: source=${r.credentials.source}${r.credentials.profile ? ` profile=${r.credentials.profile}` : ''}${r.credentials.fileMode ? ` mode=${r.credentials.fileMode}` : ''}`,\n r.credentials.warning ? ` ⚠ ${r.credentials.warning}` : undefined,\n '',\n 'Detected agents:',\n ` Claude Code: ${check(r.agents.claudeCode)}`,\n ` Cursor: ${check(r.agents.cursor)}`,\n ` Codex: ${check(r.agents.codex)}`,\n ` Windsurf: ${check(r.agents.windsurf)}`,\n ` Claude Desktop: ${check(r.agents.claudeDesktop)}`,\n ` VS Code MCP: ${check(r.agents.vscodeMcpInCwd)} (.vscode/mcp.json in cwd)`\n ].filter((l): l is string => l !== undefined);\n return lines.join('\\n');\n}\n","import { password as promptPassword } from '@inquirer/prompts';\n\nimport { Garu } from '@garuhq/node';\n\nimport { loadCredentials, saveCredentials, upsertProfile } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printStatus, printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface LoginOptions extends OutputOptions {\n /** Profile name to create/update. Default: `default`. */\n profile?: string;\n /** Pre-supplied API key (for scripting). When set, no interactive prompt. */\n apiKey?: string;\n /** Override base URL (tests). */\n baseUrl?: string;\n}\n\nexport async function loginCommand(opts: LoginOptions = {}): Promise<{ profile: string }> {\n const profile = opts.profile ?? 'default';\n\n const apiKey =\n opts.apiKey ??\n (await promptPassword({\n message: 'Paste your Garu API key (sk_live_... or sk_test_...)',\n mask: '*'\n }).catch(() => {\n throw new CliError('user_cancelled', 'Login cancelled.');\n }));\n\n if (!apiKey || !/^sk_(live|test)_[A-Za-z0-9_]+$/.test(apiKey)) {\n throw new CliError('invalid_input', 'API key must look like `sk_live_...` or `sk_test_...`.');\n }\n\n printStatus('Validating key with Garu...', opts);\n const garu = new Garu({\n apiKey,\n ...(opts.baseUrl !== undefined ? { baseUrl: opts.baseUrl } : {})\n });\n\n // Hit an unauthenticated endpoint first to confirm connectivity, then use\n // the authenticated path to prove the key works. `meta.get` tests reachability;\n // we don't yet have a light authed endpoint to verify the key, so the key is\n // stored after basic format + reachability checks. A real auth probe will\n // land once the backend exposes `GET /api/v1/me`.\n await garu.meta.get();\n\n const file = await loadCredentials();\n const updated = upsertProfile(file, profile, { apiKey });\n await saveCredentials(updated);\n\n printSuccess(`Saved profile '${profile}' to ~/.config/garu/credentials.json`, opts);\n return { profile };\n}\n","import { deleteCredentials, loadCredentials, saveCredentials } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface LogoutOptions extends OutputOptions {\n /**\n * Profile to remove. If omitted, the entire credentials file is deleted.\n */\n profile?: string;\n}\n\nexport async function logoutCommand(opts: LogoutOptions = {}): Promise<{ cleared: string }> {\n if (!opts.profile) {\n await deleteCredentials();\n printSuccess('All saved credentials deleted.', opts);\n return { cleared: 'all' };\n }\n\n const file = await loadCredentials();\n if (!file.profiles[opts.profile]) {\n throw new CliError('not_found', `Profile '${opts.profile}' not found.`);\n }\n\n const { [opts.profile]: _removed, ...rest } = file.profiles;\n void _removed;\n\n const nextActive =\n file.activeProfile === opts.profile ? (Object.keys(rest)[0] ?? 'default') : file.activeProfile;\n\n await saveCredentials({ ...file, activeProfile: nextActive, profiles: rest });\n printSuccess(`Profile '${opts.profile}' removed.`, opts);\n return { cleared: opts.profile };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/version.ts","../src/lib/errors.ts","../src/lib/credentials.ts","../src/lib/output.ts","../src/commands/auth-switch.ts","../src/lib/auth.ts","../src/lib/client.ts","../src/commands/charges.ts","../src/commands/doctor.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/index.ts"],"names":["GaruError","join","homedir","readFile","path","mkdir","dirname","writeFile","rm","stat","pc","Garu","platform","existsSync","Command","Option"],"mappings":";;;;;;;;;;;;;;;;;AAOO,IAAM,WAAA,GAAc,OAAA;ACapB,IAAM,QAAA,GAAN,cAAuB,KAAA,CAAM;AAAA,EAClB,IAAA;AAAA,EACA,QAAA;AAAA,EAEhB,WAAA,CAAY,IAAA,EAAoB,OAAA,EAAiB,QAAA,GAAW,CAAA,EAAG;AAC7D,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,UAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAAA,EAClB;AACF,CAAA;AAGO,SAAS,WAAW,GAAA,EAAwB;AACjD,EAAA,IAAI,GAAA,YAAe,UAAU,OAAO,GAAA;AACpC,EAAA,IAAI,eAAeA,cAAA,EAAW;AAC5B,IAAA,OAAO,IAAI,SAAS,mBAAA,CAAoB,GAAA,CAAI,IAAI,CAAA,EAAG,GAAA,CAAI,SAAS,CAAC,CAAA;AAAA,EACnE;AACA,EAAA,IAAI,eAAe,KAAA,EAAO,OAAO,IAAI,QAAA,CAAS,eAAA,EAAiB,IAAI,OAAO,CAAA;AAC1E,EAAA,OAAO,IAAI,QAAA,CAAS,eAAA,EAAiB,MAAA,CAAO,GAAG,CAAC,CAAA;AAClD;AAEA,SAAS,oBAAoB,OAAA,EAA+B;AAC1D,EAAA,QAAQ,OAAA;AAAS,IACf,KAAK,sBAAA;AAAA,IACL,KAAK,kBAAA;AACH,MAAA,OAAO,YAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,WAAA;AAAA,IACT,KAAK,kBAAA;AACH,MAAA,OAAO,kBAAA;AAAA,IACT,KAAK,cAAA;AACH,MAAA,OAAO,cAAA;AAAA,IACT,KAAK,cAAA;AACH,MAAA,OAAO,cAAA;AAAA,IACT,KAAK,kBAAA;AACH,MAAA,OAAO,kBAAA;AAAA,IACT,KAAK,+BAAA;AACH,MAAA,OAAO,+BAAA;AAAA,IACT;AACE,MAAA,OAAO,eAAA;AAAA;AAEb;;;AC1CA,IAAM,YAAA,GAAgC;AAAA,EACpC,OAAA,EAAS,CAAA;AAAA,EACT,aAAA,EAAe,SAAA;AAAA,EACf,UAAU;AACZ,CAAA;AASO,SAAS,eAAA,CAAgB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAa;AAC5E,EAAA,IAAI,GAAA,CAAI,qBAAA,EAAuB,OAAO,GAAA,CAAI,qBAAA;AAC1C,EAAA,MAAM,OAAO,GAAA,CAAI,eAAA,IAAmBC,SAAA,CAAKC,UAAA,IAAW,SAAS,CAAA;AAC7D,EAAA,OAAOD,SAAA,CAAK,IAAA,EAAM,MAAA,EAAQ,kBAAkB,CAAA;AAC9C;AAGA,eAAsB,eAAA,CACpB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EACP;AAC1B,EAAA,MAAM,IAAA,GAAO,gBAAgB,GAAG,CAAA;AAChC,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAME,iBAAA,CAAS,IAAA,EAAM,MAAM,CAAA;AACvC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,OAAO,UAAU,MAAM,CAAA;AAAA,EACzB,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,CAA8B,SAAS,QAAA,EAAU;AACpD,MAAA,OAAO,EAAE,GAAG,YAAA,EAAa;AAAA,IAC3B;AACA,IAAA,MAAM,IAAI,QAAA;AAAA,MACR,eAAA;AAAA,MACA,CAAA,8BAAA,EAAiC,IAAI,CAAA,EAAA,EAAM,GAAA,CAAc,OAAO,CAAA;AAAA,KAClE;AAAA,EACF;AACF;AAMA,eAAsB,eAAA,CACpB,IAAA,EACA,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAClB;AACf,EAAA,MAAMC,MAAA,GAAO,gBAAgB,GAAG,CAAA;AAChC,EAAA,MAAMC,cAAA,CAAMC,aAAQF,MAAI,CAAA,EAAG,EAAE,SAAA,EAAW,IAAA,EAAM,IAAA,EAAM,GAAA,EAAO,CAAA;AAC3D,EAAA,MAAMG,kBAAA,CAAUH,MAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAA,EAAM,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA,EAAM,EAAE,IAAA,EAAM,GAAA,EAAO,CAAA;AAC7E;AAGA,eAAsB,iBAAA,CAAkB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAoB;AAC3F,EAAA,MAAM,IAAA,GAAO,gBAAgB,GAAG,CAAA;AAChC,EAAA,IAAI;AACF,IAAA,MAAMI,YAAG,IAAI,CAAA;AAAA,EACf,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,CAA8B,IAAA,KAAS,QAAA,EAAU,MAAM,GAAA;AAAA,EAC9D;AACF;AAGO,SAAS,aAAA,CACd,IAAA,EACA,IAAA,EACA,OAAA,EACiB;AACjB,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,aAAA,EAAe,IAAA;AAAA,IACf,QAAA,EAAU,EAAE,GAAG,IAAA,CAAK,UAAU,CAAC,IAAI,GAAG,OAAA;AAAQ,GAChD;AACF;AAGA,eAAsB,mBAAA,CACpB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EACT;AACxB,EAAA,IAAI;AACF,IAAA,MAAM,CAAA,GAAI,MAAMC,aAAA,CAAK,eAAA,CAAgB,GAAG,CAAC,CAAA;AACzC,IAAA,OAAO,EAAE,IAAA,GAAO,GAAA;AAAA,EAClB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,UAAU,GAAA,EAA+B;AAChD,EAAA,IAAI,CAAC,OAAO,OAAO,GAAA,KAAQ,UAAU,OAAO,EAAE,GAAG,YAAA,EAAa;AAC9D,EAAA,MAAM,GAAA,GAAM,GAAA;AACZ,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,CAAA;AAAA,IACT,aAAA,EAAe,IAAI,aAAA,IAAiB,SAAA;AAAA,IACpC,QAAA,EAAU,IAAI,QAAA,IAAY,OAAO,IAAI,QAAA,KAAa,QAAA,GAAW,GAAA,CAAI,QAAA,GAAW;AAAC,GAC/E;AACF;AChGO,SAAS,YACd,IAAA,GAAsB,EAAC,EACvB,MAAA,GAA6B,QAAQ,MAAA,EACzB;AACZ,EAAA,IAAI,IAAA,CAAK,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA;AAC3B,EAAA,OAAO,MAAA,CAAO,QAAQ,QAAA,GAAW,MAAA;AACnC;AAOO,SAAS,WAAA,CACd,KAAA,EACA,IAAA,GAA+D,EAAC,EAC1D;AACN,EAAA,MAAM,IAAA,GAAO,YAAY,IAAI,CAAA;AAC7B,EAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,IAAA,OAAA,CAAQ,OAAO,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC;AAAA,CAAI,CAAA;AACjD,IAAA;AAAA,EACF;AACA,EAAA,IAAI,KAAK,WAAA,EAAa;AACpB,IAAA,OAAA,CAAQ,OAAO,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,WAAA,CAAY,KAAK,CAAC;AAAA,CAAI,CAAA;AACnD,IAAA;AAAA,EACF;AACA,EAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA,EAAG,IAAA,CAAK,UAAU,KAAA,EAAO,IAAA,EAAM,CAAC,CAAC;AAAA,CAAI,CAAA;AAC5D;AAGO,SAAS,WAAA,CAAY,OAAA,EAAiB,IAAA,GAAsB,EAAC,EAAS;AAC3E,EAAA,IAAI,KAAK,KAAA,EAAO;AAChB,EAAA,IAAI,WAAA,CAAY,IAAI,CAAA,KAAM,MAAA,EAAQ;AAClC,EAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA,EAAGC,mBAAA,CAAG,IAAI,QAAG,CAAC,IAAI,OAAO;AAAA,CAAI,CAAA;AACpD;AAGO,SAAS,YAAA,CAAa,OAAA,EAAiB,IAAA,GAAsB,EAAC,EAAS;AAC5E,EAAA,IAAI,KAAK,KAAA,EAAO;AAChB,EAAA,IAAI,WAAA,CAAY,IAAI,CAAA,KAAM,MAAA,EAAQ;AAClC,EAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA,EAAGA,mBAAA,CAAG,MAAM,QAAG,CAAC,IAAI,OAAO;AAAA,CAAI,CAAA;AACtD;AAOO,SAAS,iBAAA,CAAkB,GAAA,EAAc,IAAA,GAAsB,EAAC,EAAU;AAC/E,EAAA,MAAM,MAAA,GAAmB,WAAW,GAAG,CAAA;AACvC,EAAA,MAAM,OAAA,GAAU,EAAE,KAAA,EAAO,EAAE,IAAA,EAAM,OAAO,IAAA,EAAM,OAAA,EAAS,MAAA,CAAO,OAAA,EAAQ,EAAE;AAExE,EAAA,IAAI,WAAA,CAAY,IAAI,CAAA,KAAM,MAAA,EAAQ;AAChC,IAAA,OAAA,CAAQ,OAAO,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC;AAAA,CAAI,CAAA;AAAA,EACrD,CAAA,MAAO;AACL,IAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA,EAAGA,mBAAA,CAAG,IAAI,QAAQ,CAAC,CAAA,CAAA,EAAI,MAAA,CAAO,OAAO;AAAA,CAAI,CAAA;AAC9D,IAAA,IAAI,MAAA,CAAO,SAAS,eAAA,EAAiB;AACnC,MAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA,EAAGA,mBAAA,CAAG,IAAI,CAAA,QAAA,EAAW,MAAA,CAAO,IAAI,CAAA,CAAE,CAAC;AAAA,CAAI,CAAA;AAAA,IAC9D;AAAA,EACF;AACA,EAAA,OAAA,CAAQ,IAAA,CAAK,OAAO,QAAQ,CAAA;AAC9B;;;ACxEA,eAAsB,kBACpB,IAAA,EACoC;AACpC,EAAA,MAAM,IAAA,GAAO,MAAM,eAAA,EAAgB;AACnC,EAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,OAAO,CAAA,EAAG;AAChC,IAAA,MAAM,SAAA,GAAY,OAAO,IAAA,CAAK,IAAA,CAAK,QAAQ,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,IAAK,QAAA;AAC3D,IAAA,MAAM,IAAI,SAAS,WAAA,EAAa,CAAA,SAAA,EAAY,KAAK,OAAO,CAAA,wBAAA,EAA2B,SAAS,CAAA,CAAE,CAAA;AAAA,EAChG;AAEA,EAAA,MAAM,gBAAgB,EAAE,GAAG,MAAM,aAAA,EAAe,IAAA,CAAK,SAAS,CAAA;AAC9D,EAAA,YAAA,CAAa,CAAA,uBAAA,EAA0B,IAAA,CAAK,OAAO,CAAA,EAAA,CAAA,EAAM,IAAI,CAAA;AAC7D,EAAA,OAAO,EAAE,aAAA,EAAe,IAAA,CAAK,OAAA,EAAQ;AACvC;;;ACSA,eAAsB,WAAA,CAAY,IAAA,GAA2B,EAAC,EAA0B;AACtF,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,OAAA,CAAQ,GAAA;AAEhC,EAAA,IAAI,KAAK,MAAA,EAAQ;AACf,IAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAQ,QAAQ,MAAA,EAAO;AAAA,EAC/C;AAEA,EAAA,IAAI,IAAI,YAAA,EAAc;AACpB,IAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,CAAI,YAAA,EAAc,QAAQ,KAAA,EAAM;AAAA,EACnD;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,eAAA,CAAgB,GAAG,CAAA;AACtC,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,aAAA;AACzC,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,QAAA,CAAS,WAAW,CAAA;AACzC,EAAA,IAAI,OAAA,IAAW,QAAQ,MAAA,EAAQ;AAC7B,IAAA,OAAO;AAAA,MACL,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,WAAA;AAAA,MACT,WAAA,EAAa;AAAA,KACf;AAAA,EACF;AAEA,EAAA,MAAM,IAAI,QAAA,CAAS,YAAA,EAAc,yDAAyD,CAAA;AAC5F;AAMA,eAAsB,mBAAA,CACpB,IAAA,GAA2B,EAAC,EACE;AAC9B,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,YAAY,IAAI,CAAA;AAAA,EAC/B,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,GAAA,YAAe,QAAA,IAAY,GAAA,CAAI,IAAA,KAAS,cAAc,OAAO,IAAA;AACjE,IAAA,MAAM,GAAA;AAAA,EACR;AACF;ACpDO,SAAS,iBAAiB,IAAA,EAA+B;AAC9D,EAAA,OAAO,IAAIC,SAAA,CAAK;AAAA,IACd,MAAA,EAAQ,KAAK,IAAA,CAAK,MAAA;AAAA,IAClB,SAAS,IAAA,CAAK;AAAA,GACf,CAAA;AACH;;;ACqBA,eAAe,UAAU,IAAA,EAA2C;AAClE,EAAA,IAAI,IAAA,CAAK,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA;AAC3B,EAAA,MAAM,IAAA,GAAO,MAAM,WAAA,CAAY;AAAA,IAC7B,GAAI,KAAK,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAO,GAAI,EAAC;AAAA,IAC3D,GAAI,KAAK,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,IAAA,CAAK,OAAA,EAAQ,GAAI;AAAC,GAC/D,CAAA;AACD,EAAA,OAAO,gBAAA,CAAiB;AAAA,IACtB,IAAA;AAAA,IACA,GAAI,KAAK,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,IAAA,CAAK,OAAA,EAAQ,GAAI;AAAC,GAC/D,CAAA;AACH;AAaA,SAAS,wBAAwB,IAAA,EAAiE;AAChG,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,IAAI,CAAC,IAAA,CAAK,UAAA,EAAY,OAAA,CAAQ,KAAK,eAAe,CAAA;AAClD,EAAA,IAAI,CAAC,IAAA,CAAK,OAAA,EAAS,OAAA,CAAQ,KAAK,YAAY,CAAA;AAC5C,EAAA,IAAI,CAAC,IAAA,CAAK,cAAA,EAAgB,OAAA,CAAQ,KAAK,mBAAmB,CAAA;AAC1D,EAAA,IAAI,CAAC,IAAA,CAAK,UAAA,EAAY,OAAA,CAAQ,KAAK,eAAe,CAAA;AAClD,EAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,IAAA,MAAM,IAAI,SAAS,eAAA,EAAiB,CAAA,6BAAA,EAAgC,QAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EAC1F;AACF;AAEA,eAAsB,qBAAqB,IAAA,EAA6C;AACtF,EAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,IAAI,CAAA;AAEjC,EAAA,MAAM,QAAA,GAAqB;AAAA,IACzB,MAAM,IAAA,CAAK,YAAA;AAAA,IACX,OAAO,IAAA,CAAK,aAAA;AAAA,IACZ,UAAU,IAAA,CAAK,gBAAA;AAAA,IACf,OAAO,IAAA,CAAK;AAAA,GACd;AAEA,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,WAAW,IAAA,CAAK,SAAA;AAAA,IAChB,eAAe,IAAA,CAAK,IAAA;AAAA,IACpB,QAAA;AAAA,IACA,gBAAgB,IAAA,CAAK,cAAA;AAAA,IACrB,gBAAgB,IAAA,CAAK;AAAA,GACvB;AAEA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,IAAA,CAAK,SAAS,aAAA,EAAe;AAC/B,IAAA,uBAAA,CAAwB,IAAI,CAAA;AAC5B,IAAA,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO;AAAA,MACjC,GAAG,IAAA;AAAA,MACH,QAAA,EAAU;AAAA,QACR,YAAY,IAAA,CAAK,UAAA;AAAA,QACjB,KAAK,IAAA,CAAK,OAAA;AAAA,QACV,gBAAgB,IAAA,CAAK,cAAA;AAAA,QACrB,YAAY,IAAA,CAAK,UAAA;AAAA,QACjB,YAAA,EAAc,KAAK,YAAA,IAAgB;AAAA;AACrC,KACD,CAAA;AAAA,EACH,CAAA,MAAO;AACL,IAAA,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,IAAI,CAAA;AAAA,EACzC;AAEA,EAAA,WAAA,CAAY,QAAQ,EAAE,GAAG,IAAA,EAAM,WAAA,EAAa,cAAc,CAAA;AAC1D,EAAA,OAAO,MAAA;AACT;AAEA,eAAsB,kBAAkB,IAAA,EAA2C;AACjF,EAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,IAAI,CAAA;AACjC,EAAA,MAAM,SAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,KAAK,EAAE,CAAA;AAC7C,EAAA,WAAA,CAAY,QAAQ,EAAE,GAAG,IAAA,EAAM,WAAA,EAAa,cAAc,CAAA;AAC1D,EAAA,OAAO,MAAA;AACT;AAEA,eAAsB,qBAAqB,IAAA,EAA6C;AACtF,EAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,IAAI,CAAA;AACjC,EAAA,MAAM,SAA6B,EAAC;AACpC,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,MAAA,EAAW,MAAA,CAAO,SAAS,IAAA,CAAK,MAAA;AACpD,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,MAAA,EAAW,MAAA,CAAO,SAAS,IAAA,CAAK,MAAA;AACpD,EAAA,IAAI,IAAA,CAAK,cAAA,KAAmB,MAAA,EAAW,MAAA,CAAO,iBAAiB,IAAA,CAAK,cAAA;AACpE,EAAA,MAAM,SAAS,MAAM,IAAA,CAAK,QAAQ,MAAA,CAAO,IAAA,CAAK,IAAI,MAAM,CAAA;AACxD,EAAA,WAAA,CAAY,QAAQ,EAAE,GAAG,IAAA,EAAM,WAAA,EAAa,cAAc,CAAA;AAC1D,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,aAAa,MAAA,EAAwB;AAC5C,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,CAAA,OAAA,EAAU,OAAO,EAAE,CAAA,CAAA;AAAA,IACnB,CAAA,WAAA,EAAc,OAAO,MAAM,CAAA,CAAA;AAAA,IAC3B,CAAA,WAAA,EAAc,OAAO,MAAM,CAAA,CAAA;AAAA,IAC3B,CAAA,WAAA,EAAc,OAAO,eAAe,CAAA,CAAA;AAAA,IACpC,CAAA,WAAA,EAAc,OAAO,IAAI,CAAA;AAAA,GAC3B;AACA,EAAA,IAAI,OAAO,QAAA,EAAU,KAAA,CAAM,KAAK,CAAA,YAAA,EAAe,MAAA,CAAO,QAAQ,CAAA,CAAE,CAAA;AAChE,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AC3FA,eAAsB,aAAA,CAAc,IAAA,GAAsB,EAAC,EAA0B;AACnF,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,IAAQT,UAAAA,EAAQ;AAClC,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,IAAO,OAAA,CAAQ,GAAA,EAAI;AACpC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,IAAYU,WAAA,EAAS;AAEvC,EAAA,MAAM,WAAA,GAAc,MAAM,iBAAA,CAAkB,IAAI,CAAA;AAChD,EAAA,MAAM,GAAA,GAAM,MAAM,SAAA,CAAU,IAAI,CAAA;AAChC,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,IAAA,EAAM,GAAA,EAAK,IAAI,CAAA;AAE3C,EAAA,MAAM,MAAA,GAAuB;AAAA,IAC3B,GAAA,EAAK,EAAE,OAAA,EAAS,WAAA,EAAY;AAAA,IAC5B,GAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,WAAA,CAAY,QAAQ,EAAE,GAAG,IAAA,EAAM,WAAA,EAAa,cAAc,CAAA;AAC1D,EAAA,OAAO,MAAA;AACT;AAEA,eAAe,kBAAkB,IAAA,EAA2D;AAC1F,EAAA,MAAM,OAAO,eAAA,EAAgB;AAC7B,EAAA,MAAM,QAAA,GAAW,MAAM,mBAAA,CAAoB;AAAA,IACzC,GAAI,KAAK,MAAA,KAAW,MAAA,GAAY,EAAE,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAO,GAAI,EAAC;AAAA,IAC3D,GAAI,KAAK,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,IAAA,CAAK,OAAA,EAAQ,GAAI;AAAC,GAC/D,CAAA;AAED,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAO;AAAA,EAChC;AAEA,EAAA,MAAM,GAAA,GAAmC,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAS,MAAA,EAAO;AACzE,EAAA,IAAI,QAAA,CAAS,OAAA,EAAS,GAAA,CAAI,OAAA,GAAU,QAAA,CAAS,OAAA;AAE7C,EAAA,IAAI,QAAA,CAAS,WAAW,MAAA,EAAQ;AAC9B,IAAA,MAAM,IAAA,GAAO,MAAM,mBAAA,EAAoB;AACvC,IAAA,IAAI,SAAS,IAAA,EAAM;AACjB,MAAA,GAAA,CAAI,QAAA,GAAW,CAAA,CAAA,EAAI,IAAA,CAAK,QAAA,CAAS,CAAC,CAAC,CAAA,CAAA;AACnC,MAAA,IAAI,SAAS,GAAA,EAAO;AAClB,QAAA,GAAA,CAAI,OAAA,GAAU,CAAA,0BAAA,EAA6B,IAAA,CAAK,QAAA,CAAS,CAAC,CAAC,CAAA,eAAA,CAAA;AAAA,MAC7D;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,GAAA;AACT;AAEA,eAAe,UAAU,IAAA,EAAmD;AAC1E,EAAA,MAAM,GAAA,GAAM,KAAK,OAAA,IAAW,qBAAA;AAC5B,EAAA,MAAM,IAAA,GACJ,IAAA,CAAK,IAAA,IACL,IAAID,SAAAA,CAAK;AAAA,IACP,GAAI,KAAK,OAAA,KAAY,MAAA,GAAY,EAAE,OAAA,EAAS,IAAA,CAAK,OAAA,EAAQ,GAAI;AAAC,GAC/D,CAAA;AAEH,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,IAAA,CAAK,GAAA,EAAI;AACjC,IAAA,OAAO,EAAE,SAAA,EAAW,IAAA,EAAM,GAAA,EAAK,OAAA,EAAS,KAAK,OAAA,EAAQ;AAAA,EACvD,SAAS,GAAA,EAAK;AACZ,IAAA,OAAO;AAAA,MACL,SAAA,EAAW,KAAA;AAAA,MACX,GAAA;AAAA,MACA,OAAO,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,KACxD;AAAA,EACF;AACF;AAEA,SAAS,YAAA,CAAa,IAAA,EAAc,GAAA,EAAa,IAAA,EAA+C;AAC9F,EAAA,OAAO;AAAA,IACL,UAAA,EAAYE,aAAA,CAAWZ,SAAAA,CAAK,IAAA,EAAM,SAAS,CAAC,CAAA;AAAA,IAC5C,MAAA,EAAQY,aAAA,CAAWZ,SAAAA,CAAK,IAAA,EAAM,SAAS,CAAC,CAAA;AAAA,IACxC,KAAA,EAAOY,aAAA,CAAWZ,SAAAA,CAAK,IAAA,EAAM,QAAQ,CAAC,CAAA;AAAA,IACtC,QAAA,EAAUY,aAAA,CAAWZ,SAAAA,CAAK,IAAA,EAAM,WAAW,CAAC,CAAA;AAAA,IAC5C,aAAA,EAAeY,aAAA,CAAW,uBAAA,CAAwB,IAAA,EAAM,IAAI,CAAC,CAAA;AAAA,IAC7D,gBAAgBA,aAAA,CAAWZ,SAAAA,CAAK,GAAA,EAAK,SAAA,EAAW,UAAU,CAAC;AAAA,GAC7D;AACF;AAEA,SAAS,uBAAA,CAAwB,MAAc,IAAA,EAA+B;AAC5E,EAAA,IAAI,SAAS,QAAA,EAAU;AACrB,IAAA,OAAOA,SAAAA,CAAK,IAAA,EAAM,SAAA,EAAW,qBAAA,EAAuB,UAAU,4BAA4B,CAAA;AAAA,EAC5F;AACA,EAAA,IAAI,SAAS,OAAA,EAAS;AACpB,IAAA,OAAOA,SAAAA,CAAK,IAAA,EAAM,SAAA,EAAW,SAAA,EAAW,UAAU,4BAA4B,CAAA;AAAA,EAChF;AACA,EAAA,OAAOA,SAAAA,CAAK,IAAA,EAAM,SAAA,EAAW,QAAA,EAAU,4BAA4B,CAAA;AACrE;AAEA,SAAS,aAAa,CAAA,EAAyB;AAC7C,EAAA,MAAM,KAAA,GAAQ,CAAC,EAAA,KAAiB,EAAA,GAAK,KAAA,GAAQ,KAAA;AAC7C,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,CAAA,mBAAA,EAAsB,CAAA,CAAE,GAAA,CAAI,OAAO,CAAA,CAAA;AAAA,IACnC,iBAAiB,CAAA,CAAE,GAAA,CAAI,YAAY,CAAA,WAAA,EAAc,CAAA,CAAE,IAAI,GAAG,CAAA,UAAA,EAAa,CAAA,CAAE,GAAA,CAAI,WAAW,GAAG,CAAA,CAAA,CAAA,GAAM,gBAAgB,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,CAAA,CAAG,CAAA,CAAA;AAAA,IAC7H,EAAE,GAAA,CAAI,KAAA,GAAQ,iBAAiB,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA,CAAA,GAAK,MAAA;AAAA,IAC/C,CAAA,qBAAA,EAAwB,EAAE,WAAA,CAAY,MAAM,GAAG,CAAA,CAAE,WAAA,CAAY,OAAA,GAAU,CAAA,SAAA,EAAY,CAAA,CAAE,WAAA,CAAY,OAAO,CAAA,CAAA,GAAK,EAAE,CAAA,EAAG,CAAA,CAAE,WAAA,CAAY,QAAA,GAAW,SAAS,CAAA,CAAE,WAAA,CAAY,QAAQ,CAAA,CAAA,GAAK,EAAE,CAAA,CAAA;AAAA,IACjL,EAAE,WAAA,CAAY,OAAA,GAAU,wBAAmB,CAAA,CAAE,WAAA,CAAY,OAAO,CAAA,CAAA,GAAK,MAAA;AAAA,IACrE,EAAA;AAAA,IACA,kBAAA;AAAA,IACA,CAAA,kBAAA,EAAqB,KAAA,CAAM,CAAA,CAAE,MAAA,CAAO,UAAU,CAAC,CAAA,CAAA;AAAA,IAC/C,CAAA,kBAAA,EAAqB,KAAA,CAAM,CAAA,CAAE,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AAAA,IAC3C,CAAA,kBAAA,EAAqB,KAAA,CAAM,CAAA,CAAE,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAAA,IAC1C,CAAA,kBAAA,EAAqB,KAAA,CAAM,CAAA,CAAE,MAAA,CAAO,QAAQ,CAAC,CAAA,CAAA;AAAA,IAC7C,CAAA,kBAAA,EAAqB,KAAA,CAAM,CAAA,CAAE,MAAA,CAAO,aAAa,CAAC,CAAA,CAAA;AAAA,IAClD,CAAA,kBAAA,EAAqB,KAAA,CAAM,CAAA,CAAE,MAAA,CAAO,cAAc,CAAC,CAAA,0BAAA;AAAA,GACrD,CAAE,MAAA,CAAO,CAAC,CAAA,KAAmB,MAAM,MAAS,CAAA;AAC5C,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AC/IA,eAAsB,YAAA,CAAa,IAAA,GAAqB,EAAC,EAAiC;AACxF,EAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,SAAA;AAIhC,EAAA,MAAM,SACJ,IAAA,CAAK,MAAA,IACJ,MAAM,OAAO,mBAAmB,CAAA,CAC9B,IAAA;AAAA,IAAK,CAAC,EAAE,QAAA,EAAS,KAChB,QAAA,CAAS;AAAA,MACP,OAAA,EAAS,sDAAA;AAAA,MACT,IAAA,EAAM;AAAA,KACP;AAAA,GACH,CACC,MAAM,MAAM;AACX,IAAA,MAAM,IAAI,QAAA,CAAS,gBAAA,EAAkB,kBAAkB,CAAA;AAAA,EACzD,CAAC,CAAA;AAEL,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,gCAAA,CAAiC,IAAA,CAAK,MAAM,CAAA,EAAG;AAC7D,IAAA,MAAM,IAAI,QAAA,CAAS,eAAA,EAAiB,wDAAwD,CAAA;AAAA,EAC9F;AAEA,EAAA,WAAA,CAAY,oCAAoC,IAAI,CAAA;AACpD,EAAA,MAAM,IAAA,GAAO,IAAIU,SAAAA,CAAK,EAAE,QAAQ,OAAA,EAAS,IAAA,CAAK,SAAS,CAAA;AAOvD,EAAA,MAAM,IAAA,CAAK,KAAK,GAAA,EAAI;AAEpB,EAAA,MAAM,IAAA,GAAO,MAAM,eAAA,EAAgB;AACnC,EAAA,MAAM,UAAU,aAAA,CAAc,IAAA,EAAM,OAAA,EAAS,EAAE,QAAQ,CAAA;AACvD,EAAA,MAAM,gBAAgB,OAAO,CAAA;AAE7B,EAAA,YAAA,CAAa,CAAA,eAAA,EAAkB,OAAO,CAAA,oCAAA,CAAA,EAAwC,IAAI,CAAA;AAClF,EAAA,OAAO,EAAE,OAAA,EAAQ;AACnB;;;AC1CA,eAAsB,aAAA,CAAc,IAAA,GAAsB,EAAC,EAAiC;AAC1F,EAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACjB,IAAA,MAAM,iBAAA,EAAkB;AACxB,IAAA,YAAA,CAAa,kCAAkC,IAAI,CAAA;AACnD,IAAA,OAAO,EAAE,SAAS,KAAA,EAAM;AAAA,EAC1B;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,eAAA,EAAgB;AACnC,EAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,OAAO,CAAA,EAAG;AAChC,IAAA,MAAM,IAAI,QAAA,CAAS,WAAA,EAAa,CAAA,SAAA,EAAY,IAAA,CAAK,OAAO,CAAA,YAAA,CAAc,CAAA;AAAA,EACxE;AAEA,EAAA,MAAM,EAAE,CAAC,IAAA,CAAK,OAAO,GAAG,QAAA,EAAU,GAAG,IAAA,EAAK,GAAI,IAAA,CAAK,QAAA;AAMnD,EAAA,IAAI,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,WAAW,CAAA,EAAG;AAClC,IAAA,MAAM,iBAAA,EAAkB;AACxB,IAAA,YAAA,CAAa,CAAA,SAAA,EAAY,IAAA,CAAK,OAAO,CAAA,qCAAA,CAAA,EAAyC,IAAI,CAAA;AAClF,IAAA,OAAO,EAAE,OAAA,EAAS,IAAA,CAAK,OAAA,EAAQ;AAAA,EACjC;AAEA,EAAA,MAAM,UAAA,GACJ,IAAA,CAAK,aAAA,KAAkB,IAAA,CAAK,OAAA,GAAU,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,CAAC,CAAA,GAAK,IAAA,CAAK,aAAA;AAErE,EAAA,MAAM,eAAA,CAAgB,EAAE,GAAG,IAAA,EAAM,eAAe,UAAA,EAAY,QAAA,EAAU,MAAM,CAAA;AAC5E,EAAA,YAAA,CAAa,CAAA,SAAA,EAAY,IAAA,CAAK,OAAO,CAAA,UAAA,CAAA,EAAc,IAAI,CAAA;AACvD,EAAA,OAAO,EAAE,OAAA,EAAS,IAAA,CAAK,OAAA,EAAQ;AACjC;;;ACVO,SAAS,QAAA,GAAoB;AAClC,EAAA,MAAM,OAAA,GAAU,IAAIG,iBAAA,EAAQ;AAE5B,EAAA,OAAA,CACG,KAAK,MAAM,CAAA,CACX,WAAA,CAAY,sDAAsD,EAClE,OAAA,CAAQ,WAAA,EAAa,eAAe,CAAA,CACpC,UAAU,IAAIC,gBAAA,CAAO,mBAAmB,mDAAmD,CAAC,EAC5F,SAAA,CAAU,IAAIA,gBAAA,CAAO,sBAAA,EAAwB,0BAA0B,CAAC,CAAA,CACxE,SAAA,CAAU,IAAIA,iBAAO,QAAA,EAAU,8CAA8C,CAAC,CAAA,CAC9E,UAAU,IAAIA,gBAAA,CAAO,eAAe,uDAAuD,CAAC,EAC5F,kBAAA,EAAmB;AAGtB,EAAA,OAAA,CACG,QAAQ,OAAO,CAAA,CACf,WAAA,CAAY,6CAA6C,EACzD,MAAA,CAAO,iBAAA,EAAmB,yCAAyC,CAAA,CACnE,OAAO,sBAAA,EAAwB,6BAAA,EAA+B,SAAS,CAAA,CACvE,MAAA,CAAO,OAAO,OAAA,KAAkD;AAC/D,IAAA,MAAM,IAAA,GAAO,iBAAiB,OAAO,CAAA;AACrC,IAAA,MAAM,YAAA,CAAa;AAAA,MACjB,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,SAAS,OAAA,CAAQ,OAAA;AAAA,MACjB,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,OAAO,IAAA,CAAK;AAAA,KACb,EAAE,KAAA,CAAM,CAAC,QAAQ,iBAAA,CAAkB,GAAA,EAAK,IAAI,CAAC,CAAA;AAAA,EAChD,CAAC,CAAA;AAGH,EAAA,OAAA,CACG,OAAA,CAAQ,QAAQ,CAAA,CAChB,WAAA,CAAY,0BAA0B,CAAA,CACtC,MAAA,CAAO,sBAAA,EAAwB,oDAAoD,CAAA,CACnF,MAAA,CAAO,OAAO,OAAA,KAAkC;AAC/C,IAAA,MAAM,IAAA,GAAO,iBAAiB,OAAO,CAAA;AACrC,IAAA,MAAM,aAAA,CAAc;AAAA,MAClB,SAAS,OAAA,CAAQ,OAAA;AAAA,MACjB,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,OAAO,IAAA,CAAK;AAAA,KACb,EAAE,KAAA,CAAM,CAAC,QAAQ,iBAAA,CAAkB,GAAA,EAAK,IAAI,CAAC,CAAA;AAAA,EAChD,CAAC,CAAA;AAGH,EAAA,MAAM,OAAO,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA,CAAE,YAAY,6BAA6B,CAAA;AAC9E,EAAA,IAAA,CACG,OAAA,CAAQ,kBAAkB,CAAA,CAC1B,WAAA,CAAY,oCAAoC,CAAA,CAChD,MAAA,CAAO,OAAO,OAAA,KAAoB;AACjC,IAAA,MAAM,IAAA,GAAO,iBAAiB,OAAO,CAAA;AACrC,IAAA,MAAM,iBAAA,CAAkB,EAAE,OAAA,EAAS,IAAA,EAAM,IAAA,CAAK,MAAM,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,CAAA,CAAE,KAAA;AAAA,MAAM,CAAC,GAAA,KAC9E,iBAAA,CAAkB,GAAA,EAAK,IAAI;AAAA,KAC7B;AAAA,EACF,CAAC,CAAA;AAGH,EAAA,MAAM,UAAU,OAAA,CAAQ,OAAA,CAAQ,SAAS,CAAA,CAAE,YAAY,mCAAmC,CAAA;AAE1F,EAAA,OAAA,CACG,OAAA,CAAQ,QAAQ,CAAA,CAChB,WAAA,CAAY,+CAA+C,CAAA,CAC3D,cAAA,CAAe,iBAAiB,4CAA4C,CAAA,CAC5E,eAAe,qBAAA,EAAuB,cAAc,EACpD,cAAA,CAAe,wBAAA,EAA0B,oBAAoB,CAAA,CAC7D,cAAA,CAAe,0BAAA,EAA4B,gBAAgB,CAAA,CAC3D,cAAA;AAAA,IACC,gCAAA;AAAA,IACA;AAAA,IAED,cAAA,CAAe,0BAAA,EAA4B,4CAA4C,CAAA,CACvF,MAAA,CAAO,0BAA0B,+CAA+C,CAAA,CAChF,OAAO,kBAAA,EAAoB,iBAAiB,EAC5C,MAAA,CAAO,6BAAA,EAA+B,uCAAuC,CAAA,CAC7E,MAAA,CAAO,wBAAwB,yBAAyB,CAAA,CACxD,MAAA,CAAO,oBAAA,EAAsB,iCAAiC,CAAC,CAAA,KAAM,SAAS,CAAA,EAAG,EAAE,GAAG,CAAC,CAAA,CACvF,OAAO,0BAAA,EAA4B,2CAA2C,EAC9E,MAAA,CAAO,yBAAA,EAA2B,6CAA6C,CAAA,CAC/E,MAAA,CAAO,OAAO,OAAA,KAAY;AACzB,IAAA,MAAM,IAAA,GAAO,iBAAiB,OAAO,CAAA;AACrC,IAAA,MAAM,oBAAA,CAAqB;AAAA,MACzB,GAAG,IAAA;AAAA,MACH,IAAA,EAAM,kBAAA,CAAmB,OAAA,CAAQ,IAAI,CAAA;AAAA,MACrC,WAAW,OAAA,CAAQ,SAAA;AAAA,MACnB,cAAc,OAAA,CAAQ,YAAA;AAAA,MACtB,eAAe,OAAA,CAAQ,aAAA;AAAA,MACvB,kBAAkB,OAAA,CAAQ,gBAAA;AAAA,MAC1B,eAAe,OAAA,CAAQ,aAAA;AAAA,MACvB,YAAY,OAAA,CAAQ,UAAA;AAAA,MACpB,SAAS,OAAA,CAAQ,OAAA;AAAA,MACjB,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,YAAY,OAAA,CAAQ,UAAA;AAAA,MACpB,cAAc,OAAA,CAAQ,YAAA;AAAA,MACtB,gBAAgB,OAAA,CAAQ,cAAA;AAAA,MACxB,gBAAgB,OAAA,CAAQ;AAAA,KACzB,EAAE,KAAA,CAAM,CAAC,QAAQ,iBAAA,CAAkB,GAAA,EAAK,IAAI,CAAC,CAAA;AAAA,EAChD,CAAC,CAAA;AAEH,EAAA,OAAA,CACG,OAAA,CAAQ,UAAU,CAAA,CAClB,WAAA,CAAY,6BAA6B,CAAA,CACzC,MAAA,CAAO,OAAO,EAAA,KAAe;AAC5B,IAAA,MAAM,IAAA,GAAO,iBAAiB,OAAO,CAAA;AACrC,IAAA,MAAM,iBAAA,CAAkB,EAAE,GAAG,IAAA,EAAM,IAAI,OAAA,CAAQ,EAAE,CAAA,EAAG,CAAA,CAAE,KAAA;AAAA,MAAM,CAAC,GAAA,KAC3D,iBAAA,CAAkB,GAAA,EAAK,IAAI;AAAA,KAC7B;AAAA,EACF,CAAC,CAAA;AAEH,EAAA,OAAA,CACG,OAAA,CAAQ,aAAa,CAAA,CACrB,WAAA,CAAY,mCAAmC,CAAA,CAC/C,MAAA,CAAO,qBAAA,EAAuB,mCAAA,EAAqC,CAAC,CAAA,KAAM,QAAA,CAAS,CAAA,EAAG,EAAE,CAAC,CAAA,CACzF,MAAA,CAAO,iBAAA,EAAmB,wBAAwB,CAAA,CAClD,MAAA,CAAO,yBAAA,EAA2B,6CAA6C,CAAA,CAC/E,MAAA,CAAO,OAAO,EAAA,EAAY,OAAA,KAAY;AACrC,IAAA,MAAM,IAAA,GAAO,iBAAiB,OAAO,CAAA;AACrC,IAAA,MAAM,oBAAA,CAAqB;AAAA,MACzB,GAAG,IAAA;AAAA,MACH,EAAA,EAAI,QAAQ,EAAE,CAAA;AAAA,MACd,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,gBAAgB,OAAA,CAAQ;AAAA,KACzB,EAAE,KAAA,CAAM,CAAC,QAAQ,iBAAA,CAAkB,GAAA,EAAK,IAAI,CAAC,CAAA;AAAA,EAChD,CAAC,CAAA;AAGH,EAAA,OAAA,CACG,QAAQ,QAAQ,CAAA,CAChB,YAAY,wBAAwB,CAAA,CACpC,OAAO,YAAY;AAClB,IAAA,MAAM,IAAA,GAAO,iBAAiB,OAAO,CAAA;AACrC,IAAA,MAAM,aAAA,CAAc,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ,iBAAA,CAAkB,GAAA,EAAK,IAAI,CAAC,CAAA;AAAA,EACvE,CAAC,CAAA;AAEH,EAAA,OAAO,OAAA;AACT;AAQA,SAAS,iBAAiB,OAAA,EAAsC;AAC9D,EAAA,MAAM,CAAA,GAAI,QAAQ,IAAA,EAAkB;AACpC,EAAA,MAAM,MAA0B,EAAC;AACjC,EAAA,IAAI,CAAA,CAAE,MAAA,EAAQ,GAAA,CAAI,MAAA,GAAS,CAAA,CAAE,MAAA;AAC7B,EAAA,IAAI,CAAA,CAAE,OAAA,EAAS,GAAA,CAAI,OAAA,GAAU,CAAA,CAAE,OAAA;AAC/B,EAAA,IAAI,CAAA,CAAE,IAAA,EAAM,GAAA,CAAI,IAAA,GAAO,MAAA;AACvB,EAAA,IAAI,CAAA,CAAE,KAAA,EAAO,GAAA,CAAI,KAAA,GAAQ,IAAA;AACzB,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,mBAAmB,GAAA,EAA4B;AACtD,EAAA,IAAI,QAAQ,KAAA,IAAS,GAAA,KAAQ,aAAA,IAAiB,GAAA,KAAQ,UAAU,OAAO,GAAA;AACvE,EAAA,MAAM,IAAI,QAAA;AAAA,IACR,eAAA;AAAA,IACA,0DAA0D,GAAG,CAAA,EAAA;AAAA,GAC/D;AACF;AAEA,SAAS,QAAQ,GAAA,EAAqB;AACpC,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,QAAA,CAAS,GAAA,EAAK,EAAE,CAAA;AAClC,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,EAAE,CAAA,IAAK,MAAM,CAAA,EAAG;AACnC,IAAA,MAAM,IAAI,QAAA,CAAS,eAAA,EAAiB,CAAA,2CAAA,EAA8C,GAAG,CAAA,EAAA,CAAI,CAAA;AAAA,EAC3F;AACA,EAAA,OAAO,EAAA;AACT;AAGA,eAAsB,IAAA,CAAK,IAAA,GAAiB,OAAA,CAAQ,IAAA,EAAqB;AACvE,EAAA,MAAM,UAAU,QAAA,EAAS;AACzB,EAAA,MAAM,OAAA,CAAQ,WAAW,IAAI,CAAA;AAC/B;AAMA,IAAA,GAAO,KAAA,CAAM,CAAC,GAAA,KAAQ,iBAAA,CAAkB,GAAG,CAAC,CAAA","file":"index.cjs","sourcesContent":["/**\n * CLI version.\n *\n * Kept as a plain string so `bun build --compile` can inline it at compile time\n * and the resulting binary has no runtime dependency on `package.json`.\n * The release workflow bumps this in lockstep with `package.json` on `v*` tags.\n */\nexport const CLI_VERSION = '0.1.2';\n","/**\n * CLI error model. All user-visible failures flow through these types so that\n * the output layer can render them consistently — pretty with a red prefix in\n * TTY mode, strict `{\"error\":{\"code\",\"message\"}}` on stdout + exit 1 in JSON mode.\n */\n\nimport { GaruError } from '@garuhq/node';\n\nexport type CliErrorCode =\n | 'auth_error'\n | 'not_found'\n | 'validation_error'\n | 'rate_limited'\n | 'server_error'\n | 'connection_error'\n | 'signature_verification_failed'\n | 'user_cancelled'\n | 'invalid_input'\n | 'unknown_error';\n\nexport class CliError extends Error {\n public readonly code: CliErrorCode;\n public readonly exitCode: number;\n\n constructor(code: CliErrorCode, message: string, exitCode = 1) {\n super(message);\n this.name = 'CliError';\n this.code = code;\n this.exitCode = exitCode;\n }\n}\n\n/** Wrap an unknown thrown value as a {@link CliError}. */\nexport function toCliError(err: unknown): CliError {\n if (err instanceof CliError) return err;\n if (err instanceof GaruError) {\n return new CliError(mapSdkCodeToCliCode(err.code), err.message, 1);\n }\n if (err instanceof Error) return new CliError('unknown_error', err.message);\n return new CliError('unknown_error', String(err));\n}\n\nfunction mapSdkCodeToCliCode(sdkCode: string): CliErrorCode {\n switch (sdkCode) {\n case 'authentication_error':\n case 'permission_error':\n return 'auth_error';\n case 'not_found':\n return 'not_found';\n case 'validation_error':\n return 'validation_error';\n case 'rate_limited':\n return 'rate_limited';\n case 'server_error':\n return 'server_error';\n case 'connection_error':\n return 'connection_error';\n case 'signature_verification_failed':\n return 'signature_verification_failed';\n default:\n return 'unknown_error';\n }\n}\n","import { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport { mkdir, readFile, writeFile, rm, stat } from 'node:fs/promises';\n\nimport { CliError } from './errors.js';\n\nexport interface CredentialProfile {\n apiKey: string;\n /** Optional seller ID to render in `garu doctor` output. */\n sellerId?: number;\n /** Human-readable label for multi-profile setups. */\n label?: string;\n}\n\nexport interface CredentialsFile {\n version: 1;\n activeProfile: string;\n profiles: Record<string, CredentialProfile>;\n}\n\nconst DEFAULT_FILE: CredentialsFile = {\n version: 1,\n activeProfile: 'default',\n profiles: {}\n};\n\n/**\n * Resolve the credentials file path.\n *\n * Honors `$XDG_CONFIG_HOME` per the XDG base-dir spec, falling back to\n * `~/.config/garu/credentials.json`. Override with `$GARU_CREDENTIALS_PATH`\n * (primarily for tests).\n */\nexport function credentialsPath(env: NodeJS.ProcessEnv = process.env): string {\n if (env.GARU_CREDENTIALS_PATH) return env.GARU_CREDENTIALS_PATH;\n const base = env.XDG_CONFIG_HOME || join(homedir(), '.config');\n return join(base, 'garu', 'credentials.json');\n}\n\n/** Read the credentials file. Returns the default (empty) file if it doesn't exist. */\nexport async function loadCredentials(\n env: NodeJS.ProcessEnv = process.env\n): Promise<CredentialsFile> {\n const path = credentialsPath(env);\n try {\n const raw = await readFile(path, 'utf8');\n const parsed = JSON.parse(raw);\n return normalize(parsed);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { ...DEFAULT_FILE };\n }\n throw new CliError(\n 'invalid_input',\n `Failed to read credentials at ${path}: ${(err as Error).message}`\n );\n }\n}\n\n/**\n * Write the credentials file atomically with tight file-mode (0600) and\n * directory-mode (0700).\n */\nexport async function saveCredentials(\n file: CredentialsFile,\n env: NodeJS.ProcessEnv = process.env\n): Promise<void> {\n const path = credentialsPath(env);\n await mkdir(dirname(path), { recursive: true, mode: 0o700 });\n await writeFile(path, JSON.stringify(file, null, 2) + '\\n', { mode: 0o600 });\n}\n\n/** Delete the credentials file. No-op if it doesn't exist. */\nexport async function deleteCredentials(env: NodeJS.ProcessEnv = process.env): Promise<void> {\n const path = credentialsPath(env);\n try {\n await rm(path);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n}\n\n/** Add or replace a profile and set it active. */\nexport function upsertProfile(\n file: CredentialsFile,\n name: string,\n profile: CredentialProfile\n): CredentialsFile {\n return {\n ...file,\n activeProfile: name,\n profiles: { ...file.profiles, [name]: profile }\n };\n}\n\n/** Check whether the credentials file has the expected 0600 mode. Returns null on any error. */\nexport async function credentialsFileMode(\n env: NodeJS.ProcessEnv = process.env\n): Promise<number | null> {\n try {\n const s = await stat(credentialsPath(env));\n return s.mode & 0o777;\n } catch {\n return null;\n }\n}\n\nfunction normalize(raw: unknown): CredentialsFile {\n if (!raw || typeof raw !== 'object') return { ...DEFAULT_FILE };\n const obj = raw as Partial<CredentialsFile>;\n return {\n version: 1,\n activeProfile: obj.activeProfile ?? 'default',\n profiles: obj.profiles && typeof obj.profiles === 'object' ? obj.profiles : {}\n };\n}\n","import pc from 'picocolors';\n\nimport { CliError, toCliError } from './errors.js';\n\nexport type OutputMode = 'pretty' | 'json';\n\nexport interface OutputOptions {\n /** Force a mode. If omitted, auto-detect from TTY. */\n mode?: OutputMode;\n /** Passed by `--quiet`; suppresses everything except errors and the final value. */\n quiet?: boolean;\n}\n\n/**\n * Resolve the output mode. Rules:\n * - Explicit `--json` (or `opts.mode === 'json'`) wins.\n * - Non-TTY stdout (pipe, CI) → `json`.\n * - Everything else → `pretty`.\n */\nexport function resolveMode(\n opts: OutputOptions = {},\n stdout: NodeJS.WriteStream = process.stdout\n): OutputMode {\n if (opts.mode) return opts.mode;\n return stdout.isTTY ? 'pretty' : 'json';\n}\n\n/**\n * Print a successful command result. In JSON mode the full object is written\n * to stdout with a trailing newline. In pretty mode the caller's `prettyPrint`\n * fallback (if provided) is used; otherwise the JSON is indented.\n */\nexport function printResult<T>(\n value: T,\n opts: OutputOptions & { prettyPrint?: (value: T) => string } = {}\n): void {\n const mode = resolveMode(opts);\n if (mode === 'json') {\n process.stdout.write(`${JSON.stringify(value)}\\n`);\n return;\n }\n if (opts.prettyPrint) {\n process.stdout.write(`${opts.prettyPrint(value)}\\n`);\n return;\n }\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\n/** Print a short status line — suppressed in JSON mode and when `--quiet`. */\nexport function printStatus(message: string, opts: OutputOptions = {}): void {\n if (opts.quiet) return;\n if (resolveMode(opts) === 'json') return;\n process.stderr.write(`${pc.dim('→')} ${message}\\n`);\n}\n\n/** Print a success line — suppressed in JSON mode and when `--quiet`. */\nexport function printSuccess(message: string, opts: OutputOptions = {}): void {\n if (opts.quiet) return;\n if (resolveMode(opts) === 'json') return;\n process.stderr.write(`${pc.green('✓')} ${message}\\n`);\n}\n\n/**\n * Print an error and exit with the appropriate code. Always uses the\n * CLI-standard shape `{\"error\":{\"code\",\"message\"}}` on stdout in JSON mode,\n * or a red `Error:` line on stderr in pretty mode.\n */\nexport function printErrorAndExit(err: unknown, opts: OutputOptions = {}): never {\n const cliErr: CliError = toCliError(err);\n const payload = { error: { code: cliErr.code, message: cliErr.message } };\n\n if (resolveMode(opts) === 'json') {\n process.stdout.write(`${JSON.stringify(payload)}\\n`);\n } else {\n process.stderr.write(`${pc.red('Error:')} ${cliErr.message}\\n`);\n if (cliErr.code !== 'unknown_error') {\n process.stderr.write(`${pc.dim(` code: ${cliErr.code}`)}\\n`);\n }\n }\n process.exit(cliErr.exitCode);\n}\n","import { loadCredentials, saveCredentials } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface AuthSwitchOptions extends OutputOptions {\n profile: string;\n}\n\nexport async function authSwitchCommand(\n opts: AuthSwitchOptions\n): Promise<{ activeProfile: string }> {\n const file = await loadCredentials();\n if (!file.profiles[opts.profile]) {\n const available = Object.keys(file.profiles).join(', ') || '(none)';\n throw new CliError('not_found', `Profile '${opts.profile}' not found. Available: ${available}`);\n }\n\n await saveCredentials({ ...file, activeProfile: opts.profile });\n printSuccess(`Active profile set to '${opts.profile}'.`, opts);\n return { activeProfile: opts.profile };\n}\n","import { loadCredentials, type CredentialProfile } from './credentials.js';\nimport { CliError } from './errors.js';\n\nexport interface ResolvedAuth {\n apiKey: string;\n /** Where the key came from, for `doctor` and debug output. */\n source: 'flag' | 'env' | 'file';\n /** Profile name if resolved from file; undefined otherwise. */\n profile?: string;\n fileProfile?: CredentialProfile;\n}\n\nexport interface ResolveAuthOptions {\n /** `--api-key` flag value. Highest precedence. */\n apiKey?: string;\n /** `--profile` flag value. When set, reads that profile instead of the active one. */\n profile?: string;\n env?: NodeJS.ProcessEnv;\n}\n\n/**\n * Resolve the API key following SPEC §7 auth priority:\n *\n * 1. `--api-key` flag\n * 2. `GARU_API_KEY` environment variable\n * 3. credentials file active profile (or profile selected with `--profile`)\n *\n * Throws {@link CliError} with code `auth_error` if no key is found. Never logs.\n */\nexport async function resolveAuth(opts: ResolveAuthOptions = {}): Promise<ResolvedAuth> {\n const env = opts.env ?? process.env;\n\n if (opts.apiKey) {\n return { apiKey: opts.apiKey, source: 'flag' };\n }\n\n if (env.GARU_API_KEY) {\n return { apiKey: env.GARU_API_KEY, source: 'env' };\n }\n\n const file = await loadCredentials(env);\n const profileName = opts.profile ?? file.activeProfile;\n const profile = file.profiles[profileName];\n if (profile && profile.apiKey) {\n return {\n apiKey: profile.apiKey,\n source: 'file',\n profile: profileName,\n fileProfile: profile\n };\n }\n\n throw new CliError('auth_error', 'No API key found. Run `garu login` or set GARU_API_KEY.');\n}\n\n/**\n * Same as {@link resolveAuth} but returns `null` instead of throwing when no\n * credentials are available. Used by `garu doctor`.\n */\nexport async function resolveAuthOptional(\n opts: ResolveAuthOptions = {}\n): Promise<ResolvedAuth | null> {\n try {\n return await resolveAuth(opts);\n } catch (err) {\n if (err instanceof CliError && err.code === 'auth_error') return null;\n throw err;\n }\n}\n","import { Garu } from '@garuhq/node';\n\nimport type { ResolvedAuth } from './auth.js';\n\nexport interface GaruClientOptions {\n auth: ResolvedAuth;\n baseUrl?: string;\n}\n\n/**\n * Construct a `Garu` SDK instance from resolved auth.\n *\n * The CLI dogfoods `@garuhq/node` — every HTTP call flows through the SDK we\n * shipped in Chunk 3. This keeps retries, idempotency, and error mapping\n * consistent between the CLI, MCP server, and any user-written integration.\n */\nexport function createGaruClient(opts: GaruClientOptions): Garu {\n return new Garu({\n apiKey: opts.auth.apiKey,\n baseUrl: opts.baseUrl\n });\n}\n","import type { Charge, Customer, Garu, PaymentMethod, RefundChargeParams } from '@garuhq/node';\n\nimport { resolveAuth } from '../lib/auth.js';\nimport { createGaruClient } from '../lib/client.js';\nimport { CliError } from '../lib/errors.js';\nimport { printResult, type OutputOptions } from '../lib/output.js';\n\nexport interface ChargesGlobalOptions extends OutputOptions {\n apiKey?: string;\n profile?: string;\n baseUrl?: string;\n /** Injectable for tests — bypass auth resolution + SDK construction. */\n garu?: Garu;\n}\n\nexport interface ChargesCreateOptions extends ChargesGlobalOptions {\n type: PaymentMethod;\n productId: string;\n customerName: string;\n customerEmail: string;\n customerDocument: string;\n customerPhone: string;\n cardNumber?: string;\n cardCvv?: string;\n cardExpiration?: string;\n cardHolder?: string;\n installments?: number;\n idempotencyKey?: string;\n additionalInfo?: string;\n}\n\nexport interface ChargesByIdOptions extends ChargesGlobalOptions {\n id: number;\n}\n\nexport interface ChargesRefundOptions extends ChargesByIdOptions {\n /** Amount in centavos. Omit for full refund. */\n amount?: number;\n reason?: string;\n idempotencyKey?: string;\n}\n\nasync function getClient(opts: ChargesGlobalOptions): Promise<Garu> {\n if (opts.garu) return opts.garu;\n const auth = await resolveAuth({\n ...(opts.apiKey !== undefined ? { apiKey: opts.apiKey } : {}),\n ...(opts.profile !== undefined ? { profile: opts.profile } : {})\n });\n return createGaruClient({\n auth,\n ...(opts.baseUrl !== undefined ? { baseUrl: opts.baseUrl } : {})\n });\n}\n\ntype ValidatedCardFields = ChargesCreateOptions & {\n cardNumber: string;\n cardCvv: string;\n cardExpiration: string;\n cardHolder: string;\n};\n\n/**\n * Assert that a credit-card charge request has every required card field.\n * Narrows the type so downstream code doesn't need `!` assertions.\n */\nfunction assertCardFieldsPresent(opts: ChargesCreateOptions): asserts opts is ValidatedCardFields {\n const missing: string[] = [];\n if (!opts.cardNumber) missing.push('--card-number');\n if (!opts.cardCvv) missing.push('--card-cvv');\n if (!opts.cardExpiration) missing.push('--card-expiration');\n if (!opts.cardHolder) missing.push('--card-holder');\n if (missing.length) {\n throw new CliError('invalid_input', `Credit-card charges require: ${missing.join(', ')}`);\n }\n}\n\nexport async function chargesCreateCommand(opts: ChargesCreateOptions): Promise<Charge> {\n const garu = await getClient(opts);\n\n const customer: Customer = {\n name: opts.customerName,\n email: opts.customerEmail,\n document: opts.customerDocument,\n phone: opts.customerPhone\n };\n\n const base = {\n productId: opts.productId,\n paymentMethod: opts.type,\n customer,\n additionalInfo: opts.additionalInfo,\n idempotencyKey: opts.idempotencyKey\n };\n\n let charge: Charge;\n if (opts.type === 'credit_card') {\n assertCardFieldsPresent(opts);\n charge = await garu.charges.create({\n ...base,\n cardInfo: {\n cardNumber: opts.cardNumber,\n cvv: opts.cardCvv,\n expirationDate: opts.cardExpiration,\n holderName: opts.cardHolder,\n installments: opts.installments ?? 1\n }\n });\n } else {\n charge = await garu.charges.create(base);\n }\n\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nexport async function chargesGetCommand(opts: ChargesByIdOptions): Promise<Charge> {\n const garu = await getClient(opts);\n const charge = await garu.charges.get(opts.id);\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nexport async function chargesRefundCommand(opts: ChargesRefundOptions): Promise<Charge> {\n const garu = await getClient(opts);\n const params: RefundChargeParams = {};\n if (opts.amount !== undefined) params.amount = opts.amount;\n if (opts.reason !== undefined) params.reason = opts.reason;\n if (opts.idempotencyKey !== undefined) params.idempotencyKey = opts.idempotencyKey;\n const charge = await garu.charges.refund(opts.id, params);\n printResult(charge, { ...opts, prettyPrint: prettyCharge });\n return charge;\n}\n\nfunction prettyCharge(charge: Charge): string {\n const lines = [\n `Charge ${charge.id}`,\n ` status: ${charge.status}`,\n ` amount: ${charge.amount}`,\n ` method: ${charge.paymentMethodId}`,\n ` date: ${charge.date}`\n ];\n if (charge.deadline) lines.push(` deadline: ${charge.deadline}`);\n return lines.join('\\n');\n}\n","import { existsSync } from 'node:fs';\nimport { homedir, platform } from 'node:os';\nimport { join } from 'node:path';\n\nimport { Garu } from '@garuhq/node';\n\nimport { resolveAuthOptional } from '../lib/auth.js';\nimport { credentialsFileMode, credentialsPath } from '../lib/credentials.js';\nimport { printResult, type OutputOptions } from '../lib/output.js';\nimport { CLI_VERSION } from '../version.js';\n\nexport interface DoctorReport {\n cli: { version: string };\n api: { reachable: boolean; url: string; version?: string; error?: string };\n credentials: {\n path: string;\n source: 'flag' | 'env' | 'file' | 'none';\n profile?: string;\n fileMode?: string;\n warning?: string;\n };\n agents: {\n claudeCode: boolean;\n cursor: boolean;\n codex: boolean;\n windsurf: boolean;\n claudeDesktop: boolean;\n vscodeMcpInCwd: boolean;\n };\n}\n\nexport interface DoctorOptions extends OutputOptions {\n apiKey?: string;\n profile?: string;\n baseUrl?: string;\n /** Injectable for tests — bypass the real HTTP call. */\n garu?: Garu;\n /** Injectable HOME, for tests. */\n home?: string;\n /** Injectable cwd, for tests. */\n cwd?: string;\n /** Injectable platform, for tests. */\n platform?: NodeJS.Platform;\n}\n\n/**\n * Run a full environment diagnostic.\n *\n * Never throws on expected failures — bad auth, unreachable API, missing\n * credentials all become structured report fields. Only genuinely unexpected\n * errors (programming bugs) bubble up.\n */\nexport async function doctorCommand(opts: DoctorOptions = {}): Promise<DoctorReport> {\n const home = opts.home ?? homedir();\n const cwd = opts.cwd ?? process.cwd();\n const plat = opts.platform ?? platform();\n\n const credentials = await reportCredentials(opts);\n const api = await reportApi(opts);\n const agents = detectAgents(home, cwd, plat);\n\n const report: DoctorReport = {\n cli: { version: CLI_VERSION },\n api,\n credentials,\n agents\n };\n\n printResult(report, { ...opts, prettyPrint: prettyDoctor });\n return report;\n}\n\nasync function reportCredentials(opts: DoctorOptions): Promise<DoctorReport['credentials']> {\n const path = credentialsPath();\n const resolved = await resolveAuthOptional({\n ...(opts.apiKey !== undefined ? { apiKey: opts.apiKey } : {}),\n ...(opts.profile !== undefined ? { profile: opts.profile } : {})\n });\n\n if (!resolved) {\n return { path, source: 'none' };\n }\n\n const out: DoctorReport['credentials'] = { path, source: resolved.source };\n if (resolved.profile) out.profile = resolved.profile;\n\n if (resolved.source === 'file') {\n const mode = await credentialsFileMode();\n if (mode !== null) {\n out.fileMode = `0${mode.toString(8)}`;\n if (mode !== 0o600) {\n out.warning = `credentials file mode is 0${mode.toString(8)}; expected 0600`;\n }\n }\n }\n\n return out;\n}\n\nasync function reportApi(opts: DoctorOptions): Promise<DoctorReport['api']> {\n const url = opts.baseUrl ?? 'https://garu.com.br';\n const garu =\n opts.garu ??\n new Garu({\n ...(opts.baseUrl !== undefined ? { baseUrl: opts.baseUrl } : {})\n });\n\n try {\n const meta = await garu.meta.get();\n return { reachable: true, url, version: meta.version };\n } catch (err) {\n return {\n reachable: false,\n url,\n error: err instanceof Error ? err.message : String(err)\n };\n }\n}\n\nfunction detectAgents(home: string, cwd: string, plat: NodeJS.Platform): DoctorReport['agents'] {\n return {\n claudeCode: existsSync(join(home, '.claude')),\n cursor: existsSync(join(home, '.cursor')),\n codex: existsSync(join(home, '.codex')),\n windsurf: existsSync(join(home, '.windsurf')),\n claudeDesktop: existsSync(claudeDesktopConfigPath(home, plat)),\n vscodeMcpInCwd: existsSync(join(cwd, '.vscode', 'mcp.json'))\n };\n}\n\nfunction claudeDesktopConfigPath(home: string, plat: NodeJS.Platform): string {\n if (plat === 'darwin') {\n return join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');\n }\n if (plat === 'win32') {\n return join(home, 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json');\n }\n return join(home, '.config', 'Claude', 'claude_desktop_config.json');\n}\n\nfunction prettyDoctor(r: DoctorReport): string {\n const check = (ok: boolean) => (ok ? 'yes' : 'no ');\n const lines = [\n `CLI: garu ${r.cli.version}`,\n `API: ${r.api.reachable ? `reachable (${r.api.url}, backend ${r.api.version ?? '?'})` : `unreachable (${r.api.url})`}`,\n r.api.error ? ` ${r.api.error}` : undefined,\n `Credentials: source=${r.credentials.source}${r.credentials.profile ? ` profile=${r.credentials.profile}` : ''}${r.credentials.fileMode ? ` mode=${r.credentials.fileMode}` : ''}`,\n r.credentials.warning ? ` ⚠ ${r.credentials.warning}` : undefined,\n '',\n 'Detected agents:',\n ` Claude Code: ${check(r.agents.claudeCode)}`,\n ` Cursor: ${check(r.agents.cursor)}`,\n ` Codex: ${check(r.agents.codex)}`,\n ` Windsurf: ${check(r.agents.windsurf)}`,\n ` Claude Desktop: ${check(r.agents.claudeDesktop)}`,\n ` VS Code MCP: ${check(r.agents.vscodeMcpInCwd)} (.vscode/mcp.json in cwd)`\n ].filter((l): l is string => l !== undefined);\n return lines.join('\\n');\n}\n","import { Garu } from '@garuhq/node';\n\nimport { loadCredentials, saveCredentials, upsertProfile } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printStatus, printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface LoginOptions extends OutputOptions {\n /** Profile name to create/update. Default: `default`. */\n profile?: string;\n /** Pre-supplied API key (for scripting). When set, no interactive prompt. */\n apiKey?: string;\n /** Override base URL (tests). */\n baseUrl?: string;\n}\n\nexport async function loginCommand(opts: LoginOptions = {}): Promise<{ profile: string }> {\n const profile = opts.profile ?? 'default';\n\n // `@inquirer/prompts` is ESM-only; we lazy-load it via dynamic import so the\n // tsup-built CJS entry works on Node 18 (where require-of-ESM is forbidden).\n const apiKey =\n opts.apiKey ??\n (await import('@inquirer/prompts')\n .then(({ password }) =>\n password({\n message: 'Paste your Garu API key (sk_live_... or sk_test_...)',\n mask: '*'\n })\n )\n .catch(() => {\n throw new CliError('user_cancelled', 'Login cancelled.');\n }));\n\n if (!apiKey || !/^sk_(live|test)_[A-Za-z0-9_]+$/.test(apiKey)) {\n throw new CliError('invalid_input', 'API key must look like `sk_live_...` or `sk_test_...`.');\n }\n\n printStatus('Checking connectivity to Garu...', opts);\n const garu = new Garu({ apiKey, baseUrl: opts.baseUrl });\n\n // We hit the unauthenticated `/api/meta` to verify the SDK can reach the\n // backend. We do NOT yet verify the key is accepted — that requires an\n // authenticated probe endpoint (tracked as a Chunk 2b backend follow-up:\n // expose `GET /api/v1/me`). Until then, a malformed-but-valid-shape key\n // will be saved and fail on the next real command.\n await garu.meta.get();\n\n const file = await loadCredentials();\n const updated = upsertProfile(file, profile, { apiKey });\n await saveCredentials(updated);\n\n printSuccess(`Saved profile '${profile}' to ~/.config/garu/credentials.json`, opts);\n return { profile };\n}\n","import { deleteCredentials, loadCredentials, saveCredentials } from '../lib/credentials.js';\nimport { CliError } from '../lib/errors.js';\nimport { printSuccess, type OutputOptions } from '../lib/output.js';\n\nexport interface LogoutOptions extends OutputOptions {\n /**\n * Profile to remove. If omitted, the entire credentials file is deleted.\n */\n profile?: string;\n}\n\nexport async function logoutCommand(opts: LogoutOptions = {}): Promise<{ cleared: string }> {\n if (!opts.profile) {\n await deleteCredentials();\n printSuccess('All saved credentials deleted.', opts);\n return { cleared: 'all' };\n }\n\n const file = await loadCredentials();\n if (!file.profiles[opts.profile]) {\n throw new CliError('not_found', `Profile '${opts.profile}' not found.`);\n }\n\n const { [opts.profile]: _removed, ...rest } = file.profiles;\n void _removed;\n\n // If this was the only profile, delete the file entirely instead of writing\n // back an orphaned activeProfile pointing at nothing. Matches what users\n // would expect from `logout` — no credentials left on disk.\n if (Object.keys(rest).length === 0) {\n await deleteCredentials();\n printSuccess(`Profile '${opts.profile}' removed (credentials file deleted).`, opts);\n return { cleared: opts.profile };\n }\n\n const nextActive =\n file.activeProfile === opts.profile ? Object.keys(rest)[0]! : file.activeProfile;\n\n await saveCredentials({ ...file, activeProfile: nextActive, profiles: rest });\n printSuccess(`Profile '${opts.profile}' removed.`, opts);\n return { cleared: opts.profile };\n}\n","import { Command, Option } from 'commander';\n\nimport { CLI_VERSION } from './version.js';\nimport { authSwitchCommand } from './commands/auth-switch.js';\nimport {\n chargesCreateCommand,\n chargesGetCommand,\n chargesRefundCommand\n} from './commands/charges.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { loginCommand } from './commands/login.js';\nimport { logoutCommand } from './commands/logout.js';\nimport type { PaymentMethod } from '@garuhq/node';\nimport { CliError } from './lib/errors.js';\nimport { printErrorAndExit, type OutputMode } from './lib/output.js';\n\ninterface GlobalFlags {\n apiKey?: string;\n profile?: string;\n json?: boolean;\n quiet?: boolean;\n}\n\ninterface CommandBaseOptions {\n apiKey?: string;\n profile?: string;\n mode?: OutputMode;\n quiet?: boolean;\n}\n\n/** Build the top-level command tree. Exposed so tests can exercise the router. */\nexport function buildCli(): Command {\n const program = new Command();\n\n program\n .name('garu')\n .description('Command-line interface for the Garu payment gateway.')\n .version(CLI_VERSION, '-v, --version')\n .addOption(new Option('--api-key <key>', 'Garu API key (overrides env and credentials file)'))\n .addOption(new Option('-p, --profile <name>', 'credentials profile name'))\n .addOption(new Option('--json', 'emit strict JSON on stdout (forced in pipes)'))\n .addOption(new Option('-q, --quiet', 'suppress status output; only print results and errors'))\n .showHelpAfterError();\n\n // login\n program\n .command('login')\n .description('Save a Garu API key to the credentials file')\n .option('--api-key <key>', 'pre-supply the key instead of prompting')\n .option('-p, --profile <name>', 'profile name to store under', 'default')\n .action(async (cmdOpts: { apiKey?: string; profile: string }) => {\n const base = toCommandOptions(program);\n await loginCommand({\n apiKey: cmdOpts.apiKey,\n profile: cmdOpts.profile,\n mode: base.mode,\n quiet: base.quiet\n }).catch((err) => printErrorAndExit(err, base));\n });\n\n // logout\n program\n .command('logout')\n .description('Remove saved credentials')\n .option('-p, --profile <name>', 'only remove this profile instead of the whole file')\n .action(async (cmdOpts: { profile?: string }) => {\n const base = toCommandOptions(program);\n await logoutCommand({\n profile: cmdOpts.profile,\n mode: base.mode,\n quiet: base.quiet\n }).catch((err) => printErrorAndExit(err, base));\n });\n\n // auth switch\n const auth = program.command('auth').description('Manage credentials profiles');\n auth\n .command('switch <profile>')\n .description('Set the active credentials profile')\n .action(async (profile: string) => {\n const base = toCommandOptions(program);\n await authSwitchCommand({ profile, mode: base.mode, quiet: base.quiet }).catch((err) =>\n printErrorAndExit(err, base)\n );\n });\n\n // charges\n const charges = program.command('charges').description('Create, fetch, and refund charges');\n\n charges\n .command('create')\n .description('Create a charge (PIX, credit card, or boleto)')\n .requiredOption('--type <type>', 'payment method: pix | credit_card | boleto')\n .requiredOption('--product-id <uuid>', 'product UUID')\n .requiredOption('--customer-name <name>', 'customer full name')\n .requiredOption('--customer-email <email>', 'customer email')\n .requiredOption(\n '--customer-document <document>',\n 'CPF (11 digits) or CNPJ (14 digits), digits only'\n )\n .requiredOption('--customer-phone <phone>', 'customer phone with area code, digits only')\n .option('--card-number <number>', 'credit-card number (required for credit_card)')\n .option('--card-cvv <cvv>', 'credit-card CVV')\n .option('--card-expiration <yyyy-mm>', 'credit-card expiration date (YYYY-MM)')\n .option('--card-holder <name>', 'credit-card holder name')\n .option('--installments <n>', 'number of installments (1-12)', (v) => parseInt(v, 10), 1)\n .option('--additional-info <text>', 'free-form metadata attached to the charge')\n .option('--idempotency-key <key>', 'idempotency key (auto-generated if omitted)')\n .action(async (cmdOpts) => {\n const base = toCommandOptions(program);\n await chargesCreateCommand({\n ...base,\n type: parsePaymentMethod(cmdOpts.type),\n productId: cmdOpts.productId,\n customerName: cmdOpts.customerName,\n customerEmail: cmdOpts.customerEmail,\n customerDocument: cmdOpts.customerDocument,\n customerPhone: cmdOpts.customerPhone,\n cardNumber: cmdOpts.cardNumber,\n cardCvv: cmdOpts.cardCvv,\n cardExpiration: cmdOpts.cardExpiration,\n cardHolder: cmdOpts.cardHolder,\n installments: cmdOpts.installments,\n additionalInfo: cmdOpts.additionalInfo,\n idempotencyKey: cmdOpts.idempotencyKey\n }).catch((err) => printErrorAndExit(err, base));\n });\n\n charges\n .command('get <id>')\n .description('Fetch a single charge by ID')\n .action(async (id: string) => {\n const base = toCommandOptions(program);\n await chargesGetCommand({ ...base, id: parseId(id) }).catch((err) =>\n printErrorAndExit(err, base)\n );\n });\n\n charges\n .command('refund <id>')\n .description('Refund a charge (full or partial)')\n .option('--amount <centavos>', 'partial refund amount in centavos', (v) => parseInt(v, 10))\n .option('--reason <text>', 'optional refund reason')\n .option('--idempotency-key <key>', 'idempotency key (auto-generated if omitted)')\n .action(async (id: string, cmdOpts) => {\n const base = toCommandOptions(program);\n await chargesRefundCommand({\n ...base,\n id: parseId(id),\n amount: cmdOpts.amount,\n reason: cmdOpts.reason,\n idempotencyKey: cmdOpts.idempotencyKey\n }).catch((err) => printErrorAndExit(err, base));\n });\n\n // doctor\n program\n .command('doctor')\n .description('Environment diagnostic')\n .action(async () => {\n const base = toCommandOptions(program);\n await doctorCommand(base).catch((err) => printErrorAndExit(err, base));\n });\n\n return program;\n}\n\n/**\n * Collapse the root-command's global flags into the shape every command takes.\n * Commander never passes `undefined` for unset flags — they're just absent — so\n * we can forward this object to command handlers via spread without polluting\n * their signatures with `undefined` props.\n */\nfunction toCommandOptions(program: Command): CommandBaseOptions {\n const g = program.opts<GlobalFlags>();\n const out: CommandBaseOptions = {};\n if (g.apiKey) out.apiKey = g.apiKey;\n if (g.profile) out.profile = g.profile;\n if (g.json) out.mode = 'json';\n if (g.quiet) out.quiet = true;\n return out;\n}\n\nfunction parsePaymentMethod(raw: string): PaymentMethod {\n if (raw === 'pix' || raw === 'credit_card' || raw === 'boleto') return raw;\n throw new CliError(\n 'invalid_input',\n `--type must be 'pix', 'credit_card', or 'boleto' (got '${raw}')`\n );\n}\n\nfunction parseId(raw: string): number {\n const id = Number.parseInt(raw, 10);\n if (!Number.isFinite(id) || id <= 0) {\n throw new CliError('invalid_input', `Charge ID must be a positive integer (got '${raw}')`);\n }\n return id;\n}\n\n/** Main entry invoked by `bin/garu.cjs` and the compiled binary. */\nexport async function main(argv: string[] = process.argv): Promise<void> {\n const program = buildCli();\n await program.parseAsync(argv);\n}\n\n// This module is only ever loaded as the CLI entry point — either through the\n// `bin/garu.cjs` shim for npm installs or as the compiled binary produced by\n// `bun build --compile`. No test imports `src/index.ts`, so it's safe to call\n// `main()` unconditionally at module load time.\nmain().catch((err) => printErrorAndExit(err));\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import { Command } from 'commander';
|
|
|
2
2
|
|
|
3
3
|
/** Build the top-level command tree. Exposed so tests can exercise the router. */
|
|
4
4
|
declare function buildCli(): Command;
|
|
5
|
-
/** Main entry invoked by `bin/garu.
|
|
5
|
+
/** Main entry invoked by `bin/garu.cjs` and the compiled binary. */
|
|
6
6
|
declare function main(argv?: string[]): Promise<void>;
|
|
7
7
|
|
|
8
8
|
export { buildCli, main };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@garuhq/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Official command-line interface for the Garu payment gateway.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://garu.com.br",
|
|
@@ -45,15 +45,15 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@garuhq/node": "0.1.0",
|
|
48
|
-
"@inquirer/prompts": "
|
|
48
|
+
"@inquirer/prompts": "8.4.1",
|
|
49
49
|
"commander": "12.0.0",
|
|
50
50
|
"picocolors": "1.0.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/node": "20.12.7",
|
|
54
|
-
"tsup": "8.
|
|
55
|
-
"tsx": "4.
|
|
54
|
+
"tsup": "8.5.1",
|
|
55
|
+
"tsx": "4.21.0",
|
|
56
56
|
"typescript": "5.4.5",
|
|
57
|
-
"vitest": "
|
|
57
|
+
"vitest": "3.2.4"
|
|
58
58
|
}
|
|
59
59
|
}
|