@devdogsuga/devtools 0.1.26 → 0.1.27
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 +72 -11
- package/bin/devtools.mjs +4 -4
- package/dist/cli-CZKkNHK5.js +6619 -0
- package/dist/failure-log-BBPGejQv.js +256 -0
- package/dist/launch.js +267 -281
- package/dist/local-env-D8HC2JK_.js +351 -0
- package/dist/local-env-DrBCXqD8.js +2 -0
- package/dist/menu-CQBsQRgH.js +1684 -0
- package/dist/peer-redirect-hooks.js +15 -0
- package/dist/peers-RBplwovA.js +229 -0
- package/dist/root-C2OmZDwD.js +94 -0
- package/dist/stack-Bx-55oi_.js +2 -0
- package/dist/stack-BynCgRVS.js +181 -0
- package/dist/supabase-project-0knM0mqd.js +426 -0
- package/dist/telemetry-C4foD8MD.js +249 -0
- package/dist/telemetry.js +2 -148
- package/package.json +10 -29
- package/bin/devtools-ci-bare.mjs +0 -48
- package/bin/devtools-ci.mjs +0 -31
- package/dist/args.d.ts +0 -26
- package/dist/args.js +0 -78
- package/dist/bws/bw.d.ts +0 -18
- package/dist/bws/bw.js +0 -70
- package/dist/bws/client.d.ts +0 -43
- package/dist/bws/client.js +0 -363
- package/dist/bws/environments.d.ts +0 -96
- package/dist/bws/environments.js +0 -111
- package/dist/bws/pace.d.ts +0 -25
- package/dist/bws/pace.js +0 -43
- package/dist/bws/retry.d.ts +0 -12
- package/dist/bws/retry.js +0 -39
- package/dist/bws/store.d.ts +0 -1
- package/dist/bws/store.js +0 -32
- package/dist/bws/token.d.ts +0 -31
- package/dist/bws/token.js +0 -88
- package/dist/bws/vault.d.ts +0 -29
- package/dist/bws/vault.js +0 -200
- package/dist/catalog.d.ts +0 -57
- package/dist/catalog.js +0 -57
- package/dist/cf/build.d.ts +0 -13
- package/dist/cf/build.js +0 -65
- package/dist/cf/commands.d.ts +0 -1
- package/dist/cf/commands.js +0 -172
- package/dist/cf/local-env.d.ts +0 -58
- package/dist/cf/local-env.js +0 -177
- package/dist/ci.d.ts +0 -1
- package/dist/ci.js +0 -328
- package/dist/cli.d.ts +0 -11
- package/dist/cli.js +0 -1094
- package/dist/commands.d.ts +0 -261
- package/dist/commands.js +0 -1318
- package/dist/completions.d.ts +0 -4
- package/dist/completions.js +0 -110
- package/dist/cron/commands.d.ts +0 -47
- package/dist/cron/commands.js +0 -372
- package/dist/cron/discovery.d.ts +0 -55
- package/dist/cron/discovery.js +0 -85
- package/dist/cron/schema.d.ts +0 -45
- package/dist/cron/schema.js +0 -35
- package/dist/db/config-push.d.ts +0 -8
- package/dist/db/config-push.js +0 -11
- package/dist/db/connection.d.ts +0 -79
- package/dist/db/connection.js +0 -114
- package/dist/db/exec.d.ts +0 -1
- package/dist/db/exec.js +0 -11
- package/dist/db/generate-types.d.ts +0 -1
- package/dist/db/generate-types.js +0 -4
- package/dist/db/generated-env.d.ts +0 -69
- package/dist/db/generated-env.js +0 -113
- package/dist/db/introspect.d.ts +0 -1
- package/dist/db/introspect.js +0 -122
- package/dist/db/local-env.d.ts +0 -65
- package/dist/db/local-env.js +0 -23
- package/dist/db/new-migration.d.ts +0 -8
- package/dist/db/new-migration.js +0 -69
- package/dist/db/pooler.d.ts +0 -23
- package/dist/db/pooler.js +0 -55
- package/dist/db/run.d.ts +0 -68
- package/dist/db/run.js +0 -156
- package/dist/db/seed-buckets.d.ts +0 -2
- package/dist/db/seed-buckets.js +0 -4
- package/dist/db/seed-production.d.ts +0 -8
- package/dist/db/seed-production.js +0 -79
- package/dist/db/seed-roles.d.ts +0 -7
- package/dist/db/seed-roles.js +0 -33
- package/dist/db/session-refresh.d.ts +0 -43
- package/dist/db/session-refresh.js +0 -40
- package/dist/deploy/migrations.d.ts +0 -20
- package/dist/deploy/migrations.js +0 -68
- package/dist/deploy/orphans.d.ts +0 -20
- package/dist/deploy/orphans.js +0 -177
- package/dist/deploy/preflight.d.ts +0 -53
- package/dist/deploy/preflight.js +0 -189
- package/dist/deploy/report.d.ts +0 -26
- package/dist/deploy/report.js +0 -70
- package/dist/deploy/require-planner.d.ts +0 -2
- package/dist/deploy/require-planner.js +0 -60
- package/dist/deploy/require-token.d.ts +0 -15
- package/dist/deploy/require-token.js +0 -78
- package/dist/deploy/secrets-file.d.ts +0 -17
- package/dist/deploy/secrets-file.js +0 -166
- package/dist/deploy/write-env.d.ts +0 -40
- package/dist/deploy/write-env.js +0 -395
- package/dist/docs/index-pages.d.ts +0 -38
- package/dist/docs/index-pages.js +0 -186
- package/dist/emails/commands.d.ts +0 -15
- package/dist/emails/commands.js +0 -130
- package/dist/emails/email-types.d.ts +0 -13
- package/dist/emails/email-types.js +0 -1
- package/dist/emails/fixtures.d.ts +0 -20
- package/dist/emails/fixtures.js +0 -20
- package/dist/env/audit.d.ts +0 -206
- package/dist/env/audit.js +0 -436
- package/dist/env/cloudflare.d.ts +0 -21
- package/dist/env/cloudflare.js +0 -61
- package/dist/env/commands.d.ts +0 -99
- package/dist/env/commands.js +0 -613
- package/dist/env/discovery.d.ts +0 -15
- package/dist/env/discovery.js +0 -239
- package/dist/env/document.d.ts +0 -119
- package/dist/env/document.js +0 -323
- package/dist/env/example.d.ts +0 -68
- package/dist/env/example.js +0 -605
- package/dist/env/selection.d.ts +0 -105
- package/dist/env/selection.js +0 -228
- package/dist/env-entry.d.ts +0 -49
- package/dist/env-entry.js +0 -204
- package/dist/environment-doctor.d.ts +0 -45
- package/dist/environment-doctor.js +0 -429
- package/dist/environment.d.ts +0 -92
- package/dist/environment.js +0 -185
- package/dist/fingerprint.d.ts +0 -10
- package/dist/fingerprint.js +0 -18
- package/dist/gen/campus-map.d.ts +0 -1
- package/dist/gen/campus-map.js +0 -473
- package/dist/gen/commands.d.ts +0 -1
- package/dist/gen/commands.js +0 -25
- package/dist/gen/hypno.d.ts +0 -1
- package/dist/gen/hypno.js +0 -134
- package/dist/gh/client.d.ts +0 -80
- package/dist/gh/client.js +0 -259
- package/dist/gh/environments.d.ts +0 -83
- package/dist/gh/environments.js +0 -178
- package/dist/gh/rulesets/actors.d.ts +0 -14
- package/dist/gh/rulesets/actors.js +0 -69
- package/dist/gh/rulesets/api.d.ts +0 -15
- package/dist/gh/rulesets/api.js +0 -104
- package/dist/gh/rulesets/commands.d.ts +0 -3
- package/dist/gh/rulesets/commands.js +0 -203
- package/dist/gh/rulesets/desired.d.ts +0 -112
- package/dist/gh/rulesets/desired.js +0 -271
- package/dist/gh/rulesets/diff.d.ts +0 -65
- package/dist/gh/rulesets/diff.js +0 -170
- package/dist/gh/rulesets/types.d.ts +0 -76
- package/dist/gh/rulesets/types.js +0 -13
- package/dist/gh/settings/api.d.ts +0 -40
- package/dist/gh/settings/api.js +0 -180
- package/dist/gh/settings/commands.d.ts +0 -1
- package/dist/gh/settings/commands.js +0 -254
- package/dist/gh/settings/desired.d.ts +0 -53
- package/dist/gh/settings/desired.js +0 -43
- package/dist/gh/settings/diff.d.ts +0 -57
- package/dist/gh/settings/diff.js +0 -161
- package/dist/gh/settings/types.d.ts +0 -92
- package/dist/gh/settings/types.js +0 -11
- package/dist/gh/settings/workflows.d.ts +0 -41
- package/dist/gh/settings/workflows.js +0 -128
- package/dist/grantRoot.d.ts +0 -42
- package/dist/grantRoot.js +0 -89
- package/dist/help.d.ts +0 -18
- package/dist/help.js +0 -169
- package/dist/images/commands.d.ts +0 -32
- package/dist/images/commands.js +0 -231
- package/dist/images/events.d.ts +0 -47
- package/dist/images/events.js +0 -116
- package/dist/images/graphics.d.ts +0 -70
- package/dist/images/graphics.js +0 -234
- package/dist/images/open-graph-types.d.ts +0 -75
- package/dist/images/open-graph-types.js +0 -1
- package/dist/images/prompts.d.ts +0 -34
- package/dist/images/prompts.js +0 -100
- package/dist/images/render.d.ts +0 -21
- package/dist/images/render.js +0 -61
- package/dist/images/select.d.ts +0 -64
- package/dist/images/select.js +0 -96
- package/dist/instance.d.ts +0 -69
- package/dist/instance.js +0 -102
- package/dist/invocation.d.ts +0 -49
- package/dist/invocation.js +0 -78
- package/dist/launch-ci.d.ts +0 -1
- package/dist/launch-ci.js +0 -90
- package/dist/launch.d.ts +0 -18
- package/dist/menu.d.ts +0 -43
- package/dist/menu.js +0 -300
- package/dist/moderation.d.ts +0 -70
- package/dist/moderation.js +0 -128
- package/dist/oauth/browser.d.ts +0 -1
- package/dist/oauth/browser.js +0 -13
- package/dist/oauth/config.d.ts +0 -24
- package/dist/oauth/config.js +0 -24
- package/dist/oauth/connect-url.d.ts +0 -17
- package/dist/oauth/connect-url.js +0 -23
- package/dist/oauth/db.d.ts +0 -37
- package/dist/oauth/db.js +0 -108
- package/dist/oauth/device.d.ts +0 -93
- package/dist/oauth/device.js +0 -198
- package/dist/oauth/discovery.d.ts +0 -28
- package/dist/oauth/discovery.js +0 -54
- package/dist/oauth/env-file.d.ts +0 -6
- package/dist/oauth/env-file.js +0 -35
- package/dist/oauth/exchange.d.ts +0 -43
- package/dist/oauth/exchange.js +0 -93
- package/dist/oauth/label.d.ts +0 -1
- package/dist/oauth/label.js +0 -25
- package/dist/oauth/loopback.d.ts +0 -52
- package/dist/oauth/loopback.js +0 -168
- package/dist/oauth/pkce.d.ts +0 -6
- package/dist/oauth/pkce.js +0 -34
- package/dist/oauth/target.d.ts +0 -54
- package/dist/oauth/target.js +0 -102
- package/dist/oauth/transport.d.ts +0 -41
- package/dist/oauth/transport.js +0 -32
- package/dist/oauth/wizard.d.ts +0 -40
- package/dist/oauth/wizard.js +0 -578
- package/dist/persona.d.ts +0 -18
- package/dist/persona.js +0 -221
- package/dist/pick.d.ts +0 -6
- package/dist/pick.js +0 -64
- package/dist/pipes.d.ts +0 -1
- package/dist/pipes.js +0 -25
- package/dist/planner/checks.d.ts +0 -26
- package/dist/planner/checks.js +0 -104
- package/dist/planner/commands.d.ts +0 -10
- package/dist/planner/commands.js +0 -367
- package/dist/planner/db.d.ts +0 -15
- package/dist/planner/db.js +0 -33
- package/dist/planner/role.d.ts +0 -33
- package/dist/planner/role.js +0 -68
- package/dist/repo/peer-redirect-hooks.d.ts +0 -16
- package/dist/repo/peer-redirect-hooks.js +0 -10
- package/dist/repo/peer-redirect.d.ts +0 -4
- package/dist/repo/peer-redirect.js +0 -26
- package/dist/repo/peers.d.ts +0 -39
- package/dist/repo/peers.js +0 -139
- package/dist/repo/resolve.d.ts +0 -41
- package/dist/repo/resolve.js +0 -152
- package/dist/repo/root.d.ts +0 -23
- package/dist/repo/root.js +0 -91
- package/dist/repo/source.d.ts +0 -14
- package/dist/repo/source.js +0 -54
- package/dist/repo/supabase-project.d.ts +0 -60
- package/dist/repo/supabase-project.js +0 -124
- package/dist/repo/tsx-loader.d.ts +0 -6
- package/dist/repo/tsx-loader.js +0 -41
- package/dist/run/pick.d.ts +0 -90
- package/dist/run/pick.js +0 -664
- package/dist/setup.d.ts +0 -1
- package/dist/setup.js +0 -280
- package/dist/stack.d.ts +0 -48
- package/dist/stack.js +0 -403
- package/dist/telemetry.d.ts +0 -59
- package/dist/tier.d.ts +0 -40
- package/dist/tier.js +0 -96
- package/dist/ui.d.ts +0 -40
- package/dist/ui.js +0 -71
- package/dist/version.d.ts +0 -7
- package/dist/version.js +0 -17
- package/dist/workers.d.ts +0 -5
- package/dist/workers.js +0 -33
- package/dist/workflows/commands.d.ts +0 -54
- package/dist/workflows/commands.js +0 -763
package/dist/env/selection.d.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { type VaultTarget } from "../bws/environments.js";
|
|
2
|
-
export interface PushSelection {
|
|
3
|
-
push: Map<string, string>;
|
|
4
|
-
/**
|
|
5
|
-
* Public per-environment values, bound for Bitwarden and for GitHub
|
|
6
|
-
* *variables*. Plaintext at both ends, with no libsodium sealing, and
|
|
7
|
-
* readable back through the API, which is what lets `audit` compare them by
|
|
8
|
-
* value.
|
|
9
|
-
*/
|
|
10
|
-
variables: Map<string, string>;
|
|
11
|
-
refused: string[];
|
|
12
|
-
/** Present in the file, declared by no manifest. Skipped, warned about. */
|
|
13
|
-
unknown: string[];
|
|
14
|
-
/**
|
|
15
|
-
* Left to the registry: the file still holds the declared derivation itself.
|
|
16
|
-
*
|
|
17
|
-
* Its own outcome rather than part of the skipped-and-unreported majority,
|
|
18
|
-
* because `env init --target` WRITES these lines, eight of them, and a push
|
|
19
|
-
* that said nothing about them would read as "your eight `$VAR` lines were
|
|
20
|
-
* stored". They were not, deliberately. See `selectForPush()`.
|
|
21
|
-
*/
|
|
22
|
-
derived: string[];
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Public per-environment values: Bitwarden, and then GitHub *variables*.
|
|
26
|
-
*
|
|
27
|
-
* Symmetric with `neverStore()` and `minted()`: a set, read at call time,
|
|
28
|
-
* refusing an empty registry. See `getEnvSync().variableKeys()` for why the set is narrower
|
|
29
|
-
* than "every public key" and why the five `localStack` ones are still in it.
|
|
30
|
-
*/
|
|
31
|
-
export declare function pushableVariables(): Set<string>;
|
|
32
|
-
/**
|
|
33
|
-
* Nothing to send: the committed and per-developer non-secrets, the minted
|
|
34
|
-
* credentials, plus the apply-only ones outside production.
|
|
35
|
-
*
|
|
36
|
-
* ⚠️ This is `getEnvSync().neverSecretKeys()` MINUS the pushable variables, and the
|
|
37
|
-
* subtraction is what gave 27 public, environment-scoped values a remote home.
|
|
38
|
-
* They used to land here, as "not a secret, therefore uninteresting", which
|
|
39
|
-
* conflated two different facts: that a value must not be a GitHub *secret*
|
|
40
|
-
* (true of all of them) and that it goes nowhere (true only of the committed
|
|
41
|
-
* and per-developer ones). Every consumer of this set reads it as the second,
|
|
42
|
-
* so the first no longer belongs in it.
|
|
43
|
-
*
|
|
44
|
-
* The apply-only two exist to reshape production, so a copy in staging or
|
|
45
|
-
* preflight is a second write-capable token to rotate for no benefit.
|
|
46
|
-
*
|
|
47
|
-
* Minted credentials are here because there is nothing to send: the value is
|
|
48
|
-
* signed at deploy time and its only copy is on the Worker. Skipped rather
|
|
49
|
-
* than refused, because "not pushed" is the ordinary state of one of these. A
|
|
50
|
-
* refusal is for a credential somebody put in the file expecting it to sync,
|
|
51
|
-
* and nobody has this one to put there.
|
|
52
|
-
*
|
|
53
|
-
* ⚠️ AND, for a target no app boots from, EVERYTHING THAT DID NOT OPT IN. This
|
|
54
|
-
* is the one exclusion that inverts the default: a deployed target skips a
|
|
55
|
-
* named few, `preflight` skips all but a named few. It inverts it because the
|
|
56
|
-
* two questions are different. "Which keys does staging not want?" has a short
|
|
57
|
-
* answer; "which credentials may a CI-only tier hold?" has the answer "the
|
|
58
|
-
* ones deliberately narrowed for it, and nothing by omission". Until this
|
|
59
|
-
* existed, `env push --target preflight` uploaded `SUPABASE_JWT_SIGNING_KEY`,
|
|
60
|
-
* `SECRET_KEY` and `GH_APP_PRIVATE_KEY` into a project whose GitHub
|
|
61
|
-
* environment is reachable from `main`. Both halves are derived, the target
|
|
62
|
-
* from `deployEnv: false` and the keys from `EnvMeta.narrowed`, so neither is
|
|
63
|
-
* a list to keep up to date.
|
|
64
|
-
*/
|
|
65
|
-
export declare function ignoredFor(target: VaultTarget): Set<string>;
|
|
66
|
-
export declare function neverStore(): Set<string>;
|
|
67
|
-
/**
|
|
68
|
-
* The keys a push for this target ROUTES: its two destinations, unioned.
|
|
69
|
-
*
|
|
70
|
-
* The complement of everything above, stated positively, because one consumer
|
|
71
|
-
* needs the question the other way round. `env init --target staging` renders
|
|
72
|
-
* a file whose whole purpose is to be filled in and pushed, so the keys it
|
|
73
|
-
* should contain are exactly the keys a push for that target would carry
|
|
74
|
-
* somewhere. Derived from `ignoredFor()` rather than re-listed, so the file
|
|
75
|
-
* and the upload cannot disagree about which target a key belongs to. The
|
|
76
|
-
* generated file used to be byte-identical for all three targets, which put
|
|
77
|
-
* the apply-tier credentials in `.env.staging` where `ignoredFor()` refuses
|
|
78
|
-
* them. The same derivation shrank `env init --target preflight` from 45 keys
|
|
79
|
-
* to the narrowed ones: the exclusion is stated once, in `ignoredFor()`, and
|
|
80
|
-
* the rendered file follows for free.
|
|
81
|
-
*
|
|
82
|
-
* The `neverStore()` subtraction is unreachable today (a never-store key is
|
|
83
|
-
* neither `secrecy: "secret"` nor `"public"`, so neither selector returns it)
|
|
84
|
-
* and is written down anyway: this set decides what gets an assignable line in
|
|
85
|
-
* a file people fill in, and `BWS_ACCESS_TOKEN=` is the one line that must
|
|
86
|
-
* never appear in one.
|
|
87
|
-
*/
|
|
88
|
-
export declare function keysRoutedTo(target: VaultTarget): Set<string>;
|
|
89
|
-
/**
|
|
90
|
-
* Signed at deploy time; the deploy target holds the only copy.
|
|
91
|
-
*
|
|
92
|
-
* Passed to `audit` separately from `ignoredFor()` even though it is a subset,
|
|
93
|
-
* because the audit needs the distinction: an ignored key is uninteresting
|
|
94
|
-
* everywhere, whereas a minted one is CORRECT on Cloudflare (which is what
|
|
95
|
-
* stops it being reported as an orphan and pruned) and WRONG in Bitwarden or
|
|
96
|
-
* GitHub.
|
|
97
|
-
*/
|
|
98
|
-
export declare function minted(): Set<string>;
|
|
99
|
-
/**
|
|
100
|
-
* `entries` is the ACTIVE assignments in the local `.env`, in file order.
|
|
101
|
-
*
|
|
102
|
-
* A commented-out line is not an assignment and never reaches here, which is
|
|
103
|
-
* what makes commenting-out a safe way to retire a key.
|
|
104
|
-
*/
|
|
105
|
-
export declare function selectForPush(entries: readonly (readonly [string, string])[], target: VaultTarget): PushSelection;
|
package/dist/env/selection.js
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import {} from "../bws/environments.js";
|
|
2
|
-
import { assertRegistryLoaded } from "./discovery.js";
|
|
3
|
-
import { getEnvSync } from "../repo/peers.js";
|
|
4
|
-
// The key sets are DERIVED from the env manifests (see `discovery.ts`), not
|
|
5
|
-
// hand-listed here, which is why every function below insists the registry is
|
|
6
|
-
// loaded. An empty registry makes each selector return `[]`, and `[]` fails
|
|
7
|
-
// open in the one direction that matters: nothing would be refused, so
|
|
8
|
-
// `BWS_ACCESS_TOKEN` would upload.
|
|
9
|
-
/**
|
|
10
|
-
* Public per-environment values: Bitwarden, and then GitHub *variables*.
|
|
11
|
-
*
|
|
12
|
-
* Symmetric with `neverStore()` and `minted()`: a set, read at call time,
|
|
13
|
-
* refusing an empty registry. See `getEnvSync().variableKeys()` for why the set is narrower
|
|
14
|
-
* than "every public key" and why the five `localStack` ones are still in it.
|
|
15
|
-
*/
|
|
16
|
-
export function pushableVariables() {
|
|
17
|
-
assertRegistryLoaded();
|
|
18
|
-
return new Set(getEnvSync().variableKeys());
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Nothing to send: the committed and per-developer non-secrets, the minted
|
|
22
|
-
* credentials, plus the apply-only ones outside production.
|
|
23
|
-
*
|
|
24
|
-
* ⚠️ This is `getEnvSync().neverSecretKeys()` MINUS the pushable variables, and the
|
|
25
|
-
* subtraction is what gave 27 public, environment-scoped values a remote home.
|
|
26
|
-
* They used to land here, as "not a secret, therefore uninteresting", which
|
|
27
|
-
* conflated two different facts: that a value must not be a GitHub *secret*
|
|
28
|
-
* (true of all of them) and that it goes nowhere (true only of the committed
|
|
29
|
-
* and per-developer ones). Every consumer of this set reads it as the second,
|
|
30
|
-
* so the first no longer belongs in it.
|
|
31
|
-
*
|
|
32
|
-
* The apply-only two exist to reshape production, so a copy in staging or
|
|
33
|
-
* preflight is a second write-capable token to rotate for no benefit.
|
|
34
|
-
*
|
|
35
|
-
* Minted credentials are here because there is nothing to send: the value is
|
|
36
|
-
* signed at deploy time and its only copy is on the Worker. Skipped rather
|
|
37
|
-
* than refused, because "not pushed" is the ordinary state of one of these. A
|
|
38
|
-
* refusal is for a credential somebody put in the file expecting it to sync,
|
|
39
|
-
* and nobody has this one to put there.
|
|
40
|
-
*
|
|
41
|
-
* ⚠️ AND, for a target no app boots from, EVERYTHING THAT DID NOT OPT IN. This
|
|
42
|
-
* is the one exclusion that inverts the default: a deployed target skips a
|
|
43
|
-
* named few, `preflight` skips all but a named few. It inverts it because the
|
|
44
|
-
* two questions are different. "Which keys does staging not want?" has a short
|
|
45
|
-
* answer; "which credentials may a CI-only tier hold?" has the answer "the
|
|
46
|
-
* ones deliberately narrowed for it, and nothing by omission". Until this
|
|
47
|
-
* existed, `env push --target preflight` uploaded `SUPABASE_JWT_SIGNING_KEY`,
|
|
48
|
-
* `SECRET_KEY` and `GH_APP_PRIVATE_KEY` into a project whose GitHub
|
|
49
|
-
* environment is reachable from `main`. Both halves are derived, the target
|
|
50
|
-
* from `deployEnv: false` and the keys from `EnvMeta.narrowed`, so neither is
|
|
51
|
-
* a list to keep up to date.
|
|
52
|
-
*/
|
|
53
|
-
export function ignoredFor(target) {
|
|
54
|
-
assertRegistryLoaded();
|
|
55
|
-
const pushable = pushableVariables();
|
|
56
|
-
const skip = new Set(getEnvSync()
|
|
57
|
-
.neverSecretKeys()
|
|
58
|
-
.filter((key) => !pushable.has(key)));
|
|
59
|
-
for (const key of getEnvSync().mintedKeys())
|
|
60
|
-
skip.add(key);
|
|
61
|
-
if (target !== "production") {
|
|
62
|
-
for (const key of getEnvSync().applyOnlyKeys())
|
|
63
|
-
skip.add(key);
|
|
64
|
-
}
|
|
65
|
-
// Plan-tier keys are read by exactly two jobs: `main-plan` (preflight) and
|
|
66
|
-
// `production-plan` (production). Everywhere else, staging today, a copy is
|
|
67
|
-
// a credential nothing reads, so it is skipped the same way the apply-tier
|
|
68
|
-
// pair is. Preflight is NOT excluded here: the narrowed-only branch below
|
|
69
|
-
// already decides that target key by key, and a plan-tier key reaches it
|
|
70
|
-
// through its `narrowed` opt-in.
|
|
71
|
-
if (target !== "production" && !getEnvSync().holdsOnlyNarrowedKeys(target)) {
|
|
72
|
-
for (const key of getEnvSync().planOnlyKeys())
|
|
73
|
-
skip.add(key);
|
|
74
|
-
}
|
|
75
|
-
if (getEnvSync().holdsOnlyNarrowedKeys(target)) {
|
|
76
|
-
const narrow = new Set(getEnvSync().narrowedKeys());
|
|
77
|
-
// Over every DECLARED key, not over the routable ones: this set is also
|
|
78
|
-
// what `audit` treats as uninteresting and what `push` reports orphans
|
|
79
|
-
// against, and both want the full answer.
|
|
80
|
-
for (const key of getEnvSync().variables().keys()) {
|
|
81
|
-
if (!narrow.has(key))
|
|
82
|
-
skip.add(key);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return skip;
|
|
86
|
-
}
|
|
87
|
-
export function neverStore() {
|
|
88
|
-
assertRegistryLoaded();
|
|
89
|
-
return new Set(getEnvSync().neverStoreKeys());
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* The keys a push for this target ROUTES: its two destinations, unioned.
|
|
93
|
-
*
|
|
94
|
-
* The complement of everything above, stated positively, because one consumer
|
|
95
|
-
* needs the question the other way round. `env init --target staging` renders
|
|
96
|
-
* a file whose whole purpose is to be filled in and pushed, so the keys it
|
|
97
|
-
* should contain are exactly the keys a push for that target would carry
|
|
98
|
-
* somewhere. Derived from `ignoredFor()` rather than re-listed, so the file
|
|
99
|
-
* and the upload cannot disagree about which target a key belongs to. The
|
|
100
|
-
* generated file used to be byte-identical for all three targets, which put
|
|
101
|
-
* the apply-tier credentials in `.env.staging` where `ignoredFor()` refuses
|
|
102
|
-
* them. The same derivation shrank `env init --target preflight` from 45 keys
|
|
103
|
-
* to the narrowed ones: the exclusion is stated once, in `ignoredFor()`, and
|
|
104
|
-
* the rendered file follows for free.
|
|
105
|
-
*
|
|
106
|
-
* The `neverStore()` subtraction is unreachable today (a never-store key is
|
|
107
|
-
* neither `secrecy: "secret"` nor `"public"`, so neither selector returns it)
|
|
108
|
-
* and is written down anyway: this set decides what gets an assignable line in
|
|
109
|
-
* a file people fill in, and `BWS_ACCESS_TOKEN=` is the one line that must
|
|
110
|
-
* never appear in one.
|
|
111
|
-
*/
|
|
112
|
-
export function keysRoutedTo(target) {
|
|
113
|
-
assertRegistryLoaded();
|
|
114
|
-
const skip = ignoredFor(target);
|
|
115
|
-
const refuse = neverStore();
|
|
116
|
-
return new Set([...getEnvSync().storableKeys(), ...getEnvSync().variableKeys()].filter((key) => !skip.has(key) && !refuse.has(key)));
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Signed at deploy time; the deploy target holds the only copy.
|
|
120
|
-
*
|
|
121
|
-
* Passed to `audit` separately from `ignoredFor()` even though it is a subset,
|
|
122
|
-
* because the audit needs the distinction: an ignored key is uninteresting
|
|
123
|
-
* everywhere, whereas a minted one is CORRECT on Cloudflare (which is what
|
|
124
|
-
* stops it being reported as an orphan and pruned) and WRONG in Bitwarden or
|
|
125
|
-
* GitHub.
|
|
126
|
-
*/
|
|
127
|
-
export function minted() {
|
|
128
|
-
assertRegistryLoaded();
|
|
129
|
-
return new Set(getEnvSync().mintedKeys());
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Whether the file's value is still, exactly, the derivation the registry
|
|
133
|
-
* declares for this key.
|
|
134
|
-
*
|
|
135
|
-
* ⚠️ EXACT IDENTITY, and nothing looser. Not "looks like a formula", not
|
|
136
|
-
* "contains a `$`", not "starts with the derivation". String equality with
|
|
137
|
-
* what `getEnvSync().derivationOf()` returns. Everything else somebody could type is
|
|
138
|
-
* deliberate input: a real value, obviously, but also a DIFFERENT derivation,
|
|
139
|
-
* which is how a target says its value is built from something else. Widening
|
|
140
|
-
* this predicate by one inch silently drops a credential on the floor: the
|
|
141
|
-
* push reports success, the environment is missing a secret, and `env audit`
|
|
142
|
-
* agrees with the file it came from.
|
|
143
|
-
*
|
|
144
|
-
* `some` rather than `every` across duplicate declarations, matching
|
|
145
|
-
* `keysWhere()`: the safe reading is that a value matching ANY declared
|
|
146
|
-
* derivation is that derivation. It cannot discard a credential either way,
|
|
147
|
-
* since no usable credential is byte-identical to `$BASE_URL/auth/callback`.
|
|
148
|
-
*/
|
|
149
|
-
function isDeclaredDerivation(entries, value) {
|
|
150
|
-
// `getEnvSync().derivationOf()` returns null for everything that is not a derivation, and
|
|
151
|
-
// `value` is non-empty by the time this is called, so null never matches.
|
|
152
|
-
return entries.some((entry) => getEnvSync().derivationOf(entry.meta) === value);
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* `entries` is the ACTIVE assignments in the local `.env`, in file order.
|
|
156
|
-
*
|
|
157
|
-
* A commented-out line is not an assignment and never reaches here, which is
|
|
158
|
-
* what makes commenting-out a safe way to retire a key.
|
|
159
|
-
*/
|
|
160
|
-
export function selectForPush(entries, target) {
|
|
161
|
-
const skip = ignoredFor(target);
|
|
162
|
-
const refuse = neverStore();
|
|
163
|
-
const pushable = pushableVariables();
|
|
164
|
-
const declared = getEnvSync().variables();
|
|
165
|
-
const push = new Map();
|
|
166
|
-
const publicValues = new Map();
|
|
167
|
-
const refused = [];
|
|
168
|
-
const unknown = [];
|
|
169
|
-
const derived = [];
|
|
170
|
-
for (const [key, value] of entries) {
|
|
171
|
-
// Refusal is checked FIRST and independently of the value. A blank
|
|
172
|
-
// BWS_ACCESS_TOKEN is still a line somebody is about to fill in.
|
|
173
|
-
if (refuse.has(key)) {
|
|
174
|
-
if (value !== "")
|
|
175
|
-
refused.push(key);
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
// Undeclared means unclassified. Nothing says whether this is a secret,
|
|
179
|
-
// whose it is, or where it routes, so it does not leave the machine.
|
|
180
|
-
// Reported even when empty, because the problem is the missing
|
|
181
|
-
// declaration, not the value.
|
|
182
|
-
if (!declared.has(key)) {
|
|
183
|
-
unknown.push(key);
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
// Checked BEFORE the variable branch, so the exclusions about *this
|
|
187
|
-
// target* keep winning: an apply-only key outside production, or a minted
|
|
188
|
-
// one anywhere, is skipped whatever its secrecy. The two sets are disjoint
|
|
189
|
-
// today, and this ordering is what keeps a future overlap failing closed
|
|
190
|
-
// rather than open.
|
|
191
|
-
if (skip.has(key))
|
|
192
|
-
continue;
|
|
193
|
-
// An empty secret reads as "configured" to every consumer that checks for
|
|
194
|
-
// presence, which is worse than an absent one. Equally true of a variable:
|
|
195
|
-
// an empty `PROJECT_REF` builds a URL pointing at nothing.
|
|
196
|
-
if (value === "")
|
|
197
|
-
continue;
|
|
198
|
-
// Still the declared derivation, so there is no VALUE here, only the
|
|
199
|
-
// shape, which the registry already holds. Storing it is harmful rather
|
|
200
|
-
// than merely redundant: a stored value BEATS the registry when the
|
|
201
|
-
// deploy composes an env file, so the literal `https://$PROJECT_REF...`
|
|
202
|
-
// arrives as `from: "variable"`, is never expanded (only `from: "derived"`
|
|
203
|
-
// is), and is written single-quoted, which dotenvx takes as fully literal.
|
|
204
|
-
// The deployed app then resolves a host called `$PROJECT_REF.supabase.co`
|
|
205
|
-
// while `env audit` reports NO DRIFT, because the stored value does match
|
|
206
|
-
// the file.
|
|
207
|
-
//
|
|
208
|
-
// ⚠️ NOT expanded here and sent, which is the tempting alternative. That
|
|
209
|
-
// would make GitHub the source of truth for these eight shapes: changing
|
|
210
|
-
// `REST_URL` from `/rest/v1` to `/rest/v2` in the registry would then never
|
|
211
|
-
// take effect anywhere. Skipping is what lets the deploy's `fromRegistry()`
|
|
212
|
-
// run and expand at compose time.
|
|
213
|
-
if (isDeclaredDerivation(declared.get(key), value)) {
|
|
214
|
-
derived.push(key);
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
// Public and per-environment: a GitHub *variable*, not a secret. Routed
|
|
218
|
-
// here rather than dropped, because the value still has to reach CI, and
|
|
219
|
-
// still belongs in Bitwarden so that `pull` rebuilds a COMPLETE env file
|
|
220
|
-
// rather than the secret half of one.
|
|
221
|
-
if (pushable.has(key)) {
|
|
222
|
-
publicValues.set(key, value);
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
push.set(key, value);
|
|
226
|
-
}
|
|
227
|
-
return { push, variables: publicValues, refused, unknown, derived };
|
|
228
|
-
}
|
package/dist/env-entry.d.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { DeployEnvironment } from "@devdogsuga/env";
|
|
2
|
-
import type { DevDatabase } from "@devdogsuga/env/load";
|
|
3
|
-
import type * as EnvLoadModule from "@devdogsuga/env/load";
|
|
4
|
-
import type * as EnvSessionModule from "@devdogsuga/env/session";
|
|
5
|
-
import { type EnsureGeneratedEnvResult } from "./db/generated-env.js";
|
|
6
|
-
export interface EnvEntryDeps {
|
|
7
|
-
envLoad: typeof EnvLoadModule;
|
|
8
|
-
envSession: typeof EnvSessionModule;
|
|
9
|
-
/**
|
|
10
|
-
* Regenerates `.env.generated` from a running local stack when this
|
|
11
|
-
* checkout's own copy is missing, right before the session's env files
|
|
12
|
-
* load — see this module's header and `db/generated-env.ts`. Required
|
|
13
|
-
* (not defaulted here) so every caller is explicit about it: `launch.ts`
|
|
14
|
-
* uses `realEnvEntryDeps` for the real wiring, tests inject a stub that
|
|
15
|
-
* never touches a real filesystem, Docker daemon, or the Supabase CLI.
|
|
16
|
-
*/
|
|
17
|
-
ensureGeneratedEnv: (tier: DeployEnvironment, devDatabase: DevDatabase | undefined) => Promise<EnsureGeneratedEnvResult>;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* The production wiring for `EnvEntryDeps`, shared by both call sites in
|
|
21
|
-
* `launch.ts`.
|
|
22
|
-
*/
|
|
23
|
-
export declare function realEnvEntryDeps(envLoad: typeof EnvLoadModule, envSession: typeof EnvSessionModule): EnvEntryDeps;
|
|
24
|
-
/**
|
|
25
|
-
* Enters `tier` (and `devDatabase`'s overlay) for the current process,
|
|
26
|
-
* handling `LocalStackOfflineError` (the TTY offer to start the local stack,
|
|
27
|
-
* the `db`-exemption degraded-entry fallback) and `MissingEnvFileError` (the
|
|
28
|
-
* clean-clone tolerance for `development`, fatal otherwise) exactly as
|
|
29
|
-
* `launch.ts` always has. `dispatchCommand` is called exactly once, in every
|
|
30
|
-
* non-fatal branch — including immediately, in place of any further entry
|
|
31
|
-
* work, when a declined-then-accepted stack start already ran it — so its
|
|
32
|
-
* return value is always this function's own return value.
|
|
33
|
-
*/
|
|
34
|
-
export declare function enterSessionEnvironment<T>(tier: DeployEnvironment, devDatabase: DevDatabase | undefined, commandArgv: readonly string[], deps: EnvEntryDeps, dispatchCommand: () => Promise<T>): Promise<T>;
|
|
35
|
-
/**
|
|
36
|
-
* What `runMenu` calls, right before dispatching the chosen command, in
|
|
37
|
-
* place of entering the environment itself — `commandArgv` is the chosen
|
|
38
|
-
* leaf's argv, `dispatchCommand` is `runMenu`'s own injected dispatcher for
|
|
39
|
-
* it. See this module's header for why a module-level slot rather than a
|
|
40
|
-
* `runMenu` parameter.
|
|
41
|
-
*/
|
|
42
|
-
export type MenuEnvHook = (commandArgv: readonly string[], dispatchCommand: () => Promise<string | null>) => Promise<string | null>;
|
|
43
|
-
/** Set by `launch.ts` for a menu invocation; `undefined` for a typed command
|
|
44
|
-
* (which entered already) and for any test that drives `runMenu` directly
|
|
45
|
-
* without going through `launch.ts` at all. */
|
|
46
|
-
export declare function setMenuEnvHook(hook: MenuEnvHook | undefined): void;
|
|
47
|
-
/** Read by `runMenu`, then cleared — see this module's header on why a
|
|
48
|
-
* nested launcher must not inherit a stale hook. */
|
|
49
|
-
export declare function takeMenuEnvHook(): MenuEnvHook | undefined;
|
package/dist/env-entry.js
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Entering a resolved deploy tier's environment — the part of `launch.ts`
|
|
3
|
-
* that actually loads `.env.<tier>` (and its `DEV_DB` overlay) onto
|
|
4
|
-
* `process.env`, with the two recoverable failures `enterEnvironment` can
|
|
5
|
-
* throw handled the same way everywhere it is called from.
|
|
6
|
-
*
|
|
7
|
-
* ## Why this is its own module
|
|
8
|
-
*
|
|
9
|
-
* A typed command line enters its tier at launch, before `cli.ts` is even
|
|
10
|
-
* imported — see `launch.ts`'s header. A menu invocation cannot: the whole
|
|
11
|
-
* point of the wizard is to show a contributor what is possible before they
|
|
12
|
-
* have chosen anything, and loading env files (and possibly offering to
|
|
13
|
-
* start the local stack) before that first question is answered means
|
|
14
|
-
* whatever changed in another terminal while they were deciding — the stack
|
|
15
|
-
* coming up, `.env.generated` being rewritten — is missed. So a menu
|
|
16
|
-
* invocation defers this exact block until `menu.ts`'s `runMenu` is about to
|
|
17
|
-
* dispatch the ONE command the reader chose, right before it runs.
|
|
18
|
-
*
|
|
19
|
-
* `enterSessionEnvironment` is the block both callers share, generic over
|
|
20
|
-
* what "dispatch the command" means to each: `launch.ts` imports `cli.ts`
|
|
21
|
-
* fresh and calls its `main()`, `runMenu` already holds the dispatcher
|
|
22
|
-
* `cli.ts` injected into it. `commandArgv` is the argv the caller is about to
|
|
23
|
-
* dispatch — used for the two `LocalStackOfflineError` exemptions (a `db`
|
|
24
|
-
* lifecycle command, and an empty argv) exactly as `launch.ts` used `rest`
|
|
25
|
-
* for them before this was extracted.
|
|
26
|
-
*
|
|
27
|
-
* ## The hook `runMenu` calls
|
|
28
|
-
*
|
|
29
|
-
* `setMenuEnvHook`/`takeMenuEnvHook` are a module-level slot shared by
|
|
30
|
-
* `launch.ts` and `menu.ts`: `cli.ts` calls `runMenu` with a fixed signature
|
|
31
|
-
* that has no room for a per-invocation callback. `launch.ts` sets the hook
|
|
32
|
-
* for a menu invocation before handing off to `cli.ts`; `runMenu` takes it
|
|
33
|
-
* (reading clears it) right before its own dispatch, so a nested launcher
|
|
34
|
-
* never inherits a stale one.
|
|
35
|
-
*
|
|
36
|
-
* ## Regenerating `.env.generated` before entry
|
|
37
|
-
*
|
|
38
|
-
* Before either caller's `enterEnvironment` call, this also gives a running
|
|
39
|
-
* local stack a chance to fix its own absence: `deps.ensureGeneratedEnv`
|
|
40
|
-
* (`db/generated-env.ts`'s `ensureGeneratedEnvFile`, wired by
|
|
41
|
-
* `realEnvEntryDeps`) writes `.env.generated` from `supabase status -o env`
|
|
42
|
-
* when the port is listening but the file is missing — the common shape of
|
|
43
|
-
* a local stack another workspace started, sharing this repo's
|
|
44
|
-
* `project_id` — so the entry below usually just succeeds instead of
|
|
45
|
-
* throwing `LocalStackOfflineError` or warning about a file nobody wrote.
|
|
46
|
-
* A `"foreign"` result (the stack on the port belongs to a DIFFERENT
|
|
47
|
-
* project) prints its own hint and then falls through to the unchanged
|
|
48
|
-
* error handling below, since the file is still missing either way.
|
|
49
|
-
*/
|
|
50
|
-
import { confirm } from "@clack/prompts";
|
|
51
|
-
import { ensureGeneratedEnvFile, realEnsureGeneratedEnvDeps, } from "./db/generated-env.js";
|
|
52
|
-
import { unwrap } from "./ui.js";
|
|
53
|
-
/**
|
|
54
|
-
* The production wiring for `EnvEntryDeps`, shared by both call sites in
|
|
55
|
-
* `launch.ts`.
|
|
56
|
-
*/
|
|
57
|
-
export function realEnvEntryDeps(envLoad, envSession) {
|
|
58
|
-
return {
|
|
59
|
-
envLoad,
|
|
60
|
-
envSession,
|
|
61
|
-
ensureGeneratedEnv: (tier, devDatabase) => ensureGeneratedEnvFile(tier, devDatabase, realEnsureGeneratedEnvDeps(envLoad.probeLocalStack)),
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Enters `tier` (and `devDatabase`'s overlay) for the current process,
|
|
66
|
-
* handling `LocalStackOfflineError` (the TTY offer to start the local stack,
|
|
67
|
-
* the `db`-exemption degraded-entry fallback) and `MissingEnvFileError` (the
|
|
68
|
-
* clean-clone tolerance for `development`, fatal otherwise) exactly as
|
|
69
|
-
* `launch.ts` always has. `dispatchCommand` is called exactly once, in every
|
|
70
|
-
* non-fatal branch — including immediately, in place of any further entry
|
|
71
|
-
* work, when a declined-then-accepted stack start already ran it — so its
|
|
72
|
-
* return value is always this function's own return value.
|
|
73
|
-
*/
|
|
74
|
-
export async function enterSessionEnvironment(tier, devDatabase, commandArgv, deps, dispatchCommand) {
|
|
75
|
-
const { envLoad, envSession } = deps;
|
|
76
|
-
const generated = await deps.ensureGeneratedEnv(tier, devDatabase);
|
|
77
|
-
if (generated.outcome === "wrote" || generated.outcome === "foreign") {
|
|
78
|
-
process.stderr.write(`${generated.line}\n`);
|
|
79
|
-
}
|
|
80
|
-
// Mandatory, not chattiness: which database a command is about to touch
|
|
81
|
-
// must never be a guess. Names the QUALIFIED session (`development:local`)
|
|
82
|
-
// when one was resolved. See `session.ts`'s and `load.ts`'s own headers.
|
|
83
|
-
const reportEntered = (files, label) => {
|
|
84
|
-
process.stderr.write(`devtools: loaded ${files.length > 0 ? files.join(", ") : "no env files"} (${label})\n`);
|
|
85
|
-
};
|
|
86
|
-
const sessionLabel = devDatabase === undefined ? tier : `${tier}:${devDatabase}`;
|
|
87
|
-
try {
|
|
88
|
-
// `override: false` — see `launch.ts`'s former header comment on this
|
|
89
|
-
// same call, reproduced here since this IS that call now.
|
|
90
|
-
const entered = await envSession.enterEnvironment(tier, {
|
|
91
|
-
override: false,
|
|
92
|
-
devDatabase,
|
|
93
|
-
});
|
|
94
|
-
for (const warning of entered.warnings) {
|
|
95
|
-
process.stderr.write(`devtools: ${warning}\n`);
|
|
96
|
-
}
|
|
97
|
-
reportEntered(entered.files, sessionLabel);
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
if (err instanceof envLoad.LocalStackOfflineError) {
|
|
101
|
-
// The session explicitly means the local database and the stack is not
|
|
102
|
-
// reachable.
|
|
103
|
-
process.stderr.write(`devtools: ${err.message}\n`);
|
|
104
|
-
// Offer to bring the stack up right here and then carry on with the
|
|
105
|
-
// command about to dispatch. Only on a TTY, and not when the command is
|
|
106
|
-
// ITSELF a stack lifecycle command — `db start`/`stop`/`restart` do
|
|
107
|
-
// this on their own, and `db stop` against an already-down stack must
|
|
108
|
-
// not be interrupted by an offer to start it. An empty `commandArgv`
|
|
109
|
-
// (nothing chosen yet) is likewise left alone.
|
|
110
|
-
const lifecycle = commandArgv[0] === "db" &&
|
|
111
|
-
(commandArgv[1] === "start" ||
|
|
112
|
-
commandArgv[1] === "stop" ||
|
|
113
|
-
commandArgv[1] === "restart");
|
|
114
|
-
if (process.stdin.isTTY === true &&
|
|
115
|
-
commandArgv.length !== 0 &&
|
|
116
|
-
!lifecycle) {
|
|
117
|
-
const start = unwrap(await confirm({
|
|
118
|
-
message: "Start the local Supabase stack now?",
|
|
119
|
-
}));
|
|
120
|
-
if (start) {
|
|
121
|
-
// Keep the session's local qualifier set so the env refresh that
|
|
122
|
-
// `runStackCommand("start")` performs on success re-applies the
|
|
123
|
-
// overlay under it, and the command dispatched next resolves the
|
|
124
|
-
// freshly-started local database.
|
|
125
|
-
if (devDatabase !== undefined)
|
|
126
|
-
process.env.DEV_DB = devDatabase;
|
|
127
|
-
const { runStackCommand } = await import("./stack.js");
|
|
128
|
-
const { code, lines } = await runStackCommand("start", null);
|
|
129
|
-
for (const line of lines) {
|
|
130
|
-
process.stderr.write(`devtools: ${line}\n`);
|
|
131
|
-
}
|
|
132
|
-
if (code === 0) {
|
|
133
|
-
return await dispatchCommand();
|
|
134
|
-
}
|
|
135
|
-
process.stderr.write("devtools: the stack did not start — see the Supabase CLI output " +
|
|
136
|
-
"above.\n");
|
|
137
|
-
process.exit(1);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
// Declined, or nobody to ask. `db` (whose `start` is the fix, and whose
|
|
141
|
-
// data commands re-check the connection themselves) and an empty argv
|
|
142
|
-
// (the road to `db start` — the bare menu, when nothing has deferred
|
|
143
|
-
// this far, or the menu resumed on `db` itself) may continue in a
|
|
144
|
-
// degraded, unqualified entry; anything else stops here, with the
|
|
145
|
-
// error's own troubleshooting, instead of failing later against
|
|
146
|
-
// whatever `.env` happens to name.
|
|
147
|
-
if (commandArgv.length !== 0 && commandArgv[0] !== "db") {
|
|
148
|
-
process.exit(1);
|
|
149
|
-
}
|
|
150
|
-
process.stderr.write("devtools: continuing without the overlay so `db start` can fix this.\n");
|
|
151
|
-
const inherited = process.env.DEV_DB;
|
|
152
|
-
delete process.env.DEV_DB;
|
|
153
|
-
const entered = await envSession.enterEnvironment(tier, {
|
|
154
|
-
override: false,
|
|
155
|
-
});
|
|
156
|
-
if (devDatabase !== undefined) {
|
|
157
|
-
// Children spawned AFTER `db start` succeeds should still inherit
|
|
158
|
-
// the session's answer; the refresh that follows a successful start
|
|
159
|
-
// re-applies the overlay under this same variable.
|
|
160
|
-
process.env.DEV_DB = devDatabase;
|
|
161
|
-
}
|
|
162
|
-
else if (inherited !== undefined) {
|
|
163
|
-
process.env.DEV_DB = inherited;
|
|
164
|
-
}
|
|
165
|
-
for (const warning of entered.warnings) {
|
|
166
|
-
process.stderr.write(`devtools: ${warning}\n`);
|
|
167
|
-
}
|
|
168
|
-
reportEntered(entered.files, tier);
|
|
169
|
-
return await dispatchCommand();
|
|
170
|
-
}
|
|
171
|
-
if (!(err instanceof envLoad.MissingEnvFileError))
|
|
172
|
-
throw err;
|
|
173
|
-
if (tier === "development") {
|
|
174
|
-
// The clean-clone path: a fresh checkout has no `.env` at all, and
|
|
175
|
-
// `pnpm devtools setup` is how one gets created — `MissingEnvFileError`
|
|
176
|
-
// names it. Reporting and continuing here, rather than refusing, is
|
|
177
|
-
// what lets `setup` itself run through this same entry point. See
|
|
178
|
-
// `load.ts`'s `MissingEnvFileError` for the message this prints.
|
|
179
|
-
process.stderr.write(`devtools: ${err.message}\n`);
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
// An EXPLICITLY selected staging/production tier with no env file is
|
|
183
|
-
// not a first run — it is a real problem, and `env pull` is the fix
|
|
184
|
-
// `MissingEnvFileError`'s own message already names. Fatal.
|
|
185
|
-
process.stderr.write(`devtools: ${err.message}\n`);
|
|
186
|
-
process.exit(1);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return await dispatchCommand();
|
|
190
|
-
}
|
|
191
|
-
let menuEnvHook;
|
|
192
|
-
/** Set by `launch.ts` for a menu invocation; `undefined` for a typed command
|
|
193
|
-
* (which entered already) and for any test that drives `runMenu` directly
|
|
194
|
-
* without going through `launch.ts` at all. */
|
|
195
|
-
export function setMenuEnvHook(hook) {
|
|
196
|
-
menuEnvHook = hook;
|
|
197
|
-
}
|
|
198
|
-
/** Read by `runMenu`, then cleared — see this module's header on why a
|
|
199
|
-
* nested launcher must not inherit a stale hook. */
|
|
200
|
-
export function takeMenuEnvHook() {
|
|
201
|
-
const hook = menuEnvHook;
|
|
202
|
-
menuEnvHook = undefined;
|
|
203
|
-
return hook;
|
|
204
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { validateSessionPoolerUrl } from "./db/pooler.js";
|
|
2
|
-
export type CheckStatus = "ok" | "warn" | "skip";
|
|
3
|
-
export interface DoctorCheck {
|
|
4
|
-
id: string;
|
|
5
|
-
status: CheckStatus;
|
|
6
|
-
summary: string;
|
|
7
|
-
/** How to fix it, when `status !== "ok"`. */
|
|
8
|
-
fix?: string;
|
|
9
|
-
faqId?: string;
|
|
10
|
-
}
|
|
11
|
-
/** The floor is 22.12: pnpm 11 needs `node:sqlite`, stable there. `.nvmrc`
|
|
12
|
-
* pins 24, which is what a `fnm use` picks up; a machine below the floor is
|
|
13
|
-
* a WARN, not an error — plenty of contributors' shells still resolve an
|
|
14
|
-
* old global `node` first. */
|
|
15
|
-
export declare function checkNodeVersion(nodeVersion: string): DoctorCheck;
|
|
16
|
-
export declare function checkFnmHookPresent(shellProfile: string | null): DoctorCheck;
|
|
17
|
-
export declare function checkPnpmVersion(pnpmVersion: string | null, pinned: string): DoctorCheck;
|
|
18
|
-
/** `git config core.autocrlf` — `input` or `false` is correct on every
|
|
19
|
-
* platform this repo documents (WSL2, native Windows, macOS, Linux); `true`
|
|
20
|
-
* rewrites LF to CRLF on checkout and breaks anything that shells out to a
|
|
21
|
-
* script with a shebang. */
|
|
22
|
-
export declare function checkAutocrlf(value: string | null): DoctorCheck;
|
|
23
|
-
/** WSL2's own filesystem, never `/mnt/c/...` — a Windows-drive checkout
|
|
24
|
-
* makes every file operation cross the 9p boundary and Docker bind mounts
|
|
25
|
-
* silently fail to see edits. */
|
|
26
|
-
export declare function checkRepoUnderMntC(repoRoot: string): DoctorCheck;
|
|
27
|
-
/** Windows only. `RemoteSigned` (or looser) is what lets fnm's PowerShell
|
|
28
|
-
* hook and pnpm's shims actually run. */
|
|
29
|
-
export declare function checkPowerShellExecutionPolicy(policy: string | null): DoctorCheck;
|
|
30
|
-
/**
|
|
31
|
-
* The checkout's development env the way every other command loads it:
|
|
32
|
-
* `.env.generated` (the local stack's connection block, written by `db
|
|
33
|
-
* start`) first and winning, then `.env`. Reading `.env` alone reported a
|
|
34
|
-
* working local-Docker checkout as missing PUBLISHABLE_KEY, and took the
|
|
35
|
-
* blank hosted template's `https://$PROJECT_REF.supabase.co` for a real
|
|
36
|
-
* hosted project that "did not respond".
|
|
37
|
-
*/
|
|
38
|
-
export declare function readCheckoutEnv(repoRoot: string): Record<string, string | undefined>;
|
|
39
|
-
export declare function checkEnvKeysPresent(env: Record<string, string | undefined>, keys: string[]): DoctorCheck;
|
|
40
|
-
export { validateSessionPoolerUrl };
|
|
41
|
-
export interface RunDoctorOptions {
|
|
42
|
-
app?: string;
|
|
43
|
-
report?: boolean;
|
|
44
|
-
}
|
|
45
|
-
export declare function runEnvironmentDoctor(opts: RunDoctorOptions): Promise<void>;
|