@jango-blockchained/hoox-cli 0.5.2 → 0.5.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.
Files changed (114) hide show
  1. package/bin/hoox.js +3 -4
  2. package/dist/index.js +32545 -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,545 +0,0 @@
1
- /**
2
- * `hoox waf` command — Cloudflare WAF (Web Application Firewall) management.
3
- *
4
- * Subcommands:
5
- * waf status Show WAF status for the zone
6
- * waf rules list List all active firewall rules
7
- * waf rules add <type> <value> Add a WAF rule
8
- * waf rules remove <id> Remove a WAF rule by ID
9
- * waf mode enable Enable WAF protection
10
- * waf mode disable Disable WAF protection
11
- */
12
-
13
- import type { Command } from "commander";
14
- import { CloudflareService } from "../../services/cloudflare/cloudflare-service.js";
15
- import type { WranglerResult } from "../../services/cloudflare/types.js";
16
- import { CLIError, ExitCode } from "../../utils/errors.js";
17
- import { formatSuccess, formatTable } from "../../utils/formatters.js";
18
- import { withErrorHandling } from "../../utils/error-handler.js";
19
- import { theme, icons } from "../../utils/theme.js";
20
- import type { FormatOptions } from "../../utils/formatters.js";
21
- import type { WafStatus, WafRule, WafRuleInput } from "./types.js";
22
-
23
- // ---------------------------------------------------------------------------
24
- // Cloudflare API helpers
25
- // ---------------------------------------------------------------------------
26
-
27
- const CF_API_BASE = "https://api.cloudflare.com/client/v4";
28
-
29
- /**
30
- * Reads the Cloudflare API token and account ID from environment variables.
31
- * Required for direct REST API calls (wrangler doesn't have native WAF commands).
32
- */
33
- function getCredentials(): { token: string; accountId: string } {
34
- const token = process.env.CLOUDFLARE_API_TOKEN;
35
- const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
36
- if (!token) {
37
- throw new CLIError(
38
- "CLOUDFLARE_API_TOKEN environment variable is not set. Set it or run `wrangler login`.",
39
- ExitCode.ERROR
40
- );
41
- }
42
- if (!accountId) {
43
- throw new CLIError(
44
- "CLOUDFLARE_ACCOUNT_ID environment variable is not set.",
45
- ExitCode.ERROR
46
- );
47
- }
48
- return { token, accountId };
49
- }
50
-
51
- /**
52
- * Makes an authenticated request to the Cloudflare REST API.
53
- * Returns a WranglerResult-style discriminated union for consistent error handling.
54
- */
55
- async function cfApi<T>(
56
- method: "GET" | "POST" | "PATCH" | "DELETE",
57
- path: string,
58
- body?: unknown
59
- ): Promise<WranglerResult<T>> {
60
- const { token } = getCredentials();
61
- const url = `${CF_API_BASE}${path}`;
62
-
63
- try {
64
- const response = await fetch(url, {
65
- method,
66
- headers: {
67
- Authorization: `Bearer ${token}`,
68
- "Content-Type": "application/json",
69
- },
70
- body: body !== undefined ? JSON.stringify(body) : undefined,
71
- });
72
-
73
- const json = (await response.json()) as {
74
- success: boolean;
75
- result: T;
76
- errors: Array<{ message: string }>;
77
- };
78
-
79
- if (!response.ok || !json.success) {
80
- const errorMsg =
81
- json.errors?.map((e) => e.message).join("; ") ||
82
- `HTTP ${response.status}`;
83
- return { ok: false, error: errorMsg };
84
- }
85
-
86
- return { ok: true, value: json.result };
87
- } catch (err) {
88
- const message = err instanceof Error ? err.message : String(err);
89
- return { ok: false, error: `Cloudflare API request failed: ${message}` };
90
- }
91
- }
92
-
93
- // ---------------------------------------------------------------------------
94
- // WAF API operations
95
- // ---------------------------------------------------------------------------
96
-
97
- interface CfWafSetting {
98
- id: string;
99
- value: string;
100
- }
101
-
102
- interface CfFirewallRule {
103
- id: string;
104
- description: string;
105
- action: string;
106
- filter: { id: string; expression: string };
107
- created_on: string;
108
- modified_on: string;
109
- }
110
-
111
- interface CfAnalyticsOverview {
112
- totals: {
113
- threats: number;
114
- };
115
- }
116
-
117
- /**
118
- * Builds expression from rule type and value.
119
- * ip-allowlist → (ip.src eq {value})
120
- * ip-blocklist → (ip.src eq {value})
121
- * rate-limit → handled as custom with rate-limit expression
122
- * custom → uses value as raw expression
123
- */
124
- function buildExpression(type: WafRuleInput["type"], value: string): string {
125
- switch (type) {
126
- case "ip-allowlist":
127
- return `(ip.src eq ${value})`;
128
- case "ip-blocklist":
129
- return `(ip.src eq ${value})`;
130
- case "rate-limit":
131
- // Rate limiting is configured via a separate API; here we build a
132
- // basic rate-limit expression that can be extended.
133
- return `(http.request.uri.path contains "/")`;
134
- case "custom":
135
- return value;
136
- }
137
- }
138
-
139
- /**
140
- * Maps rule type and value to a Cloudflare firewall rule action.
141
- */
142
- function mapAction(type: WafRuleInput["type"]): string {
143
- switch (type) {
144
- case "ip-allowlist":
145
- return "allow";
146
- case "ip-blocklist":
147
- return "block";
148
- case "rate-limit":
149
- return "managed_challenge";
150
- case "custom":
151
- return "block";
152
- }
153
- }
154
-
155
- /**
156
- * Fetches the Cloudflare zone to operate on. Uses CloudflareService.zonesList()
157
- * and picks the first zone. Falls back to env CLOUDFLARE_ZONE_ID.
158
- */
159
- async function resolveZone(
160
- cf: CloudflareService
161
- ): Promise<{ id: string; name: string }> {
162
- // Try explicit env var first
163
- if (process.env.CLOUDFLARE_ZONE_ID) {
164
- return {
165
- id: process.env.CLOUDFLARE_ZONE_ID,
166
- name: process.env.CLOUDFLARE_ZONE_ID,
167
- };
168
- }
169
-
170
- const result = await cf.zonesList();
171
- if (!result.ok) {
172
- throw new CLIError(`Failed to list zones: ${result.error}`, ExitCode.ERROR);
173
- }
174
-
175
- // wrangler zones list outputs lines like "zone-name (zone-id)"
176
- const lines = result.value.split("\n").filter(Boolean);
177
- if (lines.length === 0) {
178
- throw new CLIError(
179
- "No zones found. Set CLOUDFLARE_ZONE_ID environment variable.",
180
- ExitCode.ERROR
181
- );
182
- }
183
-
184
- // Parse first zone: "domain.com (abc123...)"
185
- const match = lines[0].match(/^(.+?)\s+\((.+?)\)\s*$/);
186
- if (match) {
187
- return { name: match[1], id: match[2] };
188
- }
189
-
190
- // Fallback: use the first line as ID
191
- return { name: lines[0], id: lines[0] };
192
- }
193
-
194
- // ---------------------------------------------------------------------------
195
- // Command action: waf status
196
- // ---------------------------------------------------------------------------
197
-
198
- async function handleStatus(opts: FormatOptions): Promise<void> {
199
- const cf = new CloudflareService();
200
-
201
- const zone = await resolveZone(cf);
202
-
203
- // Fetch WAF setting
204
- const wafResult = await cfApi<CfWafSetting>(
205
- "GET",
206
- `/zones/${zone.id}/settings/waf`
207
- );
208
- if (!wafResult.ok) {
209
- throw new CLIError(
210
- `Failed to get WAF status: ${wafResult.error}`,
211
- ExitCode.ERROR
212
- );
213
- }
214
-
215
- // Fetch firewall rules count
216
- const rulesResult = await cfApi<CfFirewallRule[]>(
217
- "GET",
218
- `/zones/${zone.id}/firewall/rules?per_page=50`
219
- );
220
- const activeRulesCount = rulesResult.ok ? rulesResult.value.length : 0;
221
-
222
- // Fetch recent blocks (last 24h analytics overview)
223
- let recentBlocks = 0;
224
- const since = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
225
- const analyticsResult = await cfApi<CfAnalyticsOverview>(
226
- "GET",
227
- `/zones/${zone.id}/analytics/dashboard?since=${encodeURIComponent(since)}&continuous=true`
228
- );
229
- if (analyticsResult.ok) {
230
- recentBlocks = analyticsResult.value.totals?.threats ?? 0;
231
- }
232
-
233
- const status: WafStatus = {
234
- enabled: wafResult.value.value === "on",
235
- mode: wafResult.value.value,
236
- activeRulesCount,
237
- recentBlocks,
238
- zoneId: zone.id,
239
- zoneName: zone.name,
240
- };
241
-
242
- if (opts.json) {
243
- process.stdout.write(JSON.stringify(status, null, 2) + "\n");
244
- return;
245
- }
246
-
247
- process.stdout.write(theme.heading(`\nWAF status for ${zone.name}\n\n`));
248
-
249
- const colorFn = status.enabled ? theme.success : theme.error;
250
- process.stdout.write(
251
- ` Status: ${colorFn(status.enabled ? `${icons.success} ENABLED` : `${icons.error} DISABLED`)}\n`
252
- );
253
- process.stdout.write(` Mode: ${status.mode}\n`);
254
- process.stdout.write(` Rules: ${status.activeRulesCount} active\n`);
255
- process.stdout.write(` Blocks: ${status.recentBlocks} (last 24h)\n`);
256
- process.stdout.write(` Zone ID: ${theme.dim(zone.id)}\n\n`);
257
- }
258
-
259
- // ---------------------------------------------------------------------------
260
- // Command action: waf rules list
261
- // ---------------------------------------------------------------------------
262
-
263
- async function handleRulesList(opts: FormatOptions): Promise<void> {
264
- const cf = new CloudflareService();
265
- const zone = await resolveZone(cf);
266
-
267
- const result = await cfApi<CfFirewallRule[]>(
268
- "GET",
269
- `/zones/${zone.id}/firewall/rules?per_page=50`
270
- );
271
- if (!result.ok) {
272
- throw new CLIError(
273
- `Failed to list firewall rules: ${result.error}`,
274
- ExitCode.ERROR
275
- );
276
- }
277
-
278
- const rules: WafRule[] = result.value.map((r) => ({
279
- id: r.id,
280
- description: r.description,
281
- mode: r.action,
282
- expression: r.filter?.expression ?? "(unknown)",
283
- created_at: r.created_on,
284
- updated_at: r.modified_on,
285
- }));
286
-
287
- if (opts.json) {
288
- process.stdout.write(JSON.stringify(rules, null, 2) + "\n");
289
- return;
290
- }
291
-
292
- if (rules.length === 0) {
293
- process.stdout.write(
294
- `${theme.dim(`${icons.info} No firewall rules configured.\n`)}`
295
- );
296
- return;
297
- }
298
-
299
- process.stdout.write(theme.heading(`\nWAF rules for ${zone.name}\n\n`));
300
-
301
- const rows = rules.map((r) => ({
302
- ID: r.id.substring(0, 8) + "...",
303
- Description: r.description || "(no description)",
304
- Mode: r.mode,
305
- Expression:
306
- r.expression.length > 40
307
- ? r.expression.substring(0, 37) + "..."
308
- : r.expression,
309
- }));
310
-
311
- formatTable(rows, opts);
312
- }
313
-
314
- // ---------------------------------------------------------------------------
315
- // Command action: waf rules add
316
- // ---------------------------------------------------------------------------
317
-
318
- async function handleRulesAdd(
319
- type: string,
320
- value: string,
321
- opts: FormatOptions
322
- ): Promise<void> {
323
- const validTypes = ["ip-allowlist", "ip-blocklist", "rate-limit", "custom"];
324
- if (!validTypes.includes(type)) {
325
- throw new CLIError(
326
- `Invalid rule type "${type}". Must be one of: ${validTypes.join(", ")}`,
327
- ExitCode.INVALID_USAGE
328
- );
329
- }
330
-
331
- const ruleInput: WafRuleInput = {
332
- type: type as WafRuleInput["type"],
333
- value,
334
- };
335
-
336
- const cf = new CloudflareService();
337
- const zone = await resolveZone(cf);
338
-
339
- const expression = buildExpression(ruleInput.type, value);
340
- const action = mapAction(ruleInput.type);
341
-
342
- const body = {
343
- description: ruleInput.description ?? `${ruleInput.type} rule for ${value}`,
344
- action,
345
- filter: { expression },
346
- };
347
-
348
- // Create filter first, then rule referencing the filter
349
- const filterResult = await cfApi<{ id: string }>(
350
- "POST",
351
- `/zones/${zone.id}/filters`,
352
- { expression }
353
- );
354
- if (!filterResult.ok) {
355
- throw new CLIError(
356
- `Failed to create filter: ${filterResult.error}`,
357
- ExitCode.ERROR
358
- );
359
- }
360
-
361
- const ruleBody = {
362
- description: body.description,
363
- action,
364
- filter: { id: filterResult.value.id },
365
- };
366
-
367
- const ruleResult = await cfApi<CfFirewallRule>(
368
- "POST",
369
- `/zones/${zone.id}/firewall/rules`,
370
- [ruleBody] // Cloudflare expects an array of rules
371
- );
372
- if (!ruleResult.ok) {
373
- throw new CLIError(
374
- `Failed to create firewall rule: ${ruleResult.error}`,
375
- ExitCode.ERROR
376
- );
377
- }
378
-
379
- // Cloudflare returns an array of created rules
380
- const created = Array.isArray(ruleResult.value)
381
- ? (ruleResult.value[0] as unknown as CfFirewallRule)
382
- : (ruleResult.value as unknown as CfFirewallRule);
383
-
384
- formatSuccess(
385
- `WAF rule added (${created.id}) — ${created.action} for "${value}"`,
386
- opts
387
- );
388
- }
389
-
390
- // ---------------------------------------------------------------------------
391
- // Command action: waf rules remove
392
- // ---------------------------------------------------------------------------
393
-
394
- async function handleRulesRemove(
395
- ruleId: string,
396
- opts: FormatOptions
397
- ): Promise<void> {
398
- const cf = new CloudflareService();
399
- const zone = await resolveZone(cf);
400
-
401
- const result = await cfApi<{ id: string }>(
402
- "DELETE",
403
- `/zones/${zone.id}/firewall/rules/${ruleId}`
404
- );
405
- if (!result.ok) {
406
- throw new CLIError(
407
- `Failed to remove firewall rule: ${result.error}`,
408
- ExitCode.ERROR
409
- );
410
- }
411
-
412
- formatSuccess(`WAF rule ${ruleId} removed`, opts);
413
- }
414
-
415
- // ---------------------------------------------------------------------------
416
- // Command action: waf mode enable / disable
417
- // ---------------------------------------------------------------------------
418
-
419
- async function handleMode(
420
- mode: "on" | "off",
421
- opts: FormatOptions
422
- ): Promise<void> {
423
- const cf = new CloudflareService();
424
- const zone = await resolveZone(cf);
425
-
426
- const result = await cfApi<CfWafSetting>(
427
- "PATCH",
428
- `/zones/${zone.id}/settings/waf`,
429
- { value: mode }
430
- );
431
- if (!result.ok) {
432
- throw new CLIError(
433
- `Failed to ${mode === "on" ? "enable" : "disable"} WAF: ${result.error}`,
434
- ExitCode.ERROR
435
- );
436
- }
437
-
438
- const label = mode === "on" ? "enabled" : "disabled";
439
- formatSuccess(`WAF ${label} on zone ${zone.name}`, opts);
440
- }
441
-
442
- // ---------------------------------------------------------------------------
443
- // Command registration
444
- // ---------------------------------------------------------------------------
445
-
446
- /**
447
- * Registers the `hoox waf` command and all subcommands on the given
448
- * Commander.js program instance.
449
- */
450
- export function registerWafCommand(program: Command): void {
451
- const waf = program
452
- .command("waf")
453
- .description("Manage Cloudflare WAF (Web Application Firewall)");
454
-
455
- // -- waf status ------------------------------------------------------------
456
- waf
457
- .command("status")
458
- .description(
459
- "Show WAF status (enabled/disabled, active rules, recent blocks)"
460
- )
461
- .action(
462
- withErrorHandling(
463
- async (_, cmd: Command) => {
464
- const opts: FormatOptions = cmd.parent!.parent!.opts();
465
- await handleStatus(opts);
466
- },
467
- { service: "waf" }
468
- )
469
- );
470
-
471
- // -- waf rules -------------------------------------------------------------
472
- const rules = waf.command("rules").description("Manage WAF firewall rules");
473
-
474
- rules
475
- .command("list")
476
- .description("List all WAF firewall rules")
477
- .action(
478
- withErrorHandling(
479
- async (_, cmd: Command) => {
480
- const opts: FormatOptions = cmd.parent!.parent!.parent!.opts();
481
- await handleRulesList(opts);
482
- },
483
- { service: "waf" }
484
- )
485
- );
486
-
487
- rules
488
- .command("add <type> <value>")
489
- .description(
490
- "Add a WAF rule. Types: ip-allowlist, ip-blocklist, rate-limit, custom"
491
- )
492
- .action(
493
- withErrorHandling(
494
- async (type: string, value: string, _, cmd: Command) => {
495
- const opts: FormatOptions = cmd.parent!.parent!.parent!.opts();
496
- await handleRulesAdd(type, value, opts);
497
- },
498
- { service: "waf" }
499
- )
500
- );
501
-
502
- rules
503
- .command("remove <ruleId>")
504
- .description("Remove a WAF rule by ID")
505
- .action(
506
- withErrorHandling(
507
- async (ruleId: string, _, cmd: Command) => {
508
- const opts: FormatOptions = cmd.parent!.parent!.parent!.opts();
509
- await handleRulesRemove(ruleId, opts);
510
- },
511
- { service: "waf" }
512
- )
513
- );
514
-
515
- // -- waf mode --------------------------------------------------------------
516
- const mode = waf
517
- .command("mode")
518
- .description("Enable or disable WAF protection");
519
-
520
- mode
521
- .command("enable")
522
- .description("Enable WAF protection on the zone")
523
- .action(
524
- withErrorHandling(
525
- async (_, cmd: Command) => {
526
- const opts: FormatOptions = cmd.parent!.parent!.parent!.opts();
527
- await handleMode("on", opts);
528
- },
529
- { service: "waf" }
530
- )
531
- );
532
-
533
- mode
534
- .command("disable")
535
- .description("Disable WAF protection on the zone")
536
- .action(
537
- withErrorHandling(
538
- async (_, cmd: Command) => {
539
- const opts: FormatOptions = cmd.parent!.parent!.parent!.opts();
540
- await handleMode("off", opts);
541
- },
542
- { service: "waf" }
543
- )
544
- );
545
- }