@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/bws/retry.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Retrying exactly one failure class: HTTP 429, rate limiting.
|
|
3
|
-
*
|
|
4
|
-
* A 429 is the server saying "correct request, wrong minute", the only error
|
|
5
|
-
* where trying the same thing again IS the fix. Everything else (bad token,
|
|
6
|
-
* missing project, malformed input) re-throws untouched on the first attempt,
|
|
7
|
-
* because retrying those just triples the time to the real message.
|
|
8
|
-
*
|
|
9
|
-
* Written for the Secrets Manager calls, where the minute matters: a push is
|
|
10
|
-
* ~45 sequential writes plus a login, several targets get pushed back-to-back,
|
|
11
|
-
* and Bitwarden's identity endpoint rate-limits repeated access-token logins
|
|
12
|
-
* aggressively. The login half is also fixed at the source, since the client
|
|
13
|
-
* now caches its login in a state file, so the retry is the belt on that
|
|
14
|
-
* suspender.
|
|
15
|
-
*/
|
|
16
|
-
import { log } from "@clack/prompts";
|
|
17
|
-
export function isRateLimited(err) {
|
|
18
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
19
|
-
return /\b429\b|too many requests|rate.?limit/i.test(message);
|
|
20
|
-
}
|
|
21
|
-
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
22
|
-
export async function withRateLimitRetry(op, { retries = 3, baseMs = 5_000, sleep = wait, doing }) {
|
|
23
|
-
for (let attempt = 0;; attempt++) {
|
|
24
|
-
try {
|
|
25
|
-
return await op();
|
|
26
|
-
}
|
|
27
|
-
catch (err) {
|
|
28
|
-
if (!isRateLimited(err) || attempt >= retries)
|
|
29
|
-
throw err;
|
|
30
|
-
const ms = baseMs * 2 ** attempt;
|
|
31
|
-
// A silent 20-second stall reads as a hang, and a command that appears
|
|
32
|
-
// hung gets Ctrl-C'd, turning a wait the server asked for into a
|
|
33
|
-
// half-finished push.
|
|
34
|
-
log.warn(`Bitwarden rate-limited ${doing} (HTTP 429). Waiting ${ms / 1000}s ` +
|
|
35
|
-
`and retrying (${attempt + 1}/${retries})…`);
|
|
36
|
-
await sleep(ms);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
package/dist/bws/store.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function saveToDevEnv(key: string, value: string): Promise<void>;
|
package/dist/bws/store.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Saving a prompted value into the developer's own `.env`.
|
|
3
|
-
*
|
|
4
|
-
* The development file only, by construction: the path is fixed to
|
|
5
|
-
* `fileFor("development")`, so no caller can point this at a vault target's
|
|
6
|
-
* file. Those are what `env push` uploads, and the values saved here
|
|
7
|
-
* (`BWS_ACCESS_TOKEN`, `BWS_ORG_ID`) exist so they never ride a push. The
|
|
8
|
-
* token is refused there by name anyway; this keeps the write from ever being
|
|
9
|
-
* the thing that needs refusing.
|
|
10
|
-
*
|
|
11
|
-
* `EnvDocument.set` revives the commented line the rendered file already
|
|
12
|
-
* carries (never-store keys ship as `# KEY=""` with their documentation), so a
|
|
13
|
-
* saved value lands under its own doc comment rather than appended bare.
|
|
14
|
-
*/
|
|
15
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
16
|
-
import { resolve } from "node:path";
|
|
17
|
-
import { EnvDocument } from "../env/document.js";
|
|
18
|
-
import { findRepoRoot } from "../repo/root.js";
|
|
19
|
-
import { loadEnv } from "../repo/peers.js";
|
|
20
|
-
export async function saveToDevEnv(key, value) {
|
|
21
|
-
const { fileFor } = await loadEnv();
|
|
22
|
-
const path = resolve(findRepoRoot(), fileFor("development"));
|
|
23
|
-
let doc;
|
|
24
|
-
try {
|
|
25
|
-
doc = EnvDocument.parse(await readFile(path, "utf8"));
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
doc = EnvDocument.empty();
|
|
29
|
-
}
|
|
30
|
-
doc.set(key, value);
|
|
31
|
-
await writeFile(path, doc.toString());
|
|
32
|
-
}
|
package/dist/bws/token.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export declare class NoAccessTokenError extends Error {
|
|
2
|
-
}
|
|
3
|
-
export interface TokenSources {
|
|
4
|
-
/** From `--access-token`. */
|
|
5
|
-
explicit?: string;
|
|
6
|
-
/** From `process.env.BWS_ACCESS_TOKEN`. */
|
|
7
|
-
env?: string;
|
|
8
|
-
/** `undefined` for every reason the vault might not have it. */
|
|
9
|
-
fromVault: () => Promise<string | undefined>;
|
|
10
|
-
/** `undefined` when there is nobody to ask. */
|
|
11
|
-
prompt: () => Promise<string | undefined>;
|
|
12
|
-
/** Asked only after a successful prompt. */
|
|
13
|
-
offerSave: () => Promise<boolean>;
|
|
14
|
-
save: (token: string) => Promise<void>;
|
|
15
|
-
/** Where the token came from, for the caller to report. */
|
|
16
|
-
onSource?: (source: TokenSource) => void;
|
|
17
|
-
}
|
|
18
|
-
export type TokenSource = "flag" | "environment" | "vault" | "prompt";
|
|
19
|
-
export declare function resolveToken(sources: TokenSources): Promise<string>;
|
|
20
|
-
/**
|
|
21
|
-
* A weak shape check, to turn a paste error into a sentence rather than a 401.
|
|
22
|
-
*
|
|
23
|
-
* Machine account tokens are `0.<uuid>.<secret>:<secret>`. This checks the
|
|
24
|
-
* leading version segment only, and **warns rather than refuses**: the format
|
|
25
|
-
* is Bitwarden's to change, and a tool that rejects a valid token because its
|
|
26
|
-
* prefix moved is worse than one that passes a bad token to `bws` and lets the
|
|
27
|
-
* real error surface.
|
|
28
|
-
*/
|
|
29
|
-
export declare function looksLikeAccessToken(value: string): boolean;
|
|
30
|
-
/** The interactive half. Masked, and never echoed back. */
|
|
31
|
-
export declare function promptForToken(): Promise<string | undefined>;
|
package/dist/bws/token.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Finding the Secrets Manager access token, in four places, in order.
|
|
3
|
-
*
|
|
4
|
-
* 1. `--access-token` explicit, and explicit beats ambient
|
|
5
|
-
* 2. `BWS_ACCESS_TOKEN` the environment, which includes your `.env`,
|
|
6
|
-
* since `with-env` loads it for every command
|
|
7
|
-
* 3. the Bitwarden Password Manager vault, via the bundled `bw`
|
|
8
|
-
* 4. ask, and offer to save it to `.env` (the default) or the vault, so
|
|
9
|
-
* this is the last time
|
|
10
|
-
*
|
|
11
|
-
* The ordering logic is separated from the four implementations because it is
|
|
12
|
-
* the part that can be wrong invisibly. A chain that silently prefers a stale
|
|
13
|
-
* environment variable over a rotated vault entry authenticates as the wrong
|
|
14
|
-
* account and reports nothing, so the order is asserted rather than assumed.
|
|
15
|
-
*/
|
|
16
|
-
import { log, password } from "@clack/prompts";
|
|
17
|
-
import { unwrap } from "../ui.js";
|
|
18
|
-
export class NoAccessTokenError extends Error {
|
|
19
|
-
}
|
|
20
|
-
export async function resolveToken(sources) {
|
|
21
|
-
const announce = sources.onSource ?? (() => undefined);
|
|
22
|
-
// Explicit beats ambient. Someone who passes the flag while an environment
|
|
23
|
-
// variable is set is overriding on purpose, and silently ignoring them would
|
|
24
|
-
// point the command at the account they were trying to avoid.
|
|
25
|
-
if (sources.explicit) {
|
|
26
|
-
announce("flag");
|
|
27
|
-
return sources.explicit;
|
|
28
|
-
}
|
|
29
|
-
if (sources.env) {
|
|
30
|
-
announce("environment");
|
|
31
|
-
return sources.env;
|
|
32
|
-
}
|
|
33
|
-
const stored = await sources.fromVault();
|
|
34
|
-
if (stored) {
|
|
35
|
-
announce("vault");
|
|
36
|
-
return stored;
|
|
37
|
-
}
|
|
38
|
-
const typed = await sources.prompt();
|
|
39
|
-
if (!typed) {
|
|
40
|
-
throw new NoAccessTokenError("No access token. Put BWS_ACCESS_TOKEN in your .env (an interactive " +
|
|
41
|
-
"run offers to do this for you), pass --access-token, or store one " +
|
|
42
|
-
"in your Bitwarden vault. See docs/toolkit/guides/env/commands.md.");
|
|
43
|
-
}
|
|
44
|
-
announce("prompt");
|
|
45
|
-
// Offered only for a token that was just typed. Saving one that came from a
|
|
46
|
-
// flag or the environment would copy a credential into a vault nobody asked
|
|
47
|
-
// to put it in.
|
|
48
|
-
if (await sources.offerSave()) {
|
|
49
|
-
// A failed vault write must not lose the token. Somebody just pasted a live
|
|
50
|
-
// credential; making them do it again because a write failed is the worst
|
|
51
|
-
// moment to be strict, and the command itself is unaffected.
|
|
52
|
-
try {
|
|
53
|
-
await sources.save(typed);
|
|
54
|
-
}
|
|
55
|
-
catch (err) {
|
|
56
|
-
log.warn(`Could not save to your vault: ${err instanceof Error ? err.message : String(err)}. ` +
|
|
57
|
-
"Continuing with the token you typed.");
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return typed;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* A weak shape check, to turn a paste error into a sentence rather than a 401.
|
|
64
|
-
*
|
|
65
|
-
* Machine account tokens are `0.<uuid>.<secret>:<secret>`. This checks the
|
|
66
|
-
* leading version segment only, and **warns rather than refuses**: the format
|
|
67
|
-
* is Bitwarden's to change, and a tool that rejects a valid token because its
|
|
68
|
-
* prefix moved is worse than one that passes a bad token to `bws` and lets the
|
|
69
|
-
* real error surface.
|
|
70
|
-
*/
|
|
71
|
-
export function looksLikeAccessToken(value) {
|
|
72
|
-
return /^\d+\.[0-9a-f-]{36}\./i.test(value.trim());
|
|
73
|
-
}
|
|
74
|
-
/** The interactive half. Masked, and never echoed back. */
|
|
75
|
-
export async function promptForToken() {
|
|
76
|
-
if (!process.stdin.isTTY)
|
|
77
|
-
return undefined;
|
|
78
|
-
const typed = unwrap(await password({
|
|
79
|
-
message: "Paste the Secrets Manager access token for the `admin` account",
|
|
80
|
-
mask: "•",
|
|
81
|
-
validate: (v) => (v ?? "").trim() === "" ? "An access token is required." : undefined,
|
|
82
|
-
})).trim();
|
|
83
|
-
if (!looksLikeAccessToken(typed)) {
|
|
84
|
-
log.warn("That does not look like a machine account access token (they start " +
|
|
85
|
-
"`0.<uuid>.`). Continuing anyway — if it is wrong, Bitwarden will say so.");
|
|
86
|
-
}
|
|
87
|
-
return typed;
|
|
88
|
-
}
|
package/dist/bws/vault.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The item this looks for, and creates.
|
|
3
|
-
*
|
|
4
|
-
* Named for what it unlocks rather than for this tool, because whoever finds it
|
|
5
|
-
* in the vault six months from now needs to know what it is, not which script
|
|
6
|
-
* wrote it.
|
|
7
|
-
*/
|
|
8
|
-
export declare const VAULT_ITEM_NAME = "DevDogs Secrets Manager access token (admin)";
|
|
9
|
-
export type VaultStatus = "unavailable" | "unauthenticated" | "locked" | "unlocked";
|
|
10
|
-
/** `bw status`, or `unavailable` when the CLI is not installed. */
|
|
11
|
-
export declare function vaultStatus(): Promise<VaultStatus>;
|
|
12
|
-
/**
|
|
13
|
-
* The stored token, or `undefined` for every reason it might not be there.
|
|
14
|
-
*
|
|
15
|
-
* `bw get password` takes a search term and fails when it matches more than one
|
|
16
|
-
* item, which is the behaviour worth having: two items called something like
|
|
17
|
-
* this means somebody should look, not that this should guess.
|
|
18
|
-
*/
|
|
19
|
-
export declare function readTokenFromVault(): Promise<string | undefined>;
|
|
20
|
-
/**
|
|
21
|
-
* Creates the item, with the token arriving on **stdin** as base64 JSON.
|
|
22
|
-
*
|
|
23
|
-
* `bw create item` documents an encoded-JSON positional AND stdin. Using stdin
|
|
24
|
-
* is the difference between a live credential that is invisible and one that
|
|
25
|
-
* sits in `ps` output for the length of the call.
|
|
26
|
-
*/
|
|
27
|
-
export declare function saveTokenToVault(token: string): Promise<boolean>;
|
|
28
|
-
/** Why the vault could not be used, phrased as something to do about it. */
|
|
29
|
-
export declare function explainVault(status: VaultStatus): string | undefined;
|
package/dist/bws/vault.js
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The Bitwarden **Password Manager** vault, via the `bw` CLI.
|
|
3
|
-
*
|
|
4
|
-
* A different product from Secrets Manager and a different CLI, which is the
|
|
5
|
-
* point: `bws` has no user authentication at all, so the access token it needs
|
|
6
|
-
* has to be held somewhere a person can log in to. That somewhere is the
|
|
7
|
-
* Password Manager vault, and this module reads it back rather than making
|
|
8
|
-
* somebody paste a token every session.
|
|
9
|
-
*
|
|
10
|
-
* Everything here degrades to `undefined`. A missing `bw`, a locked vault, a
|
|
11
|
-
* declined unlock, a missing item: none of them are errors, because each has a
|
|
12
|
-
* good fallback, which is to ask. Throwing would turn a convenience into a
|
|
13
|
-
* prerequisite.
|
|
14
|
-
*
|
|
15
|
-
* ⚠️ The token never passes through argv in either direction. Reads use
|
|
16
|
-
* `bw get password <search>`, which puts only the item NAME on the command
|
|
17
|
-
* line, and writes pipe base64 JSON through **stdin**, which `bw create item`
|
|
18
|
-
* documents as an accepted input.
|
|
19
|
-
*/
|
|
20
|
-
import { execFile, spawn } from "node:child_process";
|
|
21
|
-
import { promisify } from "node:util";
|
|
22
|
-
import { confirm, log, spinner } from "@clack/prompts";
|
|
23
|
-
import { unwrap } from "../ui.js";
|
|
24
|
-
import { bwCommand } from "./bw.js";
|
|
25
|
-
const run = promisify(execFile);
|
|
26
|
-
/**
|
|
27
|
-
* The item this looks for, and creates.
|
|
28
|
-
*
|
|
29
|
-
* Named for what it unlocks rather than for this tool, because whoever finds it
|
|
30
|
-
* in the vault six months from now needs to know what it is, not which script
|
|
31
|
-
* wrote it.
|
|
32
|
-
*/
|
|
33
|
-
export const VAULT_ITEM_NAME = "DevDogs Secrets Manager access token (admin)";
|
|
34
|
-
/** `bw status`, or `unavailable` when the CLI is not installed. */
|
|
35
|
-
export async function vaultStatus() {
|
|
36
|
-
try {
|
|
37
|
-
const { stdout } = await run(...bwCommand(bwArgs(["status", "--response"])), {
|
|
38
|
-
shell: false,
|
|
39
|
-
});
|
|
40
|
-
// `--response` wraps the payload; the bare form is also accepted, so read
|
|
41
|
-
// whichever shape came back rather than depending on one.
|
|
42
|
-
const parsed = JSON.parse(stdout);
|
|
43
|
-
const status = ("status" in parsed ? parsed.status : undefined) ??
|
|
44
|
-
("data" in parsed ? parsed.data?.template?.status : undefined);
|
|
45
|
-
if (status === "unlocked")
|
|
46
|
-
return "unlocked";
|
|
47
|
-
if (status === "locked")
|
|
48
|
-
return "locked";
|
|
49
|
-
return "unauthenticated";
|
|
50
|
-
}
|
|
51
|
-
catch (err) {
|
|
52
|
-
if (err.code === "ENOENT")
|
|
53
|
-
return "unavailable";
|
|
54
|
-
return "unauthenticated";
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* A usable session key, unlocking if the person agrees.
|
|
59
|
-
*
|
|
60
|
-
* `BW_SESSION` is preferred and silent. Otherwise this ASKS before unlocking:
|
|
61
|
-
* a tool that pops a master-password prompt unannounced is shaped exactly like
|
|
62
|
-
* the thing people are told never to type their master password into.
|
|
63
|
-
*
|
|
64
|
-
* The password is typed straight into `bw`. stdin is inherited, so it never
|
|
65
|
-
* passes through this process.
|
|
66
|
-
*/
|
|
67
|
-
async function session(status) {
|
|
68
|
-
if (process.env.BW_SESSION)
|
|
69
|
-
return process.env.BW_SESSION;
|
|
70
|
-
if (status !== "locked")
|
|
71
|
-
return undefined;
|
|
72
|
-
if (!process.stdin.isTTY)
|
|
73
|
-
return undefined;
|
|
74
|
-
const ok = unwrap(await confirm({
|
|
75
|
-
message: "Your Bitwarden vault is locked. Unlock it to look for the access token?",
|
|
76
|
-
initialValue: true,
|
|
77
|
-
}));
|
|
78
|
-
if (!ok)
|
|
79
|
-
return undefined;
|
|
80
|
-
return new Promise((resolve) => {
|
|
81
|
-
// stdin inherited so the master password goes to `bw` and not through here;
|
|
82
|
-
// stdout piped so the session key can be captured rather than printed.
|
|
83
|
-
const child = spawn(...bwCommand(["unlock", "--raw"]), {
|
|
84
|
-
stdio: ["inherit", "pipe", "inherit"],
|
|
85
|
-
shell: false,
|
|
86
|
-
});
|
|
87
|
-
let out = "";
|
|
88
|
-
child.stdout.on("data", (c) => (out += c.toString()));
|
|
89
|
-
child.on("error", () => resolve(undefined));
|
|
90
|
-
child.on("close", (code) => resolve(code === 0 && out.trim() !== "" ? out.trim() : undefined));
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Adds the session key, and `--nointeraction` always.
|
|
95
|
-
*
|
|
96
|
-
* The second one is not belt-and-braces. `bw` prompts for a master password on
|
|
97
|
-
* stdin whenever the vault is locked, as `bw get template item` does against a
|
|
98
|
-
* locked vault, and this module runs `bw` with piped stdio, where that prompt
|
|
99
|
-
* has nobody to answer it and hangs until something gives up. `--nointeraction`
|
|
100
|
-
* turns that into an immediate non-zero exit, which every caller here already
|
|
101
|
-
* treats as "not available, ask instead".
|
|
102
|
-
*/
|
|
103
|
-
function bwArgs(args, key) {
|
|
104
|
-
const withNoInteraction = [...args, "--nointeraction"];
|
|
105
|
-
return key ? [...withNoInteraction, "--session", key] : withNoInteraction;
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* The stored token, or `undefined` for every reason it might not be there.
|
|
109
|
-
*
|
|
110
|
-
* `bw get password` takes a search term and fails when it matches more than one
|
|
111
|
-
* item, which is the behaviour worth having: two items called something like
|
|
112
|
-
* this means somebody should look, not that this should guess.
|
|
113
|
-
*/
|
|
114
|
-
export async function readTokenFromVault() {
|
|
115
|
-
const status = await vaultStatus();
|
|
116
|
-
if (status === "unavailable" || status === "unauthenticated") {
|
|
117
|
-
// Said out loud, and only here. By the time this runs the chain has already
|
|
118
|
-
// found nothing in the flag or the environment, so the person is about to
|
|
119
|
-
// be asked to paste a token. That is when knowing the vault could have
|
|
120
|
-
// answered instead is worth something.
|
|
121
|
-
log.info(explainVault(status));
|
|
122
|
-
return undefined;
|
|
123
|
-
}
|
|
124
|
-
const key = await session(status);
|
|
125
|
-
if (status === "locked" && !key)
|
|
126
|
-
return undefined;
|
|
127
|
-
const s = spinner();
|
|
128
|
-
s.start("Looking in your Bitwarden vault");
|
|
129
|
-
try {
|
|
130
|
-
const { stdout } = await run(...bwCommand(bwArgs(["get", "password", VAULT_ITEM_NAME, "--raw"], key)), { shell: false });
|
|
131
|
-
const token = stdout.trim();
|
|
132
|
-
if (token === "") {
|
|
133
|
-
s.stop("Nothing stored in the vault yet");
|
|
134
|
-
return undefined;
|
|
135
|
-
}
|
|
136
|
-
s.stop(`Read the access token from your vault ("${VAULT_ITEM_NAME}")`);
|
|
137
|
-
return token;
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
// "not found" and "more than one match" both land here, and both mean the
|
|
141
|
-
// same thing to the caller: ask instead.
|
|
142
|
-
s.stop("No single matching item in your vault");
|
|
143
|
-
return undefined;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Creates the item, with the token arriving on **stdin** as base64 JSON.
|
|
148
|
-
*
|
|
149
|
-
* `bw create item` documents an encoded-JSON positional AND stdin. Using stdin
|
|
150
|
-
* is the difference between a live credential that is invisible and one that
|
|
151
|
-
* sits in `ps` output for the length of the call.
|
|
152
|
-
*/
|
|
153
|
-
export async function saveTokenToVault(token) {
|
|
154
|
-
const status = await vaultStatus();
|
|
155
|
-
if (status === "unavailable" || status === "unauthenticated")
|
|
156
|
-
return false;
|
|
157
|
-
const key = await session(status);
|
|
158
|
-
if (status === "locked" && !key)
|
|
159
|
-
return false;
|
|
160
|
-
const item = {
|
|
161
|
-
organizationId: null,
|
|
162
|
-
collectionIds: null,
|
|
163
|
-
folderId: null,
|
|
164
|
-
type: 1, // login, so `bw get password` can retrieve it in one call
|
|
165
|
-
name: VAULT_ITEM_NAME,
|
|
166
|
-
notes: "Bitwarden Secrets Manager access token for the `admin` machine account, " +
|
|
167
|
-
"read/write on preflight, staging and production.\n\n" +
|
|
168
|
-
"Read automatically by `pnpm devtools env`. Never put this in a .env " +
|
|
169
|
-
"file: it unlocks all three projects, and the tool refuses to upload it.",
|
|
170
|
-
favorite: false,
|
|
171
|
-
reprompt: 0,
|
|
172
|
-
login: { username: null, password: token, totp: null },
|
|
173
|
-
};
|
|
174
|
-
return new Promise((resolve) => {
|
|
175
|
-
const child = spawn(...bwCommand(bwArgs(["create", "item"], key)), {
|
|
176
|
-
stdio: ["pipe", "ignore", "pipe"],
|
|
177
|
-
shell: false,
|
|
178
|
-
});
|
|
179
|
-
let stderr = "";
|
|
180
|
-
child.stderr.on("data", (c) => (stderr += c.toString()));
|
|
181
|
-
child.on("error", () => resolve(false));
|
|
182
|
-
child.on("close", (code) => {
|
|
183
|
-
if (code !== 0 && stderr.trim() !== "")
|
|
184
|
-
log.warn(stderr.trim());
|
|
185
|
-
resolve(code === 0);
|
|
186
|
-
});
|
|
187
|
-
child.stdin.end(Buffer.from(JSON.stringify(item)).toString("base64"));
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
/** Why the vault could not be used, phrased as something to do about it. */
|
|
191
|
-
export function explainVault(status) {
|
|
192
|
-
if (status === "unavailable") {
|
|
193
|
-
return ("The `bw` CLI is not installed, so the vault could not be checked. " +
|
|
194
|
-
"`pnpm devtools bw login` — the CLI is a devtools dependency, nothing to install.");
|
|
195
|
-
}
|
|
196
|
-
if (status === "unauthenticated") {
|
|
197
|
-
return "The `bw` CLI is not signed in. Run `bw login`.";
|
|
198
|
-
}
|
|
199
|
-
return undefined;
|
|
200
|
-
}
|
package/dist/catalog.d.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What can be reported on this instance, and for what reasons?
|
|
3
|
-
*
|
|
4
|
-
* Neither half of that question had an answer in the CLI before. `doctor` comes
|
|
5
|
-
* closest, but it runs `conformance_check()` for a single app and reports
|
|
6
|
-
* pass/fail per content type, a diagnostic rather than a listing, and it says
|
|
7
|
-
* nothing about reasons at all.
|
|
8
|
-
*
|
|
9
|
-
* It matters more now than it used to, because both halves stopped being
|
|
10
|
-
* editable at runtime. Content types are derived from each app's own schema and
|
|
11
|
-
* report reasons are a platform-owned enum, so there is no configuration page
|
|
12
|
-
* to open and look at. The database is the only source of truth, and this is
|
|
13
|
-
* how a contributor reads it. `docs/platform/reporting-and-feedback.md` carries
|
|
14
|
-
* a copy of the reason list for people who are not at a terminal, but that copy
|
|
15
|
-
* is maintained by hand and says so. This is what settles a disagreement.
|
|
16
|
-
*
|
|
17
|
-
* Both calls run through a moderator client rather than an admin client.
|
|
18
|
-
* `list_content_types` is `security definer` behind a `canModerate` check, so
|
|
19
|
-
* an anonymous or ordinary client sees nothing, and `list_report_reasons` is
|
|
20
|
-
* `security invoker` and subject to RLS. Using a moderator means what prints
|
|
21
|
-
* here is what a moderator would actually see, rather than what a superuser
|
|
22
|
-
* can. `moderation.ts`'s `withTemporaryModerator` is what supplies that
|
|
23
|
-
* client — this module reads with it, it does not sign in on its own.
|
|
24
|
-
*/
|
|
25
|
-
import type { DevtoolsClient } from "./instance.js";
|
|
26
|
-
export interface CatalogReason {
|
|
27
|
-
reason: string;
|
|
28
|
-
title: string;
|
|
29
|
-
description: string | null;
|
|
30
|
-
}
|
|
31
|
-
export interface CatalogContentType {
|
|
32
|
-
appSlug: string;
|
|
33
|
-
contentType: string;
|
|
34
|
-
label: string;
|
|
35
|
-
tableName: string;
|
|
36
|
-
schemaName: string;
|
|
37
|
-
visibility: string;
|
|
38
|
-
/** Null when the table carries no foreign key to reportResolutions. */
|
|
39
|
-
quarantineColumn: string | null;
|
|
40
|
-
/** Null when no single-column primary key could be derived. */
|
|
41
|
-
refColumn: string | null;
|
|
42
|
-
authorColumn: string | null;
|
|
43
|
-
}
|
|
44
|
-
export interface Catalog {
|
|
45
|
-
reasons: CatalogReason[];
|
|
46
|
-
contentTypes: CatalogContentType[];
|
|
47
|
-
}
|
|
48
|
-
export declare function readCatalog(client: DevtoolsClient): Promise<Catalog>;
|
|
49
|
-
/**
|
|
50
|
-
* Formats the catalog for `note()`.
|
|
51
|
-
*
|
|
52
|
-
* Content types are grouped by app, because a contributor asks "what does *my*
|
|
53
|
-
* app expose?". A type that cannot be quarantined or cannot be addressed is
|
|
54
|
-
* called out inline rather than left to be inferred from a blank column. Those
|
|
55
|
-
* are the two states that look like working configuration and are not.
|
|
56
|
-
*/
|
|
57
|
-
export declare function renderCatalog(catalog: Catalog): string;
|
package/dist/catalog.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
export async function readCatalog(client) {
|
|
2
|
-
const [reasons, contentTypes] = await Promise.all([
|
|
3
|
-
client.rpc("list_report_reasons"),
|
|
4
|
-
client.rpc("list_content_types"),
|
|
5
|
-
]);
|
|
6
|
-
if (reasons.error)
|
|
7
|
-
throw new Error(reasons.error.message);
|
|
8
|
-
if (contentTypes.error)
|
|
9
|
-
throw new Error(contentTypes.error.message);
|
|
10
|
-
return {
|
|
11
|
-
reasons: (reasons.data ?? []),
|
|
12
|
-
contentTypes: (contentTypes.data ?? []),
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Formats the catalog for `note()`.
|
|
17
|
-
*
|
|
18
|
-
* Content types are grouped by app, because a contributor asks "what does *my*
|
|
19
|
-
* app expose?". A type that cannot be quarantined or cannot be addressed is
|
|
20
|
-
* called out inline rather than left to be inferred from a blank column. Those
|
|
21
|
-
* are the two states that look like working configuration and are not.
|
|
22
|
-
*/
|
|
23
|
-
export function renderCatalog(catalog) {
|
|
24
|
-
const lines = [];
|
|
25
|
-
lines.push("Report reasons — one global list, every app, every content type");
|
|
26
|
-
for (const r of catalog.reasons) {
|
|
27
|
-
lines.push(` ${r.reason.padEnd(16)} ${r.title}`);
|
|
28
|
-
}
|
|
29
|
-
if (catalog.reasons.length === 0) {
|
|
30
|
-
lines.push(" (none — the presentation table is empty, which is a bug)");
|
|
31
|
-
}
|
|
32
|
-
lines.push("");
|
|
33
|
-
lines.push("Content types — derived from each app's schema, not configured");
|
|
34
|
-
const byApp = new Map();
|
|
35
|
-
for (const t of catalog.contentTypes) {
|
|
36
|
-
byApp.set(t.appSlug, [...(byApp.get(t.appSlug) ?? []), t]);
|
|
37
|
-
}
|
|
38
|
-
if (byApp.size === 0) {
|
|
39
|
-
lines.push(" (none — no registered app declares any moderatable content)");
|
|
40
|
-
}
|
|
41
|
-
for (const [app, types] of [...byApp].sort()) {
|
|
42
|
-
lines.push(` ${app}`);
|
|
43
|
-
for (const t of types) {
|
|
44
|
-
const notes = [];
|
|
45
|
-
if (!t.quarantineColumn)
|
|
46
|
-
notes.push("no quarantine column");
|
|
47
|
-
if (!t.refColumn)
|
|
48
|
-
notes.push("NOT ADDRESSABLE: no single-column key");
|
|
49
|
-
if (!t.authorColumn)
|
|
50
|
-
notes.push("no author column derived");
|
|
51
|
-
const suffix = notes.length > 0 ? ` (${notes.join("; ")})` : "";
|
|
52
|
-
lines.push(` ${t.contentType.padEnd(14)} ${t.schemaName}.${t.tableName}` +
|
|
53
|
-
` [${t.visibility}]${suffix}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return lines.join("\n");
|
|
57
|
-
}
|
package/dist/cf/build.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare function needsFrameworkBuild(app: string): boolean;
|
|
2
|
-
/** Build only `app`'s workspace dependencies — all `vinext dev` needs, since
|
|
3
|
-
* it compiles the app itself on demand. */
|
|
4
|
-
export declare function buildWorkspaceDeps(app: string): Promise<number>;
|
|
5
|
-
/** The pnpm invocations `buildWorkerApp` runs, in order. */
|
|
6
|
-
export declare function workerBuildCommands(app: string): string[][];
|
|
7
|
-
/**
|
|
8
|
-
* Build `app` for a local `wrangler dev`. `env` applies to the framework
|
|
9
|
-
* build only — it bakes tier-scoped values (NEXT_PUBLIC_*, CLOUDFLARE_ENV)
|
|
10
|
-
* into the bundle; the dependency builds are tier-independent `tsc` runs.
|
|
11
|
-
* Resolves to the first non-zero exit code, or 0.
|
|
12
|
-
*/
|
|
13
|
-
export declare function buildWorkerApp(app: string, env?: NodeJS.ProcessEnv): Promise<number>;
|
package/dist/cf/build.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The build a Worker app needs before `wrangler dev` can boot it locally.
|
|
3
|
-
*
|
|
4
|
-
* The vinext apps' `wrangler.jsonc` is the PRE-build shape: `main` is
|
|
5
|
-
* `cloudflare/worker.ts`, which imports vinext's app-router entry and its
|
|
6
|
-
* `virtual:vinext-*` modules, and `assets.directory` is `dist/client`. Plain
|
|
7
|
-
* `wrangler dev` against that file can never work — esbuild cannot resolve
|
|
8
|
-
* Vite's virtual modules, and on a fresh clone `dist/client` does not exist
|
|
9
|
-
* yet ("The directory specified by the "assets.directory" field ... does not
|
|
10
|
-
* exist"). `vinext build` writes `dist/` plus the `.wrangler/deploy/
|
|
11
|
-
* config.json` redirect that points a bare `wrangler dev` at the built
|
|
12
|
-
* `dist/server/wrangler.json` instead.
|
|
13
|
-
*
|
|
14
|
-
* Building every time, rather than only when `dist/` is missing, also keeps
|
|
15
|
-
* a checkout from running a stale bundle — or one a previous `cf preview
|
|
16
|
-
* --tier staging` baked for another tier.
|
|
17
|
-
*
|
|
18
|
-
* `workflows run`/`serve` use `vinext dev` instead and need none of this
|
|
19
|
-
* except the dependency build (`buildWorkspaceDeps`).
|
|
20
|
-
*
|
|
21
|
-
* The app's workspace dependencies build first, the way `devtools run build`
|
|
22
|
-
* orders them (see `run/pick.ts`): their `exports` resolve to gitignored
|
|
23
|
-
* `dist/` output, so on a fresh clone `vinext build` fails to load
|
|
24
|
-
* `next.config.ts` without them.
|
|
25
|
-
*/
|
|
26
|
-
import { run } from "../db/run.js";
|
|
27
|
-
/** Apps deployed without a framework build: Wrangler bundles `main` itself. */
|
|
28
|
-
const NO_FRAMEWORK_BUILD = new Set(["sandbox"]);
|
|
29
|
-
export function needsFrameworkBuild(app) {
|
|
30
|
-
return !NO_FRAMEWORK_BUILD.has(app);
|
|
31
|
-
}
|
|
32
|
-
function workspaceDepsBuildCommand(app) {
|
|
33
|
-
return ["-r", "--if-present", "--filter", `${app}^...`, "run", "build"];
|
|
34
|
-
}
|
|
35
|
-
/** Build only `app`'s workspace dependencies — all `vinext dev` needs, since
|
|
36
|
-
* it compiles the app itself on demand. */
|
|
37
|
-
export function buildWorkspaceDeps(app) {
|
|
38
|
-
return run(workspaceDepsBuildCommand(app));
|
|
39
|
-
}
|
|
40
|
-
/** The pnpm invocations `buildWorkerApp` runs, in order. */
|
|
41
|
-
export function workerBuildCommands(app) {
|
|
42
|
-
const commands = [workspaceDepsBuildCommand(app)];
|
|
43
|
-
if (needsFrameworkBuild(app)) {
|
|
44
|
-
commands.push(["--filter", app, "exec", "vinext", "build"]);
|
|
45
|
-
}
|
|
46
|
-
return commands;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Build `app` for a local `wrangler dev`. `env` applies to the framework
|
|
50
|
-
* build only — it bakes tier-scoped values (NEXT_PUBLIC_*, CLOUDFLARE_ENV)
|
|
51
|
-
* into the bundle; the dependency builds are tier-independent `tsc` runs.
|
|
52
|
-
* Resolves to the first non-zero exit code, or 0.
|
|
53
|
-
*/
|
|
54
|
-
export async function buildWorkerApp(app, env) {
|
|
55
|
-
const [, ...framework] = workerBuildCommands(app);
|
|
56
|
-
const depsCode = await buildWorkspaceDeps(app);
|
|
57
|
-
if (depsCode !== 0)
|
|
58
|
-
return depsCode;
|
|
59
|
-
for (const command of framework) {
|
|
60
|
-
const code = await run(command, env);
|
|
61
|
-
if (code !== 0)
|
|
62
|
-
return code;
|
|
63
|
-
}
|
|
64
|
-
return 0;
|
|
65
|
-
}
|
package/dist/cf/commands.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function runCf(argv: readonly string[]): Promise<number>;
|