@devdogsuga/devtools 0.1.0
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 +44 -0
- package/bin/devtools-ci-bare.mjs +48 -0
- package/bin/devtools-ci.mjs +17 -0
- package/bin/devtools.mjs +27 -0
- package/dist/args.d.ts +26 -0
- package/dist/args.js +78 -0
- package/dist/bws/bw.d.ts +9 -0
- package/dist/bws/bw.js +49 -0
- package/dist/bws/client.d.ts +43 -0
- package/dist/bws/client.js +363 -0
- package/dist/bws/environments.d.ts +96 -0
- package/dist/bws/environments.js +111 -0
- package/dist/bws/pace.d.ts +27 -0
- package/dist/bws/pace.js +43 -0
- package/dist/bws/retry.d.ts +12 -0
- package/dist/bws/retry.js +39 -0
- package/dist/bws/store.d.ts +1 -0
- package/dist/bws/store.js +32 -0
- package/dist/bws/token.d.ts +31 -0
- package/dist/bws/token.js +88 -0
- package/dist/bws/vault.d.ts +29 -0
- package/dist/bws/vault.js +200 -0
- package/dist/catalog.d.ts +55 -0
- package/dist/catalog.js +81 -0
- package/dist/cf/commands.d.ts +1 -0
- package/dist/cf/commands.js +182 -0
- package/dist/cf/local-env.d.ts +44 -0
- package/dist/cf/local-env.js +148 -0
- package/dist/ci.d.ts +1 -0
- package/dist/ci.js +319 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +1077 -0
- package/dist/commands.d.ts +255 -0
- package/dist/commands.js +1279 -0
- package/dist/completions.d.ts +4 -0
- package/dist/completions.js +110 -0
- package/dist/cron/commands.d.ts +47 -0
- package/dist/cron/commands.js +372 -0
- package/dist/cron/discovery.d.ts +55 -0
- package/dist/cron/discovery.js +85 -0
- package/dist/cron/schema.d.ts +45 -0
- package/dist/cron/schema.js +35 -0
- package/dist/db/config-push.d.ts +8 -0
- package/dist/db/config-push.js +11 -0
- package/dist/db/connection.d.ts +79 -0
- package/dist/db/connection.js +114 -0
- package/dist/db/exec.d.ts +1 -0
- package/dist/db/exec.js +11 -0
- package/dist/db/generate-migration.d.ts +1 -0
- package/dist/db/generate-migration.js +67 -0
- package/dist/db/generate-types.d.ts +1 -0
- package/dist/db/generate-types.js +4 -0
- package/dist/db/introspect.d.ts +1 -0
- package/dist/db/introspect.js +113 -0
- package/dist/db/local-env.d.ts +65 -0
- package/dist/db/local-env.js +23 -0
- package/dist/db/new-migration.d.ts +1 -0
- package/dist/db/new-migration.js +8 -0
- package/dist/db/run.d.ts +70 -0
- package/dist/db/run.js +158 -0
- package/dist/db/seed-buckets.d.ts +2 -0
- package/dist/db/seed-buckets.js +4 -0
- package/dist/db/seed-production.d.ts +8 -0
- package/dist/db/seed-production.js +73 -0
- package/dist/db/seed-roles.d.ts +7 -0
- package/dist/db/seed-roles.js +31 -0
- package/dist/db/session-refresh.d.ts +43 -0
- package/dist/db/session-refresh.js +40 -0
- package/dist/deploy/migrations.d.ts +20 -0
- package/dist/deploy/migrations.js +68 -0
- package/dist/deploy/orphans.d.ts +20 -0
- package/dist/deploy/orphans.js +177 -0
- package/dist/deploy/preflight.d.ts +53 -0
- package/dist/deploy/preflight.js +189 -0
- package/dist/deploy/report.d.ts +26 -0
- package/dist/deploy/report.js +70 -0
- package/dist/deploy/require-planner.d.ts +2 -0
- package/dist/deploy/require-planner.js +60 -0
- package/dist/deploy/require-token.d.ts +15 -0
- package/dist/deploy/require-token.js +78 -0
- package/dist/deploy/secrets-file.d.ts +17 -0
- package/dist/deploy/secrets-file.js +167 -0
- package/dist/deploy/write-env.d.ts +40 -0
- package/dist/deploy/write-env.js +393 -0
- package/dist/docs/index-pages.d.ts +36 -0
- package/dist/docs/index-pages.js +184 -0
- package/dist/doctor.d.ts +62 -0
- package/dist/doctor.js +225 -0
- package/dist/emails/commands.d.ts +15 -0
- package/dist/emails/commands.js +130 -0
- package/dist/emails/email-types.d.ts +13 -0
- package/dist/emails/email-types.js +1 -0
- package/dist/emails/fixtures.d.ts +20 -0
- package/dist/emails/fixtures.js +20 -0
- package/dist/env/audit.d.ts +206 -0
- package/dist/env/audit.js +436 -0
- package/dist/env/cloudflare.d.ts +21 -0
- package/dist/env/cloudflare.js +61 -0
- package/dist/env/commands.d.ts +99 -0
- package/dist/env/commands.js +612 -0
- package/dist/env/discovery.d.ts +15 -0
- package/dist/env/discovery.js +226 -0
- package/dist/env/document.d.ts +119 -0
- package/dist/env/document.js +323 -0
- package/dist/env/example.d.ts +68 -0
- package/dist/env/example.js +603 -0
- package/dist/env/selection.d.ts +105 -0
- package/dist/env/selection.js +226 -0
- package/dist/environment.d.ts +92 -0
- package/dist/environment.js +206 -0
- package/dist/fingerprint.d.ts +10 -0
- package/dist/fingerprint.js +18 -0
- package/dist/gen/campus-map.d.ts +1 -0
- package/dist/gen/campus-map.js +473 -0
- package/dist/gen/commands.d.ts +1 -0
- package/dist/gen/commands.js +25 -0
- package/dist/gen/hypno.d.ts +1 -0
- package/dist/gen/hypno.js +134 -0
- package/dist/gh/client.d.ts +80 -0
- package/dist/gh/client.js +258 -0
- package/dist/gh/environments.d.ts +83 -0
- package/dist/gh/environments.js +178 -0
- package/dist/gh/rulesets/actors.d.ts +14 -0
- package/dist/gh/rulesets/actors.js +68 -0
- package/dist/gh/rulesets/api.d.ts +15 -0
- package/dist/gh/rulesets/api.js +99 -0
- package/dist/gh/rulesets/commands.d.ts +3 -0
- package/dist/gh/rulesets/commands.js +203 -0
- package/dist/gh/rulesets/desired.d.ts +112 -0
- package/dist/gh/rulesets/desired.js +247 -0
- package/dist/gh/rulesets/diff.d.ts +65 -0
- package/dist/gh/rulesets/diff.js +134 -0
- package/dist/gh/rulesets/types.d.ts +76 -0
- package/dist/gh/rulesets/types.js +13 -0
- package/dist/gh/settings/api.d.ts +40 -0
- package/dist/gh/settings/api.js +172 -0
- package/dist/gh/settings/commands.d.ts +1 -0
- package/dist/gh/settings/commands.js +245 -0
- package/dist/gh/settings/desired.d.ts +53 -0
- package/dist/gh/settings/desired.js +39 -0
- package/dist/gh/settings/diff.d.ts +57 -0
- package/dist/gh/settings/diff.js +156 -0
- package/dist/gh/settings/types.d.ts +92 -0
- package/dist/gh/settings/types.js +11 -0
- package/dist/gh/settings/workflows.d.ts +41 -0
- package/dist/gh/settings/workflows.js +124 -0
- package/dist/grantRoot.d.ts +42 -0
- package/dist/grantRoot.js +89 -0
- package/dist/help.d.ts +18 -0
- package/dist/help.js +169 -0
- package/dist/images/commands.d.ts +35 -0
- package/dist/images/commands.js +233 -0
- package/dist/images/events.d.ts +36 -0
- package/dist/images/events.js +152 -0
- package/dist/images/graphics.d.ts +70 -0
- package/dist/images/graphics.js +233 -0
- package/dist/images/open-graph-types.d.ts +75 -0
- package/dist/images/open-graph-types.js +1 -0
- package/dist/images/prompts.d.ts +34 -0
- package/dist/images/prompts.js +100 -0
- package/dist/images/render.d.ts +21 -0
- package/dist/images/render.js +57 -0
- package/dist/images/select.d.ts +64 -0
- package/dist/images/select.js +96 -0
- package/dist/instance.d.ts +67 -0
- package/dist/instance.js +129 -0
- package/dist/invocation.d.ts +49 -0
- package/dist/invocation.js +78 -0
- package/dist/launch-ci.d.ts +1 -0
- package/dist/launch-ci.js +86 -0
- package/dist/launch.d.ts +29 -0
- package/dist/launch.js +371 -0
- package/dist/menu.d.ts +31 -0
- package/dist/menu.js +277 -0
- package/dist/newsletter/commands.d.ts +16 -0
- package/dist/newsletter/commands.js +311 -0
- package/dist/newsletter/imap.d.ts +17 -0
- package/dist/newsletter/imap.js +127 -0
- package/dist/newsletter/loopback.d.ts +24 -0
- package/dist/newsletter/loopback.js +100 -0
- package/dist/newsletter/oauth.d.ts +26 -0
- package/dist/newsletter/oauth.js +130 -0
- package/dist/newsletter/smtp.d.ts +23 -0
- package/dist/newsletter/smtp.js +133 -0
- package/dist/oauth/browser.d.ts +1 -0
- package/dist/oauth/browser.js +13 -0
- package/dist/oauth/config.d.ts +24 -0
- package/dist/oauth/config.js +24 -0
- package/dist/oauth/connect-url.d.ts +17 -0
- package/dist/oauth/connect-url.js +23 -0
- package/dist/oauth/db.d.ts +37 -0
- package/dist/oauth/db.js +108 -0
- package/dist/oauth/device.d.ts +93 -0
- package/dist/oauth/device.js +190 -0
- package/dist/oauth/discovery.d.ts +28 -0
- package/dist/oauth/discovery.js +54 -0
- package/dist/oauth/env-file.d.ts +6 -0
- package/dist/oauth/env-file.js +35 -0
- package/dist/oauth/exchange.d.ts +43 -0
- package/dist/oauth/exchange.js +87 -0
- package/dist/oauth/label.d.ts +1 -0
- package/dist/oauth/label.js +25 -0
- package/dist/oauth/loopback.d.ts +52 -0
- package/dist/oauth/loopback.js +162 -0
- package/dist/oauth/pkce.d.ts +6 -0
- package/dist/oauth/pkce.js +34 -0
- package/dist/oauth/target.d.ts +54 -0
- package/dist/oauth/target.js +102 -0
- package/dist/oauth/transport.d.ts +41 -0
- package/dist/oauth/transport.js +32 -0
- package/dist/oauth/wizard.d.ts +33 -0
- package/dist/oauth/wizard.js +571 -0
- package/dist/pick.d.ts +6 -0
- package/dist/pick.js +64 -0
- package/dist/planner/checks.d.ts +26 -0
- package/dist/planner/checks.js +104 -0
- package/dist/planner/commands.d.ts +10 -0
- package/dist/planner/commands.js +367 -0
- package/dist/planner/db.d.ts +15 -0
- package/dist/planner/db.js +33 -0
- package/dist/planner/role.d.ts +33 -0
- package/dist/planner/role.js +68 -0
- package/dist/repo/peers.d.ts +24 -0
- package/dist/repo/peers.js +114 -0
- package/dist/repo/preflight.d.ts +109 -0
- package/dist/repo/preflight.js +266 -0
- package/dist/repo/resolve.d.ts +41 -0
- package/dist/repo/resolve.js +152 -0
- package/dist/repo/root.d.ts +23 -0
- package/dist/repo/root.js +91 -0
- package/dist/repo/source.d.ts +14 -0
- package/dist/repo/source.js +54 -0
- package/dist/repo/tsx-loader.d.ts +6 -0
- package/dist/repo/tsx-loader.js +41 -0
- package/dist/run/pick.d.ts +60 -0
- package/dist/run/pick.js +559 -0
- package/dist/setup.d.ts +1 -0
- package/dist/setup.js +152 -0
- package/dist/stack.d.ts +48 -0
- package/dist/stack.js +290 -0
- package/dist/telemetry.d.ts +34 -0
- package/dist/telemetry.js +93 -0
- package/dist/tier.d.ts +40 -0
- package/dist/tier.js +93 -0
- package/dist/tsconfig.typecheck.tsbuildinfo +1 -0
- package/dist/ui.d.ts +25 -0
- package/dist/ui.js +51 -0
- package/dist/workers.d.ts +5 -0
- package/dist/workers.js +35 -0
- package/dist/workflows/commands.d.ts +44 -0
- package/dist/workflows/commands.js +668 -0
- package/env.ts +158 -0
- package/package.json +80 -0
package/dist/db/run.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export declare function typesFile(): string;
|
|
2
|
+
/** Spawn a pnpm command with inherited stdio; resolves to the exit code. Pass
|
|
3
|
+
* `env` to run the child against a loaded tier rather than process.env. */
|
|
4
|
+
export declare function run(args: string[], env?: NodeJS.ProcessEnv): Promise<number>;
|
|
5
|
+
export interface RunWithStderrResult {
|
|
6
|
+
code: number;
|
|
7
|
+
stderr: string;
|
|
8
|
+
}
|
|
9
|
+
/** Spawn a pnpm command while echoing and retaining stderr for diagnostics.
|
|
10
|
+
* Pass `env` to run the child against a loaded tier rather than process.env. */
|
|
11
|
+
export declare function runWithStderr(args: string[], env?: NodeJS.ProcessEnv): Promise<RunWithStderrResult>;
|
|
12
|
+
/** Spawn a pnpm command, capture stdout, throw on non-zero exit. */
|
|
13
|
+
export declare function capture(args: string[]): Promise<string>;
|
|
14
|
+
/** `pnpm exec supabase …` with inherited stdio. */
|
|
15
|
+
export declare const supabase: (...args: string[]) => Promise<number>;
|
|
16
|
+
/** `pnpm exec supabase …` with captured stdout. */
|
|
17
|
+
export declare const supabaseCapture: (...args: string[]) => Promise<string>;
|
|
18
|
+
/** Build the supabase package (compiles database.types.ts into dist/). */
|
|
19
|
+
export declare const buildSupabase: () => Promise<number>;
|
|
20
|
+
/**
|
|
21
|
+
* Generate and write Database types from the session's database.
|
|
22
|
+
*
|
|
23
|
+
* Delegates to `@devdogsuga/db/typegen`'s `generateDatabaseTypes`, which runs
|
|
24
|
+
* `pnpm exec supabase gen types --db-url <dbUrl>` (always `--db-url` — the
|
|
25
|
+
* session's own connection string, never the supabase CLI's
|
|
26
|
+
* `--local`/`--linked` modes, whose defaults can disagree with what this
|
|
27
|
+
* process entered; see `db/connection.ts`'s header) and formats the result
|
|
28
|
+
* with `pnpm exec prettier --write`, both run against `findRepoRoot()` so the
|
|
29
|
+
* workspace-pinned CLI versions are what actually run.
|
|
30
|
+
*/
|
|
31
|
+
export declare function generateTypes(dbUrl: string): Promise<number>;
|
|
32
|
+
/**
|
|
33
|
+
* `supabase db push` over `dbUrl`, inherited stdio, resolving to the exit code.
|
|
34
|
+
*
|
|
35
|
+
* The one spelling of the migration push, shared by the contributor `db
|
|
36
|
+
* migrate` path (`stack.ts`'s `pushMigrations`) and CI's `deploy migrate`.
|
|
37
|
+
* `--yes` is the unattended apply CI wants; the contributor path omits it so a
|
|
38
|
+
* human still confirms. Neither variant regenerates types — that is
|
|
39
|
+
* `pushMigrations`' own second step, layered on top only where a checkout is
|
|
40
|
+
* meant to be rewritten. A CI apply must NOT write back into the repo, which is
|
|
41
|
+
* exactly why the bare push is factored out here rather than reused whole.
|
|
42
|
+
*/
|
|
43
|
+
export declare function dbPush(dbUrl: string, opts?: {
|
|
44
|
+
yes?: boolean;
|
|
45
|
+
}): Promise<number>;
|
|
46
|
+
/**
|
|
47
|
+
* `supabase db push --dry-run` over `dbUrl`, returning the plan text (stdout
|
|
48
|
+
* and stderr combined, as the workflow's old `2>&1` did).
|
|
49
|
+
*
|
|
50
|
+
* Throws on a non-zero exit — which for a dry run means the CONNECTION failed,
|
|
51
|
+
* not that the plan came back empty. That throw is the invariant `deploy plan`
|
|
52
|
+
* leans on, and the thing the old shell needed `set -o pipefail` to preserve: a
|
|
53
|
+
* dead connection must fail the step rather than read as "no migrations to
|
|
54
|
+
* apply". The child's own output is surfaced in the thrown message, because for
|
|
55
|
+
* a dry run that output is precisely the reason the operator needs.
|
|
56
|
+
*/
|
|
57
|
+
export declare function dbPushDryRun(dbUrl: string): Promise<string>;
|
|
58
|
+
/**
|
|
59
|
+
* `seed buckets` takes no `--db-url` (verified against the supabase 2.115.0
|
|
60
|
+
* CLI) — it drives the Storage API, not Postgres — so it is the one data
|
|
61
|
+
* command still keyed on local-vs-hosted rather than on the session's URL.
|
|
62
|
+
*/
|
|
63
|
+
export type BucketsConnection = {
|
|
64
|
+
kind: "local";
|
|
65
|
+
} | {
|
|
66
|
+
kind: "remote";
|
|
67
|
+
projectRef: string | undefined;
|
|
68
|
+
};
|
|
69
|
+
/** Seed storage buckets on the local stack or a resolved tier's project. */
|
|
70
|
+
export declare function seedBuckets(conn: BucketsConnection): Promise<number>;
|
package/dist/db/run.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for running supabase CLI and pnpm commands from the repo root.
|
|
3
|
+
*
|
|
4
|
+
* The supabase CLI is a workspace devDependency (not a global install), so
|
|
5
|
+
* every invocation goes through `pnpm exec supabase`. The cwd is always
|
|
6
|
+
* findRepoRoot(), where `supabase/config.toml` lives.
|
|
7
|
+
*/
|
|
8
|
+
import { execFile, spawn as nodeSpawn } from "node:child_process";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { promisify } from "node:util";
|
|
11
|
+
import { findRepoRoot } from "../repo/root.js";
|
|
12
|
+
import { loadDbTypegen } from "../repo/peers.js";
|
|
13
|
+
const runFile = promisify(execFile);
|
|
14
|
+
export function typesFile() {
|
|
15
|
+
return join(findRepoRoot(), "packages", "supabase", "src", "database.types.ts");
|
|
16
|
+
}
|
|
17
|
+
/** Spawn a pnpm command with inherited stdio; resolves to the exit code. Pass
|
|
18
|
+
* `env` to run the child against a loaded tier rather than process.env. */
|
|
19
|
+
export function run(args, env) {
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
const child = nodeSpawn("pnpm", args, {
|
|
22
|
+
stdio: "inherit",
|
|
23
|
+
cwd: findRepoRoot(),
|
|
24
|
+
...(env ? { env } : {}),
|
|
25
|
+
});
|
|
26
|
+
child.on("error", (error) => {
|
|
27
|
+
process.stderr.write(`${error.message}\n`);
|
|
28
|
+
resolve(1);
|
|
29
|
+
});
|
|
30
|
+
child.on("exit", (code) => resolve(code ?? 1));
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/** Spawn a pnpm command while echoing and retaining stderr for diagnostics.
|
|
34
|
+
* Pass `env` to run the child against a loaded tier rather than process.env. */
|
|
35
|
+
export function runWithStderr(args, env) {
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
const child = nodeSpawn("pnpm", args, {
|
|
38
|
+
stdio: ["inherit", "inherit", "pipe"],
|
|
39
|
+
cwd: findRepoRoot(),
|
|
40
|
+
...(env ? { env } : {}),
|
|
41
|
+
});
|
|
42
|
+
let stderr = "";
|
|
43
|
+
child.stderr.setEncoding("utf8");
|
|
44
|
+
child.stderr.on("data", (chunk) => {
|
|
45
|
+
stderr += chunk;
|
|
46
|
+
process.stderr.write(chunk);
|
|
47
|
+
});
|
|
48
|
+
child.on("error", (error) => {
|
|
49
|
+
const message = `${error.message}\n`;
|
|
50
|
+
stderr += message;
|
|
51
|
+
process.stderr.write(message);
|
|
52
|
+
resolve({ code: 1, stderr });
|
|
53
|
+
});
|
|
54
|
+
child.on("exit", (code) => resolve({ code: code ?? 1, stderr }));
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Spawn a pnpm command, capture stdout, throw on non-zero exit. */
|
|
58
|
+
export async function capture(args) {
|
|
59
|
+
const { stdout } = await runFile("pnpm", args, {
|
|
60
|
+
cwd: findRepoRoot(),
|
|
61
|
+
encoding: "utf8",
|
|
62
|
+
});
|
|
63
|
+
return stdout;
|
|
64
|
+
}
|
|
65
|
+
/** `pnpm exec supabase …` with inherited stdio. */
|
|
66
|
+
export const supabase = (...args) => run(["exec", "supabase", ...args]);
|
|
67
|
+
/** `pnpm exec supabase …` with captured stdout. */
|
|
68
|
+
export const supabaseCapture = (...args) => capture(["exec", "supabase", ...args]);
|
|
69
|
+
/** Build the supabase package (compiles database.types.ts into dist/). */
|
|
70
|
+
export const buildSupabase = () => run(["--filter", "@devdogsuga/supabase", "build"]);
|
|
71
|
+
/**
|
|
72
|
+
* Generate and write Database types from the session's database.
|
|
73
|
+
*
|
|
74
|
+
* Delegates to `@devdogsuga/db/typegen`'s `generateDatabaseTypes`, which runs
|
|
75
|
+
* `pnpm exec supabase gen types --db-url <dbUrl>` (always `--db-url` — the
|
|
76
|
+
* session's own connection string, never the supabase CLI's
|
|
77
|
+
* `--local`/`--linked` modes, whose defaults can disagree with what this
|
|
78
|
+
* process entered; see `db/connection.ts`'s header) and formats the result
|
|
79
|
+
* with `pnpm exec prettier --write`, both run against `findRepoRoot()` so the
|
|
80
|
+
* workspace-pinned CLI versions are what actually run.
|
|
81
|
+
*/
|
|
82
|
+
export async function generateTypes(dbUrl) {
|
|
83
|
+
try {
|
|
84
|
+
const { generateDatabaseTypes } = await loadDbTypegen();
|
|
85
|
+
await generateDatabaseTypes({
|
|
86
|
+
dbUrl,
|
|
87
|
+
outFile: typesFile(),
|
|
88
|
+
cwd: findRepoRoot(),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return 1;
|
|
93
|
+
}
|
|
94
|
+
return buildSupabase();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* `supabase db push` over `dbUrl`, inherited stdio, resolving to the exit code.
|
|
98
|
+
*
|
|
99
|
+
* The one spelling of the migration push, shared by the contributor `db
|
|
100
|
+
* migrate` path (`stack.ts`'s `pushMigrations`) and CI's `deploy migrate`.
|
|
101
|
+
* `--yes` is the unattended apply CI wants; the contributor path omits it so a
|
|
102
|
+
* human still confirms. Neither variant regenerates types — that is
|
|
103
|
+
* `pushMigrations`' own second step, layered on top only where a checkout is
|
|
104
|
+
* meant to be rewritten. A CI apply must NOT write back into the repo, which is
|
|
105
|
+
* exactly why the bare push is factored out here rather than reused whole.
|
|
106
|
+
*/
|
|
107
|
+
export function dbPush(dbUrl, opts = {}) {
|
|
108
|
+
const args = ["db", "push", "--db-url", dbUrl];
|
|
109
|
+
if (opts.yes)
|
|
110
|
+
args.push("--yes");
|
|
111
|
+
return supabase(...args);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* `supabase db push --dry-run` over `dbUrl`, returning the plan text (stdout
|
|
115
|
+
* and stderr combined, as the workflow's old `2>&1` did).
|
|
116
|
+
*
|
|
117
|
+
* Throws on a non-zero exit — which for a dry run means the CONNECTION failed,
|
|
118
|
+
* not that the plan came back empty. That throw is the invariant `deploy plan`
|
|
119
|
+
* leans on, and the thing the old shell needed `set -o pipefail` to preserve: a
|
|
120
|
+
* dead connection must fail the step rather than read as "no migrations to
|
|
121
|
+
* apply". The child's own output is surfaced in the thrown message, because for
|
|
122
|
+
* a dry run that output is precisely the reason the operator needs.
|
|
123
|
+
*/
|
|
124
|
+
export async function dbPushDryRun(dbUrl) {
|
|
125
|
+
try {
|
|
126
|
+
const { stdout, stderr } = await runFile("pnpm", ["exec", "supabase", "db", "push", "--db-url", dbUrl, "--dry-run"], { cwd: findRepoRoot(), encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
|
|
127
|
+
return `${stdout}${stderr}`;
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
const e = err;
|
|
131
|
+
const detail = `${e.stdout ?? ""}${e.stderr ?? ""}`.trim();
|
|
132
|
+
throw new Error(detail
|
|
133
|
+
? `supabase db push --dry-run failed:\n${detail}`
|
|
134
|
+
: (e.message ?? "supabase db push --dry-run failed"));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Seed storage buckets on the local stack or a resolved tier's project. */
|
|
138
|
+
export async function seedBuckets(conn) {
|
|
139
|
+
if (conn.kind === "local") {
|
|
140
|
+
return supabase("seed", "buckets", "--local", "--yes");
|
|
141
|
+
}
|
|
142
|
+
// Surfaced here, before the supabase CLI ever runs, rather than left for it
|
|
143
|
+
// to reject: an empty `--project-ref ""` is exactly the kind of ambiguous
|
|
144
|
+
// failure this whole module exists to avoid.
|
|
145
|
+
if (!conn.projectRef) {
|
|
146
|
+
process.stderr.write("devtools db: seed buckets against a hosted project needs PROJECT_REF in the session's env file.\n");
|
|
147
|
+
return 1;
|
|
148
|
+
}
|
|
149
|
+
// `seed buckets` (unlike `config push`) rejects a bare `--project-ref` as
|
|
150
|
+
// ambiguous with `--local` and demands `--linked` alongside it. That does
|
|
151
|
+
// NOT mean it needs an ambient `supabase link` state on disk — verified
|
|
152
|
+
// empirically in an unlinked checkout, `--project-ref` names the target
|
|
153
|
+
// directly and `--linked` is just the mode selector for "use that ref",
|
|
154
|
+
// not "use whatever `supabase link` last remembered". So this stays
|
|
155
|
+
// consistent with `db/connection.ts`'s rule of never depending on
|
|
156
|
+
// `--linked`'s persisted state.
|
|
157
|
+
return supabase("seed", "buckets", "--project-ref", conn.projectRef, "--linked");
|
|
158
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Injectable so a test can fake the connection without a real Postgres. */
|
|
2
|
+
export interface SeedProductionDb {
|
|
3
|
+
unsafe(query: string): Promise<unknown>;
|
|
4
|
+
end(): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export declare function runSeedProduction(dbUrl: string, deps?: {
|
|
7
|
+
connect: (url: string) => SeedProductionDb;
|
|
8
|
+
}): Promise<number>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `db seed production` — apply `supabase/seed/production/*.sql` to a target.
|
|
3
|
+
*
|
|
4
|
+
* The DevDogsUGA repo splits its seeds into `supabase/seed/production/`
|
|
5
|
+
* (the role catalogue and the officer board — content every tier needs)
|
|
6
|
+
* and `supabase/seed/development/` (password-login personas and a worked
|
|
7
|
+
* moderation report — local-dev-only, never meant to reach a hosted
|
|
8
|
+
* target). `db reset` runs both, but only ever against a LOCAL stack,
|
|
9
|
+
* because a reset erases everything else on whatever it points at.
|
|
10
|
+
* `production/` is what a staging or production target needs applied on
|
|
11
|
+
* its own, without erasing anything: `db reset --no-seed` (or an
|
|
12
|
+
* already-migrated database) plus this command, instead of hand-picking
|
|
13
|
+
* files with `db query --file`.
|
|
14
|
+
*
|
|
15
|
+
* That is a deliberate departure from `runSeedRoles` (`seed-roles.ts`),
|
|
16
|
+
* which pipes its one file through `supabase db query --file --db-url`.
|
|
17
|
+
* `03_officers.sql` is many separate `insert into` statements in one file,
|
|
18
|
+
* and the supabase CLI's `db query` runs its `--file` argument as a single
|
|
19
|
+
* PREPARED statement — confirmed against the local stack, where it fails
|
|
20
|
+
* every multi-statement seed file with "cannot insert multiple commands
|
|
21
|
+
* into a prepared statement". `01_roles.sql` only ever worked through that
|
|
22
|
+
* path because it happens to be one big `with … insert … select`
|
|
23
|
+
* statement. So this connects directly with `postgres` (`prepare: false`,
|
|
24
|
+
* the same setting `planner/db.ts` uses and for the same reason: the
|
|
25
|
+
* simple query protocol, not the extended one, is what allows more than
|
|
26
|
+
* one statement per round trip) and runs each file's raw text, rather than
|
|
27
|
+
* shelling out per file.
|
|
28
|
+
*/
|
|
29
|
+
import { readdirSync, readFileSync } from "node:fs";
|
|
30
|
+
import { join } from "node:path";
|
|
31
|
+
import postgres from "postgres";
|
|
32
|
+
import { findRepoRoot } from "../repo/root.js";
|
|
33
|
+
const SEED_DIR = "production";
|
|
34
|
+
// Lazy, like seed-roles.ts's `seedFiles()` — computed inside
|
|
35
|
+
// `runSeedProduction`, not at module load, so importing this file never
|
|
36
|
+
// calls `findRepoRoot()` (or touches the filesystem) on its own.
|
|
37
|
+
function seedFiles() {
|
|
38
|
+
const dir = join(findRepoRoot(), "supabase", "seed", SEED_DIR);
|
|
39
|
+
return readdirSync(dir)
|
|
40
|
+
.filter((name) => name.endsWith(".sql"))
|
|
41
|
+
.sort()
|
|
42
|
+
.map((name) => join(dir, name));
|
|
43
|
+
}
|
|
44
|
+
/** Real connection: `prepare: false` so multi-statement files run over the
|
|
45
|
+
* simple query protocol instead of gotrue's `db query --file` prepared-
|
|
46
|
+
* statement path, which refuses them. `max: 1` — this is a short-lived,
|
|
47
|
+
* sequential CLI invocation, never a pool. */
|
|
48
|
+
function connect(dbUrl) {
|
|
49
|
+
const sql = postgres(dbUrl, { max: 1, prepare: false, connect_timeout: 15 });
|
|
50
|
+
return {
|
|
51
|
+
unsafe: (query) => sql.unsafe(query),
|
|
52
|
+
end: () => sql.end({ timeout: 5 }),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export async function runSeedProduction(dbUrl, deps = { connect }) {
|
|
56
|
+
const db = deps.connect(dbUrl);
|
|
57
|
+
try {
|
|
58
|
+
for (const file of seedFiles()) {
|
|
59
|
+
try {
|
|
60
|
+
await db.unsafe(readFileSync(file, "utf8"));
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
process.stderr.write(`devtools db seed production: ${file} failed: ` +
|
|
64
|
+
`${err instanceof Error ? err.message : String(err)}\n`);
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
await db.end();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Always `--db-url` — the session's own connection string, never the
|
|
3
|
+
* supabase CLI's `--local`/`--linked` modes. `db query`, which this runs
|
|
4
|
+
* through, supports it the same way `db reset`/`db push` do. See
|
|
5
|
+
* `db/connection.ts`'s header.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runSeedRoles(dbUrl: string): Promise<number>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `db seed roles` — reconcile platform's role catalogue against a target.
|
|
3
|
+
*
|
|
4
|
+
* Runs 01_roles.sql, the complete built-in and organizational role catalogue,
|
|
5
|
+
* against the chosen target. It never assigns Root: bootstrapping that
|
|
6
|
+
* break-glass role requires the explicit, service-key-backed grant-root command.
|
|
7
|
+
*/
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { findRepoRoot } from "../repo/root.js";
|
|
10
|
+
import { supabase } from "./run.js";
|
|
11
|
+
// Lazy — computed inside `runSeedRoles`, not at module load, so importing
|
|
12
|
+
// this file never calls `findRepoRoot()` on its own (it used to, as a
|
|
13
|
+
// top-level `const`, which broke `--help`/`setup` outside a repo — see
|
|
14
|
+
// `workers.ts`'s header for the general pattern this follows).
|
|
15
|
+
function seedFiles() {
|
|
16
|
+
return [join(findRepoRoot(), "supabase", "seed", "production", "01_roles.sql")];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Always `--db-url` — the session's own connection string, never the
|
|
20
|
+
* supabase CLI's `--local`/`--linked` modes. `db query`, which this runs
|
|
21
|
+
* through, supports it the same way `db reset`/`db push` do. See
|
|
22
|
+
* `db/connection.ts`'s header.
|
|
23
|
+
*/
|
|
24
|
+
export async function runSeedRoles(dbUrl) {
|
|
25
|
+
for (const file of seedFiles()) {
|
|
26
|
+
const code = await supabase("db", "query", "--file", file, "--db-url", dbUrl);
|
|
27
|
+
if (code !== 0)
|
|
28
|
+
return code;
|
|
29
|
+
}
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BUG 2 fix: keeping this process's environment in sync with the local
|
|
3
|
+
* stack's lifecycle.
|
|
4
|
+
*
|
|
5
|
+
* `launch.ts` enters a deploy tier into `process.env` exactly ONCE, before
|
|
6
|
+
* `cli.ts` ever dispatches a command. `db start` (`startLocalStack`, in
|
|
7
|
+
* `../stack.ts`) then writes a NEW `.env.generated` — the running stack's
|
|
8
|
+
* fresh connection block — and `db stop` (`stopLocalStack`) deletes it. Left
|
|
9
|
+
* alone, `process.env` keeps whatever it held at launch for the rest of a
|
|
10
|
+
* wizard session: `db start` followed by `db introspect` in the SAME
|
|
11
|
+
* session would still hand `drizzle-kit` the stale (or absent)
|
|
12
|
+
* `.env.generated` values `resolveLocalToolingEnv` reads straight off
|
|
13
|
+
* `process.env` (see `local-env.ts`) — the exact staleness BUG 1 fixed
|
|
14
|
+
* `db introspect` from reading off disk, reappearing one layer up.
|
|
15
|
+
*
|
|
16
|
+
* `refreshSessionEnv` closes that gap by re-running the SAME
|
|
17
|
+
* `enterEnvironment("development", …)` `launch.ts` used at startup —
|
|
18
|
+
* overlay-plus-liveness-probe included — after a stack command that could
|
|
19
|
+
* have changed `.env.generated` succeeds.
|
|
20
|
+
*
|
|
21
|
+
* ⚠️ Guarded to development only. `DEPLOY_ENV` naming a deployed tier means
|
|
22
|
+
* this session targets staging or production (see `../db/connection.ts`);
|
|
23
|
+
* blindly re-entering development here would silently overwrite that tier's
|
|
24
|
+
* connection with local values mid-session, for a stack command
|
|
25
|
+
* (`start`/`stop`/`restart`) that only ever touches the LOCAL Docker stack
|
|
26
|
+
* in the first place.
|
|
27
|
+
*/
|
|
28
|
+
import type { EnteredEnvironment } from "@devdogsuga/env/session";
|
|
29
|
+
export interface RefreshSessionEnvOptions {
|
|
30
|
+
/** Injectable for tests; defaults to `process.env.DEPLOY_ENV`. */
|
|
31
|
+
deployEnv?: string;
|
|
32
|
+
/** Injectable for tests; defaults to the real `enterEnvironment`. */
|
|
33
|
+
enterEnvironment?: (tier: "development", opts: {
|
|
34
|
+
override: boolean;
|
|
35
|
+
}) => Promise<EnteredEnvironment>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Re-enters development — refreshing `process.env` from `.env.generated`'s
|
|
39
|
+
* latest state — when (and only when) this process is already running under
|
|
40
|
+
* development. Returns the one-line note callers report on success, or an
|
|
41
|
+
* empty array when the guard held and nothing needed refreshing.
|
|
42
|
+
*/
|
|
43
|
+
export declare function refreshSessionEnv(opts?: RefreshSessionEnvOptions): Promise<string[]>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { loadEnvLoad, loadEnvSession } from "../repo/peers.js";
|
|
2
|
+
/**
|
|
3
|
+
* Re-enters development — refreshing `process.env` from `.env.generated`'s
|
|
4
|
+
* latest state — when (and only when) this process is already running under
|
|
5
|
+
* development. Returns the one-line note callers report on success, or an
|
|
6
|
+
* empty array when the guard held and nothing needed refreshing.
|
|
7
|
+
*/
|
|
8
|
+
export async function refreshSessionEnv(opts = {}) {
|
|
9
|
+
const deployEnv = opts.deployEnv ?? process.env.DEPLOY_ENV;
|
|
10
|
+
if (deployEnv !== undefined &&
|
|
11
|
+
deployEnv !== "" &&
|
|
12
|
+
deployEnv !== "development") {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
const envLoad = await loadEnvLoad();
|
|
16
|
+
const enter = opts.enterEnvironment ?? (await loadEnvSession()).enterEnvironment;
|
|
17
|
+
try {
|
|
18
|
+
await enter("development", { override: true });
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
if (!(err instanceof envLoad.LocalStackOfflineError))
|
|
22
|
+
throw err;
|
|
23
|
+
// A `development:local` session whose stack just went down — `db stop`
|
|
24
|
+
// did exactly what it was asked, so this refresh must not turn that into
|
|
25
|
+
// a failure. Re-enter unqualified (probe decides: `.env` alone, with its
|
|
26
|
+
// stale-overlay warning) but LEAVE `DEV_DB` in place: the session still
|
|
27
|
+
// MEANS the local database, and `db/connection.ts`'s guard is what turns
|
|
28
|
+
// a later data command into "start the stack", not `.env`'s own DB_URL.
|
|
29
|
+
const devDb = process.env[envLoad.DEV_DB_ENV];
|
|
30
|
+
delete process.env[envLoad.DEV_DB_ENV];
|
|
31
|
+
try {
|
|
32
|
+
await enter("development", { override: true });
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
if (devDb !== undefined)
|
|
36
|
+
process.env[envLoad.DEV_DB_ENV] = devDb;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return [`refreshed ${envLoad.GENERATED_FILE}`];
|
|
40
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dry-run the migrations and write the plan to the job summary.
|
|
3
|
+
*
|
|
4
|
+
* The plan text is captured, not streamed, so `dbPushDryRun`'s throw on a
|
|
5
|
+
* non-zero exit is what fails the step when the connection is dead — and the
|
|
6
|
+
* job summary then carries no plan, which is the honest outcome. `label` lets
|
|
7
|
+
* the caller distinguish the two stages (`main`'s early plan vs the one taken
|
|
8
|
+
* seconds before the apply); it is the only thing that varies between them.
|
|
9
|
+
*/
|
|
10
|
+
export declare function runDeployPlan(label?: string, env?: NodeJS.ProcessEnv, plan?: (dbUrl: string) => Promise<string>): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Apply the migrations to DB_URL.
|
|
13
|
+
*
|
|
14
|
+
* `dbPush(url, { yes: true })` — the bare push, WITHOUT the type regeneration
|
|
15
|
+
* the contributor path layers on, so a production apply never writes back into
|
|
16
|
+
* the checkout. A non-zero exit becomes a DeployError so the job fails with a
|
|
17
|
+
* line a person can read; the supabase CLI's own output (inherited stdio) says
|
|
18
|
+
* why above it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runDeployMigrate(env?: NodeJS.ProcessEnv, push?: (dbUrl: string) => Promise<number>): Promise<void>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pnpm devtools-ci deploy plan` and `deploy migrate`.
|
|
3
|
+
*
|
|
4
|
+
* The two halves of a production schema change, behind the same tested seam as
|
|
5
|
+
* the rest of the deploy group. They replace the raw `supabase db push` shell
|
|
6
|
+
* that used to live in four places in `deploy.yaml` — `--dry-run` piped to
|
|
7
|
+
* `$GITHUB_STEP_SUMMARY` for the plan, `--yes` for the apply. The load-bearing
|
|
8
|
+
* `set -o pipefail` there (so a failed connection did not read as a clean plan)
|
|
9
|
+
* was a shell idiom no test could reach; here it is `dbPushDryRun`'s
|
|
10
|
+
* throw-on-non-zero, which a test drives.
|
|
11
|
+
*
|
|
12
|
+
* Both read `DB_URL` from the step's own `env:` (the plan under the
|
|
13
|
+
* migration_planner role that `require-planner` guards, the apply under the
|
|
14
|
+
* deploy-tier credential), compose no env file, and run through the bare `ci`
|
|
15
|
+
* package script — the one-credential convention shared with `require-planner`
|
|
16
|
+
* and `require-token`. Dependencies are injected (env, the push runner) rather
|
|
17
|
+
* than reached for, so the tests exercise the argv, the refusals, the summary
|
|
18
|
+
* framing, and the failed-connection invariant without a database.
|
|
19
|
+
*/
|
|
20
|
+
import { dbPush, dbPushDryRun } from "../db/run.js";
|
|
21
|
+
import { DeployError, say, summary } from "./report.js";
|
|
22
|
+
const MISSING_DB_URL = [
|
|
23
|
+
"This step runs with the environment's DB_URL. An empty value usually",
|
|
24
|
+
"means the environment secret was never pushed, or the workflow step",
|
|
25
|
+
"lost its env: block.",
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* Dry-run the migrations and write the plan to the job summary.
|
|
29
|
+
*
|
|
30
|
+
* The plan text is captured, not streamed, so `dbPushDryRun`'s throw on a
|
|
31
|
+
* non-zero exit is what fails the step when the connection is dead — and the
|
|
32
|
+
* job summary then carries no plan, which is the honest outcome. `label` lets
|
|
33
|
+
* the caller distinguish the two stages (`main`'s early plan vs the one taken
|
|
34
|
+
* seconds before the apply); it is the only thing that varies between them.
|
|
35
|
+
*/
|
|
36
|
+
export async function runDeployPlan(label = "Migration plan", env = process.env, plan = dbPushDryRun) {
|
|
37
|
+
const url = env.DB_URL;
|
|
38
|
+
if (!url) {
|
|
39
|
+
throw new DeployError("DB_URL is not set — refusing to plan.", MISSING_DB_URL);
|
|
40
|
+
}
|
|
41
|
+
const text = await plan(url);
|
|
42
|
+
// Echoed to stderr as well as the summary, so the plan is visible in the live
|
|
43
|
+
// job log too — stdout belongs to the machine for this group (see report.ts).
|
|
44
|
+
say([text]);
|
|
45
|
+
summary([`### ${label}`, "", "```", text, "```"], env);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Apply the migrations to DB_URL.
|
|
49
|
+
*
|
|
50
|
+
* `dbPush(url, { yes: true })` — the bare push, WITHOUT the type regeneration
|
|
51
|
+
* the contributor path layers on, so a production apply never writes back into
|
|
52
|
+
* the checkout. A non-zero exit becomes a DeployError so the job fails with a
|
|
53
|
+
* line a person can read; the supabase CLI's own output (inherited stdio) says
|
|
54
|
+
* why above it.
|
|
55
|
+
*/
|
|
56
|
+
export async function runDeployMigrate(env = process.env, push = (url) => dbPush(url, { yes: true })) {
|
|
57
|
+
const url = env.DB_URL;
|
|
58
|
+
if (!url) {
|
|
59
|
+
throw new DeployError("DB_URL is not set — refusing to migrate.", MISSING_DB_URL);
|
|
60
|
+
}
|
|
61
|
+
const code = await push(url);
|
|
62
|
+
if (code !== 0) {
|
|
63
|
+
throw new DeployError(`\`supabase db push\` failed (exit ${code}).`, [
|
|
64
|
+
"The migration was not applied. The supabase CLI output above says why.",
|
|
65
|
+
]);
|
|
66
|
+
}
|
|
67
|
+
say(["deploy migrate: migrations applied."]);
|
|
68
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { listWorkerSecrets } from "../env/cloudflare.js";
|
|
2
|
+
export interface OrphansOptions {
|
|
3
|
+
/** `--prune`: delete what it found. Nothing else in here can delete. */
|
|
4
|
+
prune: boolean;
|
|
5
|
+
/** Defaults to the ambient environment; a parameter so tests need not mutate it. */
|
|
6
|
+
env?: NodeJS.ProcessEnv;
|
|
7
|
+
/** Project root; the CLI passes the real one. A parameter for the tests. */
|
|
8
|
+
root?: string;
|
|
9
|
+
/** Injectable so the tests need neither wrangler nor a Cloudflare token. */
|
|
10
|
+
listSecrets?: typeof listWorkerSecrets;
|
|
11
|
+
/** Injectable for the same reason. The tests assert it is NOT called without `--prune`. */
|
|
12
|
+
deleteSecret?: (app: string, key: string, environment: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export interface OrphansResult {
|
|
15
|
+
/** How many names nothing declares, across every readable Worker. */
|
|
16
|
+
orphans: number;
|
|
17
|
+
/** `worker/key` for each deletion that happened. Empty unless `--prune`. */
|
|
18
|
+
pruned: string[];
|
|
19
|
+
}
|
|
20
|
+
export declare function runDeployOrphans(options: OrphansOptions): Promise<OrphansResult>;
|