@jango-blockchained/hoox-cli 0.3.4 → 0.3.6
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/README.md +2 -0
- package/package.json +5 -3
- package/src/commands/check/check-command.test.ts +28 -20
- package/src/commands/check/prerequisites-command.ts +9 -5
- package/src/commands/clone/clone-command.ts +1 -10
- package/src/commands/config/config-command.ts +7 -11
- package/src/commands/config/env-command.ts +16 -35
- package/src/commands/config/kv-command.ts +33 -72
- package/src/commands/db/db-command.ts +23 -25
- package/src/commands/deploy/deploy-command.ts +133 -52
- package/src/commands/deploy/telegram-service.ts +21 -6
- package/src/commands/dev/dev-command.ts +7 -16
- package/src/commands/infra/infra-command.test.ts +2 -2
- package/src/commands/infra/infra-command.ts +45 -11
- package/src/commands/init/init-command.test.ts +2 -2
- package/src/commands/monitor/monitor-command.test.ts +44 -16
- package/src/commands/monitor/monitor-command.ts +45 -21
- package/src/commands/monitor/monitor-service.ts +19 -4
- package/src/commands/repair/repair-command.test.ts +35 -15
- package/src/commands/repair/repair-command.ts +39 -18
- package/src/commands/repair/repair-service.ts +48 -12
- package/src/commands/test/test-command.ts +4 -10
- package/src/commands/tui/index.ts +1 -0
- package/src/commands/tui/tui-command.ts +87 -0
- package/src/commands/update/index.ts +1 -0
- package/src/commands/update/update-command.ts +51 -0
- package/src/commands/waf/waf-command.test.ts +1 -1
- package/src/commands/waf/waf-command.ts +11 -11
- package/src/index.ts +52 -1
- package/src/services/cloudflare/cloudflare-service.test.ts +12 -8
- package/src/services/cloudflare/cloudflare-service.ts +8 -10
- package/src/services/cloudflare/types.ts +6 -5
- package/src/services/db/db-service.ts +8 -17
- package/src/services/env/env-service.test.ts +41 -15
- package/src/services/env/env-service.ts +276 -46
- package/src/services/kv/kv-sync-service.ts +117 -34
- package/src/services/prerequisites/prerequisites-service.ts +137 -29
- package/src/services/secrets/index.ts +0 -1
- package/src/services/secrets/secrets-service.test.ts +34 -25
- package/src/services/secrets/secrets-service.ts +10 -16
- package/src/services/secrets/types.ts +4 -11
- package/src/services/update/index.ts +2 -0
- package/src/services/update/update-service.test.ts +76 -0
- package/src/services/update/update-service.ts +193 -0
- package/src/ui/banner.ts +5 -5
- package/src/ui/menu.ts +6 -1
- package/src/utils/formatters.ts +21 -4
- package/src/utils/theme.ts +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @jango-blockchained/hoox-cli
|
|
2
2
|
|
|
3
|
+
> **See also:** [Hoox User Guide](../docs/home.md) · [CLI Command Reference](../docs/reference/cli-commands.md)
|
|
4
|
+
|
|
3
5
|
Hoox CLI — manage Cloudflare Workers, infrastructure, secrets, and deployments.
|
|
4
6
|
|
|
5
7
|
381 unit tests, 15 command groups, 50+ subcommands.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jango-blockchained/hoox-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "Hoox CLI — manage Cloudflare Workers, infrastructure, secrets, and deployments (@jango-blockchained/hoox-cli)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./bin/hoox.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
".": "./bin/hoox.js"
|
|
10
10
|
},
|
|
11
11
|
"bin": {
|
|
12
|
-
"hoox": "./bin/hoox.js"
|
|
12
|
+
"hoox": "./bin/hoox.js",
|
|
13
|
+
"hx": "./bin/hoox.js"
|
|
13
14
|
},
|
|
14
15
|
"scripts": {
|
|
15
16
|
"test": "bun test",
|
|
@@ -24,7 +25,8 @@
|
|
|
24
25
|
"@jango-blockchained/hoox-shared": "workspace:*",
|
|
25
26
|
"ansis": "^4.2.0",
|
|
26
27
|
"commander": "^14.0.3",
|
|
27
|
-
"jsonc-parser": "^3.3.1"
|
|
28
|
+
"jsonc-parser": "^3.3.1",
|
|
29
|
+
"wrangler": "^4.92.0"
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
30
32
|
"@types/node": "^25.6.0",
|
|
@@ -244,16 +244,20 @@ describe("registerCheckCommand", () => {
|
|
|
244
244
|
// -- check setup ----------------------------------------------------------
|
|
245
245
|
|
|
246
246
|
describe("check setup", () => {
|
|
247
|
-
it(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
247
|
+
it(
|
|
248
|
+
"loads config and runs all 4 categories",
|
|
249
|
+
{ timeout: 30000 },
|
|
250
|
+
async () => {
|
|
251
|
+
const program = await createProgram();
|
|
252
|
+
await program.parseAsync(["check", "setup"], { from: "user" });
|
|
253
|
+
|
|
254
|
+
expect(loadMock).toHaveBeenCalled();
|
|
255
|
+
expect(d1ListMock).toHaveBeenCalled();
|
|
256
|
+
expect(kvListMock).toHaveBeenCalled();
|
|
257
|
+
expect(r2ListMock).toHaveBeenCalled();
|
|
258
|
+
expect(queueListMock).toHaveBeenCalled();
|
|
259
|
+
}
|
|
260
|
+
);
|
|
257
261
|
|
|
258
262
|
it("outputs JSON when --json flag is set", { timeout: 30000 }, async () => {
|
|
259
263
|
const program = await createProgram();
|
|
@@ -285,18 +289,22 @@ describe("registerCheckCommand", () => {
|
|
|
285
289
|
}
|
|
286
290
|
});
|
|
287
291
|
|
|
288
|
-
it(
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
292
|
+
it(
|
|
293
|
+
"sets exitCode to ERROR when validation fails",
|
|
294
|
+
{ timeout: 30000 },
|
|
295
|
+
async () => {
|
|
296
|
+
validateMock = mock(() => ({
|
|
297
|
+
valid: false,
|
|
298
|
+
errors: ["global.cloudflare_account_id is required"],
|
|
299
|
+
}));
|
|
300
|
+
ConfigService.prototype.validate = validateMock;
|
|
294
301
|
|
|
295
|
-
|
|
296
|
-
|
|
302
|
+
const program = await createProgram();
|
|
303
|
+
await program.parseAsync(["check", "setup"], { from: "user" });
|
|
297
304
|
|
|
298
|
-
|
|
299
|
-
|
|
305
|
+
expect(process.exitCode).toBe(ExitCode.ERROR);
|
|
306
|
+
}
|
|
307
|
+
);
|
|
300
308
|
|
|
301
309
|
it("sets exitCode to ERROR when infra check fails", async () => {
|
|
302
310
|
d1ListMock = mock(async () => ({
|
|
@@ -7,7 +7,7 @@ import { CLIError, ExitCode } from "../../utils/errors.js";
|
|
|
7
7
|
import type { FormatOptions } from "../../utils/formatters.js";
|
|
8
8
|
|
|
9
9
|
export async function runPrerequisitesCheck(
|
|
10
|
-
service?: PrerequisitesService
|
|
10
|
+
service?: PrerequisitesService
|
|
11
11
|
): Promise<PrerequisitesReport> {
|
|
12
12
|
const svc = service ?? new PrerequisitesService();
|
|
13
13
|
return await svc.runAll();
|
|
@@ -15,12 +15,16 @@ export async function runPrerequisitesCheck(
|
|
|
15
15
|
|
|
16
16
|
function renderReport(report: PrerequisitesReport): void {
|
|
17
17
|
for (const check of report.checks) {
|
|
18
|
-
const icon = check.passed
|
|
18
|
+
const icon = check.passed
|
|
19
|
+
? theme.success(icons.success)
|
|
20
|
+
: theme.error(icons.error);
|
|
19
21
|
process.stdout.write(`${icon} ${check.name}\n`);
|
|
20
22
|
process.stdout.write(` ${theme.dim("Version:")} ${check.version}\n`);
|
|
21
23
|
process.stdout.write(` ${theme.dim("Required:")} ${check.required}\n`);
|
|
22
24
|
if (check.hint) {
|
|
23
|
-
process.stdout.write(
|
|
25
|
+
process.stdout.write(
|
|
26
|
+
` ${theme.warning(`${icons.warning} ${check.hint}`)}\n`
|
|
27
|
+
);
|
|
24
28
|
}
|
|
25
29
|
process.stdout.write("\n");
|
|
26
30
|
}
|
|
@@ -33,7 +37,7 @@ function renderReport(report: PrerequisitesReport): void {
|
|
|
33
37
|
|
|
34
38
|
async function handlePrerequisites(
|
|
35
39
|
opts: FormatOptions,
|
|
36
|
-
tool?: string
|
|
40
|
+
tool?: string
|
|
37
41
|
): Promise<void> {
|
|
38
42
|
try {
|
|
39
43
|
const svc = new PrerequisitesService();
|
|
@@ -78,7 +82,7 @@ OPTIONS:
|
|
|
78
82
|
EXAMPLES:
|
|
79
83
|
hoox check prerequisites
|
|
80
84
|
hoox check prerequisites --tool bun
|
|
81
|
-
hoox check prerequisites --json
|
|
85
|
+
hoox check prerequisites --json`
|
|
82
86
|
)
|
|
83
87
|
.option("--tool <name>", "Only check a specific tool")
|
|
84
88
|
.action(async (options: { tool?: string }, cmd: Command) => {
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
formatError,
|
|
21
21
|
formatTable,
|
|
22
22
|
formatJson,
|
|
23
|
+
getFormatOptions,
|
|
23
24
|
} from "../../utils/formatters.js";
|
|
24
25
|
import { CLIError, ExitCode } from "../../utils/errors.js";
|
|
25
26
|
|
|
@@ -36,16 +37,6 @@ interface CloneStatus {
|
|
|
36
37
|
error?: string;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
// Helpers
|
|
41
|
-
// ---------------------------------------------------------------------------
|
|
42
|
-
|
|
43
|
-
/** Extract --json / --quiet from the global program options. */
|
|
44
|
-
function getFormatOptions(cmd: Command) {
|
|
45
|
-
const opts = cmd.optsWithGlobals();
|
|
46
|
-
return { json: Boolean(opts.json), quiet: Boolean(opts.quiet) };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
40
|
/**
|
|
50
41
|
* Resolve the base GitHub URL for worker repos.
|
|
51
42
|
* Tries `git remote get-url origin` first, falls back to a sensible default.
|
|
@@ -490,12 +490,10 @@ EXAMPLES:
|
|
|
490
490
|
const syncSpin = spinner();
|
|
491
491
|
syncSpin.start("Syncing to Cloudflare...");
|
|
492
492
|
const result = await svc.syncToCloudflare(workerName);
|
|
493
|
-
if (result.
|
|
493
|
+
if (result.ok) {
|
|
494
494
|
syncSpin.stop(`Secret "${secretName}" synced to Cloudflare`);
|
|
495
495
|
} else {
|
|
496
|
-
syncSpin.stop(
|
|
497
|
-
`Sync partial: ${result.error ?? "unknown error"}`
|
|
498
|
-
);
|
|
496
|
+
syncSpin.stop(`Sync partial: ${result.error ?? "unknown error"}`);
|
|
499
497
|
formatError(
|
|
500
498
|
new CLIError(
|
|
501
499
|
`Sync partial: ${result.error ?? "unknown error"}`,
|
|
@@ -619,14 +617,12 @@ EXAMPLES:
|
|
|
619
617
|
const syncSpin = spinner();
|
|
620
618
|
syncSpin.start(`Syncing secrets for "${workerName}"...`);
|
|
621
619
|
const result = await svc.syncToCloudflare(workerName);
|
|
622
|
-
if (result.
|
|
620
|
+
if (result.ok) {
|
|
623
621
|
syncSpin.stop(
|
|
624
|
-
`Synced ${result.
|
|
622
|
+
`Synced ${result.value?.length ?? 0} secrets for "${workerName}"`
|
|
625
623
|
);
|
|
626
624
|
} else {
|
|
627
|
-
syncSpin.stop(
|
|
628
|
-
`Sync failed: ${result.error ?? "unknown error"}`
|
|
629
|
-
);
|
|
625
|
+
syncSpin.stop(`Sync failed: ${result.error ?? "unknown error"}`);
|
|
630
626
|
formatError(
|
|
631
627
|
new CLIError(
|
|
632
628
|
`Sync failed: ${result.error ?? "unknown error"}`,
|
|
@@ -651,9 +647,9 @@ EXAMPLES:
|
|
|
651
647
|
for (const name of workers) {
|
|
652
648
|
syncSpin.start(`Syncing ${name}...`);
|
|
653
649
|
const result = await svc.syncToCloudflare(name);
|
|
654
|
-
if (result.
|
|
650
|
+
if (result.ok) {
|
|
655
651
|
syncSpin.stop(
|
|
656
|
-
`${theme.success("synced")} ${result.
|
|
652
|
+
`${theme.success("synced")} ${result.value?.length ?? 0} for ${name}`
|
|
657
653
|
);
|
|
658
654
|
synced++;
|
|
659
655
|
} else {
|
|
@@ -63,7 +63,7 @@ async function handleInit(opts: FormatOptions): Promise<void> {
|
|
|
63
63
|
|
|
64
64
|
for (const section of sections) {
|
|
65
65
|
const sectionDefs = EnvService.getDefinitions().filter(
|
|
66
|
-
(d) => d.section === section
|
|
66
|
+
(d) => d.section === section
|
|
67
67
|
);
|
|
68
68
|
if (sectionDefs.length === 0) continue;
|
|
69
69
|
|
|
@@ -111,8 +111,7 @@ async function handleInit(opts: FormatOptions): Promise<void> {
|
|
|
111
111
|
"",
|
|
112
112
|
].join("\n");
|
|
113
113
|
await Bun.write(`${workerPath}/.dev.vars`, content);
|
|
114
|
-
if (!opts.quiet)
|
|
115
|
-
formatSuccess(`Created ${workerPath}/.dev.vars`, opts);
|
|
114
|
+
if (!opts.quiet) formatSuccess(`Created ${workerPath}/.dev.vars`, opts);
|
|
116
115
|
}
|
|
117
116
|
|
|
118
117
|
p.outro("Environment setup complete!");
|
|
@@ -127,7 +126,7 @@ async function handleShow(opts: FormatOptions): Promise<void> {
|
|
|
127
126
|
if (!(await file.exists())) {
|
|
128
127
|
throw new CLIError(
|
|
129
128
|
".env.local not found. Run `hoox config env init`.",
|
|
130
|
-
ExitCode.INVALID_USAGE
|
|
129
|
+
ExitCode.INVALID_USAGE
|
|
131
130
|
);
|
|
132
131
|
}
|
|
133
132
|
|
|
@@ -157,7 +156,9 @@ async function handleValidate(opts: FormatOptions): Promise<void> {
|
|
|
157
156
|
formatJson(result, opts);
|
|
158
157
|
} else if (!opts.quiet) {
|
|
159
158
|
if (!(await file.exists())) {
|
|
160
|
-
process.stdout.write(
|
|
159
|
+
process.stdout.write(
|
|
160
|
+
".env.local not found. Run `hoox config env init` first.\n\n"
|
|
161
|
+
);
|
|
161
162
|
}
|
|
162
163
|
if (result.missing.length > 0) {
|
|
163
164
|
process.stdout.write("Missing required variables:\n");
|
|
@@ -190,7 +191,7 @@ async function handleGenerateDevVars(opts: FormatOptions): Promise<void> {
|
|
|
190
191
|
if (!(await file.exists())) {
|
|
191
192
|
throw new CLIError(
|
|
192
193
|
".env.local not found. Run `hoox config env init`.",
|
|
193
|
-
ExitCode.INVALID_USAGE
|
|
194
|
+
ExitCode.INVALID_USAGE
|
|
194
195
|
);
|
|
195
196
|
}
|
|
196
197
|
|
|
@@ -237,7 +238,7 @@ EXAMPLES:
|
|
|
237
238
|
hoox config env init
|
|
238
239
|
hoox config env show
|
|
239
240
|
hoox config env validate
|
|
240
|
-
hoox config env generate-dev-vars
|
|
241
|
+
hoox config env generate-dev-vars`
|
|
241
242
|
);
|
|
242
243
|
|
|
243
244
|
envCmd
|
|
@@ -248,13 +249,8 @@ EXAMPLES:
|
|
|
248
249
|
try {
|
|
249
250
|
await handleInit(opts);
|
|
250
251
|
} catch (err) {
|
|
251
|
-
formatError(
|
|
252
|
-
|
|
253
|
-
opts,
|
|
254
|
-
);
|
|
255
|
-
process.exit(
|
|
256
|
-
err instanceof CLIError ? err.code : ExitCode.ERROR,
|
|
257
|
-
);
|
|
252
|
+
formatError(err instanceof Error ? err : String(err), opts);
|
|
253
|
+
process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
|
|
258
254
|
}
|
|
259
255
|
});
|
|
260
256
|
|
|
@@ -266,13 +262,8 @@ EXAMPLES:
|
|
|
266
262
|
try {
|
|
267
263
|
await handleShow(opts);
|
|
268
264
|
} catch (err) {
|
|
269
|
-
formatError(
|
|
270
|
-
|
|
271
|
-
opts,
|
|
272
|
-
);
|
|
273
|
-
process.exit(
|
|
274
|
-
err instanceof CLIError ? err.code : ExitCode.ERROR,
|
|
275
|
-
);
|
|
265
|
+
formatError(err instanceof Error ? err : String(err), opts);
|
|
266
|
+
process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
|
|
276
267
|
}
|
|
277
268
|
});
|
|
278
269
|
|
|
@@ -284,13 +275,8 @@ EXAMPLES:
|
|
|
284
275
|
try {
|
|
285
276
|
await handleValidate(opts);
|
|
286
277
|
} catch (err) {
|
|
287
|
-
formatError(
|
|
288
|
-
|
|
289
|
-
opts,
|
|
290
|
-
);
|
|
291
|
-
process.exit(
|
|
292
|
-
err instanceof CLIError ? err.code : ExitCode.ERROR,
|
|
293
|
-
);
|
|
278
|
+
formatError(err instanceof Error ? err : String(err), opts);
|
|
279
|
+
process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
|
|
294
280
|
}
|
|
295
281
|
});
|
|
296
282
|
|
|
@@ -302,13 +288,8 @@ EXAMPLES:
|
|
|
302
288
|
try {
|
|
303
289
|
await handleGenerateDevVars(opts);
|
|
304
290
|
} catch (err) {
|
|
305
|
-
formatError(
|
|
306
|
-
|
|
307
|
-
opts,
|
|
308
|
-
);
|
|
309
|
-
process.exit(
|
|
310
|
-
err instanceof CLIError ? err.code : ExitCode.ERROR,
|
|
311
|
-
);
|
|
291
|
+
formatError(err instanceof Error ? err : String(err), opts);
|
|
292
|
+
process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
|
|
312
293
|
}
|
|
313
294
|
});
|
|
314
295
|
}
|
|
@@ -27,9 +27,7 @@ function formatOpts(cmd: Command): FormatOptions {
|
|
|
27
27
|
return { json: Boolean(opts.json), quiet: Boolean(opts.quiet) };
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
async function resolveNs(
|
|
31
|
-
cmd: Command,
|
|
32
|
-
): Promise<string> {
|
|
30
|
+
async function resolveNs(cmd: Command): Promise<string> {
|
|
33
31
|
const svc = new KvSyncService();
|
|
34
32
|
const opts = cmd.optsWithGlobals<{ namespaceId?: string }>();
|
|
35
33
|
return await svc.resolveNamespaceId(opts.namespaceId);
|
|
@@ -39,10 +37,7 @@ async function resolveNs(
|
|
|
39
37
|
// kv list
|
|
40
38
|
// ---------------------------------------------------------------------------
|
|
41
39
|
|
|
42
|
-
async function handleList(
|
|
43
|
-
opts: FormatOptions,
|
|
44
|
-
nsId: string,
|
|
45
|
-
): Promise<void> {
|
|
40
|
+
async function handleList(opts: FormatOptions, nsId: string): Promise<void> {
|
|
46
41
|
const svc = new KvSyncService();
|
|
47
42
|
const keys = await svc.list(nsId);
|
|
48
43
|
|
|
@@ -65,7 +60,7 @@ async function handleList(
|
|
|
65
60
|
async function handleGet(
|
|
66
61
|
opts: FormatOptions,
|
|
67
62
|
nsId: string,
|
|
68
|
-
key: string
|
|
63
|
+
key: string
|
|
69
64
|
): Promise<void> {
|
|
70
65
|
const svc = new KvSyncService();
|
|
71
66
|
const value = await svc.get(nsId, key);
|
|
@@ -73,7 +68,7 @@ async function handleGet(
|
|
|
73
68
|
if (value === null) {
|
|
74
69
|
throw new CLIError(
|
|
75
70
|
`Key "${key}" not found in KV namespace`,
|
|
76
|
-
ExitCode.ERROR
|
|
71
|
+
ExitCode.ERROR
|
|
77
72
|
);
|
|
78
73
|
}
|
|
79
74
|
|
|
@@ -92,7 +87,7 @@ async function handleSet(
|
|
|
92
87
|
opts: FormatOptions,
|
|
93
88
|
nsId: string,
|
|
94
89
|
key: string,
|
|
95
|
-
value: string
|
|
90
|
+
value: string
|
|
96
91
|
): Promise<void> {
|
|
97
92
|
const svc = new KvSyncService();
|
|
98
93
|
await svc.set(nsId, key, value);
|
|
@@ -106,7 +101,7 @@ async function handleSet(
|
|
|
106
101
|
async function handleDelete(
|
|
107
102
|
opts: FormatOptions,
|
|
108
103
|
nsId: string,
|
|
109
|
-
key: string
|
|
104
|
+
key: string
|
|
110
105
|
): Promise<void> {
|
|
111
106
|
const svc = new KvSyncService();
|
|
112
107
|
await svc.delete(nsId, key);
|
|
@@ -119,7 +114,7 @@ async function handleDelete(
|
|
|
119
114
|
|
|
120
115
|
async function handleApplyManifest(
|
|
121
116
|
opts: FormatOptions,
|
|
122
|
-
nsId: string
|
|
117
|
+
nsId: string
|
|
123
118
|
): Promise<void> {
|
|
124
119
|
const svc = new KvSyncService();
|
|
125
120
|
const manifest = KvSyncService.getManifest();
|
|
@@ -133,7 +128,7 @@ async function handleApplyManifest(
|
|
|
133
128
|
setCount++;
|
|
134
129
|
} catch (err) {
|
|
135
130
|
errors.push(
|
|
136
|
-
`${keyDef.key}: ${err instanceof Error ? err.message : String(err)}
|
|
131
|
+
`${keyDef.key}: ${err instanceof Error ? err.message : String(err)}`
|
|
137
132
|
);
|
|
138
133
|
}
|
|
139
134
|
}
|
|
@@ -141,7 +136,7 @@ async function handleApplyManifest(
|
|
|
141
136
|
|
|
142
137
|
formatSuccess(
|
|
143
138
|
`Applied ${setCount}/${manifest.keys.length} manifest keys (${errors.length} errors)`,
|
|
144
|
-
opts
|
|
139
|
+
opts
|
|
145
140
|
);
|
|
146
141
|
}
|
|
147
142
|
|
|
@@ -156,7 +151,7 @@ async function handleManifest(opts: FormatOptions): Promise<void> {
|
|
|
156
151
|
formatJson(manifest, opts);
|
|
157
152
|
} else if (!opts.quiet) {
|
|
158
153
|
process.stdout.write(
|
|
159
|
-
`${theme.heading(`KV Manifest: ${manifest.namespace}`)}\n\n
|
|
154
|
+
`${theme.heading(`KV Manifest: ${manifest.namespace}`)}\n\n`
|
|
160
155
|
);
|
|
161
156
|
const rows = manifest.keys.map((k) => ({
|
|
162
157
|
Key: k.key,
|
|
@@ -197,11 +192,11 @@ EXAMPLES:
|
|
|
197
192
|
hoox config kv get trade:kill_switch
|
|
198
193
|
hoox config kv delete trade:kill_switch
|
|
199
194
|
hoox config kv apply-manifest
|
|
200
|
-
hoox config kv manifest
|
|
195
|
+
hoox config kv manifest`
|
|
201
196
|
)
|
|
202
197
|
.option(
|
|
203
198
|
"--namespace-id <id>",
|
|
204
|
-
"KV namespace ID (auto-detected if omitted)"
|
|
199
|
+
"KV namespace ID (auto-detected if omitted)"
|
|
205
200
|
);
|
|
206
201
|
|
|
207
202
|
// -- list
|
|
@@ -214,13 +209,8 @@ EXAMPLES:
|
|
|
214
209
|
const nsId = await resolveNs(cmd);
|
|
215
210
|
await handleList(opts, nsId);
|
|
216
211
|
} catch (err) {
|
|
217
|
-
formatError(
|
|
218
|
-
|
|
219
|
-
opts,
|
|
220
|
-
);
|
|
221
|
-
process.exit(
|
|
222
|
-
err instanceof CLIError ? err.code : ExitCode.ERROR,
|
|
223
|
-
);
|
|
212
|
+
formatError(err instanceof Error ? err : String(err), opts);
|
|
213
|
+
process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
|
|
224
214
|
}
|
|
225
215
|
});
|
|
226
216
|
|
|
@@ -234,13 +224,8 @@ EXAMPLES:
|
|
|
234
224
|
const nsId = await resolveNs(cmd);
|
|
235
225
|
await handleGet(opts, nsId, key);
|
|
236
226
|
} catch (err) {
|
|
237
|
-
formatError(
|
|
238
|
-
|
|
239
|
-
opts,
|
|
240
|
-
);
|
|
241
|
-
process.exit(
|
|
242
|
-
err instanceof CLIError ? err.code : ExitCode.ERROR,
|
|
243
|
-
);
|
|
227
|
+
formatError(err instanceof Error ? err : String(err), opts);
|
|
228
|
+
process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
|
|
244
229
|
}
|
|
245
230
|
});
|
|
246
231
|
|
|
@@ -248,23 +233,16 @@ EXAMPLES:
|
|
|
248
233
|
kvCmd
|
|
249
234
|
.command("set <key> <value>")
|
|
250
235
|
.description("Set a key's value in the KV namespace")
|
|
251
|
-
.action(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
);
|
|
262
|
-
process.exit(
|
|
263
|
-
err instanceof CLIError ? err.code : ExitCode.ERROR,
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
},
|
|
267
|
-
);
|
|
236
|
+
.action(async (key: string, value: string, _, cmd: Command) => {
|
|
237
|
+
const opts = formatOpts(cmd);
|
|
238
|
+
try {
|
|
239
|
+
const nsId = await resolveNs(cmd);
|
|
240
|
+
await handleSet(opts, nsId, key, value);
|
|
241
|
+
} catch (err) {
|
|
242
|
+
formatError(err instanceof Error ? err : String(err), opts);
|
|
243
|
+
process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
268
246
|
|
|
269
247
|
// -- delete
|
|
270
248
|
kvCmd
|
|
@@ -276,35 +254,23 @@ EXAMPLES:
|
|
|
276
254
|
const nsId = await resolveNs(cmd);
|
|
277
255
|
await handleDelete(opts, nsId, key);
|
|
278
256
|
} catch (err) {
|
|
279
|
-
formatError(
|
|
280
|
-
|
|
281
|
-
opts,
|
|
282
|
-
);
|
|
283
|
-
process.exit(
|
|
284
|
-
err instanceof CLIError ? err.code : ExitCode.ERROR,
|
|
285
|
-
);
|
|
257
|
+
formatError(err instanceof Error ? err : String(err), opts);
|
|
258
|
+
process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
|
|
286
259
|
}
|
|
287
260
|
});
|
|
288
261
|
|
|
289
262
|
// -- apply-manifest
|
|
290
263
|
kvCmd
|
|
291
264
|
.command("apply-manifest")
|
|
292
|
-
.description(
|
|
293
|
-
"Apply manifest key defaults to the KV namespace",
|
|
294
|
-
)
|
|
265
|
+
.description("Apply manifest key defaults to the KV namespace")
|
|
295
266
|
.action(async (_, cmd: Command) => {
|
|
296
267
|
const opts = formatOpts(cmd);
|
|
297
268
|
try {
|
|
298
269
|
const nsId = await resolveNs(cmd);
|
|
299
270
|
await handleApplyManifest(opts, nsId);
|
|
300
271
|
} catch (err) {
|
|
301
|
-
formatError(
|
|
302
|
-
|
|
303
|
-
opts,
|
|
304
|
-
);
|
|
305
|
-
process.exit(
|
|
306
|
-
err instanceof CLIError ? err.code : ExitCode.ERROR,
|
|
307
|
-
);
|
|
272
|
+
formatError(err instanceof Error ? err : String(err), opts);
|
|
273
|
+
process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
|
|
308
274
|
}
|
|
309
275
|
});
|
|
310
276
|
|
|
@@ -317,13 +283,8 @@ EXAMPLES:
|
|
|
317
283
|
try {
|
|
318
284
|
await handleManifest(opts);
|
|
319
285
|
} catch (err) {
|
|
320
|
-
formatError(
|
|
321
|
-
|
|
322
|
-
opts,
|
|
323
|
-
);
|
|
324
|
-
process.exit(
|
|
325
|
-
err instanceof CLIError ? err.code : ExitCode.ERROR,
|
|
326
|
-
);
|
|
286
|
+
formatError(err instanceof Error ? err : String(err), opts);
|
|
287
|
+
process.exit(err instanceof CLIError ? err.code : ExitCode.ERROR);
|
|
327
288
|
}
|
|
328
289
|
});
|
|
329
290
|
}
|