@devdogsuga/devtools 0.1.25 → 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/launch.js
CHANGED
|
@@ -1,294 +1,280 @@
|
|
|
1
|
+
import { a as cliName, t as installFailureLog } from "./failure-log-BBPGejQv.js";
|
|
2
|
+
import { C as catalog, S as unwrap, _ as setMenuEnvHook, d as nonEmpty, g as realEnvEntryDeps, h as enterSessionEnvironment, t as bareGroupStartPath, w as helpPath, y as errorMessage } from "./menu-CQBsQRgH.js";
|
|
3
|
+
import { b as setDryRun, m as formatCommand, v as isDryRun, y as resolveDryRun } from "./supabase-project-0knM0mqd.js";
|
|
4
|
+
import { n as discoverRepoRoot, r as findRepoRoot, t as RepoNotFoundError } from "./root-C2OmZDwD.js";
|
|
5
|
+
import { i as loadEnvSession, r as loadEnvLoad } from "./peers-RBplwovA.js";
|
|
6
|
+
import { d as hasYes, f as isNonInteractive, m as stripTierFlag, n as captureDevtoolsError, o as initDevtoolsTelemetry, p as stripNoEnvFlag, s as lastSentryEventId } from "./telemetry-C4foD8MD.js";
|
|
7
|
+
import { confirm, select } from "@clack/prompts";
|
|
8
|
+
//#region ../cli-core/src/session.ts
|
|
1
9
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
10
|
+
* Pieces of tier resolution both launchers use.
|
|
11
|
+
*/
|
|
12
|
+
/** The real interactive picker: a clack `select`, unwrapped so Ctrl-C exits
|
|
13
|
+
* cleanly instead of leaking a cancel symbol into `resolveSessionTier`.
|
|
14
|
+
* Values are session selector words (`"development:local"`, `"staging"`…). */
|
|
15
|
+
async function promptTier(message, choices) {
|
|
16
|
+
return unwrap(await select({
|
|
17
|
+
message,
|
|
18
|
+
options: choices
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The session for `--no-env`: the named tier, parsed and nothing more.
|
|
23
|
+
* `--tier` wins over `DEPLOY_ENV`, and a run that names neither is plain
|
|
24
|
+
* development.
|
|
25
|
+
*/
|
|
26
|
+
function resolveWithoutEnv(envSession, explicit) {
|
|
27
|
+
const selector = explicit ?? nonEmpty(process.env.DEPLOY_ENV) ?? "development";
|
|
28
|
+
const parsed = envSession.parseSessionSelector(selector);
|
|
29
|
+
if (parsed === null) return {
|
|
30
|
+
ok: false,
|
|
31
|
+
reason: `unknown tier "${selector}". Expected: development, ${envSession.SESSION_SELECTORS.join(", ")}.`
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
ok: true,
|
|
35
|
+
...parsed,
|
|
36
|
+
resolvedBy: "explicit"
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region ../cli-core/src/safety-gate.ts
|
|
41
|
+
/**
|
|
42
|
+
* The production and staging safety gate.
|
|
43
|
+
*
|
|
44
|
+
* devtools can reach any tier, and it cannot tell which `supabase`
|
|
45
|
+
* subcommands write, so the question is asked before ANY command runs against
|
|
46
|
+
* a hosted tier, passthroughs and presets included. This replaces the
|
|
47
|
+
* per-command confirmations `db reset`, `db migrate`, `seed production` and
|
|
48
|
+
* `cf preview` each used to carry.
|
|
49
|
+
*
|
|
50
|
+
* * production: shows the tier and project ref (never the `DB_URL`, which
|
|
51
|
+
* holds the password) and asks once, defaulting to no.
|
|
52
|
+
* * staging: the same, with milder wording.
|
|
53
|
+
* * non-interactive runs need `--yes`; without it the gate refuses instead
|
|
54
|
+
* of hanging on a prompt nobody can answer. clack's `confirm()` never
|
|
55
|
+
* resolves without a TTY, so `--yes` is checked before anything that
|
|
56
|
+
* could wait on one.
|
|
57
|
+
* * development (local or remote): no prompt.
|
|
58
|
+
*/
|
|
59
|
+
/** Set once the gate passed, so a devtools run spawned by devtools does not ask again. */
|
|
60
|
+
const GATE_PASSED_ENV = "DEVTOOLS_GATE_PASSED";
|
|
61
|
+
const HOSTED = /* @__PURE__ */ new Set(["staging", "production"]);
|
|
62
|
+
function isHostedTier(tier) {
|
|
63
|
+
return HOSTED.has(tier);
|
|
64
|
+
}
|
|
65
|
+
async function askClack(message) {
|
|
66
|
+
return unwrap(await confirm({
|
|
67
|
+
message,
|
|
68
|
+
initialValue: false
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
60
71
|
/**
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
* Decides whether a command may run against `tier`. Writes its own refusal to
|
|
73
|
+
* stderr, so the caller only has to exit non-zero on `proceed: false`.
|
|
74
|
+
*/
|
|
75
|
+
async function gateHostedTier(input) {
|
|
76
|
+
const env = input.env ?? process.env;
|
|
77
|
+
if (!isHostedTier(input.tier)) return { proceed: true };
|
|
78
|
+
if (env["DEVTOOLS_GATE_PASSED"] === input.tier) return { proceed: true };
|
|
79
|
+
const production = input.tier === "production";
|
|
80
|
+
const target = `${production ? "PRODUCTION" : "staging"} (project ${input.projectRef ?? "unknown"})`;
|
|
81
|
+
const cli = cliName();
|
|
82
|
+
const command = formatCommand(cli, input.argv);
|
|
83
|
+
if (input.yes) {
|
|
84
|
+
if (input.nonInteractive) process.stderr.write(`${cli}: running \`${command}\` against ${target}.\n`);
|
|
85
|
+
return { proceed: true };
|
|
86
|
+
}
|
|
87
|
+
if (input.nonInteractive) {
|
|
88
|
+
process.stderr.write(`${cli}: refusing to run \`${command}\` against ${target} without --yes. Nobody is here to confirm it.
|
|
89
|
+
`);
|
|
90
|
+
return {
|
|
91
|
+
proceed: false,
|
|
92
|
+
reason: "refused"
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (!await (input.ask ?? askClack)(production ? `This runs \`${command}\` against PRODUCTION, project ${input.projectRef ?? "unknown"}. It is live data. Continue?` : `This runs \`${command}\` against staging, project ${input.projectRef ?? "unknown"}. Continue?`)) {
|
|
96
|
+
process.stderr.write(`${cli}: left ${input.tier} alone.\n`);
|
|
97
|
+
return {
|
|
98
|
+
proceed: false,
|
|
99
|
+
reason: "declined"
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return { proceed: true };
|
|
84
103
|
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region ../cli-core/src/pipes.ts
|
|
85
106
|
/**
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
107
|
+
* Keeps a closed stdout/stderr from crashing devtools.
|
|
108
|
+
*
|
|
109
|
+
* When whatever reads devtools' output goes away first (`devtools … | head`,
|
|
110
|
+
* or a wrapper that stopped listening), the next write fails with EPIPE. The
|
|
111
|
+
* stream emits that as an `'error'` event nobody handles, so Node throws it as
|
|
112
|
+
* an uncaught exception and Sentry files it as a fatal. Nobody is left to read
|
|
113
|
+
* the output, so dropping it is the right outcome. Any other stream error is
|
|
114
|
+
* rethrown and crashes as it did before.
|
|
115
|
+
*
|
|
116
|
+
* Idempotent, because `launch`, `launchCi` and `ci.ts`'s `main` can all run in
|
|
117
|
+
* one process.
|
|
118
|
+
*/
|
|
119
|
+
let installed = false;
|
|
120
|
+
function ignoreClosedPipes() {
|
|
121
|
+
if (installed) return;
|
|
122
|
+
installed = true;
|
|
123
|
+
for (const stream of [process.stdout, process.stderr]) stream.on("error", (err) => {
|
|
124
|
+
if (err.code !== "EPIPE") throw err;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/launch.ts
|
|
129
|
+
/**
|
|
130
|
+
* Whether the command `rest` dispatches to is declared `envFree` in
|
|
131
|
+
* the command catalog — the leading run of non-flag tokens is the
|
|
132
|
+
* command path (`["oauth"]` out of `["oauth", "--json"]`), the same convention `stripTierFlag` already uses for
|
|
133
|
+
* pulling a flag out of argv wherever it sits.
|
|
134
|
+
*
|
|
135
|
+
* Catalog-driven rather than a second hardcoded name list: `setup` and
|
|
136
|
+
* `completions` below stay their own explicit branch (each skips tier
|
|
137
|
+
* resolution for a DIFFERENT reason worth spelling out at the call site —
|
|
138
|
+
* see the comment above), but a plain "this command touches no env at all"
|
|
139
|
+
* exemption reads once, from the same tree `--help` and the wizard already
|
|
140
|
+
* render, rather than as a name a future env-free command has to
|
|
141
|
+
* remember to add here too.
|
|
142
|
+
*/
|
|
100
143
|
function isEnvFreeCommand(rest) {
|
|
101
|
-
|
|
102
|
-
for (const arg of rest) {
|
|
103
|
-
if (arg.startsWith("-"))
|
|
104
|
-
break;
|
|
105
|
-
path.push(arg);
|
|
106
|
-
}
|
|
107
|
-
return findCommand(path)?.envFree === true;
|
|
144
|
+
return catalog.findCommand(helpPath(rest))?.envFree === true;
|
|
108
145
|
}
|
|
109
|
-
/**
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
146
|
+
/**
|
|
147
|
+
* Whether the command reads nothing but the checkout, so the session behaves
|
|
148
|
+
* as if `--no-env` was typed: development is named and no env file is
|
|
149
|
+
* looked for or complained about. The `check` commands, which CI runs on a
|
|
150
|
+
* runner that has no `.env` at all.
|
|
151
|
+
*/
|
|
152
|
+
function skipsEnvEntry(rest) {
|
|
153
|
+
return catalog.findCommand(helpPath(rest))?.noEnv === true;
|
|
154
|
+
}
|
|
155
|
+
/** The offer's stack start (`env-entry.ts` holds the TTY prompt, this holds
|
|
156
|
+
* the lifecycle command), imported lazily like the rest of the commands. */
|
|
157
|
+
async function startStack() {
|
|
158
|
+
const { runStackCommand } = await import("./stack-Bx-55oi_.js");
|
|
159
|
+
return runStackCommand("start");
|
|
114
160
|
}
|
|
115
161
|
/**
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
162
|
+
* Imports `cli.ts` and runs it, reporting a thrown rejection the same way
|
|
163
|
+
* `cli.ts`'s own top level used to before `main` became an export instead of
|
|
164
|
+
* an auto-running IIFE (see `main`'s own header). Shared by both places
|
|
165
|
+
* `launch()` hands off to it: the `--help`/`-h` bypass below, and the normal
|
|
166
|
+
* post-tier-resolution path.
|
|
167
|
+
*/
|
|
122
168
|
async function dispatch(argv) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
process.exit(1);
|
|
132
|
-
}
|
|
169
|
+
const { main } = await import("./cli-CZKkNHK5.js");
|
|
170
|
+
try {
|
|
171
|
+
await main(argv);
|
|
172
|
+
} catch (err) {
|
|
173
|
+
process.stderr.write(`devtools: ${errorMessage(err)}\n`);
|
|
174
|
+
await captureDevtoolsError(err);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
133
177
|
}
|
|
134
178
|
/**
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
// (see `bareGroupStartPath`'s own doc), so `rest.length === 0` is the only
|
|
155
|
-
// menu shape it can hit — mirroring `main()`'s own `process.stdin.isTTY ?
|
|
156
|
-
// bareGroupStartPath(argv) : null`.
|
|
157
|
-
const isMenuInvocation = rest.length === 0 ||
|
|
158
|
-
(process.stdin.isTTY === true && bareGroupStartPath(rest) !== null);
|
|
159
|
-
// `--help`/`-h` bypasses tier resolution entirely, BEFORE it can refuse.
|
|
160
|
-
// `cli.ts`'s own `main()` already answers these with no env in play (see
|
|
161
|
-
// its header comment); resolving a tier first anyway meant `pnpm devtools
|
|
162
|
-
// --help` refused outright on a machine with two-or-more tier files
|
|
163
|
-
// present — the ordinary state for anyone who has ever run `env pull` for
|
|
164
|
-
// staging or production — even though the command that would have run
|
|
165
|
-
// needs no database, credential, or `DEPLOY_ENV` at all. `bw --help` is
|
|
166
|
-
// NOT special-cased here the way `cli.ts` special-cases it ahead of its own
|
|
167
|
-
// `--help` check: `main()` still sees `bw` first and hands off to Bitwarden
|
|
168
|
-
// before ever reaching its `--help` branch, so routing straight to `main()`
|
|
169
|
-
// below reproduces that passthrough correctly either way.
|
|
170
|
-
if (rest.includes("--help") || rest.includes("-h")) {
|
|
171
|
-
await dispatch(rest);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
const envLoad = await loadEnvLoad();
|
|
175
|
-
const envSession = await loadEnvSession();
|
|
176
|
-
// Records, once, which keys THIS shell actually exported before devtools
|
|
177
|
-
// touched anything — the fix for the staleness bug `enterEnvironment`'s own
|
|
178
|
-
// `override: false` comment below describes. `Object.keys(process.env)` at
|
|
179
|
-
// this exact point is still a faithful snapshot of the calling shell: the
|
|
180
|
-
// imports above load code, not env; nothing before this line has mutated
|
|
181
|
-
// `process.env`. See `SHELL_KEYS_ENV` (`@devdogsuga/env/load`) for how
|
|
182
|
-
// `loadEnvironment` narrows "a shell var beats the file" to just this list.
|
|
183
|
-
//
|
|
184
|
-
// Guarded on absence so a NESTED devtools launcher (one `pnpm devtools`
|
|
185
|
-
// command spawning another, e.g. the `db start` offer below re-dispatching
|
|
186
|
-
// through `dispatch()`) keeps the ORIGINAL list instead of recomputing one:
|
|
187
|
-
// by the time a nested launcher's `launch()` runs, `process.env` already
|
|
188
|
-
// holds this session's entered values, not the outer shell's, and
|
|
189
|
-
// recomputing from it would misclassify every one of them as a genuine
|
|
190
|
-
// shell export — the exact bug this marker exists to prevent, one layer in.
|
|
191
|
-
process.env[envLoad.SHELL_KEYS_ENV] ??= Object.keys(process.env).join(",");
|
|
192
|
-
let tier;
|
|
193
|
-
let devDatabase;
|
|
194
|
-
if (rest[0] === "setup" ||
|
|
195
|
-
rest[0] === "completions" ||
|
|
196
|
-
isEnvFreeCommand(rest)) {
|
|
197
|
-
// Two commands run BEFORE there is a tier to resolve, and forcing the
|
|
198
|
-
// mandate on them breaks each in its own way:
|
|
199
|
-
//
|
|
200
|
-
// * `setup` exists to CREATE a missing env file. A stale
|
|
201
|
-
// `DEPLOY_ENV=staging` in the shell with no `.env.staging` on disk
|
|
202
|
-
// would resolve that tier, fail `enterEnvironment` fatally below, and
|
|
203
|
-
// lock a new contributor out of the one command that fixes their
|
|
204
|
-
// state — a bootstrap deadlock. It is development-only by nature
|
|
205
|
-
// (it writes `.env`), so the session tier question has one answer.
|
|
206
|
-
// * `completions` runs from shell rc files (`eval "$(pnpm devtools
|
|
207
|
-
// completions bash)"`), always non-TTY, and reads no env at all; the
|
|
208
|
-
// multi-tier refusal would exit 1 in every new shell on exactly the
|
|
209
|
-
// machines of the people working on the deploy workflow.
|
|
210
|
-
//
|
|
211
|
-
// A third, open-ended case joins them here via `isEnvFreeCommand`:
|
|
212
|
-
// `github rulesets` and `github settings` (TASK-322, TASK-342) touch no
|
|
213
|
-
// DevDogsUGA env file or database at all — every write either one makes
|
|
214
|
-
// is a `gh api` call resolved from its own `--org`/`--repo` flags — so
|
|
215
|
-
// demanding a `--tier` before either could run was never a real
|
|
216
|
-
// requirement, only every command sharing one dispatch gate. See
|
|
217
|
-
// `isEnvFreeCommand`'s own doc for why this is catalog-driven rather
|
|
218
|
-
// than a third name joining the `rest[0] ===` checks above.
|
|
219
|
-
//
|
|
220
|
-
// Development is still ENTERED below (missing-file tolerated), not
|
|
221
|
-
// skipped: `setup` under the old `with-env` wrapper saw whatever `.env`
|
|
222
|
-
// already existed, and keeping that means it can read current values
|
|
223
|
-
// when offering to rewrite them.
|
|
224
|
-
tier = "development";
|
|
225
|
-
}
|
|
226
|
-
else if (discoverRepoRoot() === null) {
|
|
227
|
-
// Every command past this point needs a real repo to resolve a tier
|
|
228
|
-
// against (`findRepoRoot()` below would throw `RepoNotFoundError`
|
|
229
|
-
// anyway) — surfaced here as the same clean, expected refusal every
|
|
230
|
-
// other repo-dependent command gives, rather than an uncaught throw
|
|
231
|
-
// with a stack trace pointing at internal module paths.
|
|
232
|
-
process.stderr.write(`devtools: ${new RepoNotFoundError().message}\n`);
|
|
233
|
-
process.exit(1);
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
// The `.env`-names-a-remote-database lookup (and the port probe that
|
|
237
|
-
// phrases the local hint) are only paid when the resolution could
|
|
238
|
-
// actually land on BARE development — an explicit staging/production or
|
|
239
|
-
// qualified selector, an already-deployed DEPLOY_ENV, or a DEV_DB answer
|
|
240
|
-
// all settle the question without them, and the lookup imports dotenvx.
|
|
241
|
-
const deployEnv = process.env.DEPLOY_ENV ?? "";
|
|
242
|
-
const couldBeBareDevelopment = (process.env.DEV_DB ?? "") === "" &&
|
|
243
|
-
(explicit === "development" ||
|
|
244
|
-
(explicit === undefined &&
|
|
245
|
-
(deployEnv === "" || deployEnv === "development")));
|
|
246
|
-
const remoteCandidate = couldBeBareDevelopment
|
|
247
|
-
? await envSession.developmentRemoteCandidate(findRepoRoot())
|
|
248
|
-
: undefined;
|
|
249
|
-
const localStackOnline = typeof remoteCandidate === "string"
|
|
250
|
-
? await envLoad.probeLocalStack()
|
|
251
|
-
: undefined;
|
|
252
|
-
const resolution = await envSession.resolveSessionTier({
|
|
253
|
-
explicit,
|
|
254
|
-
deployEnv: process.env.DEPLOY_ENV,
|
|
255
|
-
devDb: process.env.DEV_DB,
|
|
256
|
-
available: await envSession.availableTiers(findRepoRoot()),
|
|
257
|
-
isTTY: process.stdin.isTTY === true,
|
|
258
|
-
prompt: promptTier,
|
|
259
|
-
promptMessage: "Which environment should this session use?",
|
|
260
|
-
remoteCandidate,
|
|
261
|
-
localStackOnline,
|
|
262
|
-
});
|
|
263
|
-
if (!resolution.ok) {
|
|
264
|
-
process.stderr.write(`devtools: ${resolution.reason}\n`);
|
|
265
|
-
process.exit(1);
|
|
266
|
-
}
|
|
267
|
-
tier = resolution.tier;
|
|
268
|
-
devDatabase = resolution.devDatabase;
|
|
269
|
-
}
|
|
270
|
-
if (isMenuInvocation) {
|
|
271
|
-
// Export the decision, not the files: `DEPLOY_ENV`/`DEV_DB` name the
|
|
272
|
-
// session the same way `enterEnvironment` would set them, but loading
|
|
273
|
-
// `.env.<tier>` itself — and everything `enterSessionEnvironment` does
|
|
274
|
-
// around that, including the offline-stack offer — waits for a command to
|
|
275
|
-
// actually be chosen. See this file's header.
|
|
276
|
-
process.env.DEPLOY_ENV = tier;
|
|
277
|
-
if (devDatabase !== undefined)
|
|
278
|
-
process.env.DEV_DB = devDatabase;
|
|
279
|
-
setMenuEnvHook((commandArgv, dispatchCommand) => enterSessionEnvironment(tier, devDatabase, commandArgv, realEnvEntryDeps(envLoad, envSession), dispatchCommand));
|
|
280
|
-
await dispatch(rest);
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
// Caught here rather than left to `bin/devtools.mjs`'s `child.on("error",
|
|
284
|
-
// …)`, which only ever sees a spawn failure, never a rejection thrown
|
|
285
|
-
// inside this process.
|
|
286
|
-
await enterSessionEnvironment(tier, devDatabase, rest, realEnvEntryDeps(envLoad, envSession), () => dispatch(rest));
|
|
179
|
+
* Runs `proceed` only if the hosted-tier gate lets the command through (see
|
|
180
|
+
* `@devdogsuga/cli-core/safety-gate`). Called after the environment is
|
|
181
|
+
* entered, so the project ref it shows is the tier's own. A command the gate
|
|
182
|
+
* stops exits non-zero and returns `blocked`.
|
|
183
|
+
*/
|
|
184
|
+
async function gated(tier, commandArgv, proceed, blocked) {
|
|
185
|
+
if (isDryRun()) return proceed();
|
|
186
|
+
if (!(await gateHostedTier({
|
|
187
|
+
tier,
|
|
188
|
+
projectRef: nonEmpty(process.env.PROJECT_REF),
|
|
189
|
+
argv: commandArgv,
|
|
190
|
+
yes: hasYes(commandArgv),
|
|
191
|
+
nonInteractive: isNonInteractive()
|
|
192
|
+
})).proceed) {
|
|
193
|
+
process.exitCode = 1;
|
|
194
|
+
return blocked;
|
|
195
|
+
}
|
|
196
|
+
process.env[GATE_PASSED_ENV] = tier;
|
|
197
|
+
return proceed();
|
|
287
198
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Resolves the session's deploy tier, enters it (or defers entry to the
|
|
201
|
+
* menu — see this file's header), and hands off to `cli.ts`.
|
|
202
|
+
*
|
|
203
|
+
* Exits the process directly on a refusal from `resolveSessionTier` — there
|
|
204
|
+
* is no command dispatched yet for a caller to fall back to, so there is
|
|
205
|
+
* nothing this function could return that would mean anything.
|
|
206
|
+
*/
|
|
207
|
+
async function launch(argv) {
|
|
208
|
+
const { noEnv, rest: withoutNoEnv } = stripNoEnvFlag(argv);
|
|
209
|
+
const { explicit, rest: withoutTier } = stripTierFlag(withoutNoEnv);
|
|
210
|
+
const { dryRun, rest } = resolveDryRun(withoutTier);
|
|
211
|
+
setDryRun(dryRun);
|
|
212
|
+
installFailureLog({
|
|
213
|
+
argv,
|
|
214
|
+
eventId: lastSentryEventId
|
|
215
|
+
});
|
|
216
|
+
ignoreClosedPipes();
|
|
217
|
+
initDevtoolsTelemetry(rest[0] ?? "menu");
|
|
218
|
+
const isMenuInvocation = rest.length === 0 || process.stdin.isTTY === true && bareGroupStartPath(catalog, rest) !== null;
|
|
219
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
220
|
+
await dispatch(rest);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (rest[0] === "version") {
|
|
224
|
+
await dispatch(rest);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const envLoad = await loadEnvLoad();
|
|
228
|
+
const envSession = await loadEnvSession();
|
|
229
|
+
process.env[envLoad.SHELL_KEYS_ENV] ??= Object.keys(process.env).join(",");
|
|
230
|
+
let tier;
|
|
231
|
+
let devDatabase;
|
|
232
|
+
if (rest[0] === "setup" || rest[0] === "completions" || isEnvFreeCommand(rest)) tier = "development";
|
|
233
|
+
else if (discoverRepoRoot() === null) {
|
|
234
|
+
process.stderr.write(`devtools: ${new RepoNotFoundError().message}\n`);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
} else {
|
|
237
|
+
if (isNonInteractive() && rest.length > 0 && explicit === void 0 && !process.env.DEPLOY_ENV && !process.env.DEV_DB) {
|
|
238
|
+
process.stderr.write("devtools: no tier named. With no terminal (or CI=true) the tier must be explicit: pass --tier <development:local|development:remote|staging|production> or set DEPLOY_ENV.\n");
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
const deployEnv = process.env.DEPLOY_ENV ?? "";
|
|
242
|
+
const remoteCandidate = !noEnv && (process.env.DEV_DB ?? "") === "" && (explicit === "development" || explicit === void 0 && (deployEnv === "" || deployEnv === "development")) ? await envSession.developmentRemoteCandidate(findRepoRoot()) : void 0;
|
|
243
|
+
const localStackOnline = typeof remoteCandidate === "string" ? await envLoad.probeLocalStack() : void 0;
|
|
244
|
+
const resolution = noEnv ? resolveWithoutEnv(envSession, explicit) : await envSession.resolveSessionTier({
|
|
245
|
+
explicit,
|
|
246
|
+
deployEnv: process.env.DEPLOY_ENV,
|
|
247
|
+
devDb: process.env.DEV_DB,
|
|
248
|
+
available: await envSession.availableTiers(findRepoRoot()),
|
|
249
|
+
isTTY: process.stdin.isTTY === true,
|
|
250
|
+
prompt: promptTier,
|
|
251
|
+
promptMessage: "Which environment should this session use?",
|
|
252
|
+
remoteCandidate,
|
|
253
|
+
localStackOnline
|
|
254
|
+
});
|
|
255
|
+
if (!resolution.ok) {
|
|
256
|
+
process.stderr.write(`devtools: ${resolution.reason}\n`);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
259
|
+
tier = resolution.tier;
|
|
260
|
+
devDatabase = resolution.devDatabase;
|
|
261
|
+
}
|
|
262
|
+
if (isMenuInvocation) {
|
|
263
|
+
process.env.DEPLOY_ENV = tier;
|
|
264
|
+
if (devDatabase !== void 0) process.env.DEV_DB = devDatabase;
|
|
265
|
+
setMenuEnvHook((commandArgv, dispatchCommand) => enterSessionEnvironment(tier, devDatabase, commandArgv, realEnvEntryDeps(envLoad, envSession, startStack), () => gated(tier, commandArgv, dispatchCommand, null)));
|
|
266
|
+
await dispatch(rest);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const run = () => gated(tier, rest, () => dispatch(rest), void 0);
|
|
270
|
+
if (noEnv || skipsEnvEntry(rest)) {
|
|
271
|
+
process.env.DEPLOY_ENV = tier;
|
|
272
|
+
if (devDatabase !== void 0) process.env.DEV_DB = devDatabase;
|
|
273
|
+
await run();
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
await enterSessionEnvironment(tier, devDatabase, rest, realEnvEntryDeps(envLoad, envSession, startStack), run);
|
|
294
277
|
}
|
|
278
|
+
if (import.meta.url === `file://${process.argv[1]}`) await launch(process.argv.slice(2));
|
|
279
|
+
//#endregion
|
|
280
|
+
export { launch, stripTierFlag };
|