@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,433 +0,0 @@
1
- import path from "node:path";
2
- import type { WranglerResult, DeployResult, DevResult } from "./types.js";
3
-
4
- /**
5
- * CloudflareService wraps the `wrangler` CLI via Bun.spawn for all
6
- * Cloudflare operations: deploy, dev, D1, KV, R2, Queues, Secrets, DNS.
7
- *
8
- * Every public method returns a {@link WranglerResult} discriminated union
9
- * so callers handle errors explicitly without try/catch.
10
- *
11
- * @example
12
- * ```ts
13
- * const cf = new CloudflareService();
14
- * const result = await cf.whoami();
15
- * if (result.ok) {
16
- * console.log(result.value);
17
- * } else {
18
- * console.error(result.error);
19
- * }
20
- * ```
21
- */
22
- export class CloudflareService {
23
- private readonly cwd: string;
24
-
25
- constructor(cwd?: string) {
26
- this.cwd = cwd ?? process.cwd();
27
- }
28
-
29
- // ---------------------------------------------------------------------------
30
- // Private helper
31
- // ---------------------------------------------------------------------------
32
-
33
- /**
34
- * Spawns `wrangler` with the given arguments, captures stdout/stderr,
35
- * and returns a typed result.
36
- *
37
- * Security: never passes secrets via CLI args — methods like
38
- * {@link secretPut} pipe values through stdin instead.
39
- */
40
- private async runWrangler(
41
- args: string[],
42
- cwd?: string
43
- ): Promise<WranglerResult<string>> {
44
- try {
45
- const proc = Bun.spawn(["wrangler", ...args], {
46
- cwd: cwd ?? this.cwd,
47
- stdout: "pipe",
48
- stderr: "pipe",
49
- });
50
-
51
- const stdout = await new Response(proc.stdout).text();
52
- const stderr = await new Response(proc.stderr).text();
53
- const exitCode = await proc.exited;
54
-
55
- if (exitCode === 0) {
56
- return { ok: true, value: stdout.trim() };
57
- }
58
-
59
- return {
60
- ok: false,
61
- error: stderr.trim() || `wrangler exited with code ${exitCode}`,
62
- };
63
- } catch (err) {
64
- const message = err instanceof Error ? err.message : String(err);
65
- return { ok: false, error: `Failed to spawn wrangler: ${message}` };
66
- }
67
- }
68
-
69
- // ---------------------------------------------------------------------------
70
- // Auth / identity
71
- // ---------------------------------------------------------------------------
72
-
73
- /** Runs `wrangler whoami` to verify Cloudflare authentication. */
74
- async whoami(): Promise<WranglerResult<string>> {
75
- return this.runWrangler(["whoami"]);
76
- }
77
-
78
- // ---------------------------------------------------------------------------
79
- // Deploy
80
- // ---------------------------------------------------------------------------
81
-
82
- /**
83
- * Deploys a worker via `wrangler deploy`.
84
- *
85
- * @param workerPath - Relative or absolute path to the worker directory
86
- * (must contain wrangler.jsonc).
87
- * @param env - Optional Cloudflare environment (e.g. "production").
88
- */
89
- async deploy(
90
- workerPath: string,
91
- env?: string
92
- ): Promise<WranglerResult<DeployResult>> {
93
- const resolvedPath = path.resolve(this.cwd, workerPath);
94
- const args = ["deploy"];
95
-
96
- if (env) {
97
- args.push("--env", env);
98
- }
99
-
100
- const result = await this.runWrangler(args, resolvedPath);
101
-
102
- if (!result.ok) {
103
- return result;
104
- }
105
-
106
- // Extract the worker URL from deploy output.
107
- // wrangler prints lines like: https://name.subdomain.workers.dev
108
- const url = this.extractUrl(result.value);
109
-
110
- // Parse verbose output for metrics
111
- const output = result.value;
112
- const deployResult: DeployResult = { url, rawOutput: output };
113
-
114
- // Extract worker name from path
115
- const pathParts = workerPath.split("/");
116
- deployResult.name = pathParts[pathParts.length - 1];
117
-
118
- // Extract bundle size (e.g., "Total Upload: 7102.32 KiB / gzip: 1493.05 KiB")
119
- const sizeMatch = output.match(/Total Upload:\s*([\d.]+)\s*([KMGT]?i?B)/i);
120
- if (sizeMatch) {
121
- deployResult.size = `${sizeMatch[1]} ${sizeMatch[2]}`;
122
- }
123
-
124
- // Extract startup time (e.g., "Worker Startup Time: 37 ms")
125
- const startupMatch = output.match(/Worker Startup Time:\s*(\d+)\s*ms/i);
126
- if (startupMatch) {
127
- deployResult.startupTime = `${startupMatch[1]} ms`;
128
- }
129
-
130
- // Extract version ID (e.g., "Current Version ID: 6a6efd9b-64cf-422b-8b10-84d9c2c6b2d3")
131
- const versionMatch = output.match(
132
- /Current Version ID:\s*([a-f0-9-]{36,})/i
133
- );
134
- if (versionMatch) {
135
- deployResult.versionId = versionMatch[1];
136
- }
137
-
138
- return { ok: true, value: deployResult };
139
- }
140
-
141
- // ---------------------------------------------------------------------------
142
- // Dev
143
- // ---------------------------------------------------------------------------
144
-
145
- /**
146
- * Starts a local dev server via `wrangler dev`.
147
- *
148
- * Note: `wrangler dev` runs until killed (Ctrl+C). This method spawns the
149
- * process but does NOT wait for it to exit — it resolves immediately with
150
- * the configured port. The caller is responsible for process lifecycle.
151
- *
152
- * @param workerPath - Path to the worker directory.
153
- * @param port - Dev server port (default: 8787).
154
- */
155
- async dev(
156
- workerPath: string,
157
- port?: number
158
- ): Promise<WranglerResult<DevResult>> {
159
- const devPort = port ?? 8787;
160
- const resolvedPath = path.resolve(this.cwd, workerPath);
161
-
162
- try {
163
- Bun.spawn(["wrangler", "dev", "--port", String(devPort)], {
164
- cwd: resolvedPath,
165
- stdout: "pipe",
166
- stderr: "pipe",
167
- });
168
-
169
- // Dev runs indefinitely — return immediately with the known port.
170
- return { ok: true, value: { port: devPort } };
171
- } catch (err) {
172
- const message = err instanceof Error ? err.message : String(err);
173
- return { ok: false, error: `Failed to start dev server: ${message}` };
174
- }
175
- }
176
-
177
- // ---------------------------------------------------------------------------
178
- // Logs
179
- // ---------------------------------------------------------------------------
180
-
181
- /** Tails live logs via `wrangler tail <workerName>`. */
182
- async tail(workerName: string): Promise<WranglerResult<string>> {
183
- return this.runWrangler(["tail", workerName]);
184
- }
185
-
186
- // ---------------------------------------------------------------------------
187
- // D1
188
- // ---------------------------------------------------------------------------
189
-
190
- /** Lists all D1 databases (`wrangler d1 list --json`). */
191
- async d1List(): Promise<WranglerResult<string>> {
192
- return this.runWrangler(["d1", "list", "--json"]);
193
- }
194
-
195
- /** Creates a D1 database (`wrangler d1 create <name>`). */
196
- async d1Create(name: string): Promise<WranglerResult<string>> {
197
- return this.runWrangler(["d1", "create", name]);
198
- }
199
-
200
- /** Deletes a D1 database (`wrangler d1 delete <name>`). */
201
- async d1Delete(name: string): Promise<WranglerResult<string>> {
202
- return this.runWrangler(["d1", "delete", name]);
203
- }
204
-
205
- /** Runs a SQL query on a D1 database (`wrangler d1 execute`). */
206
- async d1Execute(
207
- name: string,
208
- sql: string,
209
- remote: boolean = true
210
- ): Promise<WranglerResult<string>> {
211
- const args = ["d1", "execute", name, "--command", sql];
212
- if (remote) args.push("--remote");
213
- return this.runWrangler(args);
214
- }
215
-
216
- // ---------------------------------------------------------------------------
217
- // KV (wrangler v4+: use `kv namespace` instead of deprecated `kv:namespace`)
218
- // ---------------------------------------------------------------------------
219
-
220
- /** Lists all KV namespaces (`wrangler kv namespace list`). */
221
- async kvList(): Promise<WranglerResult<string>> {
222
- return this.runWrangler(["kv", "namespace", "list"]);
223
- }
224
-
225
- /** Creates a KV namespace (`wrangler kv namespace create <name>`). */
226
- async kvCreate(name: string): Promise<WranglerResult<string>> {
227
- return this.runWrangler(["kv", "namespace", "create", name]);
228
- }
229
-
230
- /** Deletes a KV namespace (`wrangler kv namespace delete --namespace-id <id>`). */
231
- async kvDelete(id: string): Promise<WranglerResult<string>> {
232
- return this.runWrangler([
233
- "kv",
234
- "namespace",
235
- "delete",
236
- "--namespace-id",
237
- id,
238
- ]);
239
- }
240
-
241
- // ---------------------------------------------------------------------------
242
- // R2
243
- // ---------------------------------------------------------------------------
244
-
245
- /** Lists all R2 buckets (`wrangler r2 bucket list`). */
246
- async r2List(): Promise<WranglerResult<string>> {
247
- return this.runWrangler(["r2", "bucket", "list"]);
248
- }
249
-
250
- /** Creates an R2 bucket (`wrangler r2 bucket create <name>`). */
251
- async r2Create(name: string): Promise<WranglerResult<string>> {
252
- return this.runWrangler(["r2", "bucket", "create", name]);
253
- }
254
-
255
- /** Deletes an R2 bucket (`wrangler r2 bucket delete <name>`). */
256
- async r2Delete(name: string): Promise<WranglerResult<string>> {
257
- return this.runWrangler(["r2", "bucket", "delete", name]);
258
- }
259
-
260
- // ---------------------------------------------------------------------------
261
- // Queues
262
- // ---------------------------------------------------------------------------
263
-
264
- /** Lists all queues (`wrangler queues list`). */
265
- async queueList(): Promise<WranglerResult<string>> {
266
- return this.runWrangler(["queues", "list"]);
267
- }
268
-
269
- /** Creates a queue (`wrangler queues create <name>`). */
270
- async queueCreate(name: string): Promise<WranglerResult<string>> {
271
- return this.runWrangler(["queues", "create", name]);
272
- }
273
-
274
- /** Deletes a queue (`wrangler queues delete <name>`). */
275
- async queueDelete(name: string): Promise<WranglerResult<string>> {
276
- return this.runWrangler(["queues", "delete", name]);
277
- }
278
-
279
- // ---------------------------------------------------------------------------
280
- // Vectorize
281
- // ---------------------------------------------------------------------------
282
-
283
- /** Lists all vectorize indexes (`wrangler vectorize list --json`). */
284
- async vectorizeList(): Promise<WranglerResult<string>> {
285
- return this.runWrangler(["vectorize", "list", "--json"]);
286
- }
287
-
288
- /** Creates a vectorize index (`wrangler vectorize create <name> --dimensions=768 --metric=cosine`). */
289
- async vectorizeCreate(
290
- name: string,
291
- dimensions: number = 768,
292
- metric: string = "cosine"
293
- ): Promise<WranglerResult<string>> {
294
- return this.runWrangler([
295
- "vectorize",
296
- "create",
297
- name,
298
- "--dimensions",
299
- String(dimensions),
300
- "--metric",
301
- metric,
302
- ]);
303
- }
304
-
305
- /** Deletes a vectorize index (`wrangler vectorize delete <name>`). */
306
- async vectorizeDelete(name: string): Promise<WranglerResult<string>> {
307
- return this.runWrangler(["vectorize", "delete", name]);
308
- }
309
-
310
- // ---------------------------------------------------------------------------
311
- // Analytics
312
- // ---------------------------------------------------------------------------
313
-
314
- /** Lists all analytics datasets (`wrangler analytics dataset list`). */
315
- async analyticsList(): Promise<WranglerResult<string>> {
316
- return this.runWrangler(["analytics", "dataset", "list"]);
317
- }
318
-
319
- /**
320
- * Returns a helpful error — wrangler does not support creating analytics
321
- * datasets from the CLI. Users must create them via the Cloudflare Dashboard.
322
- */
323
- async analyticsCreate(_name: string): Promise<WranglerResult<string>> {
324
- return {
325
- ok: false,
326
- error:
327
- `Analytics datasets cannot be created via wrangler. ` +
328
- `Please use the Cloudflare Dashboard: ` +
329
- `https://dash.cloudflare.com/?to=/:account/analytics`,
330
- };
331
- }
332
-
333
- // ---------------------------------------------------------------------------
334
- // Secrets
335
- // ---------------------------------------------------------------------------
336
-
337
- /** Lists secrets for a worker (`wrangler secret list --name <workerName>`). */
338
- async secretList(workerName: string): Promise<WranglerResult<string>> {
339
- return this.runWrangler(["secret", "list", "--name", workerName]);
340
- }
341
-
342
- /**
343
- * Sets a secret for a worker via `wrangler secret put`.
344
- *
345
- * **Security**: the secret value is piped through stdin (never passed as a
346
- * CLI argument) to prevent exposure in `ps` output and shell history.
347
- */
348
- async secretPut(
349
- workerName: string,
350
- secretName: string,
351
- value: string
352
- ): Promise<WranglerResult<string>> {
353
- try {
354
- const proc = Bun.spawn(
355
- ["wrangler", "secret", "put", secretName, "--name", workerName],
356
- {
357
- cwd: this.cwd,
358
- stdout: "pipe",
359
- stderr: "pipe",
360
- stdin: "pipe",
361
- }
362
- );
363
-
364
- // Pipe the secret value through stdin — never via CLI args.
365
- proc.stdin.write(value + "\n");
366
- proc.stdin.end();
367
-
368
- const stdout = await new Response(proc.stdout).text();
369
- const stderr = await new Response(proc.stderr).text();
370
- const exitCode = await proc.exited;
371
-
372
- if (exitCode === 0) {
373
- return { ok: true, value: stdout.trim() };
374
- }
375
-
376
- return {
377
- ok: false,
378
- error: stderr.trim() || `wrangler exited with code ${exitCode}`,
379
- };
380
- } catch (err) {
381
- const message = err instanceof Error ? err.message : String(err);
382
- return { ok: false, error: `Failed to set secret: ${message}` };
383
- }
384
- }
385
-
386
- /** Deletes a secret from a worker (`wrangler secret delete <secretName> --name <workerName>`). */
387
- async secretDelete(
388
- workerName: string,
389
- secretName: string
390
- ): Promise<WranglerResult<string>> {
391
- return this.runWrangler([
392
- "secret",
393
- "delete",
394
- secretName,
395
- "--name",
396
- workerName,
397
- ]);
398
- }
399
-
400
- // ---------------------------------------------------------------------------
401
- // DNS / Zones
402
- // ---------------------------------------------------------------------------
403
-
404
- /** Lists all Cloudflare zones (`wrangler zones list`). */
405
- async zonesList(): Promise<WranglerResult<string>> {
406
- return this.runWrangler(["zones", "list"]);
407
- }
408
-
409
- // ---------------------------------------------------------------------------
410
- // Internal helpers
411
- // ---------------------------------------------------------------------------
412
-
413
- /**
414
- * Extracts a URL from wrangler deploy output.
415
- * wrangler v4+ prints lines like: https://name.subdomain.workers.dev
416
- */
417
- private extractUrl(stdout: string): string | undefined {
418
- // Match any https:// URL ending in workers.dev or cloudflareworkers.com
419
- // Handles direct (name.workers.dev), subdomain (name.acme.workers.dev),
420
- // and any other URL pattern wrangler v4+ might produce.
421
- // Also try to match URLs at the start of a line.
422
- for (const line of stdout.split("\n")) {
423
- const trimmed = line.trim();
424
- // wrangler v4+ outputs URLs like: https://name.subdomain.workers.dev
425
- // Possibly preceded by "Published" or "Uploaded"
426
- const match = trimmed.match(
427
- /(https?:\/\/[^\s]+(?:workers\.dev|cloudflareworkers\.com)[^\s]*)/
428
- );
429
- if (match) return match[1];
430
- }
431
- return undefined;
432
- }
433
- }
@@ -1,2 +0,0 @@
1
- export { CloudflareService } from "./cloudflare-service.js";
2
- export type { WranglerResult, DeployResult, DevResult } from "./types.js";
@@ -1,30 +0,0 @@
1
- import type { Result } from "@jango-blockchained/hoox-shared";
2
-
3
- /**
4
- * WranglerResult<T> — alias for the shared Result<T> type, used for all
5
- * wrangler CLI operations. Pattern: never throws; callers match on `ok`
6
- * to handle success/error.
7
- */
8
- export type WranglerResult<T> = Result<T>;
9
-
10
- /** Result of a wrangler deploy operation. */
11
- export interface DeployResult {
12
- /** The deployed worker URL extracted from wrangler stdout. */
13
- url?: string;
14
- /** Worker name */
15
- name?: string;
16
- /** Uploaded bundle size (e.g., "7102.32 KiB") */
17
- size?: string;
18
- /** Worker startup time (e.g., "37 ms") */
19
- startupTime?: string;
20
- /** Version ID */
21
- versionId?: string;
22
- /** Raw deploy output for verbose display */
23
- rawOutput?: string;
24
- }
25
-
26
- /** Result of a wrangler dev operation. */
27
- export interface DevResult {
28
- /** The local dev server port. */
29
- port: number;
30
- }