@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
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
// =============================================================================
|
|
2
2
|
// Fly.io CLI Response Schemas
|
|
3
3
|
// =============================================================================
|
|
4
|
-
import "
|
|
5
|
-
import { z } from "../../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
4
|
+
import { z } from "../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
6
5
|
// =============================================================================
|
|
7
6
|
// Auth Response
|
|
8
7
|
// =============================================================================
|
|
9
8
|
export const FlyAuthSchema = z.object({
|
|
10
9
|
email: z.string(),
|
|
11
|
-
}).
|
|
10
|
+
}).loose();
|
|
12
11
|
// =============================================================================
|
|
13
12
|
// App Schemas
|
|
14
13
|
// =============================================================================
|
|
@@ -18,7 +17,7 @@ export const FlyAppSchema = z.object({
|
|
|
18
17
|
Organization: z.object({
|
|
19
18
|
Slug: z.string(),
|
|
20
19
|
}).optional(),
|
|
21
|
-
}).
|
|
20
|
+
}).loose();
|
|
22
21
|
export const FlyAppsListSchema = z.array(FlyAppSchema);
|
|
23
22
|
// =============================================================================
|
|
24
23
|
// App Status
|
|
@@ -28,7 +27,7 @@ export const FlyStatusSchema = z.object({
|
|
|
28
27
|
Name: z.string().optional(),
|
|
29
28
|
Hostname: z.string().optional(),
|
|
30
29
|
Deployed: z.boolean().optional(),
|
|
31
|
-
}).
|
|
30
|
+
}).loose();
|
|
32
31
|
// =============================================================================
|
|
33
32
|
// Machine Schemas
|
|
34
33
|
// =============================================================================
|
|
@@ -36,7 +35,7 @@ export const FlyMachineGuestSchema = z.object({
|
|
|
36
35
|
cpu_kind: z.string(),
|
|
37
36
|
cpus: z.number(),
|
|
38
37
|
memory_mb: z.number(),
|
|
39
|
-
}).
|
|
38
|
+
}).loose();
|
|
40
39
|
export const FlyMachineConfigSchema = z.object({
|
|
41
40
|
guest: FlyMachineGuestSchema.optional(),
|
|
42
41
|
metadata: z.record(z.string(), z.string()).optional(),
|
|
@@ -45,11 +44,11 @@ export const FlyMachineConfigSchema = z.object({
|
|
|
45
44
|
ports: z.array(z.object({
|
|
46
45
|
port: z.number(),
|
|
47
46
|
handlers: z.array(z.string()).optional(),
|
|
48
|
-
}).
|
|
47
|
+
}).loose()).optional(),
|
|
49
48
|
protocol: z.string().optional(),
|
|
50
49
|
internal_port: z.number().optional(),
|
|
51
|
-
}).
|
|
52
|
-
}).
|
|
50
|
+
}).loose()).optional(),
|
|
51
|
+
}).loose();
|
|
53
52
|
export const FlyMachineSchema = z.object({
|
|
54
53
|
id: z.string(),
|
|
55
54
|
name: z.string(),
|
|
@@ -59,7 +58,7 @@ export const FlyMachineSchema = z.object({
|
|
|
59
58
|
config: FlyMachineConfigSchema.optional(),
|
|
60
59
|
created_at: z.string().optional(),
|
|
61
60
|
updated_at: z.string().optional(),
|
|
62
|
-
}).
|
|
61
|
+
}).loose();
|
|
63
62
|
export const FlyMachinesListSchema = z.array(FlyMachineSchema);
|
|
64
63
|
// =============================================================================
|
|
65
64
|
// Organization Schemas
|
|
@@ -71,55 +70,14 @@ export const FlyOrgsSchema = z.record(z.string(), z.string());
|
|
|
71
70
|
export const FlyDeploySchema = z.object({
|
|
72
71
|
ID: z.string().optional(),
|
|
73
72
|
Status: z.string().optional(),
|
|
74
|
-
}).
|
|
75
|
-
// =============================================================================
|
|
76
|
-
// Machine State Mapping
|
|
77
|
-
// =============================================================================
|
|
78
|
-
/**
|
|
79
|
-
* Map Fly machine state to internal state.
|
|
80
|
-
* Fly states: created, starting, started, stopping, stopped, destroying, destroyed
|
|
81
|
-
*/
|
|
82
|
-
export const mapFlyMachineState = (flyState) => {
|
|
83
|
-
switch (flyState.toLowerCase()) {
|
|
84
|
-
case "started":
|
|
85
|
-
return "running";
|
|
86
|
-
case "stopped":
|
|
87
|
-
case "suspended":
|
|
88
|
-
return "frozen";
|
|
89
|
-
case "created":
|
|
90
|
-
case "starting":
|
|
91
|
-
return "creating";
|
|
92
|
-
case "destroying":
|
|
93
|
-
case "destroyed":
|
|
94
|
-
case "failed":
|
|
95
|
-
return "failed";
|
|
96
|
-
default:
|
|
97
|
-
return "creating";
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
// =============================================================================
|
|
101
|
-
// Machine Size Mapping
|
|
102
|
-
// =============================================================================
|
|
103
|
-
/**
|
|
104
|
-
* Map Fly guest config to machine size enum.
|
|
105
|
-
*/
|
|
106
|
-
export const mapFlyMachineSize = (guest) => {
|
|
107
|
-
if (!guest)
|
|
108
|
-
return "shared-cpu-1x";
|
|
109
|
-
const cpus = guest.cpus;
|
|
110
|
-
if (cpus >= 4)
|
|
111
|
-
return "shared-cpu-4x";
|
|
112
|
-
if (cpus >= 2)
|
|
113
|
-
return "shared-cpu-2x";
|
|
114
|
-
return "shared-cpu-1x";
|
|
115
|
-
};
|
|
73
|
+
}).loose();
|
|
116
74
|
// =============================================================================
|
|
117
75
|
// IP Schemas
|
|
118
76
|
// =============================================================================
|
|
119
77
|
export const FlyIpNetworkSchema = z.object({
|
|
120
78
|
Name: z.string(),
|
|
121
79
|
Organization: z.object({ Slug: z.string() }).optional(),
|
|
122
|
-
}).
|
|
80
|
+
}).loose();
|
|
123
81
|
export const FlyIpSchema = z.object({
|
|
124
82
|
ID: z.string().optional(),
|
|
125
83
|
Address: z.string(),
|
|
@@ -127,7 +85,7 @@ export const FlyIpSchema = z.object({
|
|
|
127
85
|
Region: z.string().optional(),
|
|
128
86
|
CreatedAt: z.string().optional(),
|
|
129
87
|
Network: FlyIpNetworkSchema.optional(),
|
|
130
|
-
}).
|
|
88
|
+
}).loose();
|
|
131
89
|
export const FlyIpListSchema = z.array(FlyIpSchema);
|
|
132
90
|
// =============================================================================
|
|
133
91
|
// REST API Schemas (Machines API - api.machines.dev)
|
|
@@ -137,8 +95,8 @@ export const FlyAppInfoSchema = z.object({
|
|
|
137
95
|
network: z.string(),
|
|
138
96
|
status: z.string(),
|
|
139
97
|
organization: z.object({ slug: z.string() }).optional(),
|
|
140
|
-
}).
|
|
98
|
+
}).loose();
|
|
141
99
|
export const FlyAppInfoListSchema = z.object({
|
|
142
100
|
total_apps: z.number(),
|
|
143
101
|
apps: z.array(FlyAppInfoSchema),
|
|
144
|
-
}).
|
|
102
|
+
}).loose();
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import "
|
|
2
|
-
import { z } from "../../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
1
|
+
import { z } from "../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
3
2
|
export declare const TailscaleAuthKeySchema: z.ZodObject<{
|
|
4
3
|
key: z.ZodString;
|
|
5
4
|
id: z.ZodOptional<z.ZodString>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailscale.d.ts","sourceRoot":"","sources":["../../src/schemas/tailscale.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,4CAA4C,CAAC;AAM/D,eAAO,MAAM,sBAAsB;;;;;iBAKjC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAMtE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;iBAcxB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;iBAErC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAM9E,eAAO,MAAM,qBAAqB;;;iBAGhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAMpE,eAAO,MAAM,6BAA6B;;iBAExC,CAAC;AAEH,eAAO,MAAM,uBAAuB,mDAGnC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAMxE,eAAO,MAAM,oBAAoB;;iBAE/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAMlE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,eAAO,MAAM,oBAAoB,GAAI,MAAM,mBAAmB,KAAG,MA+BhE,CAAC"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// =============================================================================
|
|
2
2
|
// Tailscale API Response Schemas
|
|
3
3
|
// =============================================================================
|
|
4
|
-
import "
|
|
5
|
-
import { z } from "../../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
4
|
+
import { z } from "../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
6
5
|
// =============================================================================
|
|
7
6
|
// Auth Key Schemas
|
|
8
7
|
// =============================================================================
|
|
@@ -29,7 +28,7 @@ export const TailscaleDeviceSchema = z.object({
|
|
|
29
28
|
tags: z.array(z.string()).optional(),
|
|
30
29
|
advertisedRoutes: z.array(z.string()).optional(),
|
|
31
30
|
enabledRoutes: z.array(z.string()).optional(),
|
|
32
|
-
}).
|
|
31
|
+
}).loose();
|
|
33
32
|
export const TailscaleDevicesListSchema = z.object({
|
|
34
33
|
devices: z.array(TailscaleDeviceSchema),
|
|
35
34
|
});
|
|
@@ -6,7 +6,6 @@ FROM alpine:3.23.3
|
|
|
6
6
|
|
|
7
7
|
ARG TAILSCALE_VERSION=1.94.1
|
|
8
8
|
ARG COREDNS_VERSION=1.14.1
|
|
9
|
-
ARG MICROSOCKS_VERSION=1.0.5
|
|
10
9
|
|
|
11
10
|
RUN apk add --no-cache \
|
|
12
11
|
bash \
|
|
@@ -25,16 +24,6 @@ RUN cd /tmp \
|
|
|
25
24
|
&& mv coredns /usr/local/bin/coredns \
|
|
26
25
|
&& chmod +x /usr/local/bin/coredns
|
|
27
26
|
|
|
28
|
-
RUN apk add --no-cache gcc musl-dev make \
|
|
29
|
-
&& cd /tmp \
|
|
30
|
-
&& wget -q "https://github.com/rofl0r/microsocks/archive/refs/tags/v${MICROSOCKS_VERSION}.tar.gz" \
|
|
31
|
-
&& tar xzf "v${MICROSOCKS_VERSION}.tar.gz" \
|
|
32
|
-
&& cd "microsocks-${MICROSOCKS_VERSION}" \
|
|
33
|
-
&& make \
|
|
34
|
-
&& cp microsocks /usr/local/bin/ \
|
|
35
|
-
&& cd / && rm -rf /tmp/microsocks* /tmp/v${MICROSOCKS_VERSION}.tar.gz \
|
|
36
|
-
&& apk del gcc musl-dev make
|
|
37
|
-
|
|
38
27
|
RUN mkdir -p /var/lib/tailscale /var/run/tailscale /etc/coredns
|
|
39
28
|
|
|
40
29
|
COPY start.sh /start.sh
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# ambit - Self-Configuring Tailscale Subnet Router
|
|
6
|
+
# =============================================================================
|
|
7
|
+
# State is persisted to /var/lib/tailscale via Fly volume.
|
|
8
|
+
# On first run: authenticates with a pre-minted auth key, advertises routes.
|
|
9
|
+
# On restart: reuses existing state, no new device created.
|
|
10
|
+
# The router never receives the user's API token — only a single-use,
|
|
11
|
+
# tag-scoped auth key that expires after 5 minutes.
|
|
12
|
+
# =============================================================================
|
|
13
|
+
|
|
14
|
+
echo "Router: Enabling IP Forwarding"
|
|
15
|
+
echo 'net.ipv4.ip_forward = 1' | tee -a /etc/sysctl.conf
|
|
16
|
+
echo 'net.ipv6.conf.all.forwarding = 1' | tee -a /etc/sysctl.conf
|
|
17
|
+
sysctl -p /etc/sysctl.conf
|
|
18
|
+
|
|
19
|
+
PRIVATE_IP=$(grep fly-local-6pn /etc/hosts | awk '{print $1}')
|
|
20
|
+
|
|
21
|
+
# tailscaled's built-in SOCKS5 proxy routes through the WireGuard tunnel
|
|
22
|
+
# directly (no tun device needed). This handles both TCP routing and DNS
|
|
23
|
+
# resolution through the tailnet — MagicDNS, split DNS, everything.
|
|
24
|
+
echo "Router: Starting Tailscaled with SOCKS5 Proxy on [${PRIVATE_IP}]:1080"
|
|
25
|
+
/usr/local/bin/tailscaled \
|
|
26
|
+
--state=/var/lib/tailscale/tailscaled.state \
|
|
27
|
+
--socket=/var/run/tailscale/tailscaled.sock \
|
|
28
|
+
--socks5-server=[${PRIVATE_IP}]:1080 &
|
|
29
|
+
|
|
30
|
+
# Wait for tailscaled to be ready
|
|
31
|
+
sleep 3
|
|
32
|
+
|
|
33
|
+
echo "Router: Extracting Fly.io Subnet"
|
|
34
|
+
SUBNET=$(grep fly-local-6pn /etc/hosts | awk '{print $1}' | cut -d: -f1-3)::/48
|
|
35
|
+
echo "Router: Subnet ${SUBNET}"
|
|
36
|
+
|
|
37
|
+
if /usr/local/bin/tailscale status --json 2>/dev/null | jq -e '.BackendState == "Running"' > /dev/null 2>&1; then
|
|
38
|
+
echo "Router: Already Authenticated (Using Persisted State)"
|
|
39
|
+
|
|
40
|
+
/usr/local/bin/tailscale up \
|
|
41
|
+
--hostname="${FLY_APP_NAME:-ambit}" \
|
|
42
|
+
--advertise-routes="${SUBNET}"
|
|
43
|
+
else
|
|
44
|
+
# First run - authenticate with pre-minted auth key
|
|
45
|
+
if [ -z "${TAILSCALE_AUTHKEY}" ]; then
|
|
46
|
+
echo "Router: ERROR - No TAILSCALE_AUTHKEY Provided"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo "Router: Authenticating to Tailscale"
|
|
51
|
+
/usr/local/bin/tailscale up \
|
|
52
|
+
--authkey="${TAILSCALE_AUTHKEY}" \
|
|
53
|
+
--hostname="${FLY_APP_NAME:-ambit}" \
|
|
54
|
+
--advertise-routes="${SUBNET}"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
echo "Router: Fully Configured"
|
|
58
|
+
|
|
59
|
+
# Get Tailscale IPv4 for CoreDNS bind — split DNS queries arrive here
|
|
60
|
+
TAILSCALE_IP=$(/usr/local/bin/tailscale ip -4)
|
|
61
|
+
echo "Router: Tailscale IP ${TAILSCALE_IP}"
|
|
62
|
+
|
|
63
|
+
echo "Router: Starting DNS Proxy"
|
|
64
|
+
|
|
65
|
+
# Generate Corefile for CoreDNS
|
|
66
|
+
# Binds to the Fly private IP and the Tailscale IP. Split DNS queries from
|
|
67
|
+
# tailnet clients arrive on the Tailscale IP. Does NOT bind to all interfaces,
|
|
68
|
+
# so tailscaled's MagicDNS resolver on 100.100.100.100:53 remains unblocked.
|
|
69
|
+
#
|
|
70
|
+
# Rewrites NETWORK_NAME TLD to .flycast before forwarding to Fly DNS.
|
|
71
|
+
# When ROUTER_ID is set, workload app names are suffixed: app.network ->
|
|
72
|
+
# app-ROUTER_ID.flycast. This ties workloads to their router and avoids
|
|
73
|
+
# name collisions across networks.
|
|
74
|
+
if [ -n "${NETWORK_NAME}" ] && [ -n "${ROUTER_ID}" ]; then
|
|
75
|
+
echo "Router: DNS Rewrite *.${NETWORK_NAME} -> *-${ROUTER_ID}.flycast"
|
|
76
|
+
cat > /etc/coredns/Corefile <<EOF
|
|
77
|
+
.:53 {
|
|
78
|
+
bind ${PRIVATE_IP} ${TAILSCALE_IP}
|
|
79
|
+
rewrite name regex (.+)\.${NETWORK_NAME}\. {1}-${ROUTER_ID}.flycast. answer auto
|
|
80
|
+
forward . fdaa::3
|
|
81
|
+
}
|
|
82
|
+
EOF
|
|
83
|
+
elif [ -n "${NETWORK_NAME}" ]; then
|
|
84
|
+
echo "Router: DNS Rewrite ${NETWORK_NAME} -> flycast"
|
|
85
|
+
cat > /etc/coredns/Corefile <<EOF
|
|
86
|
+
.:53 {
|
|
87
|
+
bind ${PRIVATE_IP} ${TAILSCALE_IP}
|
|
88
|
+
rewrite name suffix .${NETWORK_NAME}. .flycast. answer auto
|
|
89
|
+
forward . fdaa::3
|
|
90
|
+
}
|
|
91
|
+
EOF
|
|
92
|
+
else
|
|
93
|
+
cat > /etc/coredns/Corefile <<EOF
|
|
94
|
+
.:53 {
|
|
95
|
+
bind ${PRIVATE_IP} ${TAILSCALE_IP}
|
|
96
|
+
forward . fdaa::3
|
|
97
|
+
}
|
|
98
|
+
EOF
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
exec /usr/local/bin/coredns -conf /etc/coredns/Corefile
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const ROUTER_APP_PREFIX = "ambit-";
|
|
2
|
+
export declare const DEFAULT_FLY_NETWORK = "default";
|
|
3
|
+
export declare const ROUTER_DOCKER_DIR: string;
|
|
4
|
+
export declare const SOCKS_PROXY_PORT = 1080;
|
|
5
|
+
export declare const FLY_PRIVATE_SUBNET = "fdaa::/16";
|
|
6
|
+
export declare const TAILSCALE_API_KEY_PREFIX = "tskey-api-";
|
|
7
|
+
export declare const ENV_TAILSCALE_API_KEY = "TAILSCALE_API_KEY";
|
|
8
|
+
export declare const FLYCTL_INSTALL_URL = "https://fly.io/docs/flyctl/install/";
|
|
9
|
+
export declare const SECRET_TAILSCALE_AUTHKEY = "TAILSCALE_AUTHKEY";
|
|
10
|
+
export declare const SECRET_NETWORK_NAME = "NETWORK_NAME";
|
|
11
|
+
export declare const SECRET_ROUTER_ID = "ROUTER_ID";
|
|
12
|
+
export declare const SECRET_AMBIT_OUTBOUND_PROXY = "AMBIT_OUTBOUND_PROXY";
|
|
13
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/util/constants.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAE1C,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAE7C,eAAO,MAAM,iBAAiB,QACnB,CAAC;AAMZ,eAAO,MAAM,gBAAgB,OAAO,CAAC;AAErC,eAAO,MAAM,kBAAkB,cAAc,CAAC;AAM9C,eAAO,MAAM,wBAAwB,eAAe,CAAC;AAErD,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAMzD,eAAO,MAAM,kBAAkB,wCAAwC,CAAC;AAMxE,eAAO,MAAM,wBAAwB,sBAAsB,CAAC;AAC5D,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AAClD,eAAO,MAAM,gBAAgB,cAAc,CAAC;AAM5C,eAAO,MAAM,2BAA2B,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Constants - Shared Magic Values
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// Router / App Identity
|
|
6
|
+
// =============================================================================
|
|
7
|
+
export const ROUTER_APP_PREFIX = "ambit-";
|
|
8
|
+
export const DEFAULT_FLY_NETWORK = "default";
|
|
9
|
+
export const ROUTER_DOCKER_DIR = new URL("../router", globalThis[Symbol.for("import-meta-ponyfill-esmodule")](import.meta).url)
|
|
10
|
+
.pathname;
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Networking
|
|
13
|
+
// =============================================================================
|
|
14
|
+
export const SOCKS_PROXY_PORT = 1080;
|
|
15
|
+
export const FLY_PRIVATE_SUBNET = "fdaa::/16";
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Tailscale
|
|
18
|
+
// =============================================================================
|
|
19
|
+
export const TAILSCALE_API_KEY_PREFIX = "tskey-api-";
|
|
20
|
+
export const ENV_TAILSCALE_API_KEY = "TAILSCALE_API_KEY";
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// External URLs
|
|
23
|
+
// =============================================================================
|
|
24
|
+
export const FLYCTL_INSTALL_URL = "https://fly.io/docs/flyctl/install/";
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// Fly.io Secret Names (set on router machines)
|
|
27
|
+
// =============================================================================
|
|
28
|
+
export const SECRET_TAILSCALE_AUTHKEY = "TAILSCALE_AUTHKEY";
|
|
29
|
+
export const SECRET_NETWORK_NAME = "NETWORK_NAME";
|
|
30
|
+
export const SECRET_ROUTER_ID = "ROUTER_ID";
|
|
31
|
+
// =============================================================================
|
|
32
|
+
// Fly.io Secret Names (set on workload machines)
|
|
33
|
+
// =============================================================================
|
|
34
|
+
export const SECRET_AMBIT_OUTBOUND_PROXY = "AMBIT_OUTBOUND_PROXY";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/util/credentials.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,eAAe;IAC9B,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAQD,eAAO,MAAM,2BAA2B,QAAO,eA0B9C,CAAC;AAMF,eAAO,MAAM,kBAAkB,QAAO,eAerC,CAAC;AAMF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAC5B,KAAK;IAAE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAA;CAAE,KAC1D,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,CAyBlC,CAAC"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
// =============================================================================
|
|
2
2
|
// Credential Store - Persistent Tailscale API Key Storage
|
|
3
3
|
// =============================================================================
|
|
4
|
-
import "../_dnt.polyfills.js";
|
|
5
4
|
import * as dntShim from "../_dnt.shims.js";
|
|
6
5
|
import { z } from "../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
7
|
-
import { commandExists, ensureConfigDir, fileExists } from "../lib/cli.js";
|
|
8
|
-
import {
|
|
6
|
+
import { commandExists, ensureConfigDir, fileExists, getConfigDir } from "../lib/cli.js";
|
|
7
|
+
import { ENV_TAILSCALE_API_KEY } from "./constants.js";
|
|
9
8
|
// =============================================================================
|
|
10
9
|
// Schema
|
|
11
10
|
// =============================================================================
|
|
@@ -46,8 +45,7 @@ export const getCredentialStore = () => {
|
|
|
46
45
|
const fileStore = createConfigCredentialStore();
|
|
47
46
|
return {
|
|
48
47
|
async getTailscaleApiKey() {
|
|
49
|
-
|
|
50
|
-
const envKey = dntShim.Deno.env.get("TAILSCALE_API_KEY");
|
|
48
|
+
const envKey = dntShim.Deno.env.get(ENV_TAILSCALE_API_KEY);
|
|
51
49
|
if (envKey)
|
|
52
50
|
return envKey;
|
|
53
51
|
return await fileStore.getTailscaleApiKey();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import "../
|
|
2
|
-
import type {
|
|
3
|
-
import type { TailscaleProvider } from "./providers/tailscale.js";
|
|
1
|
+
import type { FlyProvider } from "../providers/fly.js";
|
|
2
|
+
import type { TailscaleProvider } from "../providers/tailscale.js";
|
|
4
3
|
/** A router app discovered from the Fly REST API. */
|
|
5
4
|
export interface RouterApp {
|
|
6
5
|
appName: string;
|
|
7
6
|
network: string;
|
|
8
7
|
org: string;
|
|
8
|
+
routerId: string;
|
|
9
9
|
}
|
|
10
10
|
/** Machine state for a router, from the Fly Machines API. */
|
|
11
11
|
export interface RouterMachineInfo {
|
|
@@ -33,10 +33,26 @@ export interface WorkloadApp {
|
|
|
33
33
|
}
|
|
34
34
|
/** List all non-router apps on a specific custom network in an org. */
|
|
35
35
|
export declare const listWorkloadAppsOnNetwork: (fly: FlyProvider, org: string, network: string) => Promise<WorkloadApp[]>;
|
|
36
|
-
/** Find a specific workload app by name, optionally
|
|
36
|
+
/** Find a specific workload app by logical name, optionally scoped to a network.
|
|
37
|
+
* When a network is provided, resolves the router-suffixed Fly app name
|
|
38
|
+
* (e.g. "thing" on network "lab" with routerId "abc123" → "thing-abc123"). */
|
|
37
39
|
export declare const findWorkloadApp: (fly: FlyProvider, org: string, appName: string, network?: string) => Promise<WorkloadApp | null>;
|
|
38
40
|
/** Get machine info for a router app. Returns null if no machines exist. */
|
|
39
41
|
export declare const getRouterMachineInfo: (fly: FlyProvider, appName: string) => Promise<RouterMachineInfo | null>;
|
|
40
42
|
/** Get tailscale device info for a router. Returns null if not found. */
|
|
41
43
|
export declare const getRouterTailscaleInfo: (tailscale: TailscaleProvider, appName: string) => Promise<RouterTailscaleInfo | null>;
|
|
44
|
+
/** A router app with its machine and Tailscale state hydrated. */
|
|
45
|
+
export type RouterWithInfo = RouterApp & {
|
|
46
|
+
machine: RouterMachineInfo | null;
|
|
47
|
+
tailscale: RouterTailscaleInfo | null;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Discover all routers in an org and hydrate each with machine + Tailscale state.
|
|
51
|
+
* Shows a spinner while fetching. Fetches all routers in parallel.
|
|
52
|
+
*/
|
|
53
|
+
export declare const discoverRouters: (out: {
|
|
54
|
+
spinner(msg: string): {
|
|
55
|
+
success(msg: string): void;
|
|
56
|
+
};
|
|
57
|
+
}, fly: FlyProvider, tailscale: TailscaleProvider, org: string) => Promise<RouterWithInfo[]>;
|
|
42
58
|
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/util/discovery.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAWnE,qDAAqD;AACrD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAMD,wDAAwD;AACxD,eAAO,MAAM,cAAc,GACzB,KAAK,WAAW,EAChB,KAAK,MAAM,KACV,OAAO,CAAC,SAAS,EAAE,CAerB,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,aAAa,GACxB,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,SAAS,MAAM,KACd,OAAO,CAAC,SAAS,GAAG,IAAI,CAG1B,CAAC;AAMF,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,GACpC,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,SAAS,MAAM,KACd,OAAO,CAAC,WAAW,EAAE,CAcvB,CAAC;AAEF;;+EAE+E;AAC/E,eAAO,MAAM,eAAe,GAC1B,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,SAAS,MAAM,EACf,UAAU,MAAM,KACf,OAAO,CAAC,WAAW,GAAG,IAAI,CA4B5B,CAAC;AAMF,4EAA4E;AAC5E,eAAO,MAAM,oBAAoB,GAC/B,KAAK,WAAW,EAChB,SAAS,MAAM,KACd,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAclC,CAAC;AAMF,yEAAyE;AACzE,eAAO,MAAM,sBAAsB,GACjC,WAAW,iBAAiB,EAC5B,SAAS,MAAM,KACd,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAcpC,CAAC;AAMF,kEAAkE;AAClE,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG;IACvC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACvC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,GAC1B,KAAK;IAAE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CAAE,EAC7D,KAAK,WAAW,EAChB,WAAW,iBAAiB,EAC5B,KAAK,MAAM,KACV,OAAO,CAAC,cAAc,EAAE,CAa1B,CAAC"}
|
|
@@ -12,26 +12,23 @@
|
|
|
12
12
|
// Commands compose them into whatever view they need.
|
|
13
13
|
//
|
|
14
14
|
// =============================================================================
|
|
15
|
-
import "
|
|
16
|
-
import { extractSubnet } from "./
|
|
17
|
-
|
|
18
|
-
// Constants
|
|
19
|
-
// =============================================================================
|
|
20
|
-
const ROUTER_APP_PREFIX = "ambit-";
|
|
21
|
-
const DEFAULT_NETWORK = "default";
|
|
15
|
+
import { getRouterSuffix, getWorkloadAppName } from "./naming.js";
|
|
16
|
+
import { extractSubnet } from "./fly-transforms.js";
|
|
17
|
+
import { DEFAULT_FLY_NETWORK, ROUTER_APP_PREFIX, } from "./constants.js";
|
|
22
18
|
// =============================================================================
|
|
23
19
|
// 1. Which routers exist? (Fly REST API)
|
|
24
20
|
// =============================================================================
|
|
25
21
|
/** List all ambit apps on custom networks in an org. */
|
|
26
22
|
export const listRouterApps = async (fly, org) => {
|
|
27
|
-
const apps = await fly.
|
|
23
|
+
const apps = await fly.apps.listWithNetwork(org);
|
|
28
24
|
return apps
|
|
29
25
|
.filter((app) => app.name.startsWith(ROUTER_APP_PREFIX) &&
|
|
30
|
-
app.network !==
|
|
26
|
+
app.network !== DEFAULT_FLY_NETWORK)
|
|
31
27
|
.map((app) => ({
|
|
32
28
|
appName: app.name,
|
|
33
29
|
network: app.network,
|
|
34
30
|
org: app.organization?.slug ?? org,
|
|
31
|
+
routerId: getRouterSuffix(app.name, app.network),
|
|
35
32
|
}));
|
|
36
33
|
};
|
|
37
34
|
/** Find the router app for a specific network. */
|
|
@@ -41,7 +38,7 @@ export const findRouterApp = async (fly, org, network) => {
|
|
|
41
38
|
};
|
|
42
39
|
/** List all non-router apps on a specific custom network in an org. */
|
|
43
40
|
export const listWorkloadAppsOnNetwork = async (fly, org, network) => {
|
|
44
|
-
const apps = await fly.
|
|
41
|
+
const apps = await fly.apps.listWithNetwork(org);
|
|
45
42
|
return apps
|
|
46
43
|
.filter((app) => !app.name.startsWith(ROUTER_APP_PREFIX) &&
|
|
47
44
|
app.network === network)
|
|
@@ -51,20 +48,32 @@ export const listWorkloadAppsOnNetwork = async (fly, org, network) => {
|
|
|
51
48
|
org: app.organization?.slug ?? org,
|
|
52
49
|
}));
|
|
53
50
|
};
|
|
54
|
-
/** Find a specific workload app by name, optionally
|
|
51
|
+
/** Find a specific workload app by logical name, optionally scoped to a network.
|
|
52
|
+
* When a network is provided, resolves the router-suffixed Fly app name
|
|
53
|
+
* (e.g. "thing" on network "lab" with routerId "abc123" → "thing-abc123"). */
|
|
55
54
|
export const findWorkloadApp = async (fly, org, appName, network) => {
|
|
56
|
-
const apps = await fly.
|
|
55
|
+
const apps = await fly.apps.listWithNetwork(org);
|
|
57
56
|
const workloads = apps
|
|
58
57
|
.filter((app) => !app.name.startsWith(ROUTER_APP_PREFIX) &&
|
|
59
|
-
app.network !==
|
|
58
|
+
app.network !== DEFAULT_FLY_NETWORK)
|
|
60
59
|
.map((app) => ({
|
|
61
60
|
appName: app.name,
|
|
62
61
|
network: app.network,
|
|
63
62
|
org: app.organization?.slug ?? org,
|
|
64
63
|
}));
|
|
65
64
|
if (network) {
|
|
65
|
+
// Resolve the router's suffix so we can match the suffixed Fly app name
|
|
66
|
+
const router = await findRouterApp(fly, org, network);
|
|
67
|
+
if (router) {
|
|
68
|
+
const suffixedName = getWorkloadAppName(appName, router.routerId);
|
|
69
|
+
const found = workloads.find((a) => a.appName === suffixedName && a.network === network);
|
|
70
|
+
if (found)
|
|
71
|
+
return found;
|
|
72
|
+
}
|
|
73
|
+
// Fallback: try exact match (for pre-suffix apps or direct Fly name)
|
|
66
74
|
return workloads.find((a) => a.appName === appName && a.network === network) ?? null;
|
|
67
75
|
}
|
|
76
|
+
// Without network, try exact match only
|
|
68
77
|
return workloads.find((a) => a.appName === appName) ?? null;
|
|
69
78
|
};
|
|
70
79
|
// =============================================================================
|
|
@@ -72,7 +81,7 @@ export const findWorkloadApp = async (fly, org, appName, network) => {
|
|
|
72
81
|
// =============================================================================
|
|
73
82
|
/** Get machine info for a router app. Returns null if no machines exist. */
|
|
74
83
|
export const getRouterMachineInfo = async (fly, appName) => {
|
|
75
|
-
const machines = await fly.
|
|
84
|
+
const machines = await fly.machines.list(appName);
|
|
76
85
|
const machine = machines[0];
|
|
77
86
|
if (!machine)
|
|
78
87
|
return null;
|
|
@@ -91,7 +100,7 @@ export const getRouterMachineInfo = async (fly, appName) => {
|
|
|
91
100
|
/** Get tailscale device info for a router. Returns null if not found. */
|
|
92
101
|
export const getRouterTailscaleInfo = async (tailscale, appName) => {
|
|
93
102
|
try {
|
|
94
|
-
const device = await tailscale.
|
|
103
|
+
const device = await tailscale.devices.getByHostname(appName);
|
|
95
104
|
if (!device)
|
|
96
105
|
return null;
|
|
97
106
|
return {
|
|
@@ -105,3 +114,17 @@ export const getRouterTailscaleInfo = async (tailscale, appName) => {
|
|
|
105
114
|
return null;
|
|
106
115
|
}
|
|
107
116
|
};
|
|
117
|
+
/**
|
|
118
|
+
* Discover all routers in an org and hydrate each with machine + Tailscale state.
|
|
119
|
+
* Shows a spinner while fetching. Fetches all routers in parallel.
|
|
120
|
+
*/
|
|
121
|
+
export const discoverRouters = async (out, fly, tailscale, org) => {
|
|
122
|
+
const spinner = out.spinner("Discovering Routers");
|
|
123
|
+
const routerApps = await listRouterApps(fly, org);
|
|
124
|
+
spinner.success(`Found ${routerApps.length} Router${routerApps.length !== 1 ? "s" : ""}`);
|
|
125
|
+
return Promise.all(routerApps.map(async (app) => ({
|
|
126
|
+
...app,
|
|
127
|
+
machine: await getRouterMachineInfo(fly, app.appName),
|
|
128
|
+
tailscale: await getRouterTailscaleInfo(tailscale, app.appName),
|
|
129
|
+
})));
|
|
130
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { FlyMachine } from "../schemas/fly.js";
|
|
2
|
+
import { type FlyMachineGuestSchema } from "../schemas/fly.js";
|
|
3
|
+
import type { z } from "../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Map Fly machine state to internal state.
|
|
6
|
+
* Fly states: created, starting, started, stopping, stopped, destroying, destroyed
|
|
7
|
+
*/
|
|
8
|
+
export declare const mapFlyMachineState: (flyState: string) => "creating" | "running" | "frozen" | "failed";
|
|
9
|
+
/**
|
|
10
|
+
* Map Fly guest config to machine size enum.
|
|
11
|
+
*/
|
|
12
|
+
export declare const mapFlyMachineSize: (guest?: z.infer<typeof FlyMachineGuestSchema>) => "shared-cpu-1x" | "shared-cpu-2x" | "shared-cpu-4x";
|
|
13
|
+
import type { MachineResult } from "../providers/fly.js";
|
|
14
|
+
/** Map raw Fly machines to internal MachineResult format. */
|
|
15
|
+
export declare const mapMachines: (raw: FlyMachine[]) => MachineResult[];
|
|
16
|
+
import type { MachineSize } from "../providers/fly.js";
|
|
17
|
+
export declare const getSizeConfig: (size: MachineSize) => {
|
|
18
|
+
cpus: number;
|
|
19
|
+
memoryMb: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Pull the last non-empty, non-decoration line from fly stderr.
|
|
23
|
+
* Fly often prints progress lines then the actual error at the end.
|
|
24
|
+
*/
|
|
25
|
+
export declare const extractErrorDetail: (stderr: string) => string;
|
|
26
|
+
export declare const extractSubnet: (privateIp: string) => string;
|
|
27
|
+
//# sourceMappingURL=fly-transforms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fly-transforms.d.ts","sourceRoot":"","sources":["../../src/util/fly-transforms.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,4CAA4C,CAAC;AAMpE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,MAAM,KACf,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,QAiBtC,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,KAC5C,eAAe,GAAG,eAAe,GAAG,eAOtC,CAAC;AAMF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,6DAA6D;AAC7D,eAAO,MAAM,WAAW,GAAI,KAAK,UAAU,EAAE,KAAG,aAAa,EAQ5D,CAAC;AAMF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,eAAO,MAAM,aAAa,GACxB,MAAM,WAAW,KAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CASlC,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,MAOnD,CAAC;AAMF,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM,KAAG,MAKjD,CAAC"}
|