@fluid-app/fluid-cli-mist 0.1.62 → 0.1.64

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 CHANGED
@@ -33,9 +33,9 @@ fluid mist droplet egress-proxy on # ask for egress for the attached
33
33
  fluid mist droplet egress-proxy off # withdraw the request (and any grant)
34
34
  ```
35
35
 
36
- Fluid's egress proxy lets a Droplet's installations reach external systems such as Exigo from Fluid's fixed outbound IPs. Because those IPs reach every Exigo tenant, the grant is Fluid's decision: these commands set the Droplet's `egress_proxy_requested`, and a Fluid admin approves it, which sets `egress_proxy_enabled`. The output says whether the request is waiting or already granted. Withdrawing the request also withdraws the grant.
36
+ Fluid's egress proxy lets a Droplet's installations reach external systems such as Exigo from Fluid's fixed outbound IPs. These commands set the Droplet's `egress_proxy_requested`. Fluid accepts it only on a company it has enabled for egress, and the proxy then admits the Droplet with no further approval, wherever the proxy honours Fluid's answer. Withdrawing the request also clears any grant a Fluid admin recorded (`egress_proxy_enabled`).
37
37
 
38
- `--egress-proxy` works on `create --droplet`, `create --kind droplet`, `create --hostable`, `attach --kind droplet` and `attach-droplet`. On a Droplet that already exists it updates the request rather than ignoring the flag. Fluid accepts an egress request only from a company admin. For anyone else it refuses the request: `--egress-proxy` then sets the droplet up without it and warns, and `droplet egress-proxy` fails without writing, because Fluid does not show the egress fields to them either. A Fluid that predates the fields ignores them, and the commands warn or fail the same way. `droplet egress-proxy off` also clears a grant a Fluid admin gave without a request. Mist Desktop's Safe Mode treats `droplet egress-proxy` as a write.
38
+ `--egress-proxy` works on `create --droplet`, `create --kind droplet`, `create --hostable`, `attach --kind droplet` and `attach-droplet`. On a Droplet that already exists it updates the request rather than ignoring the flag. Fluid accepts an egress request only from a company admin, and only on a company Fluid has enabled for egress. Otherwise it refuses the request: `--egress-proxy` then sets the droplet up without it and warns, and `droplet egress-proxy` fails with Fluid's reason without writing. A Fluid that predates the fields ignores them, and the commands warn or fail the same way. `droplet egress-proxy off` also clears a grant a Fluid admin gave without a request. Mist Desktop's Safe Mode treats `droplet egress-proxy` as a write.
39
39
 
40
40
  ## Repairing the attached Droplet
41
41
 
package/dist/index.mjs CHANGED
@@ -2557,23 +2557,39 @@ function planReceiptMessage(code) {
2557
2557
  /**
2558
2558
  * Ask Fluid for, or withdraw, egress through its egress proxy for the Mist's
2559
2559
  * attached Droplet (`fluid mist droplet egress-proxy`). The owner's ask is the
2560
- * droplet's `egress_proxy_requested`; the grant the proxy honours,
2561
- * `egress_proxy_enabled`, is set by a Fluid root admin, who approves it.
2562
- * Withdrawing the request also withdraws the grant.
2560
+ * droplet's `egress_proxy_requested`, and the proxy admits the droplet on it
2561
+ * alone. A Fluid root admin's grant (`egress_proxy_enabled`) is now only a
2562
+ * record; withdrawing the request also clears it.
2563
2563
  */
2564
2564
  /** Why a droplet response can lack the egress fields. Fluid returns them only
2565
2565
  * to company admins (and root admins), and older Fluids not at all. */
2566
2566
  const EGRESS_NOT_RETURNED = "Fluid did not return the droplet's egress fields: only a company admin can see or ask for egress, or this Fluid predates it.";
2567
- /** Fluid refused the egress request outright (401): it accepts one only
2568
- * from a company admin. Distinct from an older Fluid, which ignores the
2569
- * field and omits it from the response. */
2570
- const EGRESS_REFUSED = "Fluid refused the egress request: only a company admin can ask for egress. The droplet was set up without it.";
2571
- /** Whether an API error is Fluid refusing the egress request: a 401 whose
2572
- * `errors` names `egress_proxy_requested`. Matched exactly, so a real
2567
+ /** Fluid refused the egress request outright: it accepts one only from a
2568
+ * company admin (401), and only on a company Fluid enabled for egress (403).
2569
+ * Distinct from an older Fluid, which ignores the field and omits it from
2570
+ * the response. */
2571
+ const EGRESS_REFUSED = "Fluid refused the egress request: only a company admin can ask for egress, and only once Fluid enables egress for the company. The droplet was set up without it.";
2572
+ /** Whether an API error is Fluid refusing the egress request: a 401 or 403
2573
+ * whose `errors` names `egress_proxy_requested`. Matched exactly, so a real
2573
2574
  * authentication failure is reported as one rather than as a refusal. */
2574
2575
  function isEgressRefusal(error) {
2575
- return error instanceof MistApiError && error.status === 401 && error.fieldErrors?.egress_proxy_requested !== void 0;
2576
- }
2576
+ return error instanceof MistApiError && (error.status === 401 || error.status === 403) && error.fieldErrors?.egress_proxy_requested !== void 0;
2577
+ }
2578
+ /** Fluid's own words for an egress refusal, falling back to EGRESS_REFUSED. */
2579
+ function egressRefusalMessage(error) {
2580
+ const reasons = error.fieldErrors?.egress_proxy_requested;
2581
+ const reason = Array.isArray(reasons) ? reasons[0] : reasons;
2582
+ return typeof reason === "string" ? `Fluid refused the egress request: ${reason}.` : EGRESS_REFUSED;
2583
+ }
2584
+ /** Fluid refused to turn egress on for the droplet. Still an API error, so
2585
+ * it keeps the response's status and the 4xx exit code; only the message
2586
+ * is Fluid's reason instead of a bare status. */
2587
+ var EgressRequestRefusedError = class extends MistApiError {
2588
+ constructor(message, refused) {
2589
+ super(message, refused.status, refused.details, refused.fieldErrors);
2590
+ this.name = "EgressRequestRefusedError";
2591
+ }
2592
+ };
2577
2593
  /** The API answered without the egress fields. */
2578
2594
  var EgressProxyUnsupportedError = class extends Error {
2579
2595
  constructor() {
@@ -2602,7 +2618,10 @@ async function setDropletEgressProxy(client, input) {
2602
2618
  granted: current.egress_proxy_enabled === true,
2603
2619
  changed: false
2604
2620
  };
2605
- const updated = (await updateDroplet(client, dropletUuid, { egress_proxy_requested: input.requested })).droplet;
2621
+ const updated = (await updateDroplet(client, dropletUuid, { egress_proxy_requested: input.requested }).catch((error) => {
2622
+ if (error instanceof MistApiError && isEgressRefusal(error)) throw new EgressRequestRefusedError(egressRefusalMessage(error), error);
2623
+ throw error;
2624
+ })).droplet;
2606
2625
  if (updated.egress_proxy_requested === void 0) throw new EgressProxyUnsupportedError();
2607
2626
  return {
2608
2627
  mistSlug,
@@ -2883,8 +2902,7 @@ async function ensureEgressProxy(client, args) {
2883
2902
  }
2884
2903
  const requested = record?.egress_proxy_requested === true;
2885
2904
  const granted = record?.egress_proxy_enabled === true;
2886
- if (granted) reporter.succeed("Egress granted — the droplet can reach Exigo through Fluid");
2887
- else if (requested) reporter.succeed("Egress requested — a Fluid admin must approve it before the proxy admits the droplet");
2905
+ if (requested) reporter.succeed("Egress requested — Fluid's proxy admits requested droplets where egress is enabled");
2888
2906
  else reporter.warn(`${EGRESS_NOT_RETURNED} Re-run \`fluid mist droplet egress-proxy on\` as a company admin.`);
2889
2907
  return {
2890
2908
  requested,
@@ -3044,7 +3062,7 @@ async function verifyManagedEnv(client, args) {
3044
3062
  }
3045
3063
  //#endregion
3046
3064
  //#region src/lib/surface-flags.ts
3047
- const EGRESS_PROXY_FLAG_DESCRIPTION = "Ask Fluid to let the droplet reach external systems such as Exigo through its egress proxy (a Fluid admin approves it)";
3065
+ const EGRESS_PROXY_FLAG_DESCRIPTION = "Ask Fluid to let the droplet reach external systems such as Exigo through its egress proxy";
3048
3066
  /**
3049
3067
  * `--egress-proxy` only means something for a droplet: only a droplet's
3050
3068
  * installation token authenticates to the proxy. Refuse it on other kinds
@@ -3123,7 +3141,7 @@ function printSurfaceSummary(result) {
3123
3141
  }
3124
3142
  if (result.kind === "droplet" && result.managedEnv) if (result.managedEnv.ready) console.log(chalk.dim(" env: managed keys provisioned ✓"));
3125
3143
  else console.log(chalk.yellow(" env: redeploy in progress — run `fluid mist env list` shortly to confirm managed keys"));
3126
- if (result.kind === "droplet" && result.egressProxy) console.log(result.egressProxy.granted ? chalk.dim(" egress proxy: granted ✓") : result.egressProxy.requested ? chalk.yellow(" egress proxy: requested — waiting for a Fluid admin to approve it") : chalk.yellow(" egress proxy: not requested — only a company admin can ask for it, or this Fluid predates it"));
3144
+ if (result.kind === "droplet" && result.egressProxy) console.log(result.egressProxy.requested ? chalk.dim(" egress proxy: requested ✓") : chalk.yellow(" egress proxy: not requested — only a company admin can ask for it, or this Fluid predates it"));
3127
3145
  }
3128
3146
  //#endregion
3129
3147
  //#region src/commands/create.ts
@@ -4061,8 +4079,8 @@ const envCommand = new Command("env").description("Manage a mist's environment v
4061
4079
  * `fluid mist droplet egress-proxy <on|off> [slug] [--json]`
4062
4080
  *
4063
4081
  * Ask Fluid (on) to let the Mist's attached Droplet reach external systems
4064
- * such as Exigo through its egress proxy, or withdraw the request (off). A
4065
- * Fluid admin approves the request; withdrawing it also removes the grant.
4082
+ * such as Exigo through its egress proxy, or withdraw the request (off). The
4083
+ * proxy admits the droplet on the request alone; no Fluid admin approves it.
4066
4084
  * Leaves an already-correct droplet untouched. Safe Mode treats this as a
4067
4085
  * write (apps/mist-desktop fluid-cli-policy).
4068
4086
  */
@@ -4072,7 +4090,7 @@ function parseEgressProxyState(value) {
4072
4090
  if (normalized === "off") return false;
4073
4091
  throw new InvalidArgumentError("Use \"on\" or \"off\".");
4074
4092
  }
4075
- const dropletEgressProxyCommand = new Command("egress-proxy").description("Ask Fluid (on) or stop asking (off) to let the attached Droplet reach external systems such as Exigo through its egress proxy; a Fluid admin approves it").argument("<state>", "on | off", parseEgressProxyState).argument("[slug]", "Mist slug (defaults to the .mist file in CWD)").option("--json", "Emit JSON").action((requested, slug, opts) => runAction(async () => {
4093
+ const dropletEgressProxyCommand = new Command("egress-proxy").description("Ask Fluid (on) or stop asking (off) to let the attached Droplet reach external systems such as Exigo through its egress proxy").argument("<state>", "on | off", parseEgressProxyState).argument("[slug]", "Mist slug (defaults to the .mist file in CWD)").option("--json", "Emit JSON").action((requested, slug, opts) => runAction(async () => {
4076
4094
  const result = await setDropletEgressProxy(createMistClient(), {
4077
4095
  slug,
4078
4096
  cwd: process.cwd(),
@@ -4081,8 +4099,7 @@ const dropletEgressProxyCommand = new Command("egress-proxy").description("Ask F
4081
4099
  if (opts.json) return printJson(result);
4082
4100
  const target = `droplet ${result.dropletUuid} (${result.mistSlug})`;
4083
4101
  if (!result.requested) console.log(result.changed ? `${chalk.green("✓")} Egress request withdrawn for ${target}` : chalk.dim(`No egress request for ${target}`));
4084
- else if (result.granted) console.log(`${chalk.green("✓")} Egress granted for ${target}`);
4085
- else console.log(`${chalk.green("✓")} Egress requested for ${target}. A Fluid admin must approve it before the proxy admits the droplet.`);
4102
+ else console.log(result.changed ? `${chalk.green("✓")} Egress requested for ${target}. Fluid's proxy admits requested droplets where egress is enabled.` : chalk.dim(`Egress already requested for ${target}`));
4086
4103
  }));
4087
4104
  //#endregion
4088
4105
  //#region src/commands/droplet/reinstall.ts