@jango-blockchained/hoox-cli 0.5.2 → 0.5.7

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.
Files changed (114) hide show
  1. package/bin/hoox.js +3 -4
  2. package/dist/index.js +32989 -0
  3. package/package.json +10 -15
  4. package/src/commands/check/check-command.test.ts +0 -476
  5. package/src/commands/check/check-command.ts +0 -1087
  6. package/src/commands/check/index.ts +0 -10
  7. package/src/commands/check/prerequisites-command.test.ts +0 -19
  8. package/src/commands/check/prerequisites-command.ts +0 -97
  9. package/src/commands/check/types.ts +0 -103
  10. package/src/commands/clone/clone-command.test.ts +0 -440
  11. package/src/commands/clone/clone-command.ts +0 -431
  12. package/src/commands/clone/index.ts +0 -1
  13. package/src/commands/config/config-command.test.ts +0 -583
  14. package/src/commands/config/config-command.ts +0 -896
  15. package/src/commands/config/env-command.test.ts +0 -43
  16. package/src/commands/config/env-command.ts +0 -292
  17. package/src/commands/config/index.ts +0 -3
  18. package/src/commands/config/kv-command.test.ts +0 -14
  19. package/src/commands/config/kv-command.ts +0 -290
  20. package/src/commands/dashboard/dashboard-command.test.ts +0 -47
  21. package/src/commands/dashboard/dashboard-command.ts +0 -130
  22. package/src/commands/dashboard/index.ts +0 -1
  23. package/src/commands/db/db-command.test.ts +0 -21
  24. package/src/commands/db/db-command.ts +0 -311
  25. package/src/commands/db/index.ts +0 -1
  26. package/src/commands/deploy/deploy-command.test.ts +0 -324
  27. package/src/commands/deploy/deploy-command.ts +0 -1054
  28. package/src/commands/deploy/index.ts +0 -2
  29. package/src/commands/deploy/telegram-service.ts +0 -76
  30. package/src/commands/deploy/types.ts +0 -34
  31. package/src/commands/dev/dev-command.test.ts +0 -405
  32. package/src/commands/dev/dev-command.ts +0 -398
  33. package/src/commands/dev/index.ts +0 -1
  34. package/src/commands/disclaimer/disclaimer-command.ts +0 -21
  35. package/src/commands/disclaimer/index.ts +0 -1
  36. package/src/commands/infra/index.ts +0 -5
  37. package/src/commands/infra/infra-command.test.ts +0 -719
  38. package/src/commands/infra/infra-command.ts +0 -974
  39. package/src/commands/infra/types.ts +0 -23
  40. package/src/commands/init/__tests__/cli-provisioner.test.ts +0 -17
  41. package/src/commands/init/cli-provisioner.ts +0 -71
  42. package/src/commands/init/index.ts +0 -1
  43. package/src/commands/init/init-command.test.ts +0 -854
  44. package/src/commands/init/init-command.ts +0 -597
  45. package/src/commands/init/types.ts +0 -23
  46. package/src/commands/logs/index.ts +0 -1
  47. package/src/commands/logs/logs-command.test.ts +0 -293
  48. package/src/commands/logs/logs-command.ts +0 -452
  49. package/src/commands/monitor/index.ts +0 -2
  50. package/src/commands/monitor/monitor-command.test.ts +0 -271
  51. package/src/commands/monitor/monitor-command.ts +0 -269
  52. package/src/commands/monitor/monitor-service.ts +0 -65
  53. package/src/commands/monitor/types.ts +0 -13
  54. package/src/commands/repair/index.ts +0 -2
  55. package/src/commands/repair/repair-command.test.ts +0 -243
  56. package/src/commands/repair/repair-command.ts +0 -220
  57. package/src/commands/repair/repair-service.ts +0 -164
  58. package/src/commands/repair/types.ts +0 -13
  59. package/src/commands/schema/index.ts +0 -1
  60. package/src/commands/schema/schema-command.ts +0 -137
  61. package/src/commands/test/index.ts +0 -2
  62. package/src/commands/test/test-command.test.ts +0 -318
  63. package/src/commands/test/test-command.ts +0 -406
  64. package/src/commands/tui/index.ts +0 -1
  65. package/src/commands/tui/tui-command.ts +0 -87
  66. package/src/commands/update/index.ts +0 -1
  67. package/src/commands/update/update-command.ts +0 -109
  68. package/src/commands/waf/index.ts +0 -2
  69. package/src/commands/waf/types.ts +0 -48
  70. package/src/commands/waf/waf-command.test.ts +0 -506
  71. package/src/commands/waf/waf-command.ts +0 -545
  72. package/src/index.ts +0 -261
  73. package/src/services/cloudflare/cloudflare-service.test.ts +0 -658
  74. package/src/services/cloudflare/cloudflare-service.ts +0 -433
  75. package/src/services/cloudflare/index.ts +0 -2
  76. package/src/services/cloudflare/types.ts +0 -30
  77. package/src/services/config/config-service.test.ts +0 -395
  78. package/src/services/config/config-service.ts +0 -202
  79. package/src/services/config/index.ts +0 -9
  80. package/src/services/config/types.ts +0 -66
  81. package/src/services/db/db-service.test.ts +0 -63
  82. package/src/services/db/db-service.ts +0 -131
  83. package/src/services/db/index.ts +0 -1
  84. package/src/services/docker/docker-service.ts +0 -155
  85. package/src/services/docker/index.ts +0 -1
  86. package/src/services/env/env-service.test.ts +0 -259
  87. package/src/services/env/env-service.ts +0 -372
  88. package/src/services/env/index.ts +0 -1
  89. package/src/services/kv/index.ts +0 -1
  90. package/src/services/kv/kv-sync-service.test.ts +0 -38
  91. package/src/services/kv/kv-sync-service.ts +0 -243
  92. package/src/services/prerequisites/index.ts +0 -1
  93. package/src/services/prerequisites/prerequisites-service.test.ts +0 -89
  94. package/src/services/prerequisites/prerequisites-service.ts +0 -377
  95. package/src/services/prerequisites/types.ts +0 -48
  96. package/src/services/schema/index.ts +0 -1
  97. package/src/services/schema/schema-service.ts +0 -99
  98. package/src/services/secrets/index.ts +0 -11
  99. package/src/services/secrets/secrets-service.test.ts +0 -502
  100. package/src/services/secrets/secrets-service.ts +0 -287
  101. package/src/services/secrets/types.ts +0 -50
  102. package/src/services/update/index.ts +0 -2
  103. package/src/services/update/update-service.test.ts +0 -76
  104. package/src/services/update/update-service.ts +0 -193
  105. package/src/ui/banner.ts +0 -141
  106. package/src/ui/index.ts +0 -8
  107. package/src/ui/menu.ts +0 -490
  108. package/src/utils/error-handler.ts +0 -62
  109. package/src/utils/errors.test.ts +0 -69
  110. package/src/utils/errors.ts +0 -24
  111. package/src/utils/formatters.test.ts +0 -180
  112. package/src/utils/formatters.ts +0 -269
  113. package/src/utils/git.ts +0 -134
  114. package/src/utils/theme.ts +0 -92
@@ -1,974 +0,0 @@
1
- /**
2
- * `hoox infra` command group — Cloudflare infrastructure management.
3
- *
4
- * Subcommands:
5
- * provision — Auto-provision D1/KV/R2/Queues from wrangler.jsonc
6
- * d1 [list|create|delete] — D1 database management
7
- * kv [list|create|delete] — KV namespace management
8
- * r2 [list|create|delete] — R2 bucket management
9
- * queues [list|create|delete] — Queue management
10
- *
11
- * All operations delegate to CloudflareService. Output respects --json / --quiet.
12
- */
13
-
14
- import { Command } from "commander";
15
- import { spinner } from "@clack/prompts";
16
- import { parse } from "jsonc-parser";
17
- import { resolve } from "node:path";
18
- import { CloudflareService } from "../../services/cloudflare/index.js";
19
- import { ConfigService } from "../../services/config/index.js";
20
- import {
21
- formatTable,
22
- formatSuccess,
23
- formatError,
24
- formatJson,
25
- } from "../../utils/formatters.js";
26
- import { CLIError, ExitCode } from "../../utils/errors.js";
27
- import { theme } from "../../utils/theme.js";
28
- import type { InfraOptions, ProvisionItem, ProvisionResult } from "./types.js";
29
- import type { WranglerResult } from "../../services/cloudflare/types.js";
30
-
31
- // ---------------------------------------------------------------------------
32
- // Helpers
33
- // ---------------------------------------------------------------------------
34
-
35
- /** Extract global options (--json, --quiet) from a commander Command. */
36
- function getOptions(cmd: Command): InfraOptions {
37
- const opts = cmd.optsWithGlobals();
38
- return { json: opts.json, quiet: opts.quiet };
39
- }
40
-
41
- /**
42
- * Try to parse a wrangler JSON list output and display as a table.
43
- * Falls back to raw text output if parsing fails.
44
- */
45
- function displayListResult(
46
- result: WranglerResult<string>,
47
- opts: InfraOptions,
48
- columns?: string[]
49
- ): void {
50
- if (!result.ok) {
51
- formatError(new CLIError(result.error, ExitCode.ERROR), opts);
52
- return;
53
- }
54
-
55
- const data = result.value;
56
-
57
- // Try JSON parse for structured output
58
- try {
59
- const parsed = JSON.parse(data);
60
- if (Array.isArray(parsed) && parsed.length > 0) {
61
- if (opts.json) {
62
- formatJson(parsed, opts);
63
- return;
64
- }
65
- const rows = parsed.map((item: Record<string, unknown>) => {
66
- if (columns) {
67
- const row: Record<string, string> = {};
68
- for (const col of columns) {
69
- row[col] = String(item[col] ?? "");
70
- }
71
- return row;
72
- }
73
- // Show all top-level keys
74
- const row: Record<string, string> = {};
75
- for (const [k, v] of Object.entries(item)) {
76
- if (typeof v !== "object" || v === null) {
77
- row[k] = String(v);
78
- }
79
- }
80
- return row;
81
- });
82
- formatTable(rows, opts);
83
- return;
84
- }
85
- if (
86
- typeof parsed === "object" &&
87
- parsed !== null &&
88
- !Array.isArray(parsed)
89
- ) {
90
- if (opts.json) {
91
- formatJson(parsed, opts);
92
- return;
93
- }
94
- }
95
- } catch {
96
- // Not JSON — fall through to raw output
97
- }
98
-
99
- // Raw text output
100
- if (opts.json) {
101
- formatJson({ output: data }, opts);
102
- } else {
103
- process.stdout.write(data + "\n");
104
- }
105
- }
106
-
107
- /** Handle a create operation: run the service call, show success/error. */
108
- async function handleCreate(
109
- name: string,
110
- label: string,
111
- fn: (name: string) => Promise<WranglerResult<string>>,
112
- opts: InfraOptions
113
- ): Promise<void> {
114
- if (!opts.quiet) {
115
- process.stdout.write(`${theme.label(`Creating ${label}:`)} ${name}\n`);
116
- }
117
-
118
- const result = await fn(name);
119
- if (result.ok) {
120
- formatSuccess(`${label} "${name}" created`, opts);
121
- } else {
122
- formatError(new CLIError(result.error, ExitCode.ERROR), opts);
123
- }
124
- }
125
-
126
- /** Handle a delete operation: run the service call, show success/error. */
127
- async function handleDelete(
128
- name: string,
129
- label: string,
130
- fn: (name: string) => Promise<WranglerResult<string>>,
131
- opts: InfraOptions
132
- ): Promise<void> {
133
- if (!opts.quiet) {
134
- process.stdout.write(`${theme.label(`Deleting ${label}:`)} ${name}\n`);
135
- }
136
-
137
- const result = await fn(name);
138
- if (result.ok) {
139
- formatSuccess(`${label} "${name}" deleted`, opts);
140
- } else {
141
- formatError(new CLIError(result.error, ExitCode.ERROR), opts);
142
- }
143
- }
144
-
145
- // ---------------------------------------------------------------------------
146
- // D1 handlers
147
- // ---------------------------------------------------------------------------
148
-
149
- async function doD1List(
150
- opts: InfraOptions,
151
- cf?: CloudflareService
152
- ): Promise<void> {
153
- const cloudflare = cf ?? new CloudflareService();
154
- const result = await cloudflare.d1List();
155
- displayListResult(result, opts, ["name", "uuid", "version", "num_tables"]);
156
- }
157
-
158
- async function doD1Create(
159
- name: string,
160
- opts: InfraOptions,
161
- cf?: CloudflareService
162
- ): Promise<void> {
163
- const cloudflare = cf ?? new CloudflareService();
164
- await handleCreate(name, "D1 database", (n) => cloudflare.d1Create(n), opts);
165
- }
166
-
167
- async function doD1Delete(
168
- name: string,
169
- opts: InfraOptions,
170
- cf?: CloudflareService
171
- ): Promise<void> {
172
- const cloudflare = cf ?? new CloudflareService();
173
- await handleDelete(name, "D1 database", (n) => cloudflare.d1Delete(n), opts);
174
- }
175
-
176
- // ---------------------------------------------------------------------------
177
- // KV handlers
178
- // ---------------------------------------------------------------------------
179
-
180
- async function doKvList(
181
- opts: InfraOptions,
182
- cf?: CloudflareService
183
- ): Promise<void> {
184
- const cloudflare = cf ?? new CloudflareService();
185
- const result = await cloudflare.kvList();
186
- displayListResult(result, opts);
187
- }
188
-
189
- async function doKvCreate(
190
- name: string,
191
- opts: InfraOptions,
192
- cf?: CloudflareService
193
- ): Promise<void> {
194
- const cloudflare = cf ?? new CloudflareService();
195
- await handleCreate(name, "KV namespace", (n) => cloudflare.kvCreate(n), opts);
196
- }
197
-
198
- async function doKvDelete(
199
- id: string,
200
- opts: InfraOptions,
201
- cf?: CloudflareService
202
- ): Promise<void> {
203
- const cloudflare = cf ?? new CloudflareService();
204
- await handleDelete(id, "KV namespace", (n) => cloudflare.kvDelete(n), opts);
205
- }
206
-
207
- // ---------------------------------------------------------------------------
208
- // R2 handlers
209
- // ---------------------------------------------------------------------------
210
-
211
- async function doR2List(
212
- opts: InfraOptions,
213
- cf?: CloudflareService
214
- ): Promise<void> {
215
- const cloudflare = cf ?? new CloudflareService();
216
- const result = await cloudflare.r2List();
217
- displayListResult(result, opts);
218
- }
219
-
220
- async function doR2Create(
221
- name: string,
222
- opts: InfraOptions,
223
- cf?: CloudflareService
224
- ): Promise<void> {
225
- const cloudflare = cf ?? new CloudflareService();
226
- await handleCreate(name, "R2 bucket", (n) => cloudflare.r2Create(n), opts);
227
- }
228
-
229
- async function doR2Delete(
230
- name: string,
231
- opts: InfraOptions,
232
- cf?: CloudflareService
233
- ): Promise<void> {
234
- const cloudflare = cf ?? new CloudflareService();
235
- await handleDelete(name, "R2 bucket", (n) => cloudflare.r2Delete(n), opts);
236
- }
237
-
238
- // ---------------------------------------------------------------------------
239
- // Queues handlers
240
- // ---------------------------------------------------------------------------
241
-
242
- async function doQueueList(
243
- opts: InfraOptions,
244
- cf?: CloudflareService
245
- ): Promise<void> {
246
- const cloudflare = cf ?? new CloudflareService();
247
- const result = await cloudflare.queueList();
248
- displayListResult(result, opts);
249
- }
250
-
251
- async function doQueueCreate(
252
- name: string,
253
- opts: InfraOptions,
254
- cf?: CloudflareService
255
- ): Promise<void> {
256
- const cloudflare = cf ?? new CloudflareService();
257
- await handleCreate(name, "Queue", (n) => cloudflare.queueCreate(n), opts);
258
- }
259
-
260
- async function doQueueDelete(
261
- name: string,
262
- opts: InfraOptions,
263
- cf?: CloudflareService
264
- ): Promise<void> {
265
- const cloudflare = cf ?? new CloudflareService();
266
- await handleDelete(name, "Queue", (n) => cloudflare.queueDelete(n), opts);
267
- }
268
-
269
- // ---------------------------------------------------------------------------
270
- // Provision handler
271
- // ---------------------------------------------------------------------------
272
-
273
- /**
274
- * Provision all infrastructure by scanning each enabled worker's wrangler.jsonc
275
- * for D1 databases, KV namespaces, R2 buckets, and Queue bindings, then
276
- * auto-creating any referenced resources via CloudflareService.
277
- */
278
- async function doProvision(
279
- opts: InfraOptions,
280
- cf?: CloudflareService,
281
- config?: ConfigService
282
- ): Promise<ProvisionResult> {
283
- const cloudflare = cf ?? new CloudflareService();
284
- const configService = config ?? new ConfigService();
285
- const items: ProvisionItem[] = [];
286
- let created = 0;
287
- let errors = 0;
288
- let exists = 0;
289
-
290
- try {
291
- await configService.load();
292
- } catch (err) {
293
- const message = err instanceof Error ? err.message : String(err);
294
- formatError(new CLIError(message, ExitCode.ERROR), opts);
295
- return {
296
- items: [],
297
- summary: { total: 0, created: 0, errors: 0, exists: 0 },
298
- };
299
- }
300
-
301
- const enabledWorkers = configService.listEnabledWorkers();
302
-
303
- if (enabledWorkers.length === 0) {
304
- if (!opts.quiet) {
305
- process.stdout.write(
306
- theme.dim("No enabled workers found in wrangler.jsonc.\n")
307
- );
308
- }
309
- return {
310
- items: [],
311
- summary: { total: 0, created: 0, errors: 0, exists: 0 },
312
- };
313
- }
314
-
315
- const s = spinner();
316
-
317
- for (const workerName of enabledWorkers) {
318
- const workerConfig = configService.getWorker(workerName);
319
- if (!workerConfig?.path) continue;
320
-
321
- const wranglerPath = resolve(workerConfig.path, "wrangler.jsonc");
322
- const file = Bun.file(wranglerPath);
323
-
324
- if (!(await file.exists())) continue;
325
-
326
- let wranglerConfig: Record<string, unknown>;
327
- try {
328
- const content = await file.text();
329
- wranglerConfig = (parse(content) ?? {}) as Record<string, unknown>;
330
- } catch {
331
- // Skip workers with invalid wrangler.jsonc
332
- continue;
333
- }
334
-
335
- // -- D1 databases --
336
- const d1Databases = Array.isArray(wranglerConfig.d1_databases)
337
- ? (wranglerConfig.d1_databases as Array<Record<string, unknown>>)
338
- : [];
339
- for (const db of d1Databases) {
340
- const dbName = (db.database_name as string) ?? (db.binding as string);
341
- if (!dbName) continue;
342
-
343
- s.start(`Provisioning D1 database: ${dbName}`);
344
- const result = await cloudflare.d1Create(dbName);
345
- if (result.ok) {
346
- items.push({ name: dbName, type: "d1", status: "created" });
347
- created++;
348
- s.stop(`D1 database "${dbName}" created`);
349
- } else if (result.error.toLowerCase().includes("already exists")) {
350
- items.push({ name: dbName, type: "d1", status: "exists" });
351
- exists++;
352
- s.stop(`D1 database "${dbName}" already exists`);
353
- } else {
354
- items.push({
355
- name: dbName,
356
- type: "d1",
357
- status: "error",
358
- error: result.error,
359
- });
360
- errors++;
361
- s.stop(`D1 database "${dbName}" failed: ${result.error}`);
362
- }
363
- }
364
-
365
- // -- KV namespaces --
366
- const kvNamespaces = Array.isArray(wranglerConfig.kv_namespaces)
367
- ? (wranglerConfig.kv_namespaces as Array<Record<string, unknown>>)
368
- : [];
369
- for (const kv of kvNamespaces) {
370
- const kvBinding = (kv.binding as string) ?? `kv-${workerName}`;
371
- s.start(`Provisioning KV namespace: ${kvBinding}`);
372
- const result = await cloudflare.kvCreate(kvBinding);
373
- if (result.ok) {
374
- items.push({ name: kvBinding, type: "kv", status: "created" });
375
- created++;
376
- s.stop(`KV namespace "${kvBinding}" created`);
377
- } else if (result.error.toLowerCase().includes("already exists")) {
378
- items.push({ name: kvBinding, type: "kv", status: "exists" });
379
- exists++;
380
- s.stop(`KV namespace "${kvBinding}" already exists`);
381
- } else {
382
- items.push({
383
- name: kvBinding,
384
- type: "kv",
385
- status: "error",
386
- error: result.error,
387
- });
388
- errors++;
389
- s.stop(`KV namespace "${kvBinding}" failed: ${result.error}`);
390
- }
391
- }
392
-
393
- // -- R2 buckets --
394
- const r2Buckets = Array.isArray(wranglerConfig.r2_buckets)
395
- ? (wranglerConfig.r2_buckets as Array<Record<string, unknown>>)
396
- : [];
397
- for (const bucket of r2Buckets) {
398
- const bucketName =
399
- (bucket.bucket_name as string) ?? (bucket.binding as string);
400
- if (!bucketName) continue;
401
-
402
- s.start(`Provisioning R2 bucket: ${bucketName}`);
403
- const result = await cloudflare.r2Create(bucketName);
404
- if (result.ok) {
405
- items.push({ name: bucketName, type: "r2", status: "created" });
406
- created++;
407
- s.stop(`R2 bucket "${bucketName}" created`);
408
- } else if (result.error.toLowerCase().includes("already exists")) {
409
- items.push({ name: bucketName, type: "r2", status: "exists" });
410
- exists++;
411
- s.stop(`R2 bucket "${bucketName}" already exists`);
412
- } else {
413
- items.push({
414
- name: bucketName,
415
- type: "r2",
416
- status: "error",
417
- error: result.error,
418
- });
419
- errors++;
420
- s.stop(`R2 bucket "${bucketName}" failed: ${result.error}`);
421
- }
422
- }
423
-
424
- // -- Queues --
425
- let queueNames: string[] = [];
426
- if (wranglerConfig.queues && typeof wranglerConfig.queues === "object") {
427
- const queues = wranglerConfig.queues as Record<string, unknown>;
428
- const producers = Array.isArray(queues.producers)
429
- ? (queues.producers as Array<Record<string, unknown>>)
430
- : [];
431
- const consumers = Array.isArray(queues.consumers)
432
- ? (queues.consumers as Array<Record<string, unknown>>)
433
- : [];
434
- queueNames = [
435
- ...producers.map((q) => q.queue as string),
436
- ...consumers.map((q) => q.queue as string),
437
- ].filter(Boolean);
438
- }
439
- for (const qName of [...new Set(queueNames)]) {
440
- s.start(`Provisioning Queue: ${qName}`);
441
- const result = await cloudflare.queueCreate(qName);
442
- if (result.ok) {
443
- items.push({ name: qName, type: "queue", status: "created" });
444
- created++;
445
- s.stop(`Queue "${qName}" created`);
446
- } else if (result.error.toLowerCase().includes("already exists")) {
447
- items.push({ name: qName, type: "queue", status: "exists" });
448
- exists++;
449
- s.stop(`Queue "${qName}" already exists`);
450
- } else {
451
- items.push({
452
- name: qName,
453
- type: "queue",
454
- status: "error",
455
- error: result.error,
456
- });
457
- errors++;
458
- s.stop(`Queue "${qName}" failed: ${result.error}`);
459
- }
460
- }
461
- }
462
-
463
- const summary = { total: items.length, created, errors, exists };
464
- const result: ProvisionResult = { items, summary };
465
-
466
- // Show summary table
467
- if (!opts.quiet) {
468
- const summaryRows = [
469
- { Metric: "Total resources", Value: String(summary.total) },
470
- { Metric: "Created", Value: String(summary.created) },
471
- { Metric: "Already existed", Value: String(summary.exists) },
472
- { Metric: "Errors", Value: String(summary.errors) },
473
- ];
474
- if (opts.json) {
475
- formatJson(result, opts);
476
- } else {
477
- process.stdout.write("\n");
478
- formatTable(summaryRows, opts);
479
- }
480
- }
481
-
482
- return result;
483
- }
484
-
485
- // ---------------------------------------------------------------------------
486
- // Vectorize handlers
487
- // ---------------------------------------------------------------------------
488
-
489
- async function doVectorizeList(
490
- opts: InfraOptions,
491
- cf?: CloudflareService
492
- ): Promise<void> {
493
- const cloudflare = cf ?? new CloudflareService();
494
- const result = await cloudflare.vectorizeList();
495
- displayListResult(result, opts, ["name", "id", "dimensions", "metric"]);
496
- }
497
-
498
- async function doVectorizeCreate(
499
- name: string,
500
- opts: InfraOptions,
501
- cf?: CloudflareService
502
- ): Promise<void> {
503
- const cloudflare = cf ?? new CloudflareService();
504
- await handleCreate(
505
- name,
506
- "Vectorize index",
507
- (n) => cloudflare.vectorizeCreate(n),
508
- opts
509
- );
510
- }
511
-
512
- async function doVectorizeDelete(
513
- name: string,
514
- opts: InfraOptions,
515
- cf?: CloudflareService
516
- ): Promise<void> {
517
- const cloudflare = cf ?? new CloudflareService();
518
- await handleDelete(
519
- name,
520
- "Vectorize index",
521
- (n) => cloudflare.vectorizeDelete(n),
522
- opts
523
- );
524
- }
525
-
526
- // ---------------------------------------------------------------------------
527
- // Analytics handlers
528
- // ---------------------------------------------------------------------------
529
-
530
- async function doAnalyticsList(
531
- opts: InfraOptions,
532
- cf?: CloudflareService
533
- ): Promise<void> {
534
- const cloudflare = cf ?? new CloudflareService();
535
- const result = await cloudflare.analyticsList();
536
- displayListResult(result, opts);
537
- }
538
-
539
- async function doAnalyticsCreate(
540
- name: string,
541
- opts: InfraOptions,
542
- cf?: CloudflareService
543
- ): Promise<void> {
544
- const cloudflare = cf ?? new CloudflareService();
545
- const result = await cloudflare.analyticsCreate(name);
546
- if (result.ok) {
547
- formatSuccess(`Analytics dataset "${name}" created`, opts);
548
- } else {
549
- process.stdout.write(`${result.error}\n`);
550
- }
551
- }
552
-
553
- // ---------------------------------------------------------------------------
554
- // Registration
555
- // ---------------------------------------------------------------------------
556
-
557
- /**
558
- * Register the `hoox infra` command group on the given commander program.
559
- *
560
- * @example
561
- * ```ts
562
- * import { Command } from "commander";
563
- * import { registerInfraCommand } from "./commands/infra/index.js";
564
- * const program = new Command();
565
- * registerInfraCommand(program);
566
- * program.parse();
567
- * ```
568
- */
569
- export function registerInfraCommand(program: Command): void {
570
- const infraCmd = program
571
- .command("infra")
572
- .summary(
573
- "Manage Cloudflare infrastructure (D1, KV, R2, Queues, Vectorize, Analytics)"
574
- )
575
- .description(
576
- `Provision and manage Cloudflare infrastructure resources.
577
-
578
- INFRASTRUCTURE TYPES:
579
- D1 - SQL databases for persistent storage
580
- KV - Key-value stores for configuration and caching
581
- R2 - S3-compatible object storage
582
- Queues - Message queues for async processing
583
- Vectorize - Vector database for AI-powered search
584
- Analytics - Time-series analytics engine
585
-
586
- EXAMPLES:
587
- hoox infra provision Auto-provision from wrangler.jsonc
588
- hoox infra d1 list List D1 databases
589
- hoox infra d1 create my-db Create a D1 database
590
- hoox infra kv list List KV namespaces
591
- hoox infra r2 list List R2 buckets
592
- hoox infra queues list List queues
593
- hoox infra vectorize list List Vectorize indexes
594
- hoox infra vectorize create my-rag-index Create a Vectorize index
595
- hoox infra analytics list List Analytics datasets`
596
- );
597
-
598
- // -- provision ---------------------------------------------------------
599
-
600
- infraCmd
601
- .command("provision")
602
- .summary("Auto-provision infrastructure from wrangler.jsonc")
603
- .description(
604
- `Automatically provision all required infrastructure based on worker wrangler.jsonc files.
605
-
606
- This reads each worker's wrangler.jsonc and creates:
607
- - D1 databases (from d1 binding)
608
- - KV namespaces (from kv_namespaces)
609
- - R2 buckets (from r2_buckets)
610
- - Queues (from queues)
611
-
612
- EXAMPLES:
613
- hoox infra provision`
614
- )
615
- .action(async function (this: Command) {
616
- const opts = getOptions(this);
617
- await doProvision(opts);
618
- });
619
-
620
- // -- d1 -----------------------------------------------------------------
621
-
622
- const d1Cmd = infraCmd
623
- .command("d1")
624
- .summary("Manage D1 SQL databases")
625
- .description(
626
- `D1 is Cloudflare's serverless SQL database.
627
-
628
- EXAMPLES:
629
- hoox infra d1 list
630
- hoox infra d1 create my-database
631
- hoox infra d1 delete my-database`
632
- );
633
-
634
- d1Cmd
635
- .command("list")
636
- .summary("List all D1 databases")
637
- .description(
638
- `List all D1 databases in your Cloudflare account.
639
-
640
- EXAMPLES:
641
- hoox infra d1 list`
642
- )
643
- .action(async function (this: Command) {
644
- const opts = getOptions(this);
645
- await doD1List(opts);
646
- });
647
-
648
- d1Cmd
649
- .command("create <name>")
650
- .summary("Create a new D1 database")
651
- .description(
652
- `Create a new D1 database.
653
-
654
- ARGUMENTS:
655
- name Database name
656
-
657
- EXAMPLES:
658
- hoox infra d1 create trade-data-db`
659
- )
660
- .action(async function (this: Command, name: string) {
661
- const opts = getOptions(this);
662
- await doD1Create(name, opts);
663
- });
664
-
665
- d1Cmd
666
- .command("delete <name>")
667
- .summary("Delete a D1 database")
668
- .description(
669
- `Delete a D1 database (WARNING: destructive operation).
670
-
671
- ARGUMENTS:
672
- name Database name
673
-
674
- EXAMPLES:
675
- hoox infra d1 delete trade-data-db`
676
- )
677
- .action(async function (this: Command, name: string) {
678
- const opts = getOptions(this);
679
- await doD1Delete(name, opts);
680
- });
681
-
682
- // -- kv -----------------------------------------------------------------
683
-
684
- const kvCmd = infraCmd
685
- .command("kv")
686
- .summary("Manage KV namespaces")
687
- .description(
688
- `KV (Key-Value) namespaces for configuration and caching.
689
-
690
- EXAMPLES:
691
- hoox infra kv list
692
- hoox infra kv create CONFIG_KV
693
- hoox infra kv delete <id>`
694
- );
695
-
696
- kvCmd
697
- .command("list")
698
- .summary("List all KV namespaces")
699
- .description(
700
- `List all KV namespaces in your Cloudflare account.
701
-
702
- EXAMPLES:
703
- hoox infra kv list`
704
- )
705
- .action(async function (this: Command) {
706
- const opts = getOptions(this);
707
- await doKvList(opts);
708
- });
709
-
710
- kvCmd
711
- .command("create <name>")
712
- .summary("Create a new KV namespace")
713
- .description(
714
- `Create a new KV namespace.
715
-
716
- ARGUMENTS:
717
- name KV namespace title
718
-
719
- EXAMPLES:
720
- hoox infra kv create CONFIG_KV`
721
- )
722
- .action(async function (this: Command, name: string) {
723
- const opts = getOptions(this);
724
- await doKvCreate(name, opts);
725
- });
726
-
727
- kvCmd
728
- .command("delete <id>")
729
- .summary("Delete a KV namespace by ID")
730
- .description(
731
- `Delete a KV namespace by its ID (WARNING: destructive operation).
732
-
733
- ARGUMENTS:
734
- id KV namespace ID (get from 'kv list')
735
-
736
- EXAMPLES:
737
- hoox infra kv delete c5917667a21745e390ff969f32b1847d`
738
- )
739
- .action(async function (this: Command, id: string) {
740
- const opts = getOptions(this);
741
- await doKvDelete(id, opts);
742
- });
743
-
744
- // -- r2 -----------------------------------------------------------------
745
-
746
- const r2Cmd = infraCmd
747
- .command("r2")
748
- .summary("Manage R2 object storage buckets")
749
- .description(
750
- `R2 is Cloudflare's S3-compatible object storage.
751
-
752
- EXAMPLES:
753
- hoox infra r2 list
754
- hoox infra r2 create trade-reports
755
- hoox infra r2 delete trade-reports`
756
- );
757
-
758
- r2Cmd
759
- .command("list")
760
- .summary("List all R2 buckets")
761
- .description(
762
- `List all R2 buckets in your Cloudflare account.
763
-
764
- EXAMPLES:
765
- hoox infra r2 list`
766
- )
767
- .action(async function (this: Command) {
768
- const opts = getOptions(this);
769
- await doR2List(opts);
770
- });
771
-
772
- r2Cmd
773
- .command("create <name>")
774
- .summary("Create a new R2 bucket")
775
- .description(
776
- `Create a new R2 bucket.
777
-
778
- ARGUMENTS:
779
- name Bucket name
780
-
781
- EXAMPLES:
782
- hoox infra r2 create trade-reports`
783
- )
784
- .action(async function (this: Command, name: string) {
785
- const opts = getOptions(this);
786
- await doR2Create(name, opts);
787
- });
788
-
789
- r2Cmd
790
- .command("delete <name>")
791
- .summary("Delete an R2 bucket")
792
- .description(
793
- `Delete an R2 bucket (WARNING: destructive operation).
794
-
795
- ARGUMENTS:
796
- name Bucket name
797
-
798
- EXAMPLES:
799
- hoox infra r2 delete trade-reports`
800
- )
801
- .action(async function (this: Command, name: string) {
802
- const opts = getOptions(this);
803
- await doR2Delete(name, opts);
804
- });
805
-
806
- // -- queues -------------------------------------------------------------
807
-
808
- const queuesCmd = infraCmd
809
- .command("queues")
810
- .summary("Manage Cloudflare Queues")
811
- .description(
812
- `Queues for asynchronous message processing between workers.
813
-
814
- EXAMPLES:
815
- hoox infra queues list
816
- hoox infra queues create trade-execution
817
- hoox infra queues delete trade-execution`
818
- );
819
-
820
- queuesCmd
821
- .command("list")
822
- .summary("List all Queues")
823
- .description(
824
- `List all queues in your Cloudflare account.
825
-
826
- EXAMPLES:
827
- hoox infra queues list`
828
- )
829
- .action(async function (this: Command) {
830
- const opts = getOptions(this);
831
- await doQueueList(opts);
832
- });
833
-
834
- queuesCmd
835
- .command("create <name>")
836
- .summary("Create a new Queue")
837
- .description(
838
- `Create a new queue.
839
-
840
- ARGUMENTS:
841
- name Queue name
842
-
843
- EXAMPLES:
844
- hoox infra queues create trade-execution`
845
- )
846
- .action(async function (this: Command, name: string) {
847
- const opts = getOptions(this);
848
- await doQueueCreate(name, opts);
849
- });
850
-
851
- queuesCmd
852
- .command("delete <name>")
853
- .summary("Delete a Queue")
854
- .description(
855
- `Delete a queue (WARNING: destructive operation).
856
-
857
- ARGUMENTS:
858
- name Queue name
859
-
860
- EXAMPLES:
861
- hoox infra queues delete trade-execution`
862
- )
863
- .action(async function (this: Command, name: string) {
864
- const opts = getOptions(this);
865
- await doQueueDelete(name, opts);
866
- });
867
-
868
- // -- vectorize ---------------------------------------------------------
869
-
870
- const vectorizeCmd = infraCmd
871
- .command("vectorize")
872
- .summary("Manage Vectorize indexes")
873
- .description(
874
- `Vectorize is Cloudflare's vector database for AI-powered search.
875
-
876
- EXAMPLES:
877
- hoox infra vectorize list
878
- hoox infra vectorize create my-rag-index
879
- hoox infra vectorize delete my-rag-index`
880
- );
881
-
882
- vectorizeCmd
883
- .command("list")
884
- .summary("List all Vectorize indexes")
885
- .description("List all Vectorize indexes in your Cloudflare account.")
886
- .action(async function (this: Command) {
887
- const opts = getOptions(this);
888
- await doVectorizeList(opts);
889
- });
890
-
891
- vectorizeCmd
892
- .command("create <name>")
893
- .summary("Create a new Vectorize index")
894
- .description(
895
- "Create a new Vectorize index with default dimensions (768) and cosine metric."
896
- )
897
- .action(async function (this: Command, name: string) {
898
- const opts = getOptions(this);
899
- await doVectorizeCreate(name, opts);
900
- });
901
-
902
- vectorizeCmd
903
- .command("delete <name>")
904
- .summary("Delete a Vectorize index")
905
- .description("Delete a Vectorize index (WARNING: destructive operation).")
906
- .action(async function (this: Command, name: string) {
907
- const opts = getOptions(this);
908
- await doVectorizeDelete(name, opts);
909
- });
910
-
911
- // -- analytics ---------------------------------------------------------
912
-
913
- const analyticsCmd = infraCmd
914
- .command("analytics")
915
- .summary("Manage Analytics Engine datasets")
916
- .description(
917
- `Analytics Engine for storing and querying time-series data.
918
-
919
- NOTE: Analytics Engine datasets must be created via Cloudflare Dashboard.
920
- The CLI provides creation instructions.
921
-
922
- EXAMPLES:
923
- hoox infra analytics list
924
- hoox infra analytics create hoox-analytics`
925
- );
926
-
927
- analyticsCmd
928
- .command("list")
929
- .summary("List all Analytics Engine datasets")
930
- .description("List all Analytics Engine datasets in your account.")
931
- .action(async function (this: Command) {
932
- const opts = getOptions(this);
933
- await doAnalyticsList(opts);
934
- });
935
-
936
- analyticsCmd
937
- .command("create <name>")
938
- .summary("Show instructions for creating an Analytics Engine dataset")
939
- .description(
940
- "Analytics Engine datasets must be created via Cloudflare Dashboard."
941
- )
942
- .action(async function (this: Command, name: string) {
943
- const opts = getOptions(this);
944
- await doAnalyticsCreate(name, opts);
945
- });
946
- }
947
-
948
- // ---------------------------------------------------------------------------
949
- // Exports (for testing)
950
- // ---------------------------------------------------------------------------
951
-
952
- export {
953
- doD1List,
954
- doD1Create,
955
- doD1Delete,
956
- doKvList,
957
- doKvCreate,
958
- doKvDelete,
959
- doR2List,
960
- doR2Create,
961
- doR2Delete,
962
- doQueueList,
963
- doQueueCreate,
964
- doQueueDelete,
965
- doVectorizeList,
966
- doVectorizeCreate,
967
- doVectorizeDelete,
968
- doAnalyticsList,
969
- doAnalyticsCreate,
970
- doProvision,
971
- displayListResult,
972
- handleCreate,
973
- handleDelete,
974
- };