@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/stack.js
DELETED
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Database commands, over the session's database.
|
|
3
|
-
*
|
|
4
|
-
* Previously delegated to `@devdogsuga/supabase` package scripts by name,
|
|
5
|
-
* then to a `--target local|remote` flag; now every data command acts on the
|
|
6
|
-
* ONE database the session entered (see `db/connection.ts`), passed to the
|
|
7
|
-
* supabase CLI as an explicit `--db-url`. That uniformity is load-bearing:
|
|
8
|
-
* the CLI's own defaults disagree per subcommand (`db push` defaults to the
|
|
9
|
-
* LINKED project, `db reset` to `--local`), and `--db-url` is the one
|
|
10
|
-
* spelling that can neither fall back to `supabase link`'s ambient state
|
|
11
|
-
* nor quietly pick a different database than the session says.
|
|
12
|
-
*
|
|
13
|
-
* The stack-lifecycle commands (`start`/`stop`/`restart`) are the deliberate
|
|
14
|
-
* exception: they act on this machine's Docker containers, which no DB_URL
|
|
15
|
-
* names, and they run under any session — starting your local stack while
|
|
16
|
-
* the session targets staging is odd but harmless, and refusing it would
|
|
17
|
-
* block the one command that fixes an offline-local session.
|
|
18
|
-
*/
|
|
19
|
-
import { existsSync, rmSync } from "node:fs";
|
|
20
|
-
import { writeFile } from "node:fs/promises";
|
|
21
|
-
import { join } from "node:path";
|
|
22
|
-
import { describeEnvironment, probeEnvironment } from "./environment.js";
|
|
23
|
-
import { findRepoRoot } from "./repo/root.js";
|
|
24
|
-
import { foreignStackMessage, foreignStackProjectId, listContainerNames, STACK_API_PORT, readProjectId, } from "./repo/supabase-project.js";
|
|
25
|
-
import { dbPush, generateTypes, seedBuckets, supabase, supabaseCapture, } from "./db/run.js";
|
|
26
|
-
import { describeDbTarget, isLocalConnection, } from "./db/connection.js";
|
|
27
|
-
import { refreshSessionEnv } from "./db/session-refresh.js";
|
|
28
|
-
import { runSeedProduction } from "./db/seed-production.js";
|
|
29
|
-
import { originReachable, resolveBaseUrl } from "./cron/commands.js";
|
|
30
|
-
import { ensureGeneratedEnvFile, realEnsureGeneratedEnvDeps, } from "./db/generated-env.js";
|
|
31
|
-
import { loadEnvLoad } from "./repo/peers.js";
|
|
32
|
-
// Scope order, matching `db`'s subcommands in `commands.ts`: the four that
|
|
33
|
-
// act on the Supabase stack (`connect` is handled separately below — it
|
|
34
|
-
// takes a positional ref), then the two that write the Postgres database
|
|
35
|
-
// inside the session's endpoint.
|
|
36
|
-
export const STACK_COMMANDS = [
|
|
37
|
-
"start",
|
|
38
|
-
"stop",
|
|
39
|
-
"restart",
|
|
40
|
-
"status",
|
|
41
|
-
"migrate",
|
|
42
|
-
"reset",
|
|
43
|
-
];
|
|
44
|
-
// ── Implementations ──────────────────────────────────────────────────────────
|
|
45
|
-
/**
|
|
46
|
-
* A running Docker container whose name says it belongs to a DIFFERENT
|
|
47
|
-
* Supabase project than this checkout's own `config.toml` — the signature
|
|
48
|
-
* of a foreign stack holding the shared ports (see
|
|
49
|
-
* `repo/supabase-project.ts`'s header). `undefined` when nothing points
|
|
50
|
-
* that way, including when Docker or `config.toml` could not be read at
|
|
51
|
-
* all: with no signal either way, `startLocalStack`'s own failure and the
|
|
52
|
-
* Supabase CLI's own output are still the reader's best explanation.
|
|
53
|
-
*/
|
|
54
|
-
function foreignStackHint() {
|
|
55
|
-
const names = listContainerNames(STACK_API_PORT);
|
|
56
|
-
if (names === null)
|
|
57
|
-
return undefined;
|
|
58
|
-
const foreign = foreignStackProjectId(names, readProjectId(findRepoRoot()));
|
|
59
|
-
return foreign === null ? undefined : foreignStackMessage(foreign);
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* `wroteEnvFile` is split out from `code` on purpose: `.env.generated` is
|
|
63
|
-
* written to disk BEFORE `seedBuckets` runs, so a nonzero `code` from
|
|
64
|
-
* `seedBuckets` alone does not mean the file on disk is unchanged — the
|
|
65
|
-
* fresh connection block is already there, a later `db start` retry or the
|
|
66
|
-
* probe table would already see it, and this process's OWN entered
|
|
67
|
-
* environment is now the stale one. `afterLocalStackChange` below refreshes
|
|
68
|
-
* whenever the file changed, independently of whether the command as a whole
|
|
69
|
-
* succeeded, and still reports the failing code so the caller does not
|
|
70
|
-
* mistake a seed failure for success.
|
|
71
|
-
*
|
|
72
|
-
* `hint` is set when `supabase start` itself fails (before anything here
|
|
73
|
-
* could have written `.env.generated`) AND a foreign project's stack is
|
|
74
|
-
* holding the ports — the same signal `db/generated-env.ts` surfaces for a
|
|
75
|
-
* failed `supabase status -o env`, named here too so `db start` explains
|
|
76
|
-
* itself instead of leaving only the bare Supabase CLI error.
|
|
77
|
-
*/
|
|
78
|
-
async function startLocalStack() {
|
|
79
|
-
const code = await supabase("start");
|
|
80
|
-
if (code !== 0) {
|
|
81
|
-
const hint = foreignStackHint();
|
|
82
|
-
return hint === undefined
|
|
83
|
-
? { code, wroteEnvFile: false }
|
|
84
|
-
: { code, wroteEnvFile: false, hint };
|
|
85
|
-
}
|
|
86
|
-
// Write the local stack's connection details so with-env can load them.
|
|
87
|
-
let env;
|
|
88
|
-
try {
|
|
89
|
-
env = await supabaseCapture("status", "-o", "env");
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
return { code: 1, wroteEnvFile: false };
|
|
93
|
-
}
|
|
94
|
-
await writeFile(join(findRepoRoot(), ".env.generated"), env);
|
|
95
|
-
const bucketsCode = await seedBuckets({ kind: "local" });
|
|
96
|
-
return { code: bucketsCode, wroteEnvFile: true };
|
|
97
|
-
}
|
|
98
|
-
async function stopLocalStack() {
|
|
99
|
-
const code = await supabase("stop");
|
|
100
|
-
if (code !== 0)
|
|
101
|
-
return code;
|
|
102
|
-
rmSync(join(findRepoRoot(), ".env.generated"), { force: true });
|
|
103
|
-
return 0;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* `db connect [<project-ref>]` — run `supabase link` for whoever drives the
|
|
107
|
-
* bare supabase CLI by hand. Nothing in devtools reads what it writes any
|
|
108
|
-
* more (see `db/connection.ts`'s header); it survives as a convenience, not
|
|
109
|
-
* a dependency.
|
|
110
|
-
*/
|
|
111
|
-
export async function connectRemoteProject(ref) {
|
|
112
|
-
const projectRef = ref ?? process.env.PROJECT_REF;
|
|
113
|
-
if (!projectRef) {
|
|
114
|
-
process.stderr.write("devtools db connect: no project ref given, and PROJECT_REF is not set. " +
|
|
115
|
-
"Pass one, or add PROJECT_REF to your .env file.\n");
|
|
116
|
-
return 1;
|
|
117
|
-
}
|
|
118
|
-
return supabase("link", "--project-ref", projectRef);
|
|
119
|
-
}
|
|
120
|
-
/** The `seed buckets` shape this connection implies — `--db-url` does not
|
|
121
|
-
* exist for that subcommand, so it is the one data command still keyed on
|
|
122
|
-
* local-vs-hosted rather than on the URL itself. */
|
|
123
|
-
function bucketsShape(connection) {
|
|
124
|
-
return isLocalConnection(connection)
|
|
125
|
-
? { kind: "local" }
|
|
126
|
-
: { kind: "remote", projectRef: connection.projectRef };
|
|
127
|
-
}
|
|
128
|
-
async function pushMigrations(connection) {
|
|
129
|
-
// The bare push (shared with CI's `deploy migrate`) then the type
|
|
130
|
-
// regeneration the contributor path layers on top — see `dbPush`'s header
|
|
131
|
-
// for why the two are split.
|
|
132
|
-
const code = await dbPush(connection.dbUrl);
|
|
133
|
-
if (code !== 0)
|
|
134
|
-
return code;
|
|
135
|
-
return generateTypes(connection.dbUrl);
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* ⚠️ SAFETY-CRITICAL: drops and re-migrates `connection.dbUrl`. The caller
|
|
139
|
-
* (`cli.ts`'s `runStack`) has already confirmed the session target —
|
|
140
|
-
* including the hard production gate — before this ever runs.
|
|
141
|
-
*
|
|
142
|
-
* A non-development target gets `--no-seed` on the reset itself, followed by
|
|
143
|
-
* an explicit `runSeedProduction` — the same two steps `db seed production`
|
|
144
|
-
* runs on its own (see `seed-production.ts`) — rather than letting the bare
|
|
145
|
-
* `supabase db reset` apply whatever `config.toml`'s `[db.seed]` happens to
|
|
146
|
-
* list. That is deliberately belt-and-suspenders: `[db.seed]` today lists
|
|
147
|
-
* only `supabase/seed/production`, so the bare reset would already do the
|
|
148
|
-
* right thing, but that is a property of the CURRENT config, not of this
|
|
149
|
-
* function. An older checkout, or a config edited to add
|
|
150
|
-
* `supabase/seed/development` back for some local-only reason, must still be
|
|
151
|
-
* structurally unable to run development's password-login seeds against a
|
|
152
|
-
* hosted, non-dev database — the one seed directory that must never reach
|
|
153
|
-
* staging or production, named in that directory's own header. Development
|
|
154
|
-
* resets are untouched: they keep applying whatever `[db.seed]` lists, same
|
|
155
|
-
* as always.
|
|
156
|
-
*
|
|
157
|
-
* Meetings and workshops are NOT among the tables `supabase/seed/*.sql`
|
|
158
|
-
* populates -- they come from `@devdogsuga/events` via
|
|
159
|
-
* `reconcileFromConfig`, an authenticated platform route rather than a
|
|
160
|
-
* devtools-side function this CLI can call directly (it needs the app's
|
|
161
|
-
* Drizzle client, relations and Sentry wiring, none of which belong in this
|
|
162
|
-
* package). On any DEVELOPMENT reset -- local Docker or the shared remote dev
|
|
163
|
-
* project alike -- this calls that route itself, over the same origin `cron
|
|
164
|
-
* run` would use, once the reset and rebuild finish -- see
|
|
165
|
-
* `reconcileConfigAfterReset` for what happens when nothing is listening yet.
|
|
166
|
-
*/
|
|
167
|
-
async function reset(connection) {
|
|
168
|
-
const isDev = connection.tier === "development";
|
|
169
|
-
const code = await supabase("db", "reset", "--db-url", connection.dbUrl, ...(isDev ? [] : ["--no-seed"]));
|
|
170
|
-
if (code !== 0)
|
|
171
|
-
return { code, lines: [] };
|
|
172
|
-
const types = await generateTypes(connection.dbUrl);
|
|
173
|
-
if (types !== 0)
|
|
174
|
-
return { code: types, lines: [] };
|
|
175
|
-
const bucketsCode = await seedBuckets(bucketsShape(connection));
|
|
176
|
-
if (bucketsCode !== 0)
|
|
177
|
-
return { code: bucketsCode, lines: [] };
|
|
178
|
-
if (!isDev) {
|
|
179
|
-
const seedCode = await runSeedProduction(connection.dbUrl);
|
|
180
|
-
if (seedCode !== 0)
|
|
181
|
-
return { code: seedCode, lines: [] };
|
|
182
|
-
return { code: 0, lines: [] };
|
|
183
|
-
}
|
|
184
|
-
return {
|
|
185
|
-
code: 0,
|
|
186
|
-
// Both development databases — local Docker and the shared remote dev
|
|
187
|
-
// project (`--tier development:remote`) — rather than gated on
|
|
188
|
-
// `isLocalConnection`. The platform dev server this hits is always local
|
|
189
|
-
// (`resolveBaseUrl("platform", "development", …)` inside
|
|
190
|
-
// `reconcileConfigAfterReset`); what varies with `devDatabase` is only
|
|
191
|
-
// which Postgres that local server happens to be pointed at, and a
|
|
192
|
-
// remote-dev reset leaves meetings and workshops just as unseeded as a
|
|
193
|
-
// local one.
|
|
194
|
-
lines: await reconcileConfigAfterReset(),
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Best-effort trigger for `GET /cron/config-reconcile` against the local
|
|
199
|
-
* platform dev server, so `db reset` leaves meetings and workshops seeded
|
|
200
|
-
* whenever that server happens to already be up -- the common case for a
|
|
201
|
-
* repeat reset during development, rather than a first clone. No
|
|
202
|
-
* `CRON_SECRET` is sent because the route itself skips auth outside a
|
|
203
|
-
* deployed `DEPLOY_ENV` (see that route's header); this is exactly the
|
|
204
|
-
* unauthenticated local request `cron run` would send.
|
|
205
|
-
*
|
|
206
|
-
* When nothing answers yet -- most likely a first-time reset, before anyone
|
|
207
|
-
* has run `pnpm --filter platform dev` -- this reports that instead of
|
|
208
|
-
* silently leaving the tables empty, and names the manual step: start the
|
|
209
|
-
* server, then either re-run this reset or fire the shared fifteen-minute
|
|
210
|
-
* cron slot directly with `pnpm devtools cron run`.
|
|
211
|
-
*/
|
|
212
|
-
export async function reconcileConfigAfterReset(deps = {
|
|
213
|
-
reachable: originReachable,
|
|
214
|
-
fetch: globalThis.fetch,
|
|
215
|
-
}) {
|
|
216
|
-
const { reachable, fetch: fetchImpl } = deps;
|
|
217
|
-
const baseUrl = resolveBaseUrl("platform", "development", undefined, {});
|
|
218
|
-
const manualStep = "Start the platform app (`pnpm --filter platform dev`) and either " +
|
|
219
|
-
"re-run `pnpm devtools db reset` or run `pnpm devtools cron run --app " +
|
|
220
|
-
"platform --cron '*/15 * * * *' --yes`.";
|
|
221
|
-
if (!(await reachable(baseUrl))) {
|
|
222
|
-
return [
|
|
223
|
-
`Meetings and workshops are not seeded yet -- nothing is listening at ${baseUrl} ` +
|
|
224
|
-
`to reconcile @devdogsuga/events into them. ${manualStep}`,
|
|
225
|
-
];
|
|
226
|
-
}
|
|
227
|
-
const url = new URL("/cron/config-reconcile", baseUrl).toString();
|
|
228
|
-
let response;
|
|
229
|
-
try {
|
|
230
|
-
response = await fetchImpl(url);
|
|
231
|
-
}
|
|
232
|
-
catch (err) {
|
|
233
|
-
return [
|
|
234
|
-
`Config reconcile request to ${url} failed: ` +
|
|
235
|
-
`${err instanceof Error ? err.message : String(err)}. ${manualStep}`,
|
|
236
|
-
];
|
|
237
|
-
}
|
|
238
|
-
if (!response.ok) {
|
|
239
|
-
return [
|
|
240
|
-
`Config reconcile answered HTTP ${response.status} at ${url}. ${manualStep}`,
|
|
241
|
-
];
|
|
242
|
-
}
|
|
243
|
-
const body = (await response.json());
|
|
244
|
-
if (!body.success) {
|
|
245
|
-
return [
|
|
246
|
-
`Config reconcile ran but was aborted (${body.reason}) -- meetings and ` +
|
|
247
|
-
"workshops are still empty. Check the platform dev server's console.",
|
|
248
|
-
];
|
|
249
|
-
}
|
|
250
|
-
return ["Meetings and workshops reconciled from @devdogsuga/events."];
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* BUG 2's fix, applied at every point `start`/`stop`/`restart` can change
|
|
254
|
-
* `.env.generated`: on success, refresh this process's entered environment
|
|
255
|
-
* (see `db/session-refresh.ts`) so the rest of the session — including a
|
|
256
|
-
* `db introspect` run right after this one — sees the stack's CURRENT
|
|
257
|
-
* connection, not whatever `process.env` held at launch. A failed stack
|
|
258
|
-
* command USUALLY changed nothing on disk, so by default there is nothing to
|
|
259
|
-
* refresh.
|
|
260
|
-
*
|
|
261
|
-
* `wroteEnvFile` is the one exception: `startLocalStack` writes
|
|
262
|
-
* `.env.generated` BEFORE the buckets-seed step that can still fail
|
|
263
|
-
* afterwards, so a nonzero `code` from THAT failure does not mean the file on
|
|
264
|
-
* disk is unchanged — see `startLocalStack`'s own doc. Passing `true` here
|
|
265
|
-
* refreshes regardless of `code`, while the failing code itself still reaches
|
|
266
|
-
* the caller untouched, so `db start` is still reported as failed even though
|
|
267
|
-
* the session's environment was brought current.
|
|
268
|
-
*/
|
|
269
|
-
async function afterLocalStackChange(code, wroteEnvFile = false) {
|
|
270
|
-
if (code !== 0 && !wroteEnvFile)
|
|
271
|
-
return [];
|
|
272
|
-
return refreshSessionEnv();
|
|
273
|
-
}
|
|
274
|
-
// ── The local stack's lifecycle ──────────────────────────────────────────────
|
|
275
|
-
/**
|
|
276
|
-
* Stop, then start again.
|
|
277
|
-
*
|
|
278
|
-
* Two steps rather than one, because `supabase restart` does not exist. The
|
|
279
|
-
* CLI's own answer to a changed `config.toml` is a stop/start pair. Doing it
|
|
280
|
-
* here turns that into one menu entry, rather than two commands the contributor
|
|
281
|
-
* has to know to run in that order.
|
|
282
|
-
*
|
|
283
|
-
* A failed stop short-circuits. Starting a stack that never went down would
|
|
284
|
-
* report success and leave the config change unapplied, which is the one
|
|
285
|
-
* outcome worse than a visible failure.
|
|
286
|
-
*/
|
|
287
|
-
async function restartLocal() {
|
|
288
|
-
const stopCode = await stopLocalStack();
|
|
289
|
-
if (stopCode !== 0) {
|
|
290
|
-
return {
|
|
291
|
-
code: stopCode,
|
|
292
|
-
lines: [
|
|
293
|
-
"Stopping failed, so nothing was restarted. " +
|
|
294
|
-
"Scroll up for the output from the Supabase CLI.",
|
|
295
|
-
],
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
const { code, wroteEnvFile, hint } = await startLocalStack();
|
|
299
|
-
const lines = await afterLocalStackChange(code, wroteEnvFile);
|
|
300
|
-
return { code, lines: hint === undefined ? lines : [hint, ...lines] };
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* What `status` says for a local session, now that it can answer for itself.
|
|
304
|
-
*
|
|
305
|
-
* `environment.ts` already reads the two facts that question is really
|
|
306
|
-
* asking about, so this reports them and names the next step. When the
|
|
307
|
-
* stack's containers are up but this checkout's own `.env.generated` is
|
|
308
|
-
* missing — most often a stack another workspace started, sharing this
|
|
309
|
-
* repo's `project_id` — this also attempts the same regeneration
|
|
310
|
-
* `enterSessionEnvironment` (`env-entry.ts`) runs before every command, so
|
|
311
|
-
* `db status` reports the file's ACTUAL state after trying to fix it,
|
|
312
|
-
* rather than a stale "the stack is up" that leaves the absence a mystery.
|
|
313
|
-
*/
|
|
314
|
-
async function localStatus() {
|
|
315
|
-
const env = probeEnvironment();
|
|
316
|
-
const lines = [describeEnvironment(env)];
|
|
317
|
-
if (env.docker === "no") {
|
|
318
|
-
lines.push("Start Docker, then `pnpm devtools db start` to bring the stack up.");
|
|
319
|
-
return { code: 0, lines };
|
|
320
|
-
}
|
|
321
|
-
if (env.stack === "no") {
|
|
322
|
-
lines.push("Nothing is running. `pnpm devtools db start` starts it.");
|
|
323
|
-
return { code: 0, lines };
|
|
324
|
-
}
|
|
325
|
-
if (env.stack === "unknown") {
|
|
326
|
-
lines.push("Could not read Docker. `supabase status` asks the stack directly.");
|
|
327
|
-
return { code: 0, lines };
|
|
328
|
-
}
|
|
329
|
-
// env.stack === "yes"
|
|
330
|
-
const repoRoot = findRepoRoot();
|
|
331
|
-
if (existsSync(join(repoRoot, ".env.generated"))) {
|
|
332
|
-
lines.push("The stack is up. `supabase status` prints its URLs and keys.");
|
|
333
|
-
return { code: 0, lines };
|
|
334
|
-
}
|
|
335
|
-
const envLoad = await loadEnvLoad();
|
|
336
|
-
const generated = await ensureGeneratedEnvFile("development", undefined, realEnsureGeneratedEnvDeps(envLoad.probeLocalStack));
|
|
337
|
-
if (generated.outcome === "wrote") {
|
|
338
|
-
lines.push(generated.line.replace(/^devtools: /, ""), "The stack is up. `supabase status` prints its URLs and keys.");
|
|
339
|
-
}
|
|
340
|
-
else if (generated.outcome === "foreign") {
|
|
341
|
-
lines.push(generated.line.replace(/^devtools: /, ""));
|
|
342
|
-
}
|
|
343
|
-
else if (generated.outcome === "unreachable") {
|
|
344
|
-
lines.push("The stack's containers are up but .env.generated could not be " +
|
|
345
|
-
"regenerated — run `supabase status -o env` yourself to see why.");
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
348
|
-
// "skipped": Docker's container list said the stack is up, but nothing
|
|
349
|
-
// answered the port probe — a race right after `db start`/`db restart`,
|
|
350
|
-
// most likely. Nothing to regenerate from yet.
|
|
351
|
-
lines.push("Docker reports the stack's containers running, but nothing is " +
|
|
352
|
-
"answering on 127.0.0.1:54321 yet — try again in a moment.");
|
|
353
|
-
}
|
|
354
|
-
return { code: 0, lines };
|
|
355
|
-
}
|
|
356
|
-
/**
|
|
357
|
-
* Runs a stack command, returning its exit code and anything to report.
|
|
358
|
-
*
|
|
359
|
-
* `connection` is present exactly when the command writes the database
|
|
360
|
-
* (`migrate`, `reset`) — the caller (`cli.ts`'s `runStack`) resolves it,
|
|
361
|
-
* because resolving means possibly refusing with a printed reason, and the
|
|
362
|
-
* lifecycle commands must keep working with no resolvable database at all
|
|
363
|
-
* (that is what `db start` is FOR). `status` receives whatever resolved,
|
|
364
|
-
* or `null`, and degrades to machine facts.
|
|
365
|
-
*/
|
|
366
|
-
export async function runStackCommand(command, connection) {
|
|
367
|
-
if (command === "restart")
|
|
368
|
-
return restartLocal();
|
|
369
|
-
if (command === "stop") {
|
|
370
|
-
const code = await stopLocalStack();
|
|
371
|
-
return { code, lines: await afterLocalStackChange(code) };
|
|
372
|
-
}
|
|
373
|
-
if (command === "start") {
|
|
374
|
-
const { code, wroteEnvFile, hint } = await startLocalStack();
|
|
375
|
-
const lines = await afterLocalStackChange(code, wroteEnvFile);
|
|
376
|
-
return { code, lines: hint === undefined ? lines : [hint, ...lines] };
|
|
377
|
-
}
|
|
378
|
-
if (command === "status") {
|
|
379
|
-
if (connection === null || isLocalConnection(connection)) {
|
|
380
|
-
return localStatus();
|
|
381
|
-
}
|
|
382
|
-
return {
|
|
383
|
-
code: 0,
|
|
384
|
-
lines: [
|
|
385
|
-
`This session targets ${describeDbTarget(connection)}` +
|
|
386
|
-
(connection.projectRef
|
|
387
|
-
? ` (project ${connection.projectRef}).`
|
|
388
|
-
: ".") +
|
|
389
|
-
" Check the Supabase dashboard for its health.",
|
|
390
|
-
],
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
if (connection === null) {
|
|
394
|
-
return {
|
|
395
|
-
code: 1,
|
|
396
|
-
lines: [`No database connection was resolved for \`${command}\`.`],
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
if (command === "migrate") {
|
|
400
|
-
return { code: await pushMigrations(connection), lines: [] };
|
|
401
|
-
}
|
|
402
|
-
return reset(connection);
|
|
403
|
-
}
|
package/dist/telemetry.d.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/** The run-time `DEVTOOLS_SENTRY_DSN` if set, else the baked one. */
|
|
2
|
-
export declare function resolveDevtoolsDsn(env: NodeJS.ProcessEnv, baked: string): string;
|
|
3
|
-
/**
|
|
4
|
-
* `'ci'` in every GitHub Actions job (`CI` is set by the runner itself,
|
|
5
|
-
* before any workflow-authored env), `'local'` on a contributor's machine.
|
|
6
|
-
* One of `@devdogsuga/telemetry`'s `ENVIRONMENTS`.
|
|
7
|
-
*/
|
|
8
|
-
export declare function devtoolsEnvironment(): "ci" | "local";
|
|
9
|
-
/**
|
|
10
|
-
* `DEVTOOLS_TELEMETRY=0` (any other value, including unset, leaves reporting
|
|
11
|
-
* on) is the only opt-out. Checked by both `initDevtoolsTelemetry` (skips
|
|
12
|
-
* `Sentry.init` outright) and `captureDevtoolsError` (so setting it mid-run,
|
|
13
|
-
* or between two invocations in the same process, still works).
|
|
14
|
-
*/
|
|
15
|
-
export declare function devtoolsTelemetryEnabled(): boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Whether anyone is actually using devtools in this process. Package-registry
|
|
18
|
-
* scanners install every published version within minutes and run it in a
|
|
19
|
-
* throwaway sandbox (random `DESKTOP-xxxxxx` hosts, Firecracker VMs, a fuzzer
|
|
20
|
-
* that turns `process.exit` into a throw). Left unfiltered, each release filed
|
|
21
|
-
* the same two issues from them. They run with no DevDogsUGA checkout and no
|
|
22
|
-
* terminal. A person has at least one of the two (`setup` runs outside a
|
|
23
|
-
* checkout, but in a terminal), and CI always has a checkout.
|
|
24
|
-
*/
|
|
25
|
-
export declare function hasRealCaller(inRepo: boolean, isTTY: boolean): boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Initializes `@sentry/node` for this CLI process. Safe to call more than
|
|
28
|
-
* once (idempotent) and safe to call with no DSN configured (no-ops via
|
|
29
|
-
* `buildSentryOptions`, see its header).
|
|
30
|
-
*
|
|
31
|
-
* `command` becomes a `command` tag on every event this process reports, so
|
|
32
|
-
* an issue in Sentry names the subcommand it came from (`db reset`,
|
|
33
|
-
* `deploy platform`, …) without anyone opening the job log first.
|
|
34
|
-
*/
|
|
35
|
-
export declare function initDevtoolsTelemetry(command: string): void;
|
|
36
|
-
/**
|
|
37
|
-
* Reports an error nothing below the entry points caught — `launch.ts`'s
|
|
38
|
-
* `dispatch`, `launch-ci.ts`, and the bins — then flushes before the process
|
|
39
|
-
* exits. Node's event loop dies with `process.exit`, taking any in-flight
|
|
40
|
-
* request to Sentry's ingest endpoint with it, so the flush must be awaited
|
|
41
|
-
* BEFORE that call — never after.
|
|
42
|
-
*
|
|
43
|
-
* A short timeout: a CLI exiting on error should not hang perceptibly longer
|
|
44
|
-
* because Sentry's ingest is slow or unreachable.
|
|
45
|
-
*/
|
|
46
|
-
export declare function captureDevtoolsError(err: unknown): Promise<void>;
|
|
47
|
-
/**
|
|
48
|
-
* Reports an error a command caught and explained to the reader itself
|
|
49
|
-
* (`explainError` in `ui.ts`, `devtools-ci deploy`'s catch), then carried on
|
|
50
|
-
* to a normal exit. Not flushed: the SDK's in-flight request keeps the event
|
|
51
|
-
* loop alive until it lands, so a natural exit waits for it on its own. A
|
|
52
|
-
* path that ends in `process.exit` instead must use `captureDevtoolsError`.
|
|
53
|
-
*/
|
|
54
|
-
export declare function reportDevtoolsError(err: unknown): void;
|
|
55
|
-
/**
|
|
56
|
-
* Reports a failure that has no error object — a subprocess or deploy step
|
|
57
|
-
* that exited non-zero. Same no-flush contract as `reportDevtoolsError`.
|
|
58
|
-
*/
|
|
59
|
-
export declare function reportDevtoolsFailure(message: string, extra?: Record<string, unknown>): void;
|
package/dist/tier.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { DeployEnvironment } from "@devdogsuga/env";
|
|
2
|
-
interface ResolveTierOptions {
|
|
3
|
-
/** Stderr prefix, e.g. "devtools cf preview". */
|
|
4
|
-
label?: string;
|
|
5
|
-
/** Injectable for tests; defaults to the repo's `availableTiers()`. */
|
|
6
|
-
available?: DeployEnvironment[];
|
|
7
|
-
/**
|
|
8
|
-
* The tier the process has already ENTERED, honoured when no explicit tier
|
|
9
|
-
* was passed. Injectable for tests; defaults to `process.env.DEPLOY_ENV`.
|
|
10
|
-
*
|
|
11
|
-
* The wizard enters a tier once, up front (see `menu.ts`), by loading its
|
|
12
|
-
* env and setting `DEPLOY_ENV`; a `DEPLOY_ENV=staging pnpm devtools …` on
|
|
13
|
-
* the command line does the same. Either way a command that resolves its own
|
|
14
|
-
* tier should use that answer rather than ask a question already settled for
|
|
15
|
-
* the whole session.
|
|
16
|
-
*/
|
|
17
|
-
deployEnv?: string;
|
|
18
|
-
/** Injectable for tests; defaults to `process.stdin.isTTY`. */
|
|
19
|
-
isTTY?: boolean;
|
|
20
|
-
/** Injectable for tests; defaults to a clack `select` wrapped in `unwrap`. */
|
|
21
|
-
prompt?: (message: string, choices: {
|
|
22
|
-
value: DeployEnvironment;
|
|
23
|
-
label: string;
|
|
24
|
-
hint?: string;
|
|
25
|
-
}[]) => Promise<DeployEnvironment>;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* The deploy tier a command runs under when `--tier` was not passed.
|
|
29
|
-
*
|
|
30
|
-
* Prompts ONLY when more than one deploy tier's file is present — the
|
|
31
|
-
* handful of contributors working on the deploy workflow — so that everyone
|
|
32
|
-
* else (just development, possibly with `.env.generated` from a running
|
|
33
|
-
* local stack) falls straight through to development with no prompt at all.
|
|
34
|
-
*
|
|
35
|
-
* Returns `null` after reporting an error on stderr — an invalid `--tier`, or
|
|
36
|
-
* an interactive pick of a tier whose file is missing — so the caller can
|
|
37
|
-
* exit nonzero without printing a second message of its own.
|
|
38
|
-
*/
|
|
39
|
-
export declare function resolveTier(given: string | undefined, message: string, opts?: ResolveTierOptions): Promise<DeployEnvironment | null>;
|
|
40
|
-
export {};
|
package/dist/tier.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The shared `--tier` resolver for the handful of commands that pick a
|
|
3
|
-
* deploy tier of their OWN, separate from the session-wide tier
|
|
4
|
-
* `src/launch.ts` already resolved and entered before this CLI ever runs
|
|
5
|
-
* (see that file's header, and `@devdogsuga/env/session`, which is where
|
|
6
|
-
* `availableTiers` and the session-wide policy now live — this module used
|
|
7
|
-
* to carry its own copy of both, one of two the wizard's tier question also
|
|
8
|
-
* used to keep before it moved into `launch.ts`).
|
|
9
|
-
*
|
|
10
|
-
* `cf preview`, `cron run` and `workflows run` still need a resolver of their
|
|
11
|
-
* own: each names the tier something it is doing right now — running a
|
|
12
|
-
* workflow, previewing a build — SEPARATELY from the tier the session as a
|
|
13
|
-
* whole is running under (`process.env.DEPLOY_ENV`, honoured here as the
|
|
14
|
-
* fallback below), and a command flag can still name a different one. All
|
|
15
|
-
* three used to ask the same "which tier?" question with a subtly different
|
|
16
|
-
* answer, which is what this module unified. It asks only when the answer is
|
|
17
|
-
* not foregone: when more than one deploy tier's env file is actually
|
|
18
|
-
* present. That is the signature of someone working on the deploy workflow
|
|
19
|
-
* itself, who keeps `.env.staging` or `.env.production` around to test
|
|
20
|
-
* against. Everyone else falls straight through to development, exactly as
|
|
21
|
-
* if `--tier development` had been typed.
|
|
22
|
-
*/
|
|
23
|
-
import { select } from "@clack/prompts";
|
|
24
|
-
import { loadEnv, loadEnvSession } from "./repo/peers.js";
|
|
25
|
-
import { findRepoRoot } from "./repo/root.js";
|
|
26
|
-
import { unwrap } from "./ui.js";
|
|
27
|
-
/**
|
|
28
|
-
* The deploy tier a command runs under when `--tier` was not passed.
|
|
29
|
-
*
|
|
30
|
-
* Prompts ONLY when more than one deploy tier's file is present — the
|
|
31
|
-
* handful of contributors working on the deploy workflow — so that everyone
|
|
32
|
-
* else (just development, possibly with `.env.generated` from a running
|
|
33
|
-
* local stack) falls straight through to development with no prompt at all.
|
|
34
|
-
*
|
|
35
|
-
* Returns `null` after reporting an error on stderr — an invalid `--tier`, or
|
|
36
|
-
* an interactive pick of a tier whose file is missing — so the caller can
|
|
37
|
-
* exit nonzero without printing a second message of its own.
|
|
38
|
-
*/
|
|
39
|
-
export async function resolveTier(given, message, opts = {}) {
|
|
40
|
-
const label = opts.label ?? "devtools";
|
|
41
|
-
const env = await loadEnv();
|
|
42
|
-
if (given !== undefined) {
|
|
43
|
-
if (env.isDeployEnvironment(given))
|
|
44
|
-
return given;
|
|
45
|
-
process.stderr.write(`${label}: unknown tier "${given}". Expected: ${env.DEPLOY_ENVIRONMENTS.join(", ")}.\n`);
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
// Already inside a tier? Honour it instead of prompting. An entered tier is
|
|
49
|
-
// an answer, exactly like an explicit `--tier` above — including one whose
|
|
50
|
-
// file is missing, which `loadEnvironment` then reports — so it is validated
|
|
51
|
-
// for shape only, not existence, and does NOT fall through to the picker.
|
|
52
|
-
const entered = opts.deployEnv ?? process.env.DEPLOY_ENV;
|
|
53
|
-
if (entered !== undefined &&
|
|
54
|
-
entered !== "" &&
|
|
55
|
-
env.isDeployEnvironment(entered)) {
|
|
56
|
-
return entered;
|
|
57
|
-
}
|
|
58
|
-
const available = opts.available ??
|
|
59
|
-
(await (await loadEnvSession()).availableTiers(findRepoRoot()));
|
|
60
|
-
// Zero or one tier file present: there is nothing to choose between, so
|
|
61
|
-
// asking would be a question with one possible answer. Fall through to
|
|
62
|
-
// whichever tier is present, or development when nothing is (a machine
|
|
63
|
-
// that has never run `env pull` at all).
|
|
64
|
-
if (available.length <= 1)
|
|
65
|
-
return available[0] ?? "development";
|
|
66
|
-
const isTTY = opts.isTTY ?? process.stdin.isTTY;
|
|
67
|
-
if (!isTTY)
|
|
68
|
-
return "development";
|
|
69
|
-
const prompt = opts.prompt ??
|
|
70
|
-
(async (msg, choices) => unwrap(await select({
|
|
71
|
-
message: msg,
|
|
72
|
-
options: choices,
|
|
73
|
-
})));
|
|
74
|
-
// Show every deploy tier, not just the present ones: clack's `select` has
|
|
75
|
-
// no true "disabled" state, so a tier whose file is missing is shown with
|
|
76
|
-
// a hint that says so and how to fix it, rather than removed from the list
|
|
77
|
-
// where a contributor who expected to see "production" would wonder if
|
|
78
|
-
// they misconfigured something.
|
|
79
|
-
const choices = env.DEPLOY_ENVIRONMENTS.map((tier) => ({
|
|
80
|
-
value: tier,
|
|
81
|
-
label: tier,
|
|
82
|
-
hint: !available.includes(tier)
|
|
83
|
-
? `needs env pull --target ${tier}`
|
|
84
|
-
: tier === "development"
|
|
85
|
-
? "the default"
|
|
86
|
-
: tier === "production"
|
|
87
|
-
? "⚠️ live data"
|
|
88
|
-
: undefined,
|
|
89
|
-
}));
|
|
90
|
-
const choice = await prompt(message, choices);
|
|
91
|
-
if (!available.includes(choice)) {
|
|
92
|
-
process.stderr.write(`${label}: ${env.fileFor(choice)} is not present — run \`pnpm devtools env pull --target ${choice}\` first.\n`);
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
return choice;
|
|
96
|
-
}
|
package/dist/ui.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
export declare function bail(message?: string): never;
|
|
2
|
-
/** Exits cleanly on Ctrl-C rather than letting a cancel symbol leak onward. */
|
|
3
|
-
export declare function unwrap<T>(value: T | symbol): T;
|
|
4
|
-
/**
|
|
5
|
-
* Reports a failure with the next thing to try.
|
|
6
|
-
*
|
|
7
|
-
* `hints` is not decoration: for most of these failures the fix is one command,
|
|
8
|
-
* and printing it is the difference between a contributor continuing and a
|
|
9
|
-
* contributor asking in Discord.
|
|
10
|
-
*/
|
|
11
|
-
export declare function explain(summary: string, detail: string, hints?: string[]): void;
|
|
12
|
-
/**
|
|
13
|
-
* A refusal the reader can fix themselves — a name that matches nothing, a
|
|
14
|
-
* flag missing where there is no terminal to ask. Thrown from deep enough
|
|
15
|
-
* that the command's catch can't tell it from a real failure any other way;
|
|
16
|
-
* `explainError` prints it like any other error but keeps it out of Sentry.
|
|
17
|
-
*/
|
|
18
|
-
export declare class UsageError extends Error {
|
|
19
|
-
name: string;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* `explain()` for a caught error rather than a refusal: prints the same way,
|
|
23
|
-
* with `err`'s message as the detail, and reports `err` to Sentry unless it
|
|
24
|
-
* is a {@link UsageError}. Only failures nobody anticipated belong there.
|
|
25
|
-
*/
|
|
26
|
-
export declare function explainError(summary: string, err: unknown, hints?: string[]): void;
|
|
27
|
-
export declare function errorMessage(err: unknown): string;
|
|
28
|
-
export interface CheckResult {
|
|
29
|
-
name: string;
|
|
30
|
-
ok: boolean;
|
|
31
|
-
detail: string;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* A pass/fail list.
|
|
35
|
-
*
|
|
36
|
-
* Deliberately plain text rather than a box-drawing table: these lines get
|
|
37
|
-
* pasted into Discord and GitHub issues, where anything fancier turns to
|
|
38
|
-
* rubble.
|
|
39
|
-
*/
|
|
40
|
-
export declare function renderChecks(checks: CheckResult[]): string;
|