@cardelli/ambit 0.1.4 → 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.
- package/esm/cli/commands/create/index.d.ts +2 -0
- package/esm/cli/commands/create/index.d.ts.map +1 -0
- package/esm/cli/commands/create/index.js +292 -0
- package/esm/cli/commands/create/machine.d.ts +33 -0
- package/esm/cli/commands/create/machine.d.ts.map +1 -0
- package/esm/cli/commands/create/machine.js +162 -0
- package/esm/cli/commands/deploy/index.d.ts +2 -0
- package/esm/cli/commands/deploy/index.d.ts.map +1 -0
- package/esm/cli/commands/deploy/index.js +290 -0
- package/esm/cli/commands/deploy/machine.d.ts +52 -0
- package/esm/cli/commands/deploy/machine.d.ts.map +1 -0
- package/esm/cli/commands/deploy/machine.js +116 -0
- package/esm/cli/commands/deploy/modes.d.ts +18 -0
- package/esm/cli/commands/deploy/modes.d.ts.map +1 -0
- package/esm/cli/commands/deploy/modes.js +152 -0
- package/esm/cli/commands/destroy/app.d.ts +2 -0
- package/esm/cli/commands/destroy/app.d.ts.map +1 -0
- package/esm/cli/commands/destroy/app.js +173 -0
- package/esm/cli/commands/destroy/index.d.ts +2 -0
- package/esm/cli/commands/destroy/index.d.ts.map +1 -0
- package/esm/cli/commands/destroy/index.js +63 -0
- package/esm/cli/commands/destroy/network.d.ts +2 -0
- package/esm/cli/commands/destroy/network.d.ts.map +1 -0
- package/esm/cli/commands/destroy/network.js +210 -0
- package/esm/cli/commands/doctor.d.ts.map +1 -0
- package/esm/cli/commands/doctor.js +295 -0
- package/esm/{src/cli → cli}/commands/list.d.ts.map +1 -1
- package/esm/{src/cli → cli}/commands/list.js +39 -54
- package/esm/cli/commands/status.d.ts.map +1 -0
- package/esm/cli/commands/status.js +331 -0
- package/esm/cli/mod.d.ts.map +1 -0
- package/esm/{src/cli → cli}/mod.js +4 -4
- package/esm/deno.d.ts +4 -18
- package/esm/deno.js +5 -19
- package/esm/deps/jsr.io/@std/path/1.1.4/constants.d.ts +1 -1
- package/esm/deps/jsr.io/@zod/zod/4.3.6/src/v4/core/json-schema-generator.d.ts +1 -1
- package/esm/lib/args.d.ts +11 -0
- package/esm/lib/args.d.ts.map +1 -0
- package/esm/lib/args.js +28 -0
- package/esm/lib/cli.d.ts +0 -2
- package/esm/lib/cli.d.ts.map +1 -1
- package/esm/lib/cli.js +41 -27
- package/esm/lib/command.d.ts +21 -49
- package/esm/lib/command.d.ts.map +1 -1
- package/esm/lib/command.js +55 -95
- package/esm/lib/machine.d.ts +11 -0
- package/esm/lib/machine.d.ts.map +1 -0
- package/esm/lib/machine.js +15 -0
- package/esm/lib/output.d.ts +3 -2
- package/esm/lib/output.d.ts.map +1 -1
- package/esm/lib/output.js +25 -11
- package/esm/lib/result.d.ts +18 -7
- package/esm/lib/result.d.ts.map +1 -1
- package/esm/lib/result.js +46 -1
- package/esm/main.d.ts +6 -6
- package/esm/main.d.ts.map +1 -1
- package/esm/main.js +7 -9
- package/esm/providers/fly.d.ts +81 -0
- package/esm/providers/fly.d.ts.map +1 -0
- package/esm/providers/fly.js +372 -0
- package/esm/providers/tailscale.d.ts +31 -0
- package/esm/providers/tailscale.d.ts.map +1 -0
- package/esm/providers/tailscale.js +150 -0
- package/esm/{src/schemas → schemas}/fly.d.ts +1 -11
- package/esm/schemas/fly.d.ts.map +1 -0
- package/esm/{src/schemas → schemas}/fly.js +14 -56
- package/esm/{src/schemas → schemas}/tailscale.d.ts +1 -2
- package/esm/schemas/tailscale.d.ts.map +1 -0
- package/esm/{src/schemas → schemas}/tailscale.js +2 -3
- package/esm/src/{docker/router → router}/Dockerfile +0 -11
- package/esm/src/router/start.sh +101 -0
- package/esm/util/constants.d.ts +13 -0
- package/esm/util/constants.d.ts.map +1 -0
- package/esm/util/constants.js +34 -0
- package/esm/{src → util}/credentials.d.ts +0 -1
- package/esm/util/credentials.d.ts.map +1 -0
- package/esm/{src → util}/credentials.js +3 -5
- package/esm/{src → util}/discovery.d.ts +20 -4
- package/esm/util/discovery.d.ts.map +1 -0
- package/esm/{src → util}/discovery.js +38 -15
- package/esm/util/fly-transforms.d.ts +27 -0
- package/esm/util/fly-transforms.d.ts.map +1 -0
- package/esm/util/fly-transforms.js +87 -0
- package/esm/{src → util}/guard.d.ts +1 -2
- package/esm/util/guard.d.ts.map +1 -0
- package/esm/{src → util}/guard.js +27 -27
- package/esm/util/naming.d.ts +5 -0
- package/esm/util/naming.d.ts.map +1 -0
- package/esm/util/naming.js +12 -0
- package/esm/{src → util}/resolve.d.ts +2 -3
- package/esm/util/resolve.d.ts.map +1 -0
- package/esm/{src → util}/resolve.js +1 -2
- package/esm/util/session.d.ts +16 -0
- package/esm/util/session.d.ts.map +1 -0
- package/esm/util/session.js +19 -0
- package/esm/util/tailscale-local.d.ts +13 -0
- package/esm/util/tailscale-local.d.ts.map +1 -0
- package/esm/util/tailscale-local.js +63 -0
- package/esm/{src → util}/template.d.ts +2 -4
- package/esm/util/template.d.ts.map +1 -0
- package/esm/{src → util}/template.js +14 -17
- package/package.json +1 -43
- package/esm/lib/paths.d.ts +0 -3
- package/esm/lib/paths.d.ts.map +0 -1
- package/esm/lib/paths.js +0 -5
- package/esm/src/cli/commands/create.d.ts +0 -2
- package/esm/src/cli/commands/create.d.ts.map +0 -1
- package/esm/src/cli/commands/create.js +0 -294
- package/esm/src/cli/commands/deploy.d.ts +0 -2
- package/esm/src/cli/commands/deploy.d.ts.map +0 -1
- package/esm/src/cli/commands/deploy.js +0 -426
- package/esm/src/cli/commands/destroy.d.ts +0 -2
- package/esm/src/cli/commands/destroy.d.ts.map +0 -1
- package/esm/src/cli/commands/destroy.js +0 -340
- package/esm/src/cli/commands/doctor.d.ts.map +0 -1
- package/esm/src/cli/commands/doctor.js +0 -141
- package/esm/src/cli/commands/status.d.ts.map +0 -1
- package/esm/src/cli/commands/status.js +0 -152
- package/esm/src/cli/mod.d.ts.map +0 -1
- package/esm/src/credentials.d.ts.map +0 -1
- package/esm/src/discovery.d.ts.map +0 -1
- package/esm/src/docker/router/start.sh +0 -146
- package/esm/src/guard.d.ts.map +0 -1
- package/esm/src/providers/fly.d.ts +0 -70
- package/esm/src/providers/fly.d.ts.map +0 -1
- package/esm/src/providers/fly.js +0 -411
- package/esm/src/providers/tailscale.d.ts +0 -31
- package/esm/src/providers/tailscale.d.ts.map +0 -1
- package/esm/src/providers/tailscale.js +0 -195
- package/esm/src/resolve.d.ts.map +0 -1
- package/esm/src/schemas/config.d.ts +0 -5
- package/esm/src/schemas/config.d.ts.map +0 -1
- package/esm/src/schemas/config.js +0 -22
- package/esm/src/schemas/fly.d.ts.map +0 -1
- package/esm/src/schemas/tailscale.d.ts.map +0 -1
- package/esm/src/template.d.ts.map +0 -1
- /package/esm/{src/cli → cli}/commands/doctor.d.ts +0 -0
- /package/esm/{src/cli → cli}/commands/list.d.ts +0 -0
- /package/esm/{src/cli → cli}/commands/status.d.ts +0 -0
- /package/esm/{src/cli → cli}/mod.d.ts +0 -0
- /package/esm/src/{docker/router → router}/fly.toml +0 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Status Command - Show Network, App, and Router Status
|
|
3
|
+
// =============================================================================
|
|
4
|
+
import { parseArgs } from "../../deps/jsr.io/@std/cli/1.0.28/mod.js";
|
|
5
|
+
import { Table } from "../../deps/jsr.io/@cliffy/table/1.0.0/mod.js";
|
|
6
|
+
import { bold } from "../../lib/cli.js";
|
|
7
|
+
import { checkArgs } from "../../lib/args.js";
|
|
8
|
+
import { createOutput } from "../../lib/output.js";
|
|
9
|
+
import { registerCommand } from "../mod.js";
|
|
10
|
+
import { discoverRouters, findRouterApp, findWorkloadApp, getRouterMachineInfo, getRouterTailscaleInfo, listWorkloadAppsOnNetwork, } from "../../util/discovery.js";
|
|
11
|
+
import { initSession } from "../../util/session.js";
|
|
12
|
+
import { SOCKS_PROXY_PORT } from "../../util/constants.js";
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Network Status: Single Router Detailed View
|
|
15
|
+
// =============================================================================
|
|
16
|
+
const stageNetworkStatus = async (fly, tailscale, network, org, json) => {
|
|
17
|
+
const out = createOutput(json);
|
|
18
|
+
const app = await findRouterApp(fly, org, network);
|
|
19
|
+
if (!app) {
|
|
20
|
+
return out.die(`No Router Found for Network '${network}'`);
|
|
21
|
+
}
|
|
22
|
+
const machine = await getRouterMachineInfo(fly, app.appName);
|
|
23
|
+
const ts = await getRouterTailscaleInfo(tailscale, app.appName);
|
|
24
|
+
const tag = ts?.tags?.[0] ?? null;
|
|
25
|
+
out.blank()
|
|
26
|
+
.header("Ambit Status: Network")
|
|
27
|
+
.blank()
|
|
28
|
+
.text(` Network: ${bold(app.network)}`)
|
|
29
|
+
.text(` TLD: *.${app.network}`)
|
|
30
|
+
.text(` Tag: ${tag ?? "unknown"}`)
|
|
31
|
+
.blank()
|
|
32
|
+
.text(` Router App: ${app.appName}`)
|
|
33
|
+
.text(` Region: ${machine?.region ?? "unknown"}`)
|
|
34
|
+
.text(` Machine State: ${machine?.state ?? "unknown"}`)
|
|
35
|
+
.text(` Private IP: ${machine?.privateIp ?? "unknown"}`)
|
|
36
|
+
.text(` SOCKS Proxy: ${machine?.privateIp
|
|
37
|
+
? `socks5://[${machine.privateIp}]:${SOCKS_PROXY_PORT}`
|
|
38
|
+
: "unknown"}`);
|
|
39
|
+
if (machine?.subnet) {
|
|
40
|
+
out.text(` Subnet: ${machine.subnet}`);
|
|
41
|
+
}
|
|
42
|
+
out.blank();
|
|
43
|
+
if (ts) {
|
|
44
|
+
out.text(` Tailscale IP: ${ts.ip}`)
|
|
45
|
+
.text(` Online: ${ts.online ? "yes" : "no"}`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
out.text(" Tailscale: Not Found in Tailnet");
|
|
49
|
+
}
|
|
50
|
+
// Show workload apps on this network
|
|
51
|
+
const workloads = await listWorkloadAppsOnNetwork(fly, org, network);
|
|
52
|
+
if (workloads.length > 0) {
|
|
53
|
+
out.blank().header(" Apps on Network").blank();
|
|
54
|
+
for (const w of workloads) {
|
|
55
|
+
const machines = await fly.machines.list(w.appName);
|
|
56
|
+
const state = machines[0]?.state ?? "no machines";
|
|
57
|
+
const region = machines[0]?.region ?? "-";
|
|
58
|
+
out.text(` ${w.appName} ${region} ${state}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
out.blank();
|
|
62
|
+
out.done({
|
|
63
|
+
network: app.network,
|
|
64
|
+
router: app,
|
|
65
|
+
machine,
|
|
66
|
+
tag,
|
|
67
|
+
tailscale: ts,
|
|
68
|
+
});
|
|
69
|
+
out.print();
|
|
70
|
+
};
|
|
71
|
+
// =============================================================================
|
|
72
|
+
// Network Status: Summary Table of All Routers
|
|
73
|
+
// =============================================================================
|
|
74
|
+
const stageAllStatus = async (fly, tailscale, org, json) => {
|
|
75
|
+
const out = createOutput(json);
|
|
76
|
+
const routers = await discoverRouters(out, fly, tailscale, org);
|
|
77
|
+
if (routers.length === 0) {
|
|
78
|
+
out.blank()
|
|
79
|
+
.text("No Routers Found.")
|
|
80
|
+
.dim(" Create One with: ambit create <network>")
|
|
81
|
+
.blank();
|
|
82
|
+
out.done({ routers: [] });
|
|
83
|
+
out.print();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
out.blank().header("Router Status").blank();
|
|
87
|
+
const rows = routers.map((r) => {
|
|
88
|
+
const tsStatus = r.tailscale
|
|
89
|
+
? (r.tailscale.online ? "online" : "offline")
|
|
90
|
+
: "not found";
|
|
91
|
+
return [r.network, r.appName, r.machine?.state ?? "unknown", tsStatus];
|
|
92
|
+
});
|
|
93
|
+
const table = new Table()
|
|
94
|
+
.header(["Network", "App", "State", "Tailscale"])
|
|
95
|
+
.body(rows)
|
|
96
|
+
.indent(2)
|
|
97
|
+
.padding(2);
|
|
98
|
+
out.text(table.toString());
|
|
99
|
+
out.blank();
|
|
100
|
+
out.done({ routers });
|
|
101
|
+
out.print();
|
|
102
|
+
};
|
|
103
|
+
// =============================================================================
|
|
104
|
+
// Status Network Subcommand
|
|
105
|
+
// =============================================================================
|
|
106
|
+
const statusNetwork = async (argv) => {
|
|
107
|
+
const opts = { string: ["org"], boolean: ["help", "json"] };
|
|
108
|
+
const args = parseArgs(argv, opts);
|
|
109
|
+
checkArgs(args, opts, "ambit status network");
|
|
110
|
+
if (args.help) {
|
|
111
|
+
console.log(`
|
|
112
|
+
${bold("ambit status network")} - Show Router and Network Status
|
|
113
|
+
|
|
114
|
+
${bold("USAGE")}
|
|
115
|
+
ambit status network [<name>] [--org <org>] [--json]
|
|
116
|
+
|
|
117
|
+
${bold("OPTIONS")}
|
|
118
|
+
<name> Network to show status for (shows all if omitted)
|
|
119
|
+
--org <org> Fly.io organization slug
|
|
120
|
+
--json Output as JSON
|
|
121
|
+
|
|
122
|
+
${bold("EXAMPLES")}
|
|
123
|
+
ambit status network Show summary of all routers
|
|
124
|
+
ambit status network browsers Show detailed status for one network
|
|
125
|
+
`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const network = typeof args._[0] === "string" ? args._[0] : undefined;
|
|
129
|
+
const prereqOut = createOutput(args.json);
|
|
130
|
+
const { fly, tailscale, org } = await initSession(prereqOut, {
|
|
131
|
+
json: args.json,
|
|
132
|
+
org: args.org,
|
|
133
|
+
});
|
|
134
|
+
if (network) {
|
|
135
|
+
await stageNetworkStatus(fly, tailscale, network, org, args.json);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
await stageAllStatus(fly, tailscale, org, args.json);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
// =============================================================================
|
|
142
|
+
// App Status: Detailed App View
|
|
143
|
+
// =============================================================================
|
|
144
|
+
const stageAppStatus = async (fly, tailscale, app, network, org, json) => {
|
|
145
|
+
const out = createOutput(json);
|
|
146
|
+
const workload = await findWorkloadApp(fly, org, app, network);
|
|
147
|
+
if (!workload) {
|
|
148
|
+
return out.die(`App '${app}' Not Found on Network '${network}'`);
|
|
149
|
+
}
|
|
150
|
+
const machines = await fly.machines.list(workload.appName);
|
|
151
|
+
const ips = await fly.ips.list(workload.appName);
|
|
152
|
+
const mappedMachines = machines.map((m) => ({
|
|
153
|
+
id: m.id,
|
|
154
|
+
region: m.region,
|
|
155
|
+
state: m.state,
|
|
156
|
+
privateIp: m.private_ip,
|
|
157
|
+
}));
|
|
158
|
+
const mappedIps = ips.map((ip) => ({
|
|
159
|
+
address: ip.Address,
|
|
160
|
+
type: ip.Type,
|
|
161
|
+
network: ip.Network?.Name,
|
|
162
|
+
}));
|
|
163
|
+
const router = await findRouterApp(fly, org, network);
|
|
164
|
+
out.blank()
|
|
165
|
+
.header(`Ambit Status: ${app}.${network}`)
|
|
166
|
+
.blank()
|
|
167
|
+
.text(` App: ${bold(app)}`)
|
|
168
|
+
.text(` Network: ${network}`)
|
|
169
|
+
.text(` Fly App: ${workload.appName}`)
|
|
170
|
+
.blank();
|
|
171
|
+
if (machines.length === 0) {
|
|
172
|
+
out.text(" Machines: None");
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
out.header(" Machines").blank();
|
|
176
|
+
for (const m of machines) {
|
|
177
|
+
out.text(` ${m.id} ${m.region} ${m.state}${m.private_ip ? ` ${m.private_ip}` : ""}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
out.blank();
|
|
181
|
+
const flycastIps = ips.filter((ip) => ip.Type === "private_v6");
|
|
182
|
+
const publicIps = ips.filter((ip) => ip.Type !== "private_v6");
|
|
183
|
+
if (flycastIps.length > 0) {
|
|
184
|
+
out.header(" Flycast IPs").blank();
|
|
185
|
+
for (const ip of flycastIps) {
|
|
186
|
+
out.text(` ${ip.Address} (network: ${ip.Network?.Name ?? "default"})`);
|
|
187
|
+
}
|
|
188
|
+
out.blank();
|
|
189
|
+
}
|
|
190
|
+
if (publicIps.length > 0) {
|
|
191
|
+
out.header(" Public IPs (Warning: Ambit Apps Should Not Have Public IPs)")
|
|
192
|
+
.blank();
|
|
193
|
+
for (const ip of publicIps) {
|
|
194
|
+
out.text(` ${ip.Address} ${ip.Type}`);
|
|
195
|
+
}
|
|
196
|
+
out.blank();
|
|
197
|
+
}
|
|
198
|
+
if (router) {
|
|
199
|
+
const routerMachine = await getRouterMachineInfo(fly, router.appName);
|
|
200
|
+
const ts = await getRouterTailscaleInfo(tailscale, router.appName);
|
|
201
|
+
out.header(" Router").blank()
|
|
202
|
+
.text(` App: ${router.appName}`)
|
|
203
|
+
.text(` State: ${routerMachine?.state ?? "unknown"}`)
|
|
204
|
+
.text(` Tailscale: ${ts ? (ts.online ? "online" : "offline") : "not found"}`);
|
|
205
|
+
if (routerMachine?.privateIp) {
|
|
206
|
+
out.text(` SOCKS Proxy: socks5://[${routerMachine.privateIp}]:${SOCKS_PROXY_PORT}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
out.text(" Router: Not Found");
|
|
211
|
+
}
|
|
212
|
+
out.blank();
|
|
213
|
+
out.done({
|
|
214
|
+
app,
|
|
215
|
+
network,
|
|
216
|
+
flyAppName: workload.appName,
|
|
217
|
+
machines: mappedMachines,
|
|
218
|
+
ips: mappedIps,
|
|
219
|
+
router,
|
|
220
|
+
});
|
|
221
|
+
out.print();
|
|
222
|
+
};
|
|
223
|
+
// =============================================================================
|
|
224
|
+
// Status App Subcommand
|
|
225
|
+
// =============================================================================
|
|
226
|
+
const statusApp = async (argv) => {
|
|
227
|
+
const opts = { string: ["network", "org"], boolean: ["help", "json"] };
|
|
228
|
+
const args = parseArgs(argv, opts);
|
|
229
|
+
checkArgs(args, opts, "ambit status app");
|
|
230
|
+
if (args.help) {
|
|
231
|
+
console.log(`
|
|
232
|
+
${bold("ambit status app")} - Show App Status
|
|
233
|
+
|
|
234
|
+
${bold("USAGE")}
|
|
235
|
+
ambit status app <app>.<network> [--org <org>] [--json]
|
|
236
|
+
ambit status app <app> --network <name> [--org <org>] [--json]
|
|
237
|
+
|
|
238
|
+
${bold("OPTIONS")}
|
|
239
|
+
--network <name> Target network (if not using dot syntax)
|
|
240
|
+
--org <org> Fly.io organization slug
|
|
241
|
+
--json Output as JSON
|
|
242
|
+
|
|
243
|
+
${bold("EXAMPLES")}
|
|
244
|
+
ambit status app my-app.browsers
|
|
245
|
+
ambit status app my-app --network browsers --json
|
|
246
|
+
`);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
const out = createOutput(args.json);
|
|
250
|
+
const appArg = args._[0];
|
|
251
|
+
if (!appArg || typeof appArg !== "string") {
|
|
252
|
+
return out.die("Missing App Name. Usage: ambit status app <app>.<network>");
|
|
253
|
+
}
|
|
254
|
+
let app;
|
|
255
|
+
let network;
|
|
256
|
+
if (appArg.includes(".")) {
|
|
257
|
+
const parts = appArg.split(".");
|
|
258
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
259
|
+
return out.die(`'${appArg}' Should Have Exactly One Dot, Like my-app.my-network`);
|
|
260
|
+
}
|
|
261
|
+
app = parts[0];
|
|
262
|
+
network = parts[1];
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
app = appArg;
|
|
266
|
+
if (!args.network) {
|
|
267
|
+
return out.die(`Missing Network. Use: ambit status app ${app}.<network>`);
|
|
268
|
+
}
|
|
269
|
+
network = args.network;
|
|
270
|
+
}
|
|
271
|
+
const prereqOut = createOutput(args.json);
|
|
272
|
+
const { fly, tailscale, org } = await initSession(prereqOut, {
|
|
273
|
+
json: args.json,
|
|
274
|
+
org: args.org,
|
|
275
|
+
});
|
|
276
|
+
await stageAppStatus(fly, tailscale, app, network, org, args.json);
|
|
277
|
+
};
|
|
278
|
+
// =============================================================================
|
|
279
|
+
// Top-Level Help
|
|
280
|
+
// =============================================================================
|
|
281
|
+
const showStatusHelp = () => {
|
|
282
|
+
console.log(`
|
|
283
|
+
${bold("ambit status")} - Show Network, App, and Router Status
|
|
284
|
+
|
|
285
|
+
${bold("USAGE")}
|
|
286
|
+
ambit status [options]
|
|
287
|
+
ambit status network [<name>] [options]
|
|
288
|
+
ambit status app <app>.<network> [options]
|
|
289
|
+
|
|
290
|
+
${bold("SUBCOMMANDS")}
|
|
291
|
+
network Show router/network status — default when no subcommand given
|
|
292
|
+
app Show a specific app's status
|
|
293
|
+
|
|
294
|
+
${bold("OPTIONS")}
|
|
295
|
+
--org <org> Fly.io organization slug
|
|
296
|
+
--json Output as JSON
|
|
297
|
+
|
|
298
|
+
${bold("EXAMPLES")}
|
|
299
|
+
ambit status
|
|
300
|
+
ambit status network
|
|
301
|
+
ambit status network browsers
|
|
302
|
+
ambit status app my-app.browsers
|
|
303
|
+
|
|
304
|
+
Run 'ambit status network --help' or 'ambit status app --help' for details.
|
|
305
|
+
`);
|
|
306
|
+
};
|
|
307
|
+
// =============================================================================
|
|
308
|
+
// Dispatcher
|
|
309
|
+
// =============================================================================
|
|
310
|
+
const status = async (argv) => {
|
|
311
|
+
const subcommand = typeof argv[0] === "string" ? argv[0] : undefined;
|
|
312
|
+
if (subcommand === "network")
|
|
313
|
+
return statusNetwork(argv.slice(1));
|
|
314
|
+
if (subcommand === "app")
|
|
315
|
+
return statusApp(argv.slice(1));
|
|
316
|
+
const args = parseArgs(argv, { boolean: ["help"] });
|
|
317
|
+
if (args.help) {
|
|
318
|
+
showStatusHelp();
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
return statusNetwork(argv);
|
|
322
|
+
};
|
|
323
|
+
// =============================================================================
|
|
324
|
+
// Register Command
|
|
325
|
+
// =============================================================================
|
|
326
|
+
registerCommand({
|
|
327
|
+
name: "status",
|
|
328
|
+
description: "Show network, app, and router status",
|
|
329
|
+
usage: "ambit status [network|app] [<name>] [--org <org>] [--json]",
|
|
330
|
+
run: status,
|
|
331
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/cli/mod.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAQD,eAAO,MAAM,eAAe,GAAI,SAAS,OAAO,KAAG,IAElD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,OAAO,GAAG,SAEnD,CAAC;AAEF,eAAO,MAAM,cAAc,QAAO,OAAO,EAExC,CAAC;AAQF,eAAO,MAAM,QAAQ,QAAO,IA6B3B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAE9B,CAAC;AAMF,eAAO,MAAM,MAAM,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAuCzD,CAAC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// =============================================================================
|
|
2
2
|
// CLI Framework - Command Parser and Router
|
|
3
3
|
// =============================================================================
|
|
4
|
-
import * as dntShim from "
|
|
5
|
-
import { parseArgs } from "
|
|
6
|
-
import { bold, dim } from "
|
|
7
|
-
import denoConfig from "
|
|
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, dim } from "../lib/cli.js";
|
|
7
|
+
import denoConfig from "../deno.js";
|
|
8
8
|
// =============================================================================
|
|
9
9
|
// Commands Registry
|
|
10
10
|
// =============================================================================
|
package/esm/deno.d.ts
CHANGED
|
@@ -3,24 +3,6 @@ declare namespace _default {
|
|
|
3
3
|
let version: string;
|
|
4
4
|
let description: string;
|
|
5
5
|
let license: string;
|
|
6
|
-
let exports: {
|
|
7
|
-
".": string;
|
|
8
|
-
"./providers/fly": string;
|
|
9
|
-
"./providers/tailscale": string;
|
|
10
|
-
"./schemas/config": string;
|
|
11
|
-
"./schemas/fly": string;
|
|
12
|
-
"./schemas/tailscale": string;
|
|
13
|
-
"./lib/cli": string;
|
|
14
|
-
"./lib/command": string;
|
|
15
|
-
"./lib/output": string;
|
|
16
|
-
"./lib/result": string;
|
|
17
|
-
"./lib/paths": string;
|
|
18
|
-
"./src/credentials": string;
|
|
19
|
-
"./src/discovery": string;
|
|
20
|
-
"./src/guard": string;
|
|
21
|
-
"./src/resolve": string;
|
|
22
|
-
"./src/template": string;
|
|
23
|
-
};
|
|
24
6
|
let tasks: {
|
|
25
7
|
dev: string;
|
|
26
8
|
run: string;
|
|
@@ -29,6 +11,10 @@ declare namespace _default {
|
|
|
29
11
|
"check-versions": string;
|
|
30
12
|
build: string;
|
|
31
13
|
};
|
|
14
|
+
let exports: {
|
|
15
|
+
".": string;
|
|
16
|
+
};
|
|
17
|
+
let exclude: string[];
|
|
32
18
|
let imports: {
|
|
33
19
|
"@/": string;
|
|
34
20
|
"@cliffy/table": string;
|
package/esm/deno.js
CHANGED
|
@@ -1,26 +1,8 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
"name": "@cardelli/ambit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Deploy apps to the cloud that only you and your AI agents can reach",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"exports": {
|
|
7
|
-
".": "./main.ts",
|
|
8
|
-
"./providers/fly": "./src/providers/fly.ts",
|
|
9
|
-
"./providers/tailscale": "./src/providers/tailscale.ts",
|
|
10
|
-
"./schemas/config": "./src/schemas/config.ts",
|
|
11
|
-
"./schemas/fly": "./src/schemas/fly.ts",
|
|
12
|
-
"./schemas/tailscale": "./src/schemas/tailscale.ts",
|
|
13
|
-
"./lib/cli": "./lib/cli.ts",
|
|
14
|
-
"./lib/command": "./lib/command.ts",
|
|
15
|
-
"./lib/output": "./lib/output.ts",
|
|
16
|
-
"./lib/result": "./lib/result.ts",
|
|
17
|
-
"./lib/paths": "./lib/paths.ts",
|
|
18
|
-
"./src/credentials": "./src/credentials.ts",
|
|
19
|
-
"./src/discovery": "./src/discovery.ts",
|
|
20
|
-
"./src/guard": "./src/guard.ts",
|
|
21
|
-
"./src/resolve": "./src/resolve.ts",
|
|
22
|
-
"./src/template": "./src/template.ts"
|
|
23
|
-
},
|
|
24
6
|
"tasks": {
|
|
25
7
|
"dev": "deno run --watch main.ts",
|
|
26
8
|
"run": "deno run -A main.ts",
|
|
@@ -29,6 +11,10 @@ export default {
|
|
|
29
11
|
"check-versions": "deno run --allow-net --allow-run=git scripts/check-versions.ts",
|
|
30
12
|
"build": "deno run -A scripts/build_npm.ts"
|
|
31
13
|
},
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./main.ts"
|
|
16
|
+
},
|
|
17
|
+
"exclude": ["**/npm/"],
|
|
32
18
|
"imports": {
|
|
33
19
|
"@/": "./",
|
|
34
20
|
"@cliffy/table": "jsr:@cliffy/table@^1.0.0",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* The character used to separate entries in the PATH environment variable.
|
|
3
3
|
* On Windows, this is `;`. On all other platforms, this is `:`.
|
|
4
4
|
*/
|
|
5
|
-
export declare const DELIMITER: "
|
|
5
|
+
export declare const DELIMITER: ";" | ":";
|
|
6
6
|
/**
|
|
7
7
|
* The character used to separate components of a file path.
|
|
8
8
|
* On Windows, this is `\`. On all other platforms, this is `/`.
|
|
@@ -44,7 +44,7 @@ export declare class JSONSchemaGenerator {
|
|
|
44
44
|
path: (string | number)[];
|
|
45
45
|
}) => void;
|
|
46
46
|
/** @deprecated Access via ctx instead */
|
|
47
|
-
get io(): "
|
|
47
|
+
get io(): "input" | "output";
|
|
48
48
|
/** @deprecated Access via ctx instead */
|
|
49
49
|
get counter(): number;
|
|
50
50
|
set counter(value: number);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validates parsed args against the declared options spec.
|
|
3
|
+
* Dies with a Title Case error if unknown flags are found.
|
|
4
|
+
* Pass the same options object you gave to parseArgs.
|
|
5
|
+
*/
|
|
6
|
+
export declare const checkArgs: (args: Record<string, unknown>, opts: {
|
|
7
|
+
string?: readonly string[] | string[];
|
|
8
|
+
boolean?: readonly string[] | string[];
|
|
9
|
+
alias?: Record<string, string | string[]>;
|
|
10
|
+
}, command: string) => void;
|
|
11
|
+
//# sourceMappingURL=args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/lib/args.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,eAAO,MAAM,SAAS,GACpB,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM;IACJ,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACtC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;CAC3C,EACD,SAAS,MAAM,KACd,IAmBF,CAAC"}
|
package/esm/lib/args.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Strict Argument Validation — rejects unknown flags via out.die()
|
|
3
|
+
// =============================================================================
|
|
4
|
+
import { createOutput } from "./output.js";
|
|
5
|
+
/**
|
|
6
|
+
* Validates parsed args against the declared options spec.
|
|
7
|
+
* Dies with a Title Case error if unknown flags are found.
|
|
8
|
+
* Pass the same options object you gave to parseArgs.
|
|
9
|
+
*/
|
|
10
|
+
export const checkArgs = (args, opts, command) => {
|
|
11
|
+
const known = new Set(["_"]);
|
|
12
|
+
for (const k of opts.string ?? [])
|
|
13
|
+
known.add(k);
|
|
14
|
+
for (const k of opts.boolean ?? [])
|
|
15
|
+
known.add(k);
|
|
16
|
+
for (const [k, v] of Object.entries(opts.alias ?? {})) {
|
|
17
|
+
known.add(k);
|
|
18
|
+
for (const a of Array.isArray(v) ? v : [v])
|
|
19
|
+
known.add(a);
|
|
20
|
+
}
|
|
21
|
+
const bad = Object.keys(args)
|
|
22
|
+
.filter((k) => !known.has(k))
|
|
23
|
+
.map((k) => `--${k}`);
|
|
24
|
+
if (bad.length > 0) {
|
|
25
|
+
const out = createOutput(!!args.json);
|
|
26
|
+
out.die(`Unknown Flag(s): ${bad.join(", ")}. Run '${command} --help' for Usage.`);
|
|
27
|
+
}
|
|
28
|
+
};
|
package/esm/lib/cli.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import "../_dnt.polyfills.js";
|
|
2
1
|
export declare const bold: (text: string) => string;
|
|
3
2
|
export declare const dim: (text: string) => string;
|
|
4
3
|
export declare const red: (text: string) => string;
|
|
@@ -25,7 +24,6 @@ export declare const prompt: (message: string) => Promise<string>;
|
|
|
25
24
|
export declare const confirm: (message: string) => Promise<boolean>;
|
|
26
25
|
export declare const readSecret: (message: string) => Promise<string>;
|
|
27
26
|
export declare const fileExists: (path: string) => Promise<boolean>;
|
|
28
|
-
export declare const fileExistsSync: (path: string) => boolean;
|
|
29
27
|
export declare const getConfigDir: () => string;
|
|
30
28
|
export declare const getConfigPath: () => string;
|
|
31
29
|
export declare const ensureConfigDir: () => Promise<void>;
|
package/esm/lib/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/lib/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/lib/cli.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,KAAG,MAAkC,CAAC;AACvE,eAAO,MAAM,GAAG,GAAI,MAAM,MAAM,KAAG,MAAiC,CAAC;AACrE,eAAO,MAAM,GAAG,GAAI,MAAM,MAAM,KAAG,MAAiC,CAAC;AACrE,eAAO,MAAM,KAAK,GAAI,MAAM,MAAM,KAAG,MAAmC,CAAC;AACzE,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,KAAG,MAAoC,CAAC;AAC3E,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,KAAG,MAAkC,CAAC;AACvE,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,KAAG,MAAkC,CAAC;AAMvE,eAAO,MAAM,QAAQ,GAAI,SAAS,MAAM,KAAG,IAE1C,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,KAAG,IAE5C,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,SAAS,MAAM,KAAG,IAE3C,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,KAAG,IAE5C,CAAC;AAMF,eAAO,MAAM,GAAG,GAAI,SAAS,MAAM,KAAG,KAGrC,CAAC;AAQF,qBAAa,OAAO;IAClB,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,OAAO,CAAM;IAErB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAe5B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI7B,IAAI,IAAI,IAAI;IASZ,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK9B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAI5B;AAMD,eAAO,MAAM,MAAM,GAAU,SAAS,MAAM,KAAG,OAAO,CAAC,MAAM,CAW5D,CAAC;AAEF,eAAO,MAAM,OAAO,GAAU,SAAS,MAAM,KAAG,OAAO,CAAC,OAAO,CAG9D,CAAC;AAEF,eAAO,MAAM,UAAU,GAAU,SAAS,MAAM,KAAG,OAAO,CAAC,MAAM,CAoChE,CAAC;AAMF,eAAO,MAAM,UAAU,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,OAAO,CAI9D,CAAC;AAMF,eAAO,MAAM,YAAY,QAAO,MAG/B,CAAC;AAEF,eAAO,MAAM,aAAa,QAAO,MAEhC,CAAC;AAEF,eAAO,MAAM,eAAe,QAAa,OAAO,CAAC,IAAI,CAUpD,CAAC;AAMF,eAAO,MAAM,QAAQ,GAAI,SAAQ,MAAU,KAAG,MAM7C,CAAC;AAMF,eAAO,MAAM,aAAa,GAAU,SAAS,MAAM,KAAG,OAAO,CAAC,OAAO,CASpE,CAAC"}
|
package/esm/lib/cli.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// CLI Utilities - Colors, Spinner, Status Output
|
|
3
3
|
// =============================================================================
|
|
4
4
|
// ANSI Color Codes
|
|
5
|
-
import "../_dnt.polyfills.js";
|
|
6
5
|
import * as dntShim from "../_dnt.shims.js";
|
|
7
6
|
const RESET = "\x1b[0m";
|
|
8
7
|
const BOLD = "\x1b[1m";
|
|
@@ -102,30 +101,46 @@ export const confirm = async (message) => {
|
|
|
102
101
|
return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
103
102
|
};
|
|
104
103
|
export const readSecret = async (message) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
if (!dntShim.Deno.stdin.isTerminal) {
|
|
105
|
+
return await prompt(message);
|
|
106
|
+
}
|
|
107
|
+
const encoder = new TextEncoder();
|
|
108
|
+
const decoder = new TextDecoder();
|
|
109
|
+
await dntShim.Deno.stdout.write(encoder.encode(message));
|
|
110
|
+
let echoDisabled = false;
|
|
111
|
+
try {
|
|
112
|
+
const sttyOff = await new dntShim.Deno.Command("stty", {
|
|
113
|
+
args: ["-echo"],
|
|
114
|
+
stdin: "inherit",
|
|
115
|
+
stdout: "null",
|
|
116
|
+
stderr: "null",
|
|
117
|
+
}).output();
|
|
118
|
+
echoDisabled = sttyOff.success;
|
|
119
|
+
const buf = new Uint8Array(1024);
|
|
120
|
+
const n = await dntShim.Deno.stdin.read(buf);
|
|
121
|
+
if (n === null)
|
|
122
|
+
return "";
|
|
123
|
+
return decoder.decode(buf.subarray(0, n)).trim();
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
if (echoDisabled) {
|
|
127
|
+
await new dntShim.Deno.Command("stty", {
|
|
128
|
+
args: ["echo"],
|
|
129
|
+
stdin: "inherit",
|
|
130
|
+
stdout: "null",
|
|
131
|
+
stderr: "null",
|
|
132
|
+
}).output();
|
|
133
|
+
}
|
|
134
|
+
await dntShim.Deno.stdout.write(encoder.encode("\n"));
|
|
135
|
+
}
|
|
108
136
|
};
|
|
109
137
|
// =============================================================================
|
|
110
138
|
// File Utilities
|
|
111
139
|
// =============================================================================
|
|
112
140
|
export const fileExists = async (path) => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
export const fileExistsSync = (path) => {
|
|
122
|
-
try {
|
|
123
|
-
dntShim.Deno.statSync(path);
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
141
|
+
return dntShim.Deno.stat(path)
|
|
142
|
+
.then(() => true)
|
|
143
|
+
.catch(() => false);
|
|
129
144
|
};
|
|
130
145
|
// =============================================================================
|
|
131
146
|
// Config Directory
|
|
@@ -142,8 +157,11 @@ export const ensureConfigDir = async () => {
|
|
|
142
157
|
try {
|
|
143
158
|
await dntShim.Deno.mkdir(dir, { recursive: true });
|
|
144
159
|
}
|
|
145
|
-
catch {
|
|
146
|
-
|
|
160
|
+
catch (error) {
|
|
161
|
+
if (error instanceof dntShim.Deno.errors.AlreadyExists) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
throw error;
|
|
147
165
|
}
|
|
148
166
|
};
|
|
149
167
|
// =============================================================================
|
|
@@ -151,11 +169,7 @@ export const ensureConfigDir = async () => {
|
|
|
151
169
|
// =============================================================================
|
|
152
170
|
export const randomId = (length = 6) => {
|
|
153
171
|
const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
154
|
-
|
|
155
|
-
for (let i = 0; i < length; i++) {
|
|
156
|
-
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
157
|
-
}
|
|
158
|
-
return result;
|
|
172
|
+
return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join("");
|
|
159
173
|
};
|
|
160
174
|
// =============================================================================
|
|
161
175
|
// Command Exists Check
|