@cardelli/ambit 0.3.3 → 0.3.5
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/README.md +55 -0
- package/esm/cli/commands/create/index.js +2 -2
- package/esm/cli/commands/create/machine.d.ts +1 -1
- package/esm/cli/commands/create/machine.d.ts.map +1 -1
- package/esm/cli/commands/deploy/index.js +1 -1
- package/esm/cli/commands/deploy/machine.d.ts +1 -1
- package/esm/cli/commands/deploy/machine.d.ts.map +1 -1
- package/esm/cli/commands/deploy/modes.d.ts +1 -1
- package/esm/cli/commands/deploy/modes.d.ts.map +1 -1
- package/esm/cli/commands/destroy/app.js +1 -1
- package/esm/cli/commands/destroy/index.js +4 -1
- package/esm/cli/commands/destroy/network.js +1 -1
- package/esm/cli/commands/doctor.js +5 -3
- package/esm/cli/commands/list/apps.d.ts.map +1 -1
- package/esm/cli/commands/list/apps.js +2 -2
- package/esm/cli/commands/list/index.js +4 -1
- package/esm/cli/commands/list/networks.js +1 -1
- package/esm/cli/commands/logs.d.ts +2 -0
- package/esm/cli/commands/logs.d.ts.map +1 -0
- package/esm/cli/commands/logs.js +142 -0
- package/esm/cli/commands/secrets.d.ts +2 -0
- package/esm/cli/commands/secrets.d.ts.map +1 -0
- package/esm/cli/commands/secrets.js +302 -0
- package/esm/cli/commands/share.js +1 -1
- package/esm/cli/commands/status/app.js +1 -1
- package/esm/cli/commands/status/index.js +4 -1
- package/esm/cli/commands/status/network.js +1 -1
- package/esm/cli/commands/status/networks.js +1 -1
- package/esm/cli/mod.d.ts.map +1 -1
- package/esm/cli/mod.js +2 -0
- package/esm/deno.js +1 -1
- package/esm/lib/args.d.ts +6 -3
- package/esm/lib/args.d.ts.map +1 -1
- package/esm/lib/args.js +12 -3
- package/esm/lib/command.d.ts +9 -0
- package/esm/lib/command.d.ts.map +1 -1
- package/esm/lib/command.js +32 -0
- package/esm/lib/table.d.ts +23 -0
- package/esm/lib/table.d.ts.map +1 -0
- package/esm/lib/table.js +64 -0
- package/esm/main.d.ts +2 -0
- package/esm/main.d.ts.map +1 -1
- package/esm/main.js +4 -0
- package/esm/providers/fly.d.ts +8 -0
- package/esm/providers/fly.d.ts.map +1 -1
- package/esm/providers/fly.js +28 -0
- package/esm/util/fly-transforms.d.ts +1 -2
- package/esm/util/fly-transforms.d.ts.map +1 -1
- package/esm/util/resolve.d.ts.map +1 -1
- package/esm/util/resolve.js +3 -1
- package/esm/util/template.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -211,6 +211,61 @@ Shows detailed status for a specific app: machines, Flycast IPs, and the backing
|
|
|
211
211
|
| `--org <org>` | Fly.io organization slug |
|
|
212
212
|
| `--json` | Machine-readable JSON output |
|
|
213
213
|
|
|
214
|
+
### `ambit secrets list|set|unset|deploy <app>.<network>`
|
|
215
|
+
|
|
216
|
+
Manage secrets for workload apps. Secrets are encrypted environment variables provided to the app at runtime.
|
|
217
|
+
|
|
218
|
+
#### `ambit secrets list <app>.<network>`
|
|
219
|
+
|
|
220
|
+
Lists secret names and digests (not values) for an app.
|
|
221
|
+
|
|
222
|
+
#### `ambit secrets set <app>.<network> KEY=VALUE ...`
|
|
223
|
+
|
|
224
|
+
Sets one or more secrets. Positional `KEY=VALUE` pairs and `--env` can be combined — positional args take precedence.
|
|
225
|
+
|
|
226
|
+
| Flag | Description |
|
|
227
|
+
| ----------------- | -------------------------------------------- |
|
|
228
|
+
| `--env <file>` | Load secrets from an env file |
|
|
229
|
+
| `--stage` | Stage secrets without deploying |
|
|
230
|
+
| `--org <org>` | Fly.io organization slug |
|
|
231
|
+
| `--json` | Machine-readable JSON output |
|
|
232
|
+
|
|
233
|
+
#### `ambit secrets unset <app>.<network> KEY ...`
|
|
234
|
+
|
|
235
|
+
Removes one or more secrets by name.
|
|
236
|
+
|
|
237
|
+
| Flag | Description |
|
|
238
|
+
| ----------------- | -------------------------------------------- |
|
|
239
|
+
| `--stage` | Stage removal without deploying |
|
|
240
|
+
| `--org <org>` | Fly.io organization slug |
|
|
241
|
+
| `--json` | Machine-readable JSON output |
|
|
242
|
+
|
|
243
|
+
#### `ambit secrets deploy <app>.<network>`
|
|
244
|
+
|
|
245
|
+
Deploys staged secrets (from `set --stage` or `unset --stage`).
|
|
246
|
+
|
|
247
|
+
| Flag | Description |
|
|
248
|
+
| ----------------- | -------------------------------------------- |
|
|
249
|
+
| `--org <org>` | Fly.io organization slug |
|
|
250
|
+
| `--json` | Machine-readable JSON output |
|
|
251
|
+
|
|
252
|
+
### `ambit logs <app>.<network>`
|
|
253
|
+
|
|
254
|
+
Streams logs for a workload app. By default, logs are streamed continuously. Use `--no-tail` to fetch only buffered logs. Pipe through `less` for scrollable output:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
npx @cardelli/ambit logs my-app.lab | less +F -R # stream with scroll (Ctrl+C to scroll, F to resume)
|
|
258
|
+
npx @cardelli/ambit logs my-app.lab --no-tail | less -R # scroll buffered logs
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
| Flag | Description |
|
|
262
|
+
| -------------------- | -------------------------------------------- |
|
|
263
|
+
| `-r`, `--region <r>` | Filter by region |
|
|
264
|
+
| `--machine <id>` | Filter by machine ID |
|
|
265
|
+
| `-n`, `--no-tail` | Only fetch buffered logs (no streaming) |
|
|
266
|
+
| `--org <org>` | Fly.io organization slug |
|
|
267
|
+
| `--json` | JSON output |
|
|
268
|
+
|
|
214
269
|
### `ambit destroy network <name>`
|
|
215
270
|
|
|
216
271
|
Tears down a network: destroys the router, cleans up DNS, removes the Tailscale device, and automatically removes the router's tag from your Tailscale ACL policy (tagOwners and autoApprovers). If there are workload apps still on the network, ambit warns you before proceeding.
|
|
@@ -169,7 +169,7 @@ const stageDeploy = async (out, fly, tailscale, opts) => {
|
|
|
169
169
|
// =============================================================================
|
|
170
170
|
// Stage 4: Summary
|
|
171
171
|
// =============================================================================
|
|
172
|
-
const stageSummary = async (out,
|
|
172
|
+
const stageSummary = async (out, _fly, tailscale, ctx, opts) => {
|
|
173
173
|
const policy = await tailscale.acl.getPolicy();
|
|
174
174
|
const hasAutoApprover = isAutoApproverConfigured(policy, opts.tag);
|
|
175
175
|
out.done({
|
|
@@ -245,7 +245,7 @@ const create = async (argv) => {
|
|
|
245
245
|
alias: { y: "yes" },
|
|
246
246
|
};
|
|
247
247
|
const args = parseArgs(argv, opts);
|
|
248
|
-
checkArgs(args, opts, "ambit create");
|
|
248
|
+
checkArgs(args, opts, "ambit create", 1);
|
|
249
249
|
if (args.help) {
|
|
250
250
|
console.log(`
|
|
251
251
|
${bold("ambit create")} - Create Tailscale Subnet Router
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Output } from "../../../lib/output.js";
|
|
2
2
|
import { Result } from "../../../lib/result.js";
|
|
3
3
|
import { type FlyProvider } from "../../../providers/fly.js";
|
|
4
4
|
import type { TailscaleProvider } from "../../../providers/tailscale.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/create/machine.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/create/machine.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAQhD,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAW7E,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAOrE,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,eAAe,GACf,gBAAgB,GAChB,eAAe,GACf,eAAe,GACf,UAAU,CAAC;AAMf,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACxD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,WAAW,CAAC;IACjB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAcD,eAAO,MAAM,aAAa,GACxB,KAAK,MAAM,CAAC,YAAY,CAAC,EACzB,YAAY,WAAW,SAMxB,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,KAAK,SAAS,KACb,OAAO,CAAC,WAAW,CA4BrB,CAAC;AAMF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,WAAW,EAClB,KAAK,SAAS,KACb,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CA+K7B,CAAC"}
|
|
@@ -153,7 +153,7 @@ const deploy = async (argv) => {
|
|
|
153
153
|
default: { "main-port": "80" },
|
|
154
154
|
};
|
|
155
155
|
const args = parseArgs(argv, opts);
|
|
156
|
-
checkArgs(args, opts, "ambit deploy");
|
|
156
|
+
checkArgs(args, opts, "ambit deploy", 1);
|
|
157
157
|
if (args.help) {
|
|
158
158
|
console.log(`
|
|
159
159
|
${bold("ambit deploy")} - Deploy an App Safely on a Custom Private Network
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Output } from "../../../lib/output.js";
|
|
2
2
|
import { Result } from "../../../lib/result.js";
|
|
3
3
|
import { type FlyProvider, type SafeDeployOptions } from "../../../providers/fly.js";
|
|
4
4
|
import type { DeployConfig } from "./modes.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/machine.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/machine.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,OAAO,GACP,UAAU,CAAC;AAMf,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE;QACL,mBAAmB,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,MAAM,CAAC;QACtB,mBAAmB,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,SAAS,EAAE;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,WAAW,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,iBAAiB,CAAC;IACjC,KAAK,CAAC,EAAE;QACN,mBAAmB,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,MAAM,CAAC;QACtB,mBAAmB,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH;AAaD,eAAO,MAAM,mBAAmB,GAC9B,KAAK,MAAM,CAAC,YAAY,CAAC,EACzB,YAAY,WAAW,SAMxB,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,KAAK,SAAS,KACb,OAAO,CAAC,WAAW,CAMrB,CAAC;AAMF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,WAAW,EAClB,KAAK,SAAS,KACb,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CA6G7B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modes.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/modes.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"modes.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/modes.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAQ3D,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoCD,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,EACb,aAAa,MAAM,EACnB,KAAK,UAAU,CAAC,OAAO,YAAY,CAAC,KACnC,YAAY,GAAG,IAmBjB,CAAC;AAMF,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,GAC5B,gBAAgB,MAAM,GAAG,SAAS,EAClC,KAAK,UAAU,CAAC,OAAO,YAAY,CAAC,KACnC,OAAO,CAAC,YAAY,GAAG,IAAI,CAqC7B,CAAC;AAMF,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,GAC9B,aAAa,MAAM,EACnB,KAAK,UAAU,CAAC,OAAO,YAAY,CAAC,KACnC,OAAO,CAAC,YAAY,GAAG,IAAI,CAyE7B,CAAC"}
|
|
@@ -107,7 +107,7 @@ export const destroyApp = async (argv) => {
|
|
|
107
107
|
alias: { y: "yes" },
|
|
108
108
|
};
|
|
109
109
|
const args = parseArgs(argv, opts);
|
|
110
|
-
checkArgs(args, opts, "ambit destroy app");
|
|
110
|
+
checkArgs(args, opts, "ambit destroy app", 1);
|
|
111
111
|
if (args.help) {
|
|
112
112
|
console.log(`
|
|
113
113
|
${bold("ambit destroy app")} - Destroy a Workload App
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import * as dntShim from "../../../_dnt.shims.js";
|
|
5
5
|
import { parseArgs } from "../../../deps/jsr.io/@std/cli/1.0.28/mod.js";
|
|
6
6
|
import { bold } from "../../../lib/cli.js";
|
|
7
|
+
import { checkArgs } from "../../../lib/args.js";
|
|
7
8
|
import { registerCommand } from "../../mod.js";
|
|
8
9
|
import { destroyNetwork } from "./network.js";
|
|
9
10
|
import { destroyApp } from "./app.js";
|
|
@@ -46,7 +47,9 @@ const destroy = async (argv) => {
|
|
|
46
47
|
if (subcommand === "app") {
|
|
47
48
|
return destroyApp(argv.slice(1));
|
|
48
49
|
}
|
|
49
|
-
const
|
|
50
|
+
const opts = { boolean: ["help"] };
|
|
51
|
+
const args = parseArgs(argv, opts);
|
|
52
|
+
checkArgs(args, opts, "ambit destroy", 0);
|
|
50
53
|
if (args.help) {
|
|
51
54
|
showDestroyHelp();
|
|
52
55
|
return;
|
|
@@ -225,7 +225,7 @@ export const destroyNetwork = async (argv) => {
|
|
|
225
225
|
alias: { y: "yes" },
|
|
226
226
|
};
|
|
227
227
|
const args = parseArgs(argv, opts);
|
|
228
|
-
checkArgs(args, opts, "ambit destroy network");
|
|
228
|
+
checkArgs(args, opts, "ambit destroy network", 1);
|
|
229
229
|
if (args.help) {
|
|
230
230
|
console.log(`
|
|
231
231
|
${bold("ambit destroy network")} - Tear Down Router
|
|
@@ -145,7 +145,7 @@ const doctorNetwork = async (argv) => {
|
|
|
145
145
|
boolean: ["help", "json"],
|
|
146
146
|
};
|
|
147
147
|
const args = parseArgs(argv, opts);
|
|
148
|
-
checkArgs(args, opts, "ambit doctor network");
|
|
148
|
+
checkArgs(args, opts, "ambit doctor network", 1);
|
|
149
149
|
if (args.help) {
|
|
150
150
|
console.log(`
|
|
151
151
|
${bold("ambit doctor network")} - Check Router Health
|
|
@@ -192,7 +192,7 @@ const doctorApp = async (argv) => {
|
|
|
192
192
|
boolean: ["help", "json"],
|
|
193
193
|
};
|
|
194
194
|
const args = parseArgs(argv, opts);
|
|
195
|
-
checkArgs(args, opts, "ambit doctor app");
|
|
195
|
+
checkArgs(args, opts, "ambit doctor app", 1);
|
|
196
196
|
if (args.help) {
|
|
197
197
|
console.log(`
|
|
198
198
|
${bold("ambit doctor app")} - Check App Health
|
|
@@ -286,7 +286,9 @@ const doctor = async (argv) => {
|
|
|
286
286
|
return doctorNetwork(argv.slice(1));
|
|
287
287
|
if (subcommand === "app")
|
|
288
288
|
return doctorApp(argv.slice(1));
|
|
289
|
-
const
|
|
289
|
+
const opts = { string: ["org"], boolean: ["help", "json"] };
|
|
290
|
+
const args = parseArgs(argv, opts);
|
|
291
|
+
checkArgs(args, opts, "ambit doctor", 0);
|
|
290
292
|
if (args.help) {
|
|
291
293
|
showDoctorHelp();
|
|
292
294
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/list/apps.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/list/apps.ts"],"names":[],"mappings":"AA6BA,eAAO,MAAM,QAAQ,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAqE3D,CAAC"}
|
|
@@ -6,7 +6,7 @@ import { Table } from "../../../deps/jsr.io/@cliffy/table/1.0.0/mod.js";
|
|
|
6
6
|
import { bold } from "../../../lib/cli.js";
|
|
7
7
|
import { checkArgs } from "../../../lib/args.js";
|
|
8
8
|
import { createOutput } from "../../../lib/output.js";
|
|
9
|
-
import { findRouterApp, listWorkloadAppsOnNetwork
|
|
9
|
+
import { findRouterApp, listWorkloadAppsOnNetwork } from "../../../util/discovery.js";
|
|
10
10
|
import { initSession } from "../../../util/session.js";
|
|
11
11
|
// =============================================================================
|
|
12
12
|
// List Apps Command
|
|
@@ -14,7 +14,7 @@ import { initSession } from "../../../util/session.js";
|
|
|
14
14
|
export const listApps = async (argv) => {
|
|
15
15
|
const opts = { string: ["org"], boolean: ["help", "json"] };
|
|
16
16
|
const args = parseArgs(argv, opts);
|
|
17
|
-
checkArgs(args, opts, "ambit list apps");
|
|
17
|
+
checkArgs(args, opts, "ambit list apps", 1);
|
|
18
18
|
if (args.help) {
|
|
19
19
|
console.log(`
|
|
20
20
|
${bold("ambit list apps")} - List Apps on a Network
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import * as dntShim from "../../../_dnt.shims.js";
|
|
5
5
|
import { parseArgs } from "../../../deps/jsr.io/@std/cli/1.0.28/mod.js";
|
|
6
6
|
import { bold } from "../../../lib/cli.js";
|
|
7
|
+
import { checkArgs } from "../../../lib/args.js";
|
|
7
8
|
import { registerCommand } from "../../mod.js";
|
|
8
9
|
import { listNetworks } from "./networks.js";
|
|
9
10
|
import { listApps } from "./apps.js";
|
|
@@ -43,7 +44,9 @@ const list = async (argv) => {
|
|
|
43
44
|
return listNetworks(argv.slice(1));
|
|
44
45
|
if (subcommand === "apps")
|
|
45
46
|
return listApps(argv.slice(1));
|
|
46
|
-
const
|
|
47
|
+
const opts = { boolean: ["help"] };
|
|
48
|
+
const args = parseArgs(argv, opts);
|
|
49
|
+
checkArgs(args, opts, "ambit list", 0);
|
|
47
50
|
if (args.help) {
|
|
48
51
|
showListHelp();
|
|
49
52
|
return;
|
|
@@ -52,7 +52,7 @@ const stageRender = (out, routers) => {
|
|
|
52
52
|
export const listNetworks = async (argv) => {
|
|
53
53
|
const opts = { string: ["org"], boolean: ["help", "json"] };
|
|
54
54
|
const args = parseArgs(argv, opts);
|
|
55
|
-
checkArgs(args, opts, "ambit list networks");
|
|
55
|
+
checkArgs(args, opts, "ambit list networks", 0);
|
|
56
56
|
if (args.help) {
|
|
57
57
|
console.log(`
|
|
58
58
|
${bold("ambit list networks")} - List All Networks
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/logs.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Logs Command - Stream Logs for Workload Apps
|
|
3
|
+
// =============================================================================
|
|
4
|
+
import { parseArgs } from "../../deps/jsr.io/@std/cli/1.0.28/mod.js";
|
|
5
|
+
import { bold } from "../../lib/cli.js";
|
|
6
|
+
import { checkArgs } from "../../lib/args.js";
|
|
7
|
+
import { createOutput } from "../../lib/output.js";
|
|
8
|
+
import { streamCommand } from "../../lib/command.js";
|
|
9
|
+
import { registerCommand } from "../mod.js";
|
|
10
|
+
import { findWorkloadApp } from "../../util/discovery.js";
|
|
11
|
+
import { initSession } from "../../util/session.js";
|
|
12
|
+
import { StreamTable } from "../../lib/table.js";
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Log Table
|
|
15
|
+
// =============================================================================
|
|
16
|
+
const logTable = new StreamTable([
|
|
17
|
+
{ name: "Timestamp", width: 19 },
|
|
18
|
+
{ name: "Region", width: 6 },
|
|
19
|
+
{ name: "Level", width: 5 },
|
|
20
|
+
{ name: "Message", width: 0 },
|
|
21
|
+
]);
|
|
22
|
+
const formatTimestamp = (ts) => {
|
|
23
|
+
return ts.replace("T", " ").replace(/\.\d+Z$/, "");
|
|
24
|
+
};
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// Logs Command
|
|
27
|
+
// =============================================================================
|
|
28
|
+
const logs = async (argv) => {
|
|
29
|
+
const opts = {
|
|
30
|
+
string: ["org", "region", "machine"],
|
|
31
|
+
boolean: ["help", "json", "no-tail"],
|
|
32
|
+
alias: { r: "region", n: "no-tail" },
|
|
33
|
+
};
|
|
34
|
+
const args = parseArgs(argv, opts);
|
|
35
|
+
checkArgs(args, opts, "ambit logs", 1);
|
|
36
|
+
if (args.help) {
|
|
37
|
+
console.log(`
|
|
38
|
+
${bold("ambit logs")} - Stream Logs for a Workload App
|
|
39
|
+
|
|
40
|
+
${bold("USAGE")}
|
|
41
|
+
ambit logs <app>.<network> [options]
|
|
42
|
+
|
|
43
|
+
${bold("OPTIONS")}
|
|
44
|
+
--org <org> Fly.io organization slug
|
|
45
|
+
-r, --region <r> Filter by region
|
|
46
|
+
--machine <id> Filter by machine ID
|
|
47
|
+
-n, --no-tail Only fetch buffered logs (no streaming)
|
|
48
|
+
--json JSON output
|
|
49
|
+
|
|
50
|
+
${bold("EXAMPLES")}
|
|
51
|
+
ambit logs my-app.browsers
|
|
52
|
+
ambit logs my-app.browsers | less +F -R
|
|
53
|
+
ambit logs my-app.browsers --no-tail | less -R
|
|
54
|
+
ambit logs my-app.browsers --region iad --json
|
|
55
|
+
`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const out = createOutput(args.json);
|
|
59
|
+
const appArg = args._[0];
|
|
60
|
+
if (!appArg || typeof appArg !== "string") {
|
|
61
|
+
return out.die("Missing App Name. Usage: ambit logs <app>.<network>");
|
|
62
|
+
}
|
|
63
|
+
if (!appArg.includes(".")) {
|
|
64
|
+
return out.die(`Missing Network. Use: ambit logs ${appArg}.<network>`);
|
|
65
|
+
}
|
|
66
|
+
const parts = appArg.split(".");
|
|
67
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
68
|
+
return out.die(`'${appArg}' Should Have Exactly One Dot, Like my-app.my-network`);
|
|
69
|
+
}
|
|
70
|
+
const app = parts[0];
|
|
71
|
+
const network = parts[1];
|
|
72
|
+
const { fly, org } = await initSession(out, {
|
|
73
|
+
json: args.json,
|
|
74
|
+
org: args.org,
|
|
75
|
+
});
|
|
76
|
+
const workload = await findWorkloadApp(fly, org, app, network);
|
|
77
|
+
if (!workload) {
|
|
78
|
+
return out.die(`App '${app}' Not Found on Network '${network}'`);
|
|
79
|
+
}
|
|
80
|
+
// Always request JSON from fly so we can parse and format
|
|
81
|
+
const flyArgs = ["fly", "logs", "-a", workload.appName, "--json"];
|
|
82
|
+
if (args["no-tail"])
|
|
83
|
+
flyArgs.push("--no-tail");
|
|
84
|
+
if (args.region)
|
|
85
|
+
flyArgs.push("--region", args.region);
|
|
86
|
+
if (args.machine)
|
|
87
|
+
flyArgs.push("--machine", args.machine);
|
|
88
|
+
const stream = streamCommand(flyArgs);
|
|
89
|
+
out.blank();
|
|
90
|
+
out.text(logTable.header());
|
|
91
|
+
out.text(logTable.separator());
|
|
92
|
+
// fly logs --json emits pretty-printed multi-line JSON objects.
|
|
93
|
+
// Accumulate lines and parse when brace depth returns to zero.
|
|
94
|
+
let buf = [];
|
|
95
|
+
let depth = 0;
|
|
96
|
+
for await (const line of stream.lines) {
|
|
97
|
+
const trimmed = line.trim();
|
|
98
|
+
if (!trimmed)
|
|
99
|
+
continue;
|
|
100
|
+
for (const ch of trimmed) {
|
|
101
|
+
if (ch === "{")
|
|
102
|
+
depth++;
|
|
103
|
+
else if (ch === "}")
|
|
104
|
+
depth--;
|
|
105
|
+
}
|
|
106
|
+
buf.push(trimmed);
|
|
107
|
+
if (depth === 0 && buf.length > 0) {
|
|
108
|
+
const block = buf.join("");
|
|
109
|
+
buf = [];
|
|
110
|
+
try {
|
|
111
|
+
const entry = JSON.parse(block);
|
|
112
|
+
if (out.isJson()) {
|
|
113
|
+
console.log(JSON.stringify(entry));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
out.text(logTable.row([
|
|
117
|
+
formatTimestamp(entry.timestamp ?? ""),
|
|
118
|
+
entry.region ?? "",
|
|
119
|
+
entry.level ?? "",
|
|
120
|
+
entry.message ?? "",
|
|
121
|
+
]));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
out.dim(` ${block}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const result = await stream.done;
|
|
130
|
+
if (!result.ok && result.stderr) {
|
|
131
|
+
out.err(result.stderr.trim());
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
// =============================================================================
|
|
135
|
+
// Register Command
|
|
136
|
+
// =============================================================================
|
|
137
|
+
registerCommand({
|
|
138
|
+
name: "logs",
|
|
139
|
+
description: "Stream logs for a workload app",
|
|
140
|
+
usage: "ambit logs <app>.<network> [--region <r>] [--no-tail] [--json]",
|
|
141
|
+
run: logs,
|
|
142
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/secrets.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Secrets Command - Manage Secrets for Workload 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 { Table } from "../../deps/jsr.io/@cliffy/table/1.0.0/mod.js";
|
|
7
|
+
import { bold } from "../../lib/cli.js";
|
|
8
|
+
import { checkArgs } from "../../lib/args.js";
|
|
9
|
+
import { createOutput } from "../../lib/output.js";
|
|
10
|
+
import { registerCommand } from "../mod.js";
|
|
11
|
+
import { findWorkloadApp } from "../../util/discovery.js";
|
|
12
|
+
import { initSession } from "../../util/session.js";
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Shared Helpers
|
|
15
|
+
// =============================================================================
|
|
16
|
+
const resolveAppTarget = (out, appArg, command) => {
|
|
17
|
+
if (!appArg || typeof appArg !== "string") {
|
|
18
|
+
return out.die(`Missing App Name. Usage: ${command} <app>.<network>`);
|
|
19
|
+
}
|
|
20
|
+
if (!appArg.includes(".")) {
|
|
21
|
+
return out.die(`Missing Network. Use: ${command} ${appArg}.<network>`);
|
|
22
|
+
}
|
|
23
|
+
const parts = appArg.split(".");
|
|
24
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
25
|
+
return out.die(`'${appArg}' Should Have Exactly One Dot, Like my-app.my-network`);
|
|
26
|
+
}
|
|
27
|
+
return { app: parts[0], network: parts[1] };
|
|
28
|
+
};
|
|
29
|
+
const resolveFlyAppName = async (out, fly, org, app, network) => {
|
|
30
|
+
const workload = await findWorkloadApp(fly, org, app, network);
|
|
31
|
+
if (!workload) {
|
|
32
|
+
return out.die(`App '${app}' Not Found on Network '${network}'`);
|
|
33
|
+
}
|
|
34
|
+
return workload.appName;
|
|
35
|
+
};
|
|
36
|
+
// =============================================================================
|
|
37
|
+
// Secrets List
|
|
38
|
+
// =============================================================================
|
|
39
|
+
const secretsList = async (argv) => {
|
|
40
|
+
const opts = { string: ["org"], boolean: ["help", "json"] };
|
|
41
|
+
const args = parseArgs(argv, opts);
|
|
42
|
+
checkArgs(args, opts, "ambit secrets list", 1);
|
|
43
|
+
if (args.help) {
|
|
44
|
+
console.log(`
|
|
45
|
+
${bold("ambit secrets list")} - List Secrets for an App
|
|
46
|
+
|
|
47
|
+
${bold("USAGE")}
|
|
48
|
+
ambit secrets list <app>.<network> [--org <org>] [--json]
|
|
49
|
+
|
|
50
|
+
${bold("OPTIONS")}
|
|
51
|
+
--org <org> Fly.io organization slug
|
|
52
|
+
--json Output as JSON
|
|
53
|
+
|
|
54
|
+
${bold("EXAMPLES")}
|
|
55
|
+
ambit secrets list my-app.browsers
|
|
56
|
+
ambit secrets list my-app.browsers --json
|
|
57
|
+
`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const out = createOutput(args.json);
|
|
61
|
+
const { app, network } = resolveAppTarget(out, args._[0], "ambit secrets list");
|
|
62
|
+
const { fly, org } = await initSession(out, {
|
|
63
|
+
json: args.json,
|
|
64
|
+
org: args.org,
|
|
65
|
+
});
|
|
66
|
+
const flyAppName = await resolveFlyAppName(out, fly, org, app, network);
|
|
67
|
+
const secrets = await fly.secrets.list(flyAppName);
|
|
68
|
+
if (secrets.length === 0) {
|
|
69
|
+
out.blank()
|
|
70
|
+
.text(`No Secrets Found for ${app}.${network}.`)
|
|
71
|
+
.blank();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
out.blank().header(`Secrets for ${app}.${network}`).blank();
|
|
75
|
+
const table = new Table()
|
|
76
|
+
.header(["Name", "Digest"])
|
|
77
|
+
.body(secrets.map((s) => [s.name, s.digest]))
|
|
78
|
+
.indent(2)
|
|
79
|
+
.padding(2);
|
|
80
|
+
out.text(table.toString());
|
|
81
|
+
out.blank();
|
|
82
|
+
}
|
|
83
|
+
out.done({ app, network, flyAppName, secrets });
|
|
84
|
+
out.print();
|
|
85
|
+
};
|
|
86
|
+
// =============================================================================
|
|
87
|
+
// Secrets Set
|
|
88
|
+
// =============================================================================
|
|
89
|
+
const secretsSet = async (argv) => {
|
|
90
|
+
const opts = {
|
|
91
|
+
string: ["org", "env"],
|
|
92
|
+
boolean: ["help", "json", "stage"],
|
|
93
|
+
};
|
|
94
|
+
const args = parseArgs(argv, opts);
|
|
95
|
+
checkArgs(args, opts, "ambit secrets set", Infinity);
|
|
96
|
+
if (args.help) {
|
|
97
|
+
console.log(`
|
|
98
|
+
${bold("ambit secrets set")} - Set Secrets for an App
|
|
99
|
+
|
|
100
|
+
${bold("USAGE")}
|
|
101
|
+
ambit secrets set <app>.<network> KEY=VALUE ... [--org <org>] [--stage] [--json]
|
|
102
|
+
ambit secrets set <app>.<network> --env <file> [--org <org>] [--stage] [--json]
|
|
103
|
+
|
|
104
|
+
${bold("OPTIONS")}
|
|
105
|
+
--env <file> Load secrets from an env file (KEY=VALUE per line)
|
|
106
|
+
--org <org> Fly.io organization slug
|
|
107
|
+
--stage Stage secrets without deploying
|
|
108
|
+
--json Output as JSON
|
|
109
|
+
|
|
110
|
+
${bold("EXAMPLES")}
|
|
111
|
+
ambit secrets set my-app.browsers API_KEY=abc123
|
|
112
|
+
ambit secrets set my-app.browsers KEY1=val1 KEY2=val2 --stage
|
|
113
|
+
ambit secrets set my-app.browsers --env .env
|
|
114
|
+
`);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const out = createOutput(args.json);
|
|
118
|
+
const { app, network } = resolveAppTarget(out, args._[0], "ambit secrets set");
|
|
119
|
+
const secretsObj = {};
|
|
120
|
+
// Load from env file if provided
|
|
121
|
+
if (args.env) {
|
|
122
|
+
let content;
|
|
123
|
+
try {
|
|
124
|
+
content = await dntShim.Deno.readTextFile(args.env);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return out.die(`Failed to Read Env File: ${args.env}`);
|
|
128
|
+
}
|
|
129
|
+
for (const line of content.split("\n")) {
|
|
130
|
+
const trimmed = line.trim();
|
|
131
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
132
|
+
continue;
|
|
133
|
+
const eq = trimmed.indexOf("=");
|
|
134
|
+
if (eq === -1)
|
|
135
|
+
continue;
|
|
136
|
+
secretsObj[trimmed.slice(0, eq)] = trimmed.slice(eq + 1);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Load from positional KEY=VALUE args
|
|
140
|
+
const pairs = args._.slice(1).map(String);
|
|
141
|
+
for (const pair of pairs) {
|
|
142
|
+
const eq = pair.indexOf("=");
|
|
143
|
+
if (eq === -1) {
|
|
144
|
+
return out.die(`Invalid Format: '${pair}'. Expected KEY=VALUE`);
|
|
145
|
+
}
|
|
146
|
+
secretsObj[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
147
|
+
}
|
|
148
|
+
if (Object.keys(secretsObj).length === 0) {
|
|
149
|
+
return out.die("No Secrets Provided. Use KEY=VALUE args or --env <file>");
|
|
150
|
+
}
|
|
151
|
+
const { fly, org } = await initSession(out, {
|
|
152
|
+
json: args.json,
|
|
153
|
+
org: args.org,
|
|
154
|
+
});
|
|
155
|
+
const flyAppName = await resolveFlyAppName(out, fly, org, app, network);
|
|
156
|
+
await out.spin(args.stage ? "Staging Secrets" : "Setting Secrets", () => fly.secrets.set(flyAppName, secretsObj, { stage: args.stage }));
|
|
157
|
+
out.done({ app, network, flyAppName });
|
|
158
|
+
out.print();
|
|
159
|
+
};
|
|
160
|
+
// =============================================================================
|
|
161
|
+
// Secrets Unset
|
|
162
|
+
// =============================================================================
|
|
163
|
+
const secretsUnset = async (argv) => {
|
|
164
|
+
const opts = {
|
|
165
|
+
string: ["org"],
|
|
166
|
+
boolean: ["help", "json", "stage"],
|
|
167
|
+
};
|
|
168
|
+
const args = parseArgs(argv, opts);
|
|
169
|
+
checkArgs(args, opts, "ambit secrets unset", Infinity);
|
|
170
|
+
if (args.help) {
|
|
171
|
+
console.log(`
|
|
172
|
+
${bold("ambit secrets unset")} - Remove Secrets from an App
|
|
173
|
+
|
|
174
|
+
${bold("USAGE")}
|
|
175
|
+
ambit secrets unset <app>.<network> KEY ... [--org <org>] [--stage] [--json]
|
|
176
|
+
|
|
177
|
+
${bold("OPTIONS")}
|
|
178
|
+
--org <org> Fly.io organization slug
|
|
179
|
+
--stage Stage removal without deploying
|
|
180
|
+
--json Output as JSON
|
|
181
|
+
|
|
182
|
+
${bold("EXAMPLES")}
|
|
183
|
+
ambit secrets unset my-app.browsers API_KEY
|
|
184
|
+
ambit secrets unset my-app.browsers KEY1 KEY2 --stage
|
|
185
|
+
`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const out = createOutput(args.json);
|
|
189
|
+
const { app, network } = resolveAppTarget(out, args._[0], "ambit secrets unset");
|
|
190
|
+
const keys = args._.slice(1).map(String);
|
|
191
|
+
if (keys.length === 0) {
|
|
192
|
+
return out.die("No Secret Names Provided. Usage: ambit secrets unset <app>.<network> KEY ...");
|
|
193
|
+
}
|
|
194
|
+
const { fly, org } = await initSession(out, {
|
|
195
|
+
json: args.json,
|
|
196
|
+
org: args.org,
|
|
197
|
+
});
|
|
198
|
+
const flyAppName = await resolveFlyAppName(out, fly, org, app, network);
|
|
199
|
+
await out.spin(args.stage ? "Staging Secrets Removal" : "Removing Secrets", () => fly.secrets.unset(flyAppName, keys, { stage: args.stage }));
|
|
200
|
+
out.done({ app, network, flyAppName });
|
|
201
|
+
out.print();
|
|
202
|
+
};
|
|
203
|
+
// =============================================================================
|
|
204
|
+
// Secrets Deploy
|
|
205
|
+
// =============================================================================
|
|
206
|
+
const secretsDeploy = async (argv) => {
|
|
207
|
+
const opts = { string: ["org"], boolean: ["help", "json"] };
|
|
208
|
+
const args = parseArgs(argv, opts);
|
|
209
|
+
checkArgs(args, opts, "ambit secrets deploy", 1);
|
|
210
|
+
if (args.help) {
|
|
211
|
+
console.log(`
|
|
212
|
+
${bold("ambit secrets deploy")} - Deploy Staged Secrets
|
|
213
|
+
|
|
214
|
+
${bold("USAGE")}
|
|
215
|
+
ambit secrets deploy <app>.<network> [--org <org>] [--json]
|
|
216
|
+
|
|
217
|
+
${bold("OPTIONS")}
|
|
218
|
+
--org <org> Fly.io organization slug
|
|
219
|
+
--json Output as JSON
|
|
220
|
+
|
|
221
|
+
${bold("EXAMPLES")}
|
|
222
|
+
ambit secrets deploy my-app.browsers
|
|
223
|
+
`);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const out = createOutput(args.json);
|
|
227
|
+
const { app, network } = resolveAppTarget(out, args._[0], "ambit secrets deploy");
|
|
228
|
+
const { fly, org } = await initSession(out, {
|
|
229
|
+
json: args.json,
|
|
230
|
+
org: args.org,
|
|
231
|
+
});
|
|
232
|
+
const flyAppName = await resolveFlyAppName(out, fly, org, app, network);
|
|
233
|
+
await out.spin("Deploying Secrets", () => fly.secrets.deploy(flyAppName));
|
|
234
|
+
out.done({ app, network, flyAppName });
|
|
235
|
+
out.print();
|
|
236
|
+
};
|
|
237
|
+
// =============================================================================
|
|
238
|
+
// Top-Level Help
|
|
239
|
+
// =============================================================================
|
|
240
|
+
const showSecretsHelp = () => {
|
|
241
|
+
console.log(`
|
|
242
|
+
${bold("ambit secrets")} - Manage Secrets for Workload Apps
|
|
243
|
+
|
|
244
|
+
${bold("USAGE")}
|
|
245
|
+
ambit secrets list <app>.<network> [options]
|
|
246
|
+
ambit secrets set <app>.<network> KEY=VALUE ... [options]
|
|
247
|
+
ambit secrets unset <app>.<network> KEY ... [options]
|
|
248
|
+
ambit secrets deploy <app>.<network> [options]
|
|
249
|
+
|
|
250
|
+
${bold("SUBCOMMANDS")}
|
|
251
|
+
list List secret names and digests
|
|
252
|
+
set Set one or more secrets
|
|
253
|
+
unset Remove one or more secrets
|
|
254
|
+
deploy Deploy staged secrets
|
|
255
|
+
|
|
256
|
+
${bold("OPTIONS")}
|
|
257
|
+
--org <org> Fly.io organization slug
|
|
258
|
+
--stage Stage changes without deploying (set/unset only)
|
|
259
|
+
--json Output as JSON
|
|
260
|
+
|
|
261
|
+
${bold("EXAMPLES")}
|
|
262
|
+
ambit secrets list my-app.browsers
|
|
263
|
+
ambit secrets set my-app.browsers API_KEY=abc123
|
|
264
|
+
ambit secrets unset my-app.browsers API_KEY
|
|
265
|
+
ambit secrets deploy my-app.browsers
|
|
266
|
+
|
|
267
|
+
Run 'ambit secrets <subcommand> --help' for details.
|
|
268
|
+
`);
|
|
269
|
+
};
|
|
270
|
+
// =============================================================================
|
|
271
|
+
// Dispatcher
|
|
272
|
+
// =============================================================================
|
|
273
|
+
const secrets = async (argv) => {
|
|
274
|
+
const subcommand = typeof argv[0] === "string" ? argv[0] : undefined;
|
|
275
|
+
if (subcommand === "list" || subcommand === "ls") {
|
|
276
|
+
return secretsList(argv.slice(1));
|
|
277
|
+
}
|
|
278
|
+
if (subcommand === "set")
|
|
279
|
+
return secretsSet(argv.slice(1));
|
|
280
|
+
if (subcommand === "unset")
|
|
281
|
+
return secretsUnset(argv.slice(1));
|
|
282
|
+
if (subcommand === "deploy")
|
|
283
|
+
return secretsDeploy(argv.slice(1));
|
|
284
|
+
const opts = { boolean: ["help"] };
|
|
285
|
+
const args = parseArgs(argv, opts);
|
|
286
|
+
checkArgs(args, opts, "ambit secrets", 0);
|
|
287
|
+
if (args.help) {
|
|
288
|
+
showSecretsHelp();
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
showSecretsHelp();
|
|
292
|
+
dntShim.Deno.exit(1);
|
|
293
|
+
};
|
|
294
|
+
// =============================================================================
|
|
295
|
+
// Register Command
|
|
296
|
+
// =============================================================================
|
|
297
|
+
registerCommand({
|
|
298
|
+
name: "secrets",
|
|
299
|
+
description: "Manage secrets for workload apps",
|
|
300
|
+
usage: "ambit secrets list|set|unset|deploy <app>.<network> [options]",
|
|
301
|
+
run: secrets,
|
|
302
|
+
});
|
|
@@ -168,7 +168,7 @@ const share = async (argv) => {
|
|
|
168
168
|
boolean: ["help", "json"],
|
|
169
169
|
};
|
|
170
170
|
const args = parseArgs(argv, opts);
|
|
171
|
-
checkArgs(args, opts, "ambit share");
|
|
171
|
+
checkArgs(args, opts, "ambit share", Infinity);
|
|
172
172
|
if (args.help) {
|
|
173
173
|
console.log(`
|
|
174
174
|
${bold("ambit share")} - Grant Members Access to a Network
|
|
@@ -100,7 +100,7 @@ export const statusApp = async (argv) => {
|
|
|
100
100
|
boolean: ["help", "json"],
|
|
101
101
|
};
|
|
102
102
|
const args = parseArgs(argv, opts);
|
|
103
|
-
checkArgs(args, opts, "ambit status app");
|
|
103
|
+
checkArgs(args, opts, "ambit status app", 1);
|
|
104
104
|
if (args.help) {
|
|
105
105
|
console.log(`
|
|
106
106
|
${bold("ambit status app")} - Show App Status
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// =============================================================================
|
|
4
4
|
import { parseArgs } from "../../../deps/jsr.io/@std/cli/1.0.28/mod.js";
|
|
5
5
|
import { bold } from "../../../lib/cli.js";
|
|
6
|
+
import { checkArgs } from "../../../lib/args.js";
|
|
6
7
|
import { registerCommand } from "../../mod.js";
|
|
7
8
|
import { statusNetworks } from "./networks.js";
|
|
8
9
|
import { statusNetwork } from "./network.js";
|
|
@@ -50,7 +51,9 @@ const status = async (argv) => {
|
|
|
50
51
|
return statusNetwork(argv.slice(1));
|
|
51
52
|
if (subcommand === "app")
|
|
52
53
|
return statusApp(argv.slice(1));
|
|
53
|
-
const
|
|
54
|
+
const opts = { string: ["org"], boolean: ["help", "json"] };
|
|
55
|
+
const args = parseArgs(argv, opts);
|
|
56
|
+
checkArgs(args, opts, "ambit status", 0);
|
|
54
57
|
if (args.help) {
|
|
55
58
|
showStatusHelp();
|
|
56
59
|
return;
|
|
@@ -73,7 +73,7 @@ const stageNetworkStatus = async (fly, tailscale, network, org, json) => {
|
|
|
73
73
|
export const statusNetwork = async (argv) => {
|
|
74
74
|
const opts = { string: ["org"], boolean: ["help", "json"] };
|
|
75
75
|
const args = parseArgs(argv, opts);
|
|
76
|
-
checkArgs(args, opts, "ambit status network");
|
|
76
|
+
checkArgs(args, opts, "ambit status network", 1);
|
|
77
77
|
if (args.help) {
|
|
78
78
|
console.log(`
|
|
79
79
|
${bold("ambit status network")} - Show Detailed Status for a Network
|
|
@@ -14,7 +14,7 @@ import { initSession } from "../../../util/session.js";
|
|
|
14
14
|
export const statusNetworks = async (argv) => {
|
|
15
15
|
const opts = { string: ["org"], boolean: ["help", "json"] };
|
|
16
16
|
const args = parseArgs(argv, opts);
|
|
17
|
-
checkArgs(args, opts, "ambit status networks");
|
|
17
|
+
checkArgs(args, opts, "ambit status networks", 0);
|
|
18
18
|
if (args.help) {
|
|
19
19
|
console.log(`
|
|
20
20
|
${bold("ambit status networks")} - Show Status of All Networks
|
package/esm/cli/mod.d.ts.map
CHANGED
|
@@ -1 +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,
|
|
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,IAiC3B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAE9B,CAAC;AAMF,eAAO,MAAM,MAAM,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAuCzD,CAAC"}
|
package/esm/cli/mod.js
CHANGED
|
@@ -35,6 +35,8 @@ ${bold("COMMANDS")}
|
|
|
35
35
|
share Grant a Tailscale group access to a network via ACL rules
|
|
36
36
|
list List all discovered routers across networks
|
|
37
37
|
status Show router status, network, and tailnet info
|
|
38
|
+
secrets Manage secrets for workload apps
|
|
39
|
+
logs Stream logs for a workload app
|
|
38
40
|
destroy Destroy a network (router) or a workload app
|
|
39
41
|
doctor Check that Tailscale and the router are working correctly
|
|
40
42
|
|
package/esm/deno.js
CHANGED
package/esm/lib/args.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Validates parsed args against the declared options spec.
|
|
3
|
-
* Dies with a Title Case error if unknown flags
|
|
4
|
-
* Pass the same options object you gave to parseArgs.
|
|
3
|
+
* Dies with a Title Case error if unknown flags or unexpected positional
|
|
4
|
+
* arguments are found. Pass the same options object you gave to parseArgs.
|
|
5
|
+
*
|
|
6
|
+
* `maxPositional` (default 0) limits how many bare positional args are
|
|
7
|
+
* allowed. Set it to the number the command actually expects.
|
|
5
8
|
*/
|
|
6
9
|
export declare const checkArgs: (args: Record<string, unknown>, opts: {
|
|
7
10
|
string?: readonly string[] | string[];
|
|
8
11
|
boolean?: readonly string[] | string[];
|
|
9
12
|
alias?: Record<string, string | string[]>;
|
|
10
|
-
}, command: string) => void;
|
|
13
|
+
}, command: string, maxPositional?: number) => void;
|
|
11
14
|
//# sourceMappingURL=args.d.ts.map
|
package/esm/lib/args.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/lib/args.ts"],"names":[],"mappings":"AAMA
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/lib/args.ts"],"names":[],"mappings":"AAMA;;;;;;;GAOG;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,EACf,sBAAiB,KAChB,IA4BF,CAAC"}
|
package/esm/lib/args.js
CHANGED
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
import { createOutput } from "./output.js";
|
|
5
5
|
/**
|
|
6
6
|
* Validates parsed args against the declared options spec.
|
|
7
|
-
* Dies with a Title Case error if unknown flags
|
|
8
|
-
* Pass the same options object you gave to parseArgs.
|
|
7
|
+
* Dies with a Title Case error if unknown flags or unexpected positional
|
|
8
|
+
* arguments are found. Pass the same options object you gave to parseArgs.
|
|
9
|
+
*
|
|
10
|
+
* `maxPositional` (default 0) limits how many bare positional args are
|
|
11
|
+
* allowed. Set it to the number the command actually expects.
|
|
9
12
|
*/
|
|
10
|
-
export const checkArgs = (args, opts, command) => {
|
|
13
|
+
export const checkArgs = (args, opts, command, maxPositional = 0) => {
|
|
11
14
|
const known = new Set(["_"]);
|
|
12
15
|
for (const k of opts.string ?? [])
|
|
13
16
|
known.add(k);
|
|
@@ -25,4 +28,10 @@ export const checkArgs = (args, opts, command) => {
|
|
|
25
28
|
const out = createOutput(!!args.json);
|
|
26
29
|
out.die(`Unknown Flag(s): ${bad.join(", ")}. Run '${command} --help' for Usage.`);
|
|
27
30
|
}
|
|
31
|
+
const positional = Array.isArray(args._) ? args._ : [];
|
|
32
|
+
if (positional.length > maxPositional) {
|
|
33
|
+
const extra = positional.slice(maxPositional).join(", ");
|
|
34
|
+
const out = createOutput(!!args.json);
|
|
35
|
+
out.die(`Unexpected Argument(s): ${extra}. Run '${command} --help' for Usage.`);
|
|
36
|
+
}
|
|
28
37
|
};
|
package/esm/lib/command.d.ts
CHANGED
|
@@ -23,4 +23,13 @@ export declare class CmdResult {
|
|
|
23
23
|
export declare const runCommand: (args: string[], options?: RunOptions) => Promise<CmdResult>;
|
|
24
24
|
/** Run and parse stdout as JSON. */
|
|
25
25
|
export declare const runJson: <T>(args: string[], options?: RunOptions) => Promise<Result<T>>;
|
|
26
|
+
export interface StreamHandle {
|
|
27
|
+
lines: AsyncIterable<string>;
|
|
28
|
+
done: Promise<CmdResult>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Spawn a command and stream stdout line-by-line via an async iterable.
|
|
32
|
+
* Use `done` to check the exit code after the stream ends.
|
|
33
|
+
*/
|
|
34
|
+
export declare const streamCommand: (args: string[], options?: Omit<RunOptions, "interactive">) => StreamHandle;
|
|
26
35
|
//# sourceMappingURL=command.d.ts.map
|
package/esm/lib/command.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/lib/command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/lib/command.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAMrC,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC5B;AAMD,qBAAa,SAAS;IAIlB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM;IALzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;gBAGV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM;IAKzB,iDAAiD;IACjD,IAAI,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC;IAapB,8BAA8B;IAC9B,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF;AAMD;;;GAGG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EAAE,EACd,UAAU,UAAU,KACnB,OAAO,CAAC,SAAS,CAyCnB,CAAC;AAMF,oCAAoC;AACpC,eAAO,MAAM,OAAO,GAAI,CAAC,EACvB,MAAM,MAAM,EAAE,EACd,UAAU,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAuD,CAAC;AAM5E,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CAC1B;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,MAAM,MAAM,EAAE,EACd,UAAU,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,KACxC,YA+BF,CAAC"}
|
package/esm/lib/command.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Shell Command Helpers
|
|
3
3
|
// =============================================================================
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
|
+
import { createInterface } from "node:readline";
|
|
6
|
+
import process from "node:process";
|
|
5
7
|
import { Result } from "./result.js";
|
|
6
8
|
// =============================================================================
|
|
7
9
|
// Command Result
|
|
@@ -82,3 +84,33 @@ export const runCommand = (args, options) => {
|
|
|
82
84
|
// =============================================================================
|
|
83
85
|
/** Run and parse stdout as JSON. */
|
|
84
86
|
export const runJson = (args, options) => runCommand(args, options).then((r) => r.json());
|
|
87
|
+
/**
|
|
88
|
+
* Spawn a command and stream stdout line-by-line via an async iterable.
|
|
89
|
+
* Use `done` to check the exit code after the stream ends.
|
|
90
|
+
*/
|
|
91
|
+
export const streamCommand = (args, options) => {
|
|
92
|
+
const [cmd, ...cmdArgs] = args;
|
|
93
|
+
const child = spawn(cmd, cmdArgs, {
|
|
94
|
+
cwd: options?.cwd,
|
|
95
|
+
env: options?.env ? { ...process.env, ...options.env } : undefined,
|
|
96
|
+
stdio: [
|
|
97
|
+
options?.stdin === "inherit" ? "inherit" : "ignore",
|
|
98
|
+
"pipe",
|
|
99
|
+
"pipe",
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
child.stdout.setEncoding("utf8");
|
|
103
|
+
child.stderr.setEncoding("utf8");
|
|
104
|
+
const rl = createInterface({ input: child.stdout });
|
|
105
|
+
const stderr = [];
|
|
106
|
+
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
107
|
+
const done = new Promise((resolve) => {
|
|
108
|
+
child.on("error", (error) => {
|
|
109
|
+
resolve(new CmdResult(-1, "", error.message));
|
|
110
|
+
});
|
|
111
|
+
child.on("close", (code) => {
|
|
112
|
+
resolve(new CmdResult(code ?? 1, "", stderr.join("")));
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
return { lines: rl, done };
|
|
116
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface Column {
|
|
2
|
+
name: string;
|
|
3
|
+
width: number;
|
|
4
|
+
}
|
|
5
|
+
export interface StreamTableOptions {
|
|
6
|
+
indent?: number;
|
|
7
|
+
padding?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class StreamTable {
|
|
10
|
+
private columns;
|
|
11
|
+
private indent;
|
|
12
|
+
private padding;
|
|
13
|
+
constructor(columns: Column[], opts?: StreamTableOptions);
|
|
14
|
+
/** Render the header row (bold column names). */
|
|
15
|
+
header(): string;
|
|
16
|
+
/** Render a separator line under the header. */
|
|
17
|
+
separator(): string;
|
|
18
|
+
/** Render a single data row. */
|
|
19
|
+
row(values: string[]): string;
|
|
20
|
+
private effectiveWidth;
|
|
21
|
+
private pad;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/lib/table.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,kBAAkB;IAMxD,iDAAiD;IACjD,MAAM,IAAI,MAAM;IAMhB,gDAAgD;IAChD,SAAS,IAAI,MAAM;IAWnB,gCAAgC;IAChC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM;IAU7B,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,GAAG;CAMZ"}
|
package/esm/lib/table.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// StreamTable - Fixed-Width Column Formatter for Streaming Output
|
|
3
|
+
// =============================================================================
|
|
4
|
+
//
|
|
5
|
+
// Unlike @cliffy/table which needs all rows upfront to calculate widths,
|
|
6
|
+
// StreamTable uses fixed column widths so rows can be rendered one at a time.
|
|
7
|
+
// Each method returns a string — pass it to out.text() for JSON mode guard.
|
|
8
|
+
//
|
|
9
|
+
// =============================================================================
|
|
10
|
+
import { bold, dim } from "./cli.js";
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// StreamTable
|
|
13
|
+
// =============================================================================
|
|
14
|
+
export class StreamTable {
|
|
15
|
+
columns;
|
|
16
|
+
indent;
|
|
17
|
+
padding;
|
|
18
|
+
constructor(columns, opts) {
|
|
19
|
+
this.columns = columns;
|
|
20
|
+
this.indent = " ".repeat(opts?.indent ?? 2);
|
|
21
|
+
this.padding = " ".repeat(opts?.padding ?? 2);
|
|
22
|
+
}
|
|
23
|
+
/** Render the header row (bold column names). */
|
|
24
|
+
header() {
|
|
25
|
+
return this.indent + this.columns
|
|
26
|
+
.map((col, i) => bold(this.pad(col.name, col.width, i)))
|
|
27
|
+
.join(this.padding);
|
|
28
|
+
}
|
|
29
|
+
/** Render a separator line under the header. */
|
|
30
|
+
separator() {
|
|
31
|
+
return this.indent + dim(this.columns
|
|
32
|
+
.map((col, i) => {
|
|
33
|
+
const w = this.effectiveWidth(col.width, i);
|
|
34
|
+
return w > 0 ? "─".repeat(w) : "─".repeat(col.name.length);
|
|
35
|
+
})
|
|
36
|
+
.join(this.padding));
|
|
37
|
+
}
|
|
38
|
+
/** Render a single data row. */
|
|
39
|
+
row(values) {
|
|
40
|
+
return this.indent + this.columns
|
|
41
|
+
.map((col, i) => this.pad(values[i] ?? "", col.width, i))
|
|
42
|
+
.join(this.padding);
|
|
43
|
+
}
|
|
44
|
+
// ===========================================================================
|
|
45
|
+
// Internal
|
|
46
|
+
// ===========================================================================
|
|
47
|
+
effectiveWidth(width, index) {
|
|
48
|
+
// width=0 on last column means unbounded
|
|
49
|
+
if (width === 0 && index === this.columns.length - 1)
|
|
50
|
+
return 0;
|
|
51
|
+
// width=0 on non-last column falls back to header name length
|
|
52
|
+
if (width === 0)
|
|
53
|
+
return this.columns[index].name.length;
|
|
54
|
+
return width;
|
|
55
|
+
}
|
|
56
|
+
pad(value, width, index) {
|
|
57
|
+
const w = this.effectiveWidth(width, index);
|
|
58
|
+
if (w === 0)
|
|
59
|
+
return value; // unbounded last column
|
|
60
|
+
if (value.length > w)
|
|
61
|
+
return value.slice(0, w - 1) + "…";
|
|
62
|
+
return value.padEnd(w);
|
|
63
|
+
}
|
|
64
|
+
}
|
package/esm/main.d.ts
CHANGED
|
@@ -7,4 +7,6 @@ import "./cli/commands/list/index.js";
|
|
|
7
7
|
import "./cli/commands/status/index.js";
|
|
8
8
|
import "./cli/commands/destroy/index.js";
|
|
9
9
|
import "./cli/commands/doctor.js";
|
|
10
|
+
import "./cli/commands/secrets.js";
|
|
11
|
+
import "./cli/commands/logs.js";
|
|
10
12
|
//# sourceMappingURL=main.d.ts.map
|
package/esm/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,qBAAqB,CAAC;AAoC7B,OAAO,gCAAgC,CAAC;AACxC,OAAO,gCAAgC,CAAC;AACxC,OAAO,yBAAyB,CAAC;AACjC,OAAO,8BAA8B,CAAC;AACtC,OAAO,gCAAgC,CAAC;AACxC,OAAO,iCAAiC,CAAC;AACzC,OAAO,0BAA0B,CAAC;AAClC,OAAO,2BAA2B,CAAC;AACnC,OAAO,wBAAwB,CAAC"}
|
package/esm/main.js
CHANGED
|
@@ -14,6 +14,8 @@ import * as dntShim from "./_dnt.shims.js";
|
|
|
14
14
|
// deploy Deploy an app safely on a custom private network
|
|
15
15
|
// share Grant a group access to a network via Tailscale ACL rules
|
|
16
16
|
// status Show router status, network, and tailnet info
|
|
17
|
+
// secrets Manage secrets for workload apps
|
|
18
|
+
// logs Stream logs for a workload app
|
|
17
19
|
// destroy Destroy a network (router) or a workload app
|
|
18
20
|
// doctor Check that Tailscale and the router are working correctly
|
|
19
21
|
//
|
|
@@ -37,6 +39,8 @@ import "./cli/commands/list/index.js";
|
|
|
37
39
|
import "./cli/commands/status/index.js";
|
|
38
40
|
import "./cli/commands/destroy/index.js";
|
|
39
41
|
import "./cli/commands/doctor.js";
|
|
42
|
+
import "./cli/commands/secrets.js";
|
|
43
|
+
import "./cli/commands/logs.js";
|
|
40
44
|
// =============================================================================
|
|
41
45
|
// Main
|
|
42
46
|
// =============================================================================
|
package/esm/providers/fly.d.ts
CHANGED
|
@@ -57,9 +57,17 @@ export interface FlyProvider {
|
|
|
57
57
|
destroy(app: string, machineId: string): Promise<void>;
|
|
58
58
|
};
|
|
59
59
|
secrets: {
|
|
60
|
+
list(app: string): Promise<Array<{
|
|
61
|
+
name: string;
|
|
62
|
+
digest: string;
|
|
63
|
+
}>>;
|
|
60
64
|
set(app: string, secrets: Record<string, string>, opts?: {
|
|
61
65
|
stage?: boolean;
|
|
62
66
|
}): Promise<void>;
|
|
67
|
+
unset(app: string, keys: string[], opts?: {
|
|
68
|
+
stage?: boolean;
|
|
69
|
+
}): Promise<void>;
|
|
70
|
+
deploy(app: string): Promise<void>;
|
|
63
71
|
};
|
|
64
72
|
ips: {
|
|
65
73
|
list(app: string): Promise<FlyIp[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fly.d.ts","sourceRoot":"","sources":["../../src/providers/fly.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,UAAU,EAIf,KAAK,KAAK,EAEV,KAAK,UAAU,EAIhB,MAAM,mBAAmB,CAAC;AAa3B;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAMxC;AAMD,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,eAAe,GAAG,eAAe,CAAC;AAE9E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAMD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAMD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE;QACJ,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,EAAE;YAAE,WAAW,CAAC,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QACzD,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;KAC7B,CAAC;IACF,IAAI,EAAE;QACJ,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;KACzC,CAAC;IACF,IAAI,EAAE;QACJ,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACtC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QACpD,MAAM,CACJ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,GAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;QACjB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QACvC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;KAClE,CAAC;IACF,QAAQ,EAAE;QACR,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QACzC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACxD,CAAC;IACF,OAAO,EAAE;QACP,GAAG,CACD,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,OAAO,CAAA;SAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"fly.d.ts","sourceRoot":"","sources":["../../src/providers/fly.ts"],"names":[],"mappings":"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"}
|
package/esm/providers/fly.js
CHANGED
|
@@ -246,6 +246,10 @@ export const createFlyProvider = () => {
|
|
|
246
246
|
},
|
|
247
247
|
},
|
|
248
248
|
secrets: {
|
|
249
|
+
async list(app) {
|
|
250
|
+
const result = await runJson(["fly", "secrets", "list", "-a", app, "--json"]);
|
|
251
|
+
return result.unwrapOr([]);
|
|
252
|
+
},
|
|
249
253
|
async set(app, secrets, opts) {
|
|
250
254
|
const pairs = Object.entries(secrets)
|
|
251
255
|
.filter(([_, v]) => v !== undefined && v !== "")
|
|
@@ -261,6 +265,30 @@ export const createFlyProvider = () => {
|
|
|
261
265
|
return die("Failed to Set Secrets");
|
|
262
266
|
}
|
|
263
267
|
},
|
|
268
|
+
async unset(app, keys, opts) {
|
|
269
|
+
if (keys.length === 0)
|
|
270
|
+
return;
|
|
271
|
+
const args = ["fly", "secrets", "unset", ...keys, "-a", app];
|
|
272
|
+
if (opts?.stage) {
|
|
273
|
+
args.push("--stage");
|
|
274
|
+
}
|
|
275
|
+
const result = await runCommand(args);
|
|
276
|
+
if (!result.ok) {
|
|
277
|
+
return die("Failed to Unset Secrets");
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
async deploy(app) {
|
|
281
|
+
const result = await runCommand([
|
|
282
|
+
"fly",
|
|
283
|
+
"secrets",
|
|
284
|
+
"deploy",
|
|
285
|
+
"-a",
|
|
286
|
+
app,
|
|
287
|
+
]);
|
|
288
|
+
if (!result.ok) {
|
|
289
|
+
return die("Failed to Deploy Secrets");
|
|
290
|
+
}
|
|
291
|
+
},
|
|
264
292
|
},
|
|
265
293
|
ips: {
|
|
266
294
|
async list(app) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { FlyMachine } from "../schemas/fly.js";
|
|
2
|
-
import { type FlyMachineGuestSchema } from "../schemas/fly.js";
|
|
1
|
+
import type { FlyMachine, FlyMachineGuestSchema } from "../schemas/fly.js";
|
|
3
2
|
import type { z } from "../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
|
|
4
3
|
/**
|
|
5
4
|
* Map Fly machine state to internal state.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fly-transforms.d.ts","sourceRoot":"","sources":["../../src/util/fly-transforms.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"fly-transforms.d.ts","sourceRoot":"","sources":["../../src/util/fly-transforms.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/util/resolve.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMvD;;GAEG;AACH,eAAO,MAAM,UAAU,GACrB,KAAK,WAAW,EAChB,MAAM;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/util/resolve.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMvD;;GAEG;AACH,eAAO,MAAM,UAAU,GACrB,KAAK,WAAW,EAChB,MAAM;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,EAEtC,KAAK,MAAM,CAAC,GAAG,CAAC,KACf,OAAO,CAAC,MAAM,CA6BhB,CAAC"}
|
package/esm/util/resolve.js
CHANGED
|
@@ -8,7 +8,9 @@ import { prompt } from "../lib/cli.js";
|
|
|
8
8
|
/**
|
|
9
9
|
* Resolve Fly.io organization: --org flag → single org auto-select → prompt.
|
|
10
10
|
*/
|
|
11
|
-
export const resolveOrg = async (fly, args,
|
|
11
|
+
export const resolveOrg = async (fly, args,
|
|
12
|
+
// deno-lint-ignore no-explicit-any
|
|
13
|
+
out) => {
|
|
12
14
|
if (args.org)
|
|
13
15
|
return args.org;
|
|
14
16
|
if (args.json) {
|
package/esm/util/template.js
CHANGED
|
@@ -24,7 +24,7 @@ import { Result } from "../lib/result.js";
|
|
|
24
24
|
/** Shorthand for returning a typed fetch error. */
|
|
25
25
|
const fail = (message) => Result.err(message);
|
|
26
26
|
/** Format a template reference for display. */
|
|
27
|
-
const
|
|
27
|
+
const _formatRef = (ref) => {
|
|
28
28
|
const base = ref.path === "."
|
|
29
29
|
? `${ref.owner}/${ref.repo}`
|
|
30
30
|
: `${ref.owner}/${ref.repo}/${ref.path}`;
|