@cardelli/ambit 0.2.1 → 0.2.3

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.
@@ -12,7 +12,7 @@ import { isPublicTld } from "../../../util/guard.js";
12
12
  import { createFlyProvider, } from "../../../providers/fly.js";
13
13
  import { createTailscaleProvider, } from "../../../providers/tailscale.js";
14
14
  import { getCredentialStore } from "../../../util/credentials.js";
15
- import { FLY_PRIVATE_SUBNET, SOCKS_PROXY_PORT, TAILSCALE_API_KEY_PREFIX, } from "../../../util/constants.js";
15
+ import { FLY_PRIVATE_SUBNET, TAILSCALE_API_KEY_PREFIX, } from "../../../util/constants.js";
16
16
  import { resolveOrg } from "../../../util/resolve.js";
17
17
  import { isAutoApproverConfigured, isTagOwnerConfigured } from "../../../util/tailscale-local.js";
18
18
  import { createTransition, hydrateCreate, reportSkipped, } from "./machine.js";
@@ -43,7 +43,7 @@ const stageTailscaleConfig = async (out, opts) => {
43
43
  return out.die("--api-key Is Required in JSON Mode");
44
44
  }
45
45
  out.dim("Ambit Needs an API Access Token (Not an Auth Key) to Manage Your Tailnet.")
46
- .dim("Create One at: https://login.tailscale.com/admin/settings/keys")
46
+ .dim("Create One at:").link(" https://login.tailscale.com/admin/settings/keys")
47
47
  .blank();
48
48
  apiKey = await readSecret("API access token (tskey-api-...): ");
49
49
  if (!apiKey) {
@@ -66,35 +66,38 @@ const stageTailscaleConfig = async (out, opts) => {
66
66
  const policy = await tailscale.acl.getPolicy();
67
67
  const hasTagOwner = isTagOwnerConfigured(policy, opts.tag);
68
68
  if (!hasTagOwner) {
69
- tagOwnerSpinner.fail(`Tag ${opts.tag} Not Configured in tagOwners`);
69
+ tagOwnerSpinner.fail(`${opts.tag} Not Set Up Yet`);
70
70
  out.blank()
71
- .text(` The Tag ${opts.tag} Does Not Exist in Your Tailscale ACL tagOwners.`)
72
- .text(" Tailscale Will Reject Auth Keys for Undefined Tags.")
71
+ .text(` You need to grant yourself permission to create the "${opts.network}"`)
72
+ .text(` network by setting up ${opts.tag} in Tailscale.`)
73
73
  .blank()
74
- .text(" Add This Tag in Your Tailscale ACL Settings:")
75
- .dim(" https://login.tailscale.com/admin/acls/visual/tags")
74
+ .text(` You can create the tag and assign it to yourself or a group`)
75
+ .text(` you're a part of in the Tailscale dashboard:`)
76
+ .link(" https://login.tailscale.com/admin/acls/visual/tags")
76
77
  .blank()
78
+ .dim(" Or you can do it manually with this JSON config:")
77
79
  .dim(` "tagOwners": { "${opts.tag}": ["autogroup:admin"] }`)
78
80
  .blank();
79
- return out.die(`Add ${opts.tag} to tagOwners Before Creating Router`);
81
+ return out.die(`Set Up ${opts.tag} in Tailscale, Then Try Again`);
80
82
  }
81
- tagOwnerSpinner.success(`Tag ${opts.tag} Configured in tagOwners`);
83
+ tagOwnerSpinner.success(`${opts.tag} Found in Tailscale ACL`);
82
84
  if (opts.json) {
83
85
  const approverSpinner = out.spinner(`Checking autoApprovers for ${opts.tag}`);
84
86
  const hasApprover = isAutoApproverConfigured(policy, opts.tag);
85
87
  if (!hasApprover) {
86
- approverSpinner.fail(`autoApprovers Not Configured for ${opts.tag}`);
88
+ approverSpinner.fail(`Auto-approve Not Configured for ${opts.tag}`);
87
89
  out.blank()
88
- .text(" JSON mode skips interactive route approval.")
89
- .text(` Configure autoApprovers for ${opts.tag} so routes are approved on deploy.`)
90
- .blank()
91
- .dim(" Add to your ACL at: https://login.tailscale.com/admin/acls/file")
90
+ .text(" In JSON mode, ambit can't interactively approve the router's")
91
+ .text(` network connections. You can set this up from the Tailscale dashboard:`)
92
+ .link(" https://login.tailscale.com/admin/acls/visual/auto-approvers")
93
+ .dim(` Route: ${FLY_PRIVATE_SUBNET} Owner: ${opts.tag}`)
92
94
  .blank()
95
+ .dim(" Or you can do it manually with this JSON config:")
93
96
  .dim(` "autoApprovers": { "routes": { "${FLY_PRIVATE_SUBNET}": ["${opts.tag}"] } }`)
94
97
  .blank();
95
- return out.die(`Configure autoApprovers for ${opts.tag} Before Using --json`);
98
+ return out.die(`Set Up Auto-approve for ${opts.tag} to Use --json`);
96
99
  }
97
- approverSpinner.success(`autoApprovers Configured for ${opts.tag}`);
100
+ approverSpinner.success(`Auto-approve Configured for ${opts.tag}`);
98
101
  }
99
102
  out.blank();
100
103
  return tailscale;
@@ -157,52 +160,50 @@ const stageSummary = async (out, fly, tailscale, ctx, opts) => {
157
160
  .header(" Router Created!")
158
161
  .header("=".repeat(50))
159
162
  .blank()
160
- .text(`Any Flycast App on the "${opts.network}" Network Is Reachable as:`)
161
- .text(` <app-name>.${opts.network}`)
162
- .blank();
163
- if (ctx.subnet) {
164
- const machines = await fly.machines.list(ctx.appName);
165
- const routerMachine = machines.find((m) => m.private_ip);
166
- if (routerMachine?.private_ip) {
167
- out.text("SOCKS5 Proxy Available at:")
168
- .text(` socks5://[${routerMachine.private_ip}]:${SOCKS_PROXY_PORT}`)
169
- .dim("Containers on This Network Can Use It to Reach Your Tailnet.")
170
- .blank();
171
- }
172
- }
173
- out.dim("Deploy an App to This Network:")
174
- .dim(` ambit deploy my-app --network ${opts.network}`)
163
+ .text(`The "${opts.network}" Network Is Ready.`)
175
164
  .blank()
176
- .dim("Invite People to Your Tailnet:")
177
- .dim(" https://login.tailscale.com/admin/users")
178
- .dim("Control Their Access:")
179
- .dim(" https://login.tailscale.com/admin/acls/visual/general-access-rules")
165
+ .text(`You Can Deploy Apps to It With:`)
166
+ .text(` npx @cardelli/ambit deploy <app-name>.${opts.network}`)
167
+ .blank();
168
+ out.dim("Invite People to Your Tailnet:")
169
+ .link(" https://login.tailscale.com/admin/users")
180
170
  .blank();
181
- if (ctx.subnet && !hasAutoApprover) {
182
- out.header("Recommended: Configure autoApprovers")
183
- .blank()
184
- .dim(" Add to Your Tailnet Policy File at:")
185
- .dim(" https://login.tailscale.com/admin/acls/file")
186
- .blank()
187
- .text(` "autoApprovers": { "routes": { "${ctx.subnet}": ["${opts.tag}"] } }`)
188
- .blank()
189
- .dim(" Routes Were Approved via API for This Session.")
190
- .dim(" autoApprovers Will Auto-Approve on Future Restarts.")
191
- .blank();
192
- }
193
171
  if (ctx.subnet) {
194
- out.header("Recommended ACL Rules:")
172
+ out.header("Next: Allow Traffic Through the Router")
173
+ .blank()
174
+ .text(" You must configure Tailscale so that traffic can flow from your")
175
+ .text(` devices through the router and into the "${opts.network}" network.`);
176
+ if (!hasAutoApprover) {
177
+ out.blank()
178
+ .text(" 1. Automatically Allow Traffic Through the Router:")
179
+ .dim(" Tailscale needs to trust the router's network connections.")
180
+ .blank()
181
+ .dim(" You can do this from the Tailscale dashboard:")
182
+ .link(" https://login.tailscale.com/admin/acls/visual/auto-approvers")
183
+ .dim(` Route: ${ctx.subnet} Owner: ${opts.tag}`)
184
+ .blank()
185
+ .dim(" Or you can do it manually with this JSON config:")
186
+ .dim(` "autoApprovers": { "routes": { "${ctx.subnet}": ["${opts.tag}"] } }`);
187
+ if (opts.shouldApprove) {
188
+ out.blank().dim(" Traffic Was Allowed via API for This Session.");
189
+ }
190
+ }
191
+ out.blank()
192
+ .text(` ${hasAutoApprover ? "1" : "2"}. Control Who Can Reach Apps on This Network:`)
193
+ .dim(" This lets you restrict which users or devices can access your apps.")
195
194
  .blank()
196
- .dim(" To Restrict Access, Add ACL Rules to Your Policy File:")
197
- .dim(" https://login.tailscale.com/admin/acls/file")
195
+ .dim(" You can do this from the Tailscale dashboard:")
196
+ .link(" https://login.tailscale.com/admin/acls/visual/general-access-rules")
197
+ .dim(` Source: group:YOUR_GROUP Destination: ${opts.tag}:*`)
198
198
  .blank()
199
- .dim(` {"action": "accept", "src": ["group:YOUR_GROUP"], "dst": ["${opts.tag}:53"]}`)
200
- .dim(` {"action": "accept", "src": ["group:YOUR_GROUP"], "dst": ["${ctx.subnet}:*"]}`)
199
+ .dim(" Or you can do it manually with this JSON config:")
200
+ .dim(` {"action": "accept", "src": ["group:YOUR_GROUP"], "dst": ["${opts.tag}:53"]}`)
201
+ .dim(` {"action": "accept", "src": ["group:YOUR_GROUP"], "dst": ["${ctx.subnet}:*"]}`)
201
202
  .blank();
202
203
  }
203
204
  if (!opts.shouldApprove) {
204
205
  out.dim("Route Approval Was Skipped. To Complete Setup:")
205
- .dim(` ambit doctor --network ${opts.network}`)
206
+ .dim(` ambit doctor network ${opts.network}`)
206
207
  .blank();
207
208
  }
208
209
  out.print();
@@ -1 +1 @@
1
- {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/create/machine.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAQhD,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,2BAA2B,CAAC;AASnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAOrE,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,eAAe,GACf,cAAc,GACd,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,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD,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,CA8G7B,CAAC"}
1
+ {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/create/machine.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAQhD,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,2BAA2B,CAAC;AASnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAOrE,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,eAAe,GACf,cAAc,GACd,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,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD,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,CAgH7B,CAAC"}
@@ -83,19 +83,21 @@ export const createTransition = async (phase, ctx) => {
83
83
  [SECRET_ROUTER_ID]: ctx.routerId,
84
84
  }, { stage: true }));
85
85
  const dockerDir = ROUTER_DOCKER_DIR;
86
+ const deploySpinner = ctx.out.spinner("Deploying Router to Fly.io");
86
87
  try {
87
88
  await ctx.fly.deploy.router(ctx.appName, dockerDir, {
88
89
  region: ctx.region,
89
90
  });
90
91
  }
91
92
  catch (e) {
93
+ deploySpinner.fail("Router Deploy Failed");
92
94
  if (e instanceof FlyDeployError) {
93
95
  ctx.out.dim(` ${e.detail}`);
94
96
  return Result.err(e.message);
95
97
  }
96
98
  throw e;
97
99
  }
98
- ctx.out.ok("Router Deployed");
100
+ deploySpinner.success("Router Deployed");
99
101
  const machines = await ctx.fly.machines.list(ctx.appName);
100
102
  const m = machines.find((m) => m.private_ip);
101
103
  if (m?.private_ip)
@@ -1 +1 @@
1
- {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/machine.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,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,CAyG7B,CAAC"}
1
+ {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/machine.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,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,CA2G7B,CAAC"}
@@ -67,11 +67,13 @@ export const deployTransition = async (phase, ctx) => {
67
67
  return Result.ok("deploy");
68
68
  }
69
69
  case "deploy": {
70
- ctx.out.blank().dim("Deploying with --no-public-ips --flycast ...");
70
+ ctx.out.blank();
71
+ const deploySpinner = ctx.out.spinner("Deploying to Fly.io");
71
72
  try {
72
73
  await ctx.fly.deploy.app(ctx.app, ctx.deployOptions);
73
74
  }
74
75
  catch (e) {
76
+ deploySpinner.fail("Deploy Failed");
75
77
  if (e instanceof FlyDeployError) {
76
78
  ctx.out.dim(` ${e.detail}`);
77
79
  return Result.err(e.message);
@@ -88,7 +90,7 @@ export const deployTransition = async (phase, ctx) => {
88
90
  }
89
91
  }
90
92
  }
91
- ctx.out.ok("Deploy Succeeded");
93
+ deploySpinner.success("Deploy Succeeded");
92
94
  return Result.ok("audit");
93
95
  }
94
96
  case "audit": {
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "@cardelli/ambit",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Deploy apps to the cloud that only you and your AI agents can reach",
5
5
  "license": "MIT",
6
6
  "tasks": {
@@ -19,6 +19,7 @@ export declare class Output<T extends Record<string, unknown>> {
19
19
  warn(text: string): this;
20
20
  text(text: string): this;
21
21
  dim(text: string): this;
22
+ link(text: string): this;
22
23
  header(text: string): this;
23
24
  blank(): this;
24
25
  spinner(message: string): {
@@ -1 +1 @@
1
- {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG,CAAC,CAAC;AAChD,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAMvD,qBAAa,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACnD,OAAO,CAAC,MAAM,CAGE;IAChB,OAAO,CAAC,QAAQ,CAAU;gBAEd,QAAQ,EAAE,OAAO;IAS7B,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAMnB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAKzD,KAAK,IAAI,IAAI;IAUb,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKtB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKvB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKvB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK1B,KAAK,IAAI,IAAI;IAKb,OAAO,CACL,OAAO,EAAE,MAAM,GACd;QAAE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,IAAI,IAAI,CAAA;KAAE;IAiBlE,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAgB9D,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK;IAS3B,MAAM,IAAI,OAAO;CAGlB;AAMD,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5D,QAAQ,EAAE,OAAO,GAChB,MAAM,CAAC,CAAC,CAAC,CAEX"}
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAmBA,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG,CAAC,CAAC;AAChD,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAMvD,qBAAa,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACnD,OAAO,CAAC,MAAM,CAGE;IAChB,OAAO,CAAC,QAAQ,CAAU;gBAEd,QAAQ,EAAE,OAAO;IAS7B,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI;IAMnB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAKzD,KAAK,IAAI,IAAI;IAUb,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKtB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKvB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKvB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK1B,KAAK,IAAI,IAAI;IAKb,OAAO,CACL,OAAO,EAAE,MAAM,GACd;QAAE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,IAAI,IAAI,CAAA;KAAE;IAiBlE,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAgB9D,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK;IAS3B,MAAM,IAAI,OAAO;CAGlB;AAMD,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5D,QAAQ,EAAE,OAAO,GAChB,MAAM,CAAC,CAAC,CAAC,CAEX"}
package/esm/lib/output.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // =============================================================================
2
2
  // Output - Unified Output Handling for CLI Commands
3
3
  // =============================================================================
4
- import { bold, dim, Spinner, statusErr, statusInfo, statusOk, statusWarn, } from "./cli.js";
4
+ import { blue, bold, dim, Spinner, statusErr, statusInfo, statusOk, statusWarn, } from "./cli.js";
5
5
  // =============================================================================
6
6
  // Output Class
7
7
  // =============================================================================
@@ -67,6 +67,11 @@ export class Output {
67
67
  console.log(dim(text));
68
68
  return this;
69
69
  }
70
+ link(text) {
71
+ if (!this.jsonMode)
72
+ console.log(blue(text));
73
+ return this;
74
+ }
70
75
  header(text) {
71
76
  if (!this.jsonMode)
72
77
  console.log(bold(text));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardelli/ambit",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Deploy apps to the cloud that only you and your AI agents can reach",
5
5
  "license": "MIT",
6
6
  "scripts": {},
File without changes
File without changes
File without changes