@cardelli/ambit 0.1.5 → 0.2.0

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 (139) hide show
  1. package/esm/cli/commands/create/index.d.ts +2 -0
  2. package/esm/cli/commands/create/index.d.ts.map +1 -0
  3. package/esm/cli/commands/create/index.js +292 -0
  4. package/esm/cli/commands/create/machine.d.ts +33 -0
  5. package/esm/cli/commands/create/machine.d.ts.map +1 -0
  6. package/esm/cli/commands/create/machine.js +162 -0
  7. package/esm/cli/commands/deploy/index.d.ts +2 -0
  8. package/esm/cli/commands/deploy/index.d.ts.map +1 -0
  9. package/esm/cli/commands/deploy/index.js +290 -0
  10. package/esm/cli/commands/deploy/machine.d.ts +52 -0
  11. package/esm/cli/commands/deploy/machine.d.ts.map +1 -0
  12. package/esm/cli/commands/deploy/machine.js +116 -0
  13. package/esm/cli/commands/deploy/modes.d.ts +18 -0
  14. package/esm/cli/commands/deploy/modes.d.ts.map +1 -0
  15. package/esm/cli/commands/deploy/modes.js +152 -0
  16. package/esm/cli/commands/destroy/app.d.ts +2 -0
  17. package/esm/cli/commands/destroy/app.d.ts.map +1 -0
  18. package/esm/cli/commands/destroy/app.js +173 -0
  19. package/esm/cli/commands/destroy/index.d.ts +2 -0
  20. package/esm/cli/commands/destroy/index.d.ts.map +1 -0
  21. package/esm/cli/commands/destroy/index.js +63 -0
  22. package/esm/cli/commands/destroy/network.d.ts +2 -0
  23. package/esm/cli/commands/destroy/network.d.ts.map +1 -0
  24. package/esm/cli/commands/destroy/network.js +210 -0
  25. package/esm/cli/commands/doctor.d.ts.map +1 -0
  26. package/esm/cli/commands/doctor.js +295 -0
  27. package/esm/{src/cli → cli}/commands/list.d.ts.map +1 -1
  28. package/esm/{src/cli → cli}/commands/list.js +39 -54
  29. package/esm/cli/commands/status.d.ts.map +1 -0
  30. package/esm/cli/commands/status.js +331 -0
  31. package/esm/cli/mod.d.ts.map +1 -0
  32. package/esm/{src/cli → cli}/mod.js +4 -4
  33. package/esm/deno.d.ts +4 -18
  34. package/esm/deno.js +5 -19
  35. package/esm/deps/jsr.io/@std/path/1.1.4/constants.d.ts +1 -1
  36. package/esm/lib/args.d.ts +11 -0
  37. package/esm/lib/args.d.ts.map +1 -0
  38. package/esm/lib/args.js +28 -0
  39. package/esm/lib/cli.d.ts +0 -1
  40. package/esm/lib/cli.d.ts.map +1 -1
  41. package/esm/lib/cli.js +0 -1
  42. package/esm/lib/command.d.ts +0 -3
  43. package/esm/lib/command.d.ts.map +1 -1
  44. package/esm/lib/command.js +2 -13
  45. package/esm/lib/machine.d.ts +11 -0
  46. package/esm/lib/machine.d.ts.map +1 -0
  47. package/esm/lib/machine.js +15 -0
  48. package/esm/lib/output.d.ts +2 -1
  49. package/esm/lib/output.d.ts.map +1 -1
  50. package/esm/lib/output.js +21 -3
  51. package/esm/lib/result.d.ts +0 -1
  52. package/esm/lib/result.d.ts.map +1 -1
  53. package/esm/lib/result.js +0 -1
  54. package/esm/main.d.ts +6 -6
  55. package/esm/main.d.ts.map +1 -1
  56. package/esm/main.js +7 -9
  57. package/esm/providers/fly.d.ts +81 -0
  58. package/esm/providers/fly.d.ts.map +1 -0
  59. package/esm/providers/fly.js +372 -0
  60. package/esm/providers/tailscale.d.ts +31 -0
  61. package/esm/providers/tailscale.d.ts.map +1 -0
  62. package/esm/providers/tailscale.js +150 -0
  63. package/esm/{src/schemas → schemas}/fly.d.ts +1 -11
  64. package/esm/schemas/fly.d.ts.map +1 -0
  65. package/esm/{src/schemas → schemas}/fly.js +14 -56
  66. package/esm/{src/schemas → schemas}/tailscale.d.ts +1 -2
  67. package/esm/schemas/tailscale.d.ts.map +1 -0
  68. package/esm/{src/schemas → schemas}/tailscale.js +2 -3
  69. package/esm/src/{docker/router → router}/Dockerfile +0 -11
  70. package/esm/src/{docker/router → router}/start.sh +18 -9
  71. package/esm/util/constants.d.ts +13 -0
  72. package/esm/util/constants.d.ts.map +1 -0
  73. package/esm/util/constants.js +34 -0
  74. package/esm/{src → util}/credentials.d.ts +0 -1
  75. package/esm/util/credentials.d.ts.map +1 -0
  76. package/esm/{src → util}/credentials.js +3 -5
  77. package/esm/{src → util}/discovery.d.ts +16 -3
  78. package/esm/util/discovery.d.ts.map +1 -0
  79. package/esm/{src → util}/discovery.js +24 -15
  80. package/esm/util/fly-transforms.d.ts +27 -0
  81. package/esm/util/fly-transforms.d.ts.map +1 -0
  82. package/esm/util/fly-transforms.js +87 -0
  83. package/esm/{src → util}/guard.d.ts +1 -2
  84. package/esm/util/guard.d.ts.map +1 -0
  85. package/esm/{src → util}/guard.js +27 -27
  86. package/esm/util/naming.d.ts +5 -0
  87. package/esm/util/naming.d.ts.map +1 -0
  88. package/esm/util/naming.js +12 -0
  89. package/esm/{src → util}/resolve.d.ts +2 -3
  90. package/esm/util/resolve.d.ts.map +1 -0
  91. package/esm/{src → util}/resolve.js +1 -2
  92. package/esm/util/session.d.ts +16 -0
  93. package/esm/util/session.d.ts.map +1 -0
  94. package/esm/util/session.js +19 -0
  95. package/esm/util/tailscale-local.d.ts +13 -0
  96. package/esm/util/tailscale-local.d.ts.map +1 -0
  97. package/esm/util/tailscale-local.js +63 -0
  98. package/esm/{src → util}/template.d.ts +0 -1
  99. package/esm/util/template.d.ts.map +1 -0
  100. package/esm/{src → util}/template.js +0 -1
  101. package/package.json +1 -49
  102. package/esm/lib/paths.d.ts +0 -3
  103. package/esm/lib/paths.d.ts.map +0 -1
  104. package/esm/lib/paths.js +0 -5
  105. package/esm/src/cli/commands/create.d.ts +0 -2
  106. package/esm/src/cli/commands/create.d.ts.map +0 -1
  107. package/esm/src/cli/commands/create.js +0 -308
  108. package/esm/src/cli/commands/deploy.d.ts +0 -2
  109. package/esm/src/cli/commands/deploy.d.ts.map +0 -1
  110. package/esm/src/cli/commands/deploy.js +0 -430
  111. package/esm/src/cli/commands/destroy.d.ts +0 -2
  112. package/esm/src/cli/commands/destroy.d.ts.map +0 -1
  113. package/esm/src/cli/commands/destroy.js +0 -340
  114. package/esm/src/cli/commands/doctor.d.ts.map +0 -1
  115. package/esm/src/cli/commands/doctor.js +0 -141
  116. package/esm/src/cli/commands/status.d.ts.map +0 -1
  117. package/esm/src/cli/commands/status.js +0 -152
  118. package/esm/src/cli/mod.d.ts.map +0 -1
  119. package/esm/src/credentials.d.ts.map +0 -1
  120. package/esm/src/discovery.d.ts.map +0 -1
  121. package/esm/src/guard.d.ts.map +0 -1
  122. package/esm/src/providers/fly.d.ts +0 -76
  123. package/esm/src/providers/fly.d.ts.map +0 -1
  124. package/esm/src/providers/fly.js +0 -407
  125. package/esm/src/providers/tailscale.d.ts +0 -31
  126. package/esm/src/providers/tailscale.d.ts.map +0 -1
  127. package/esm/src/providers/tailscale.js +0 -189
  128. package/esm/src/resolve.d.ts.map +0 -1
  129. package/esm/src/schemas/config.d.ts +0 -5
  130. package/esm/src/schemas/config.d.ts.map +0 -1
  131. package/esm/src/schemas/config.js +0 -22
  132. package/esm/src/schemas/fly.d.ts.map +0 -1
  133. package/esm/src/schemas/tailscale.d.ts.map +0 -1
  134. package/esm/src/template.d.ts.map +0 -1
  135. /package/esm/{src/cli → cli}/commands/doctor.d.ts +0 -0
  136. /package/esm/{src/cli → cli}/commands/list.d.ts +0 -0
  137. /package/esm/{src/cli → cli}/commands/status.d.ts +0 -0
  138. /package/esm/{src/cli → cli}/mod.d.ts +0 -0
  139. /package/esm/src/{docker/router → router}/fly.toml +0 -0
@@ -0,0 +1,173 @@
1
+ // =============================================================================
2
+ // Destroy App — Destroy a Workload App on a Network
3
+ // =============================================================================
4
+ import { parseArgs } from "../../../deps/jsr.io/@std/cli/1.0.28/mod.js";
5
+ import { bold, confirm } from "../../../lib/cli.js";
6
+ import { checkArgs } from "../../../lib/args.js";
7
+ import { createOutput } from "../../../lib/output.js";
8
+ import { Result } from "../../../lib/result.js";
9
+ import { runMachine } from "../../../lib/machine.js";
10
+ import { findWorkloadApp } from "../../../util/discovery.js";
11
+ import { assertNotRouter } from "../../../util/guard.js";
12
+ import { initSession } from "../../../util/session.js";
13
+ // =============================================================================
14
+ // Hydration
15
+ // =============================================================================
16
+ const hydrateDestroyApp = async (ctx) => {
17
+ const workloadApp = await findWorkloadApp(ctx.fly, ctx.org, ctx.app, ctx.network);
18
+ if (!workloadApp) {
19
+ const anyApp = await findWorkloadApp(ctx.fly, ctx.org, ctx.app);
20
+ if (anyApp) {
21
+ ctx.out.die(`App '${ctx.app}' Exists on Network '${anyApp.network}', Not '${ctx.network}'`);
22
+ }
23
+ return "complete";
24
+ }
25
+ ctx.flyAppName = workloadApp.appName;
26
+ return "confirm";
27
+ };
28
+ // =============================================================================
29
+ // Transitions
30
+ // =============================================================================
31
+ const destroyAppTransition = async (phase, ctx) => {
32
+ switch (phase) {
33
+ case "confirm": {
34
+ ctx.out.blank()
35
+ .header("Ambit Destroy App")
36
+ .blank()
37
+ .text(` App: ${ctx.flyAppName}`)
38
+ .text(` Network: ${ctx.network}`)
39
+ .blank();
40
+ if (!ctx.yes && !ctx.json) {
41
+ const confirmed = await confirm(`Destroy App '${ctx.app}' on Network '${ctx.network}'?`);
42
+ if (!confirmed) {
43
+ ctx.out.text("Cancelled.");
44
+ return Result.err("Cancelled");
45
+ }
46
+ ctx.out.blank();
47
+ }
48
+ return Result.ok("delete_app");
49
+ }
50
+ case "delete_app": {
51
+ if (ctx.flyAppName) {
52
+ await ctx.out.spin("Deleting App", () => ctx.fly.apps.delete(ctx.flyAppName));
53
+ ctx.out.ok("Fly App Destroyed");
54
+ }
55
+ else {
56
+ ctx.out.skip("Fly App Already Destroyed");
57
+ }
58
+ return Result.ok("complete");
59
+ }
60
+ default:
61
+ return Result.err(`Unknown Phase: ${phase}`);
62
+ }
63
+ };
64
+ // =============================================================================
65
+ // Stage 1: Destroy
66
+ // =============================================================================
67
+ const stageDestroy = async (out, fly, opts) => {
68
+ const ctx = { fly, out, ...opts };
69
+ const phase = await hydrateDestroyApp(ctx);
70
+ if (phase === "complete" && !ctx.flyAppName) {
71
+ out.ok(`App '${opts.app}' on Network '${opts.network}' Already Destroyed`);
72
+ out.print();
73
+ return;
74
+ }
75
+ const machine = {
76
+ terminal: "complete",
77
+ transition: destroyAppTransition,
78
+ };
79
+ const result = await runMachine(machine, phase, ctx);
80
+ if (!result.ok) {
81
+ if (result.error === "Cancelled")
82
+ return;
83
+ return out.die(result.error);
84
+ }
85
+ stageSummary(out, ctx);
86
+ };
87
+ // =============================================================================
88
+ // Stage 3: Summary
89
+ // =============================================================================
90
+ const stageSummary = (out, ctx) => {
91
+ out.done({
92
+ destroyed: true,
93
+ appName: ctx.flyAppName ?? ctx.app,
94
+ network: ctx.network,
95
+ });
96
+ out.ok("App Destroyed");
97
+ out.blank();
98
+ out.print();
99
+ };
100
+ // =============================================================================
101
+ // Destroy App Command
102
+ // =============================================================================
103
+ export const destroyApp = async (argv) => {
104
+ const opts = {
105
+ string: ["network", "org"],
106
+ boolean: ["help", "yes", "json"],
107
+ alias: { y: "yes" },
108
+ };
109
+ const args = parseArgs(argv, opts);
110
+ checkArgs(args, opts, "ambit destroy app");
111
+ if (args.help) {
112
+ console.log(`
113
+ ${bold("ambit destroy app")} - Destroy a Workload App
114
+
115
+ ${bold("USAGE")}
116
+ ambit destroy app <app>.<network> [--org <org>] [--yes] [--json]
117
+ ambit destroy app <app> --network <name> [--org <org>] [--yes] [--json]
118
+
119
+ ${bold("OPTIONS")}
120
+ --network <name> Target network (if not using dot syntax)
121
+ --org <org> Fly.io organization slug
122
+ -y, --yes Skip confirmation prompts
123
+ --json Output as JSON
124
+
125
+ ${bold("EXAMPLES")}
126
+ ambit destroy app my-app.browsers
127
+ ambit destroy app my-app --network browsers --yes
128
+ `);
129
+ return;
130
+ }
131
+ const out = createOutput(args.json);
132
+ const appArg = args._[0];
133
+ if (!appArg || typeof appArg !== "string") {
134
+ return out.die("Missing App Name. Usage: ambit destroy app <app>.<network>");
135
+ }
136
+ let app;
137
+ let network;
138
+ if (appArg.includes(".")) {
139
+ const parts = appArg.split(".");
140
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
141
+ return out.die(`'${appArg}' Should Have Exactly One Dot, Like my-app.my-network`);
142
+ }
143
+ if (args.network) {
144
+ return out.die(`Network Is Already Part of the Name ('${appArg}'), --network Is Not Needed`);
145
+ }
146
+ app = parts[0];
147
+ network = parts[1];
148
+ }
149
+ else {
150
+ app = appArg;
151
+ if (!args.network) {
152
+ return out.die(`Missing Network. Use: ambit destroy app ${app}.<network>`);
153
+ }
154
+ network = args.network;
155
+ }
156
+ try {
157
+ assertNotRouter(app);
158
+ }
159
+ catch (e) {
160
+ return out.die(e instanceof Error ? e.message : String(e));
161
+ }
162
+ const { fly, org } = await initSession(out, {
163
+ json: args.json,
164
+ org: args.org,
165
+ });
166
+ await stageDestroy(out, fly, {
167
+ app,
168
+ network,
169
+ org,
170
+ yes: args.yes,
171
+ json: args.json,
172
+ });
173
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/destroy/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,63 @@
1
+ // =============================================================================
2
+ // Destroy Command - Destroy Networks or Apps
3
+ // =============================================================================
4
+ import * as dntShim from "../../../_dnt.shims.js";
5
+ import { parseArgs } from "../../../deps/jsr.io/@std/cli/1.0.28/mod.js";
6
+ import { bold } from "../../../lib/cli.js";
7
+ import { registerCommand } from "../../mod.js";
8
+ import { destroyNetwork } from "./network.js";
9
+ import { destroyApp } from "./app.js";
10
+ // =============================================================================
11
+ // Top-Level Help
12
+ // =============================================================================
13
+ const showDestroyHelp = () => {
14
+ console.log(`
15
+ ${bold("ambit destroy")} - Destroy Networks or Apps
16
+
17
+ ${bold("USAGE")}
18
+ ambit destroy network <name> [options]
19
+ ambit destroy app <app>.<network> [options]
20
+
21
+ ${bold("SUBCOMMANDS")}
22
+ network Tear down a router, clean up DNS and tailnet device
23
+ app Destroy a workload app on a network
24
+
25
+ ${bold("OPTIONS")}
26
+ --help Show help for a subcommand
27
+
28
+ ${bold("EXAMPLES")}
29
+ ambit destroy network browsers
30
+ ambit destroy app my-app.browsers
31
+ ambit destroy app my-app --network browsers
32
+
33
+ Run 'ambit destroy network --help' or 'ambit destroy app --help' for details.
34
+ `);
35
+ };
36
+ // =============================================================================
37
+ // Dispatcher
38
+ // =============================================================================
39
+ const destroy = async (argv) => {
40
+ const subcommand = typeof argv[0] === "string" ? argv[0] : undefined;
41
+ if (subcommand === "network") {
42
+ return destroyNetwork(argv.slice(1));
43
+ }
44
+ if (subcommand === "app") {
45
+ return destroyApp(argv.slice(1));
46
+ }
47
+ const args = parseArgs(argv, { boolean: ["help"] });
48
+ if (args.help) {
49
+ showDestroyHelp();
50
+ return;
51
+ }
52
+ showDestroyHelp();
53
+ dntShim.Deno.exit(1);
54
+ };
55
+ // =============================================================================
56
+ // Register Command
57
+ // =============================================================================
58
+ registerCommand({
59
+ name: "destroy",
60
+ description: "Destroy a network (router) or a workload app",
61
+ usage: "ambit destroy network|app <name> [options]",
62
+ run: destroy,
63
+ });
@@ -0,0 +1,2 @@
1
+ export declare const destroyNetwork: (argv: string[]) => Promise<void>;
2
+ //# sourceMappingURL=network.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/destroy/network.ts"],"names":[],"mappings":"AAwQA,eAAO,MAAM,cAAc,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAkDjE,CAAC"}
@@ -0,0 +1,210 @@
1
+ // =============================================================================
2
+ // Destroy Network — Tear Down Router and Clean Up Tailnet
3
+ // =============================================================================
4
+ import { parseArgs } from "../../../deps/jsr.io/@std/cli/1.0.28/mod.js";
5
+ import { bold, confirm } from "../../../lib/cli.js";
6
+ import { checkArgs } from "../../../lib/args.js";
7
+ import { createOutput } from "../../../lib/output.js";
8
+ import { Result } from "../../../lib/result.js";
9
+ import { runMachine } from "../../../lib/machine.js";
10
+ import { findRouterApp, listWorkloadAppsOnNetwork, } from "../../../util/discovery.js";
11
+ import { initSession } from "../../../util/session.js";
12
+ // =============================================================================
13
+ // Phase Labels
14
+ // =============================================================================
15
+ const DESTROY_NETWORK_PHASES = [
16
+ { phase: "confirm", label: "Confirmed" },
17
+ { phase: "clear_dns", label: "Split DNS Cleared" },
18
+ { phase: "remove_device", label: "Tailscale Device Removed" },
19
+ { phase: "delete_app", label: "Fly App Destroyed" },
20
+ ];
21
+ const reportSkipped = (out, startPhase) => {
22
+ for (const { phase, label } of DESTROY_NETWORK_PHASES) {
23
+ if (phase === startPhase)
24
+ break;
25
+ out.skip(label);
26
+ }
27
+ };
28
+ // =============================================================================
29
+ // Hydration
30
+ // =============================================================================
31
+ const hydrateDestroyNetwork = async (ctx) => {
32
+ const router = await findRouterApp(ctx.fly, ctx.org, ctx.network);
33
+ const dns = await ctx.tailscale.dns.getSplit();
34
+ const hasDns = (dns[ctx.network]?.length ?? 0) > 0;
35
+ if (router) {
36
+ ctx.appName = router.appName;
37
+ const device = await ctx.tailscale.devices.getByHostname(router.appName);
38
+ if (device) {
39
+ ctx.device = device;
40
+ ctx.tag = device.tags?.[0] ?? undefined;
41
+ }
42
+ }
43
+ if (!router && !ctx.device && !hasDns)
44
+ return "complete";
45
+ if (!hasDns && !ctx.device && router)
46
+ return "delete_app";
47
+ if (!hasDns && ctx.device)
48
+ return "remove_device";
49
+ if (!hasDns)
50
+ return router ? "delete_app" : "complete";
51
+ return "confirm";
52
+ };
53
+ // =============================================================================
54
+ // Transitions
55
+ // =============================================================================
56
+ const destroyNetworkTransition = async (phase, ctx) => {
57
+ switch (phase) {
58
+ case "confirm": {
59
+ const workloads = await listWorkloadAppsOnNetwork(ctx.fly, ctx.org, ctx.network);
60
+ ctx.out.blank()
61
+ .header("Ambit Destroy Network")
62
+ .blank()
63
+ .text(` Network: ${ctx.network}`)
64
+ .text(` Router App: ${ctx.appName ?? "unknown"}`)
65
+ .text(` Tag: ${ctx.tag ?? "unknown"}`)
66
+ .blank();
67
+ if (workloads.length > 0) {
68
+ ctx.out.warn(`${workloads.length} Workload App(s) Still on Network '${ctx.network}':`);
69
+ for (const wa of workloads) {
70
+ ctx.out.text(` - ${wa.appName}`);
71
+ }
72
+ ctx.out.blank();
73
+ ctx.out.dim("These Apps Will Lose Connectivity when the Router Is Destroyed.");
74
+ ctx.out.dim(`Consider Destroying Them First with: ambit destroy app <name>.${ctx.network}`);
75
+ ctx.out.blank();
76
+ }
77
+ if (!ctx.yes && !ctx.json) {
78
+ const confirmed = await confirm("Destroy This Router?");
79
+ if (!confirmed) {
80
+ ctx.out.text("Cancelled.");
81
+ return Result.err("Cancelled");
82
+ }
83
+ ctx.out.blank();
84
+ }
85
+ return Result.ok("clear_dns");
86
+ }
87
+ case "clear_dns": {
88
+ await ctx.tailscale.dns.clearSplit(ctx.network);
89
+ ctx.out.ok("Split DNS Cleared");
90
+ return Result.ok("remove_device");
91
+ }
92
+ case "remove_device": {
93
+ if (ctx.device) {
94
+ await ctx.tailscale.devices.delete(ctx.device.id);
95
+ ctx.out.ok("Tailscale Device Removed");
96
+ }
97
+ else {
98
+ ctx.out.skip("Tailscale Device Already Removed");
99
+ }
100
+ return Result.ok("delete_app");
101
+ }
102
+ case "delete_app": {
103
+ if (ctx.appName) {
104
+ await ctx.out.spin("Deleting App", () => ctx.fly.apps.delete(ctx.appName));
105
+ ctx.out.ok("Fly App Destroyed");
106
+ }
107
+ else {
108
+ ctx.out.skip("Fly App Already Destroyed");
109
+ }
110
+ return Result.ok("complete");
111
+ }
112
+ default:
113
+ return Result.err(`Unknown Phase: ${phase}`);
114
+ }
115
+ };
116
+ // =============================================================================
117
+ // Stage 1: Destroy
118
+ // =============================================================================
119
+ const stageDestroy = async (out, fly, tailscale, opts) => {
120
+ const ctx = { fly, tailscale, out, ...opts };
121
+ const phase = await hydrateDestroyNetwork(ctx);
122
+ if (phase === "complete") {
123
+ out.ok(`Network "${opts.network}" Already Destroyed`);
124
+ out.print();
125
+ return;
126
+ }
127
+ reportSkipped(out, phase);
128
+ const machine = {
129
+ terminal: "complete",
130
+ transition: destroyNetworkTransition,
131
+ };
132
+ const result = await runMachine(machine, phase, ctx);
133
+ if (!result.ok) {
134
+ if (result.error === "Cancelled")
135
+ return;
136
+ return out.die(result.error);
137
+ }
138
+ stageSummary(out, ctx);
139
+ };
140
+ // =============================================================================
141
+ // Stage 3: Summary
142
+ // =============================================================================
143
+ const stageSummary = (out, ctx) => {
144
+ out.done({
145
+ destroyed: true,
146
+ appName: ctx.appName ?? "",
147
+ workloadAppsWarned: 0,
148
+ });
149
+ out.ok("Router Destroyed");
150
+ if (ctx.tag) {
151
+ out.blank()
152
+ .dim("If You Added ACL Policy Entries for This Router, Remember to Remove:")
153
+ .dim(` tagOwners: ${ctx.tag}`)
154
+ .dim(` autoApprovers: routes for ${ctx.tag}`)
155
+ .dim(` acls: rules referencing ${ctx.tag}`)
156
+ .blank();
157
+ }
158
+ else {
159
+ out.blank()
160
+ .dim("If You Added ACL Policy Entries for This Router, Remember to Remove")
161
+ .dim("the Associated Tag from tagOwners, autoApprovers, and acls.")
162
+ .blank();
163
+ }
164
+ out.print();
165
+ };
166
+ // =============================================================================
167
+ // Destroy Network Command
168
+ // =============================================================================
169
+ export const destroyNetwork = async (argv) => {
170
+ const opts = {
171
+ string: ["network", "org"],
172
+ boolean: ["help", "yes", "json"],
173
+ alias: { y: "yes" },
174
+ };
175
+ const args = parseArgs(argv, opts);
176
+ checkArgs(args, opts, "ambit destroy network");
177
+ if (args.help) {
178
+ console.log(`
179
+ ${bold("ambit destroy network")} - Tear Down Router
180
+
181
+ ${bold("USAGE")}
182
+ ambit destroy network <name> [--org <org>] [--yes] [--json]
183
+
184
+ ${bold("OPTIONS")}
185
+ --org <org> Fly.io organization slug
186
+ -y, --yes Skip confirmation prompts
187
+ --json Output as JSON
188
+
189
+ ${bold("EXAMPLES")}
190
+ ambit destroy network browsers
191
+ ambit destroy network browsers --org my-org --yes
192
+ `);
193
+ return;
194
+ }
195
+ const out = createOutput(args.json);
196
+ const network = (typeof args._[0] === "string" ? args._[0] : undefined) || args.network;
197
+ if (!network) {
198
+ return out.die("Network Name Required. Usage: ambit destroy network <name>");
199
+ }
200
+ const { fly, tailscale, org } = await initSession(out, {
201
+ json: args.json,
202
+ org: args.org,
203
+ });
204
+ await stageDestroy(out, fly, tailscale, {
205
+ network,
206
+ org,
207
+ yes: args.yes,
208
+ json: args.json,
209
+ });
210
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":""}