@rebasepro/server-postgres 0.24.1-canary.gcb918fc → 0.25.0-canary.ge06257e
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/dist/{BranchService-Bsn2wfaj.js → BranchService-DNg4txyf.js} +14 -4
- package/dist/BranchService-DNg4txyf.js.map +1 -0
- package/dist/PostgresBackendDriver.d.ts +13 -0
- package/dist/PostgresBootstrapper.d.ts +10 -0
- package/dist/backup/backup-cli.d.ts +88 -2
- package/dist/backup/backup-service.d.ts +11 -1
- package/dist/backup/pg-tools.d.ts +18 -0
- package/dist/{backup-cli-DnpJi6I7.js → backup-cli-HCEkPcQj.js} +215 -79
- package/dist/backup-cli-HCEkPcQj.js.map +1 -0
- package/dist/{backup-service-BTBB7RXn.js → backup-service-D-UpT7DH.js} +121 -11
- package/dist/backup-service-D-UpT7DH.js.map +1 -0
- package/dist/{boot-ddl-DVpsFN6r.js → boot-ddl-Dnvpmm_T.js} +3 -3
- package/dist/{boot-ddl-DVpsFN6r.js.map → boot-ddl-Dnvpmm_T.js.map} +1 -1
- package/dist/branch-argv.d.ts +18 -6
- package/dist/cli-console-C_ISGwJo.js +255 -0
- package/dist/cli-console-C_ISGwJo.js.map +1 -0
- package/dist/cli-console.d.ts +10 -0
- package/dist/{cli-errors-CaI4ntyD.js → cli-errors-mx4sSjB8.js} +477 -103
- package/dist/cli-errors-mx4sSjB8.js.map +1 -0
- package/dist/cli-errors.d.ts +40 -4
- package/dist/{cli-flags-JNI-pwSf.js → cli-flags-DUozBFyK.js} +70 -6
- package/dist/cli-flags-DUozBFyK.js.map +1 -0
- package/dist/cli-flags.d.ts +21 -0
- package/dist/cli-helpers.d.ts +53 -24
- package/dist/{arg-Dni7MzLB.js → cli-prompt-egtNKkZl.js} +49 -3
- package/dist/cli-prompt-egtNKkZl.js.map +1 -0
- package/dist/cli-prompt.d.ts +19 -0
- package/dist/cli-scratch-database.d.ts +47 -8
- package/dist/cli.js +548 -94
- package/dist/cli.js.map +1 -1
- package/dist/{column-plan-helpers-drZIsSNf.js → column-plan-helpers-D_V4oaZh.js} +2 -2
- package/dist/{column-plan-helpers-drZIsSNf.js.map → column-plan-helpers-D_V4oaZh.js.map} +1 -1
- package/dist/{connection-C9mT8bgf.js → connection-C938nR3E.js} +2 -2
- package/dist/{connection-C9mT8bgf.js.map → connection-C938nR3E.js.map} +1 -1
- package/dist/{databasePoolManager-BIuewidb.js → databasePoolManager-Yqdw14wY.js} +4 -4
- package/dist/{databasePoolManager-BIuewidb.js.map → databasePoolManager-Yqdw14wY.js.map} +1 -1
- package/dist/{deferred-index-build-DP1_SNFo.js → deferred-index-build-Ca6OqKyR.js} +8 -8
- package/dist/{deferred-index-build-DP1_SNFo.js.map → deferred-index-build-Ca6OqKyR.js.map} +1 -1
- package/dist/{doctor-C4WiftHm.js → doctor-CJyuhV1n.js} +8 -8
- package/dist/{doctor-C4WiftHm.js.map → doctor-CJyuhV1n.js.map} +1 -1
- package/dist/{ensure-collection-policies-CXpbeNag.js → ensure-collection-policies-C1ux3V_z.js} +79 -18
- package/dist/ensure-collection-policies-C1ux3V_z.js.map +1 -0
- package/dist/{ensure-collection-tables-BhsU6qUE.js → ensure-collection-tables-Do-Bvb64.js} +10 -10
- package/dist/{ensure-collection-tables-BhsU6qUE.js.map → ensure-collection-tables-Do-Bvb64.js.map} +1 -1
- package/dist/{ensure-tables-CVm_yvzb.js → ensure-tables-Dl_Eh9ow.js} +5 -5
- package/dist/{ensure-tables-CVm_yvzb.js.map → ensure-tables-Dl_Eh9ow.js.map} +1 -1
- package/dist/{enum-labels-kept-D8fI1MoX.js → enum-labels-kept-D9eTIWCz.js} +3 -3
- package/dist/{enum-labels-kept-D8fI1MoX.js.map → enum-labels-kept-D9eTIWCz.js.map} +1 -1
- package/dist/{generate-drizzle-schema-Bz52jH2h.js → generate-drizzle-schema-Bf8canaR.js} +3 -3
- package/dist/{generate-drizzle-schema-Bz52jH2h.js.map → generate-drizzle-schema-Bf8canaR.js.map} +1 -1
- package/dist/{generate-drizzle-schema-logic-B74WN37S.js → generate-drizzle-schema-logic-BaT0H7Gq.js} +4 -4
- package/dist/{generate-drizzle-schema-logic-B74WN37S.js.map → generate-drizzle-schema-logic-BaT0H7Gq.js.map} +1 -1
- package/dist/{generate-files-CdEckX6c.js → generate-files-D50Pxw1G.js} +6 -47
- package/dist/generate-files-D50Pxw1G.js.map +1 -0
- package/dist/generate-next-step-DCd7yiJ2.js +66 -0
- package/dist/generate-next-step-DCd7yiJ2.js.map +1 -0
- package/dist/{generate-postgres-ddl-logic-B64O2oZF.js → generate-postgres-ddl-logic-B4k9djAV.js} +4 -4
- package/dist/{generate-postgres-ddl-logic-B64O2oZF.js.map → generate-postgres-ddl-logic-B4k9djAV.js.map} +1 -1
- package/dist/{generated-schema-staleness-Di9c4ZxN.js → generated-schema-staleness-FlxM2i4i.js} +102 -12
- package/dist/{generated-schema-staleness-Di9c4ZxN.js.map → generated-schema-staleness-FlxM2i4i.js.map} +1 -1
- package/dist/index.es.js +11 -11
- package/dist/{introspect-db-logic-C-Di8dA9.js → introspect-db-logic-j2vYhmdP.js} +145 -9
- package/dist/introspect-db-logic-j2vYhmdP.js.map +1 -0
- package/dist/{introspect-db-queries-D6kAqReI.js → introspect-db-queries-DevUrzll.js} +41 -6
- package/dist/introspect-db-queries-DevUrzll.js.map +1 -0
- package/dist/{open-rebase-CbOur0TU.js → open-rebase-D8rytTP0.js} +95 -45
- package/dist/open-rebase-D8rytTP0.js.map +1 -0
- package/dist/open-rebase.d.ts +12 -4
- package/dist/{pg-error-utils-vJezlXdI.js → pg-error-utils-CdsGYMTm.js} +10 -3
- package/dist/pg-error-utils-CdsGYMTm.js.map +1 -0
- package/dist/{plan-schema-B1YF_tYq.js → plan-schema-CsNgK0qi.js} +4 -4
- package/dist/{plan-schema-B1YF_tYq.js.map → plan-schema-CsNgK0qi.js.map} +1 -1
- package/dist/{policy-drift-Dm8i-s1J.js → policy-drift-CY5P1ZRu.js} +28 -14
- package/dist/{policy-drift-Dm8i-s1J.js.map → policy-drift-CY5P1ZRu.js.map} +1 -1
- package/dist/{push-index-prebuild-Db4AQF4i.js → push-index-prebuild-BDFcfRPo.js} +4 -4
- package/dist/{push-index-prebuild-Db4AQF4i.js.map → push-index-prebuild-BDFcfRPo.js.map} +1 -1
- package/dist/{push-legacy-renames-BK6ilQq2.js → push-legacy-renames-D4bvMWAb.js} +4 -4
- package/dist/{push-legacy-renames-BK6ilQq2.js.map → push-legacy-renames-D4bvMWAb.js.map} +1 -1
- package/dist/push-policy-plan-DTXE6aVa.js +111 -0
- package/dist/push-policy-plan-DTXE6aVa.js.map +1 -0
- package/dist/{render-ddl-CtC3y9Ol.js → render-ddl-CrfEe__B.js} +10 -9
- package/dist/render-ddl-CrfEe__B.js.map +1 -0
- package/dist/{rls-bootstrap-sql-RQUljnJ1.js → rls-bootstrap-sql-Bd-hJk08.js} +3 -58
- package/dist/rls-bootstrap-sql-Bd-hJk08.js.map +1 -0
- package/dist/{rls-enforcement-DvzqlaL1.js → rls-enforcement-D7P4-ZYX.js} +2 -2
- package/dist/{rls-enforcement-DvzqlaL1.js.map → rls-enforcement-D7P4-ZYX.js.map} +1 -1
- package/dist/{__vite-browser-external-BnuHet1e.js → rolldown-runtime-V7rFbMRe.js} +1 -8
- package/dist/schema/atlas-apply-report.d.ts +23 -0
- package/dist/schema/atlas-argv.d.ts +22 -1
- package/dist/schema/atlas-exclude.d.ts +42 -0
- package/dist/schema/atlas-revisions.d.ts +4 -0
- package/dist/schema/carved-out-migration.d.ts +5 -4
- package/dist/schema/destructive-sql.d.ts +23 -1
- package/dist/schema/doctor-cli.js +5 -5
- package/dist/schema/ensure-collection-policies.d.ts +50 -0
- package/dist/schema/generate-drizzle-schema.js +1 -1
- package/dist/schema/generate-next-step.d.ts +11 -0
- package/dist/schema/generate-postgres-ddl.js +2 -2
- package/dist/schema/generated-schema-diff.d.ts +7 -0
- package/dist/schema/generated-schema-staleness.d.ts +7 -1
- package/dist/schema/introspect-db-logic.d.ts +32 -1
- package/dist/schema/introspect-db-queries.d.ts +18 -5
- package/dist/schema/introspect-db.js +53 -52
- package/dist/schema/introspect-db.js.map +1 -1
- package/dist/schema/migrate-baseline.d.ts +51 -0
- package/dist/schema/plan/render-ddl.d.ts +2 -1
- package/dist/schema/push-policy-plan.d.ts +67 -0
- package/dist/schema/undeclarable-constraints.d.ts +59 -0
- package/dist/security/policy-drift.d.ts +5 -0
- package/dist/services/BranchService.d.ts +7 -0
- package/dist/{source-DBDbBTL4.js → source-DB6xJv3p.js} +65 -3
- package/dist/source-DB6xJv3p.js.map +1 -0
- package/dist/utils/connection-string.d.ts +47 -0
- package/dist/{vector-index-CMJKb3C9.js → vector-index-BFhyEaiz.js} +2 -2
- package/dist/{vector-index-CMJKb3C9.js.map → vector-index-BFhyEaiz.js.map} +1 -1
- package/dist/{websocket-BLGc5yhs.js → websocket-DMeXOoyv.js} +41 -13
- package/dist/websocket-DMeXOoyv.js.map +1 -0
- package/package.json +7 -7
- package/dist/BranchService-Bsn2wfaj.js.map +0 -1
- package/dist/__vite-browser-external-BnuHet1e.js.map +0 -1
- package/dist/arg-Dni7MzLB.js.map +0 -1
- package/dist/backup-cli-DnpJi6I7.js.map +0 -1
- package/dist/backup-service-BTBB7RXn.js.map +0 -1
- package/dist/cli-console-Ca6ZlAVU.js +0 -154
- package/dist/cli-console-Ca6ZlAVU.js.map +0 -1
- package/dist/cli-errors-CaI4ntyD.js.map +0 -1
- package/dist/cli-flags-JNI-pwSf.js.map +0 -1
- package/dist/ensure-collection-policies-CXpbeNag.js.map +0 -1
- package/dist/generate-files-CdEckX6c.js.map +0 -1
- package/dist/introspect-db-logic-C-Di8dA9.js.map +0 -1
- package/dist/introspect-db-queries-D6kAqReI.js.map +0 -1
- package/dist/open-rebase-CbOur0TU.js.map +0 -1
- package/dist/pg-error-utils-vJezlXdI.js.map +0 -1
- package/dist/render-ddl-CtC3y9Ol.js.map +0 -1
- package/dist/rls-bootstrap-sql-RQUljnJ1.js.map +0 -1
- package/dist/source-DBDbBTL4.js.map +0 -1
- package/dist/websocket-BLGc5yhs.js.map +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "module";
|
|
2
2
|
__createRequire(import.meta.url);
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { i as __toESM } from "./rolldown-runtime-V7rFbMRe.js";
|
|
4
|
+
import { n as require_arg } from "./cli-prompt-egtNKkZl.js";
|
|
5
|
+
import { suggestNearMiss } from "@rebasepro/utils";
|
|
5
6
|
//#region src/cli-flags.ts
|
|
6
7
|
var import_arg = /* @__PURE__ */ __toESM(require_arg(), 1);
|
|
7
8
|
/**
|
|
@@ -75,7 +76,9 @@ var DRIVER_FLAG_SPECS = {
|
|
|
75
76
|
"-c": "--collections",
|
|
76
77
|
"--force": Boolean,
|
|
77
78
|
"-f": "--force",
|
|
78
|
-
"--schema": String
|
|
79
|
+
"--schema": String,
|
|
80
|
+
"--data-inference": Boolean,
|
|
81
|
+
"--no-data-inference": Boolean
|
|
79
82
|
},
|
|
80
83
|
"schema stale": {
|
|
81
84
|
"--collections": String,
|
|
@@ -131,11 +134,72 @@ function assertKnownFlags(domain, subcommand, args) {
|
|
|
131
134
|
...spec
|
|
132
135
|
}, { argv: args.slice(2) });
|
|
133
136
|
} catch (err) {
|
|
134
|
-
|
|
137
|
+
const unknown = unknownFlagIn(err);
|
|
138
|
+
if (unknown !== null && err instanceof Error) {
|
|
139
|
+
const suggestion = closestFlag(unknown, {
|
|
140
|
+
...RELAYED_FLAGS,
|
|
141
|
+
...spec
|
|
142
|
+
});
|
|
143
|
+
throw new Error(`${err.message}${suggestion ? ` (did you mean ${suggestion}?)` : ""} — run \`rebase ${domain} --help\` for the options \`${domain} ${subcommand}\` takes.`);
|
|
144
|
+
}
|
|
135
145
|
throw err;
|
|
136
146
|
}
|
|
137
147
|
}
|
|
148
|
+
/** The flag `arg` refused as undeclared, or `null` for any other failure. */
|
|
149
|
+
function unknownFlagIn(err) {
|
|
150
|
+
if (!(err instanceof Error) || !("code" in err) || err.code !== "ARG_UNKNOWN_OPTION") return null;
|
|
151
|
+
return /option: (\S+)$/.exec(err.message)?.[1] ?? null;
|
|
152
|
+
}
|
|
153
|
+
/** The declared long flag `typed` is one edit or one swap away from, if there is one. */
|
|
154
|
+
function closestFlag(typed, spec) {
|
|
155
|
+
const name = typed.split("=")[0];
|
|
156
|
+
return closestWord(name, Object.keys(spec).filter((flag) => flag.startsWith("--")));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* The word in `known` that `typed` was probably meant to be: one edit away
|
|
160
|
+
* (`--targt-db`), or two neighbouring letters swapped (`--clena`, `--froce`),
|
|
161
|
+
* which `suggestNearMiss` counts as two edits and so never offers.
|
|
162
|
+
*/
|
|
163
|
+
function closestWord(typed, known) {
|
|
164
|
+
return suggestNearMiss(known, typed) ?? transposedFrom(known, typed);
|
|
165
|
+
}
|
|
166
|
+
function transposedFrom(known, typed) {
|
|
167
|
+
return known.find((candidate) => {
|
|
168
|
+
if (candidate.length !== typed.length || candidate === typed) return false;
|
|
169
|
+
const differ = [...candidate].flatMap((letter, index) => letter === typed[index] ? [] : [index]);
|
|
170
|
+
return differ.length === 2 && differ[1] === differ[0] + 1 && candidate[differ[0]] === typed[differ[1]] && candidate[differ[1]] === typed[differ[0]];
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Parse a command that owns its argument handling, refusing what it does not
|
|
175
|
+
* declare.
|
|
176
|
+
*
|
|
177
|
+
* `db backup`, `db restore` and `db backups list` parsed permissively, so an
|
|
178
|
+
* undeclared flag became a positional and was ignored: `db restore <dump>
|
|
179
|
+
* --targt-db x --create-db --yes` dropped the misspelled target and restored
|
|
180
|
+
* into the live database. A typo is refused here before anything runs, naming
|
|
181
|
+
* the declared flag it is one edit from, or every flag the command takes when
|
|
182
|
+
* none is that close.
|
|
183
|
+
*
|
|
184
|
+
* @param argv the words after the command, e.g. `rawArgs.slice(2)`.
|
|
185
|
+
* @param command the command as typed, for the message: `"db restore"`.
|
|
186
|
+
*/
|
|
187
|
+
function parseCommandFlags(spec, argv, command) {
|
|
188
|
+
const full = {
|
|
189
|
+
...RELAYED_FLAGS,
|
|
190
|
+
...spec
|
|
191
|
+
};
|
|
192
|
+
try {
|
|
193
|
+
return (0, import_arg.default)(full, { argv });
|
|
194
|
+
} catch (err) {
|
|
195
|
+
const unknown = unknownFlagIn(err);
|
|
196
|
+
if (unknown === null) throw err;
|
|
197
|
+
const suggestion = closestFlag(unknown, full);
|
|
198
|
+
const flags = Object.keys(spec).filter((flag) => flag.startsWith("--"));
|
|
199
|
+
throw new Error(`\`rebase ${command}\` has no option ${unknown}` + (suggestion ? ` — did you mean ${suggestion}?` : ` — it takes ${flags.join(", ")}.`) + ` Nothing was run. See \`rebase ${command} --help\`.`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
138
202
|
//#endregion
|
|
139
|
-
export {
|
|
203
|
+
export { parseCommandFlags as a, collectionsPathIn as i, assertKnownFlags as n, parseDriverLine as o, closestWord as r, RELAYED_FLAGS as t };
|
|
140
204
|
|
|
141
|
-
//# sourceMappingURL=cli-flags-
|
|
205
|
+
//# sourceMappingURL=cli-flags-DUozBFyK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-flags-DUozBFyK.js","names":[],"sources":["../src/cli-flags.ts"],"sourcesContent":["/**\n * The flags each driver command takes, in one place, and the check that\n * enforces them.\n *\n * Every parser in `cli.ts` runs `arg(..., { permissive: true })`, which does not\n * mean \"be lenient\" — it means **an undeclared flag becomes a positional**. So\n * `rebase db push --alow-destructive` did not fail: the typo landed in `_`, the\n * push ran with the destructive gate still closed, and the developer read the\n * refusal as Rebase ignoring the flag they had just typed. `rebase schema\n * generate --ouput src/schema.ts` was worse — it wrote the default path and\n * said nothing, so the next build compiled a file nobody had regenerated.\n *\n * The check has to live at the entry point rather than in those parsers, and\n * that is not a detail: `db push` and `db generate` re-enter `schemaCommand`\n * and `generatePostgresDdlCommand` with the *db* line, so a strict parser\n * inside either of them would reject `--allow-destructive` on a line where it\n * is correct. One validation, once, against the spec for the command the user\n * actually named; the inner parsers keep reading an already-validated line.\n *\n * Commands with their own argument handling — `db branch` (`unexpectedBranchArgs`),\n * `db backup`, `db restore`, `db backups` — are deliberately absent: they own\n * their spec, and a second list here would be one more thing to keep in step.\n * An absent entry is \"not checked here\", never \"takes nothing\".\n */\nimport arg from \"arg\";\nimport { suggestNearMiss } from \"@rebasepro/utils\";\n\n/**\n * Flags that reach this process on a line it did not compose.\n *\n * `rebase db …` hands the driver the user's whole line: the CLI *reads*\n * `--database-url` and `--docker` to resolve the database and then relays them\n * verbatim, and `--debug` is what `bin/rebase.js` prints after every failure as\n * the thing to re-run with. Rejecting any of the three would make the driver\n * refuse commands the CLI documents.\n */\nexport const RELAYED_FLAGS = {\n \"--database-url\": String,\n \"--docker\": Boolean,\n \"--debug\": Boolean,\n \"--help\": Boolean,\n \"-h\": \"--help\"\n} satisfies arg.Spec;\n\n/**\n * Parse a driver command's line — `[\"db\", \"<subcommand>\", …]` — with the\n * relayed flags declared alongside the command's own.\n *\n * Every driver parser is permissive, and an undeclared flag in a permissive\n * parse is a positional. The positionals are what `db migrate` hands\n * `atlas migrate apply`, what `db generate` names its migration after and\n * which backup `db restore` restores, so a relayed flag left undeclared was\n * read as one of those: `rebase db migrate --docker` died on Atlas's\n * `unknown flag: --docker` after it had already written the auth schema.\n */\nexport function parseDriverLine<S extends arg.Spec>(\n spec: S,\n args: string[]\n): arg.Result<typeof RELAYED_FLAGS & S> {\n return arg({ ...RELAYED_FLAGS, ...spec }, { argv: args.slice(2), permissive: true });\n}\n\n/** Keyed by `\"<domain> <subcommand>\"`, the way the user types it. */\nexport const DRIVER_FLAG_SPECS: Record<string, arg.Spec> = {\n \"db push\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--dry-run\": Boolean,\n \"--allow-destructive\": Boolean,\n \"--yes\": Boolean,\n \"-y\": \"--yes\"\n },\n \"db generate\": {\n \"--collections\": String,\n \"-c\": \"--collections\"\n },\n // Bare positionals still pass through to `atlas migrate apply`, which takes\n // an optional amount; flags do not, apart from `--baseline`.\n //\n // `--baseline <version>` is the escape hatch for the normal case, not an\n // exotic one: every Rebase boot ensures the schema, so a production\n // database has the tables before its first migration ever runs, and\n // `migrate apply` then dies on `type \"…\" already exists (42710)`. It maps\n // onto Atlas's own `migrate apply --baseline`, which writes the revision\n // row Atlas reads — no ledger of ours.\n //\n // `--refuse-destructive` is opt-in: it dry-runs the pending files and exits\n // 1, applying nothing, when one drops or narrows data — the gate `db push`\n // has always had, for the path that had none.\n \"db migrate\": {\n \"--baseline\": String,\n \"--refuse-destructive\": Boolean\n },\n \"schema generate\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--watch\": Boolean,\n \"-w\": \"--watch\"\n },\n \"schema introspect\": {\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--force\": Boolean,\n \"-f\": \"--force\",\n \"--schema\": String,\n // Whether rows are sampled at all: without a terminal the prompt is\n // skipped, and the skip line names `--data-inference`.\n \"--data-inference\": Boolean,\n \"--no-data-inference\": Boolean\n },\n \"schema stale\": {\n \"--collections\": String,\n \"-c\": \"--collections\",\n \"--output\": String,\n \"-o\": \"--output\",\n \"--out\": \"--output\",\n \"--fix\": Boolean\n }\n};\n\n/**\n * One destination flag, two spellings, everywhere.\n *\n * `--out` is the primary on `rebase build`, an alias on `generate-sdk`, `db\n * backup` and `cloud env pull`, and was refused outright by the three `schema`\n * commands — so the spelling a user learned on one command was an\n * \"unknown or unexpected option\" on the next. Neither name can be retired (both\n * are shipped), so both are accepted, and {@link assertOutputAliasesPaired}\n * makes that the rule rather than a habit.\n */\nexport const OUTPUT_FLAG_ALIASES = [\"--out\", \"--output\"] as const;\n\n/**\n * Every spec that names one of the pair names both.\n *\n * Exported so the CLI's own specs can be held to it too: the drift this fixes\n * ran across two packages, and a check that only reads this file would let the\n * next `--out`-only command through.\n */\nexport function assertOutputAliasesPaired(specs: Record<string, arg.Spec>): string[] {\n const problems: string[] = [];\n for (const [command, spec] of Object.entries(specs)) {\n const present = OUTPUT_FLAG_ALIASES.filter(flag => flag in spec);\n if (present.length === 0 || present.length === OUTPUT_FLAG_ALIASES.length) continue;\n const missing = OUTPUT_FLAG_ALIASES.filter(flag => !(flag in spec));\n problems.push(`\\`${command}\\` takes ${present.join(\", \")} but not ${missing.join(\", \")}`);\n }\n return problems;\n}\n\n/**\n * The `--collections` path the user typed, or `null` if they typed none.\n *\n * Read once, at the entry point, because every command that takes it re-enters\n * the generators with the same line and each of them resolved it again — which\n * is how \"Collections path not found\" came to be printed four times before the\n * real output, and how a path that does not exist got as far as *writing* an\n * empty schema.\n *\n * Permissive, and it has to be: {@link assertKnownFlags} has already judged the\n * line, and `db push` carries flags the `--collections` spec does not name.\n */\nexport function collectionsPathIn(args: string[]): string | null {\n try {\n const parsed = arg(\n { \"--collections\": String, \"-c\": \"--collections\" },\n { argv: args.slice(2), permissive: true }\n );\n\n return parsed[\"--collections\"] ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * The long flags a `--help` usage line documents.\n *\n * `\"rebase db push [--collections <dir>] [--dry-run] …\"` → `[\"--collections\",\n * \"--dry-run\"]`. Placeholders (`<dir>`) and the alternation inside a positional\n * (`<create|list|switch>`) are not flags and are not returned.\n */\nexport function flagsInUsage(usage: string): string[] {\n return [...new Set(usage.match(/--[a-z][a-z0-9-]*/g) ?? [])];\n}\n\n/**\n * Every flag the help documents is accepted, and every flag accepted is documented.\n *\n * The drift this catches shipped: `rebase db push --help` has printed\n * `[--dry-run]` since the flag was written, `DRIVER_FLAG_SPECS[\"db push\"]` never\n * listed it, and {@link assertKnownFlags} — added later to stop typos being\n * swallowed — turned the documented flag into `unknown or unexpected option`.\n * The only way to see a push's SQL was to trip the destructive gate, which is\n * the exact problem `--dry-run` was written to solve. Worse in a project on an\n * older driver, whose permissive parser *applied* the schema on that line.\n *\n * Two hand-maintained lists in two packages cannot be kept in step by care, so\n * they are held to each other instead: `usages` is keyed the way\n * {@link DRIVER_FLAG_SPECS} is (`\"db push\"`), and comes from the CLI's own help\n * pages. A key in only one of the two is not this function's business — the\n * help covers commands that parse their own lines (`db branch`, `db backup`),\n * and an absent spec entry means \"not checked here\".\n *\n * Aliases (`\"-c\": \"--collections\"`, `\"--out\": \"--output\"`) need no line of their\n * own: they are spellings of a documented flag. Neither do {@link RELAYED_FLAGS},\n * which every driver command accepts because the CLI relays them.\n */\nexport function assertSpecMatchesUsage(\n specs: Record<string, arg.Spec>,\n usages: Record<string, string>\n): string[] {\n const problems: string[] = [];\n for (const [command, spec] of Object.entries(specs)) {\n const usage = usages[command];\n if (usage === undefined) continue;\n\n const documented = flagsInUsage(usage);\n const accepted = Object.entries(spec);\n // An alias resolves to the flag it spells; only the target needs a line.\n const canonical = new Set(\n accepted\n .map(([flag, kind]) => (typeof kind === \"string\" ? kind : flag))\n .filter(flag => flag.startsWith(\"--\"))\n );\n\n for (const flag of documented) {\n if (flag in spec || flag in RELAYED_FLAGS) continue;\n problems.push(`\\`${command}\\` documents ${flag} in its usage line but the spec rejects it`);\n }\n for (const flag of canonical) {\n if (documented.includes(flag) || flag in RELAYED_FLAGS) continue;\n problems.push(`\\`${command}\\` accepts ${flag} but no usage line documents it`);\n }\n }\n return problems;\n}\n\n/**\n * Reject a flag the named command does not take.\n *\n * `args` is the driver's whole line — `[\"db\", \"push\", …]` — so the flags are\n * read from `args.slice(2)`, past the two command words.\n *\n * Throws rather than exiting: `runPluginCommand`'s caller already turns a\n * thrown error into one red line and exit 1, and a thrown error is what the\n * tests can see.\n */\nexport function assertKnownFlags(domain: string, subcommand: string | undefined, args: string[]): void {\n if (!subcommand) return;\n const spec = DRIVER_FLAG_SPECS[`${domain} ${subcommand}`];\n if (!spec) return;\n\n try {\n arg({ ...RELAYED_FLAGS, ...spec }, { argv: args.slice(2) });\n } catch (err) {\n const unknown = unknownFlagIn(err);\n if (unknown !== null && err instanceof Error) {\n const suggestion = closestFlag(unknown, { ...RELAYED_FLAGS, ...spec });\n throw new Error(\n `${err.message}${suggestion ? ` (did you mean ${suggestion}?)` : \"\"} — run ` +\n `\\`rebase ${domain} --help\\` for the options \\`${domain} ${subcommand}\\` takes.`\n );\n }\n throw err;\n }\n}\n\n/** The flag `arg` refused as undeclared, or `null` for any other failure. */\nfunction unknownFlagIn(err: unknown): string | null {\n if (!(err instanceof Error) || !(\"code\" in err) || err.code !== \"ARG_UNKNOWN_OPTION\") return null;\n // arg's wording: `unknown or unexpected option: --targt-db`.\n return /option: (\\S+)$/.exec(err.message)?.[1] ?? null;\n}\n\n/** The declared long flag `typed` is one edit or one swap away from, if there is one. */\nfunction closestFlag(typed: string, spec: arg.Spec): string | undefined {\n const name = typed.split(\"=\")[0];\n return closestWord(name, Object.keys(spec).filter(flag => flag.startsWith(\"--\")));\n}\n\n/**\n * The word in `known` that `typed` was probably meant to be: one edit away\n * (`--targt-db`), or two neighbouring letters swapped (`--clena`, `--froce`),\n * which `suggestNearMiss` counts as two edits and so never offers.\n */\nexport function closestWord(typed: string, known: readonly string[]): string | undefined {\n return suggestNearMiss(known, typed) ?? transposedFrom(known, typed);\n}\n\nfunction transposedFrom(known: readonly string[], typed: string): string | undefined {\n return known.find((candidate) => {\n if (candidate.length !== typed.length || candidate === typed) return false;\n const differ = [...candidate].flatMap((letter, index) => (letter === typed[index] ? [] : [index]));\n return differ.length === 2 && differ[1] === differ[0] + 1\n && candidate[differ[0]] === typed[differ[1]] && candidate[differ[1]] === typed[differ[0]];\n });\n}\n\n/**\n * Parse a command that owns its argument handling, refusing what it does not\n * declare.\n *\n * `db backup`, `db restore` and `db backups list` parsed permissively, so an\n * undeclared flag became a positional and was ignored: `db restore <dump>\n * --targt-db x --create-db --yes` dropped the misspelled target and restored\n * into the live database. A typo is refused here before anything runs, naming\n * the declared flag it is one edit from, or every flag the command takes when\n * none is that close.\n *\n * @param argv the words after the command, e.g. `rawArgs.slice(2)`.\n * @param command the command as typed, for the message: `\"db restore\"`.\n */\nexport function parseCommandFlags<S extends arg.Spec>(\n spec: S,\n argv: string[],\n command: string\n): arg.Result<typeof RELAYED_FLAGS & S> {\n const full = { ...RELAYED_FLAGS, ...spec };\n try {\n return arg(full, { argv });\n } catch (err) {\n const unknown = unknownFlagIn(err);\n if (unknown === null) throw err;\n const suggestion = closestFlag(unknown, full);\n const flags = Object.keys(spec).filter(flag => flag.startsWith(\"--\"));\n throw new Error(\n `\\`rebase ${command}\\` has no option ${unknown}` +\n (suggestion ? ` — did you mean ${suggestion}?` : ` — it takes ${flags.join(\", \")}.`) +\n ` Nothing was run. See \\`rebase ${command} --help\\`.`\n );\n }\n}\n"],"mappings":"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"}
|
package/dist/cli-flags.d.ts
CHANGED
|
@@ -127,3 +127,24 @@ export declare function assertSpecMatchesUsage(specs: Record<string, arg.Spec>,
|
|
|
127
127
|
* tests can see.
|
|
128
128
|
*/
|
|
129
129
|
export declare function assertKnownFlags(domain: string, subcommand: string | undefined, args: string[]): void;
|
|
130
|
+
/**
|
|
131
|
+
* The word in `known` that `typed` was probably meant to be: one edit away
|
|
132
|
+
* (`--targt-db`), or two neighbouring letters swapped (`--clena`, `--froce`),
|
|
133
|
+
* which `suggestNearMiss` counts as two edits and so never offers.
|
|
134
|
+
*/
|
|
135
|
+
export declare function closestWord(typed: string, known: readonly string[]): string | undefined;
|
|
136
|
+
/**
|
|
137
|
+
* Parse a command that owns its argument handling, refusing what it does not
|
|
138
|
+
* declare.
|
|
139
|
+
*
|
|
140
|
+
* `db backup`, `db restore` and `db backups list` parsed permissively, so an
|
|
141
|
+
* undeclared flag became a positional and was ignored: `db restore <dump>
|
|
142
|
+
* --targt-db x --create-db --yes` dropped the misspelled target and restored
|
|
143
|
+
* into the live database. A typo is refused here before anything runs, naming
|
|
144
|
+
* the declared flag it is one edit from, or every flag the command takes when
|
|
145
|
+
* none is that close.
|
|
146
|
+
*
|
|
147
|
+
* @param argv the words after the command, e.g. `rawArgs.slice(2)`.
|
|
148
|
+
* @param command the command as typed, for the message: `"db restore"`.
|
|
149
|
+
*/
|
|
150
|
+
export declare function parseCommandFlags<S extends arg.Spec>(spec: S, argv: string[], command: string): arg.Result<typeof RELAYED_FLAGS & S>;
|
package/dist/cli-helpers.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GeneratedColumnDependency } from "./schema/generated-column-conflicts.js";
|
|
2
2
|
import { type ExistingColumnType } from "./schema/destructive-sql.js";
|
|
3
|
+
import { type ExistingConstraint } from "./schema/undeclarable-constraints.js";
|
|
3
4
|
import type { CollectionConfig } from "@rebasepro/types";
|
|
4
5
|
/**
|
|
5
6
|
* Why is a dependency's binary missing — never installed, or installed with its
|
|
@@ -58,8 +59,23 @@ export declare function describeBuildScriptRemedy(packageName: string, manager?:
|
|
|
58
59
|
* relink rather than decide the tree is already up to date.
|
|
59
60
|
*/
|
|
60
61
|
export declare function describeReinstallCommand(manager?: ProjectPackageManager): string;
|
|
61
|
-
/**
|
|
62
|
-
|
|
62
|
+
/**
|
|
63
|
+
* The workspace member a command runs in, relative to the workspace's root —
|
|
64
|
+
* `backend` in a scaffolded project — or null at that root and outside any
|
|
65
|
+
* workspace.
|
|
66
|
+
*
|
|
67
|
+
* The member is the nearest directory at or above `startDir` holding a
|
|
68
|
+
* `package.json`; the root is the nearest one above it holding a
|
|
69
|
+
* `pnpm-workspace.yaml`, or a `package.json` that declares `workspaces`.
|
|
70
|
+
*/
|
|
71
|
+
export declare function workspaceMemberDir(startDir?: string): string | null;
|
|
72
|
+
/**
|
|
73
|
+
* `add <pkg>` as a dev dependency, in the reader's own package manager, typed
|
|
74
|
+
* from the project root: into `workspaceDir` when the command runs in a
|
|
75
|
+
* workspace member, where a bare `pnpm add -D` at the root refuses with
|
|
76
|
+
* `ERR_PNPM_ADDING_TO_ROOT`.
|
|
77
|
+
*/
|
|
78
|
+
export declare function describeDevAddCommand(packageName: string, manager?: ProjectPackageManager, workspaceDir?: string | null): string;
|
|
63
79
|
/**
|
|
64
80
|
* Why a dependency's binary is not on `PATH`.
|
|
65
81
|
*
|
|
@@ -277,15 +293,21 @@ export declare function getTriggerExcludes(collectionsPath: string): Promise<str
|
|
|
277
293
|
* catalogs. Separated from {@link getTableExcludes} so its failure mode can
|
|
278
294
|
* be handled explicitly (fail closed) and so tests can inject a stub.
|
|
279
295
|
*/
|
|
296
|
+
/** An index as the catalogue names it: its schema, its table and its own name. */
|
|
297
|
+
export interface ExistingIndex {
|
|
298
|
+
schema: string;
|
|
299
|
+
table: string;
|
|
300
|
+
index: string;
|
|
301
|
+
}
|
|
280
302
|
/**
|
|
281
|
-
* Every index Postgres holds on a table
|
|
282
|
-
*
|
|
303
|
+
* Every index Postgres holds on a table, by its parts — never joined with `.`,
|
|
304
|
+
* which a name may itself contain.
|
|
283
305
|
*
|
|
284
306
|
* Constraint-backed indexes are left out: a `PRIMARY KEY` or a `UNIQUE` is a
|
|
285
307
|
* *constraint* to Atlas, diffed from the constraint declaration, and naming its
|
|
286
308
|
* index in an exclude would shield the constraint itself.
|
|
287
309
|
*/
|
|
288
|
-
export declare function queryExistingIndexes(databaseUrl: string): Promise<
|
|
310
|
+
export declare function queryExistingIndexes(databaseUrl: string): Promise<ExistingIndex[]>;
|
|
289
311
|
/**
|
|
290
312
|
* Glob patterns keeping Atlas away from indexes that are not Rebase's.
|
|
291
313
|
*
|
|
@@ -312,13 +334,35 @@ export declare function queryExistingIndexes(databaseUrl: string): Promise<strin
|
|
|
312
334
|
*
|
|
313
335
|
* Three-part `schema.table.index`, never two: a two-part pattern reads as a
|
|
314
336
|
* *table* named `<index>` in a *schema* named `<table>`, matches nothing, and
|
|
315
|
-
* reports no error — the trap already recorded for the search excludes.
|
|
337
|
+
* reports no error — the trap already recorded for the search excludes. And
|
|
338
|
+
* spelled by `atlasExcludePattern`: a raw `orders_idx[v1]` is a glob that
|
|
339
|
+
* matches `orders_idxv`, so that index was dropped with no prompt.
|
|
316
340
|
*/
|
|
317
341
|
export declare function getForeignIndexExcludes(databaseUrl: string, collectionsPath: string, deps?: {
|
|
318
|
-
queryExistingIndexes?: (databaseUrl: string) => Promise<
|
|
342
|
+
queryExistingIndexes?: (databaseUrl: string) => Promise<ExistingIndex[]>;
|
|
319
343
|
getManagedIndexNames?: (collectionsPath: string) => Promise<Set<string>>;
|
|
320
344
|
}): Promise<string[]>;
|
|
321
|
-
|
|
345
|
+
/** Every CHECK and EXCLUDE constraint the database holds. @see UNDECLARABLE_CONSTRAINTS_SQL */
|
|
346
|
+
export declare function queryUndeclarableConstraints(databaseUrl: string): Promise<ExistingConstraint[]>;
|
|
347
|
+
/**
|
|
348
|
+
* Patterns keeping Atlas away from the CHECK and EXCLUDE constraints the
|
|
349
|
+
* collections do not declare — which, since a collection cannot declare
|
|
350
|
+
* either, is all of them. See `schema/undeclarable-constraints.ts`.
|
|
351
|
+
*
|
|
352
|
+
* Fails CLOSED, like {@link getTableExcludes}: without the catalogue nothing
|
|
353
|
+
* says which constraints are there, and a partial list lets the push drop a
|
|
354
|
+
* rule the database enforces. `desiredSql` is the `schema.sql` Atlas is about
|
|
355
|
+
* to diff against; a constraint it declares is Atlas's to manage.
|
|
356
|
+
*/
|
|
357
|
+
export declare function getUndeclaredConstraintExcludes(databaseUrl: string, desiredSql: string, deps?: {
|
|
358
|
+
queryConstraints?: (databaseUrl: string) => Promise<ExistingConstraint[]>;
|
|
359
|
+
}): Promise<string[]>;
|
|
360
|
+
/** A table or view as the catalogue names it. */
|
|
361
|
+
export interface ExistingTable {
|
|
362
|
+
schema: string;
|
|
363
|
+
table: string;
|
|
364
|
+
}
|
|
365
|
+
export declare function queryExistingTables(databaseUrl: string): Promise<ExistingTable[]>;
|
|
322
366
|
/**
|
|
323
367
|
* Raised when the exclude list could not be built. `db push` MUST abort on
|
|
324
368
|
* this rather than continue: the exclude list is the only thing shielding
|
|
@@ -343,22 +387,7 @@ export declare class ExcludeIntrospectionError extends Error {
|
|
|
343
387
|
* `deps` is injectable for tests; production uses the real pg-backed queries.
|
|
344
388
|
*/
|
|
345
389
|
export declare function getTableExcludes(databaseUrl: string, collectionsPath: string, deps?: {
|
|
346
|
-
queryExistingTables?: (databaseUrl: string) => Promise<
|
|
390
|
+
queryExistingTables?: (databaseUrl: string) => Promise<ExistingTable[]>;
|
|
347
391
|
getIncludes?: (collectionsPath: string) => Promise<string[]>;
|
|
348
392
|
}): Promise<string[]>;
|
|
349
|
-
/**
|
|
350
|
-
* Ask a yes/no question on an interactive terminal.
|
|
351
|
-
*
|
|
352
|
-
* The `isTTY` guard is the contract, not an optimisation: non-interactive
|
|
353
|
-
* shells (CI, pipes, agents) can never answer, and `readline` on a
|
|
354
|
-
* non-TTY stdin resolves with whatever the pipe happens to contain — or never
|
|
355
|
-
* resolves at all. Returning false there is what makes an unattended
|
|
356
|
-
* `db push` abort instead of auto-confirming a destructive change. Callers
|
|
357
|
-
* should already have gone through {@link decidePushSafety}, which decides
|
|
358
|
-
* whether interactive confirmation is even possible; this is the backstop.
|
|
359
|
-
*
|
|
360
|
-
* Lives here rather than in cli.ts so it is reachable from a test — cli.ts uses
|
|
361
|
-
* `import.meta` and cannot be imported by the jest runner.
|
|
362
|
-
*/
|
|
363
|
-
export declare function promptConfirm(question: string): Promise<boolean>;
|
|
364
393
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "module";
|
|
2
2
|
__createRequire(import.meta.url);
|
|
3
|
-
import {
|
|
3
|
+
import { t as __commonJSMin } from "./rolldown-runtime-V7rFbMRe.js";
|
|
4
|
+
import readline from "readline";
|
|
4
5
|
//#region ../../node_modules/.pnpm/arg@5.0.2/node_modules/arg/index.js
|
|
5
6
|
var require_arg = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6
7
|
var flagSymbol = Symbol("arg flag");
|
|
@@ -82,6 +83,51 @@ var require_arg = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
82
83
|
module.exports = arg;
|
|
83
84
|
}));
|
|
84
85
|
//#endregion
|
|
85
|
-
|
|
86
|
+
//#region src/cli-prompt.ts
|
|
87
|
+
/**
|
|
88
|
+
* The one yes/no question the driver CLI asks: before a destructive `db push`,
|
|
89
|
+
* before a `db restore` without `--yes`, before `db branch prune` removes
|
|
90
|
+
* anything, and before `schema introspect` samples rows.
|
|
91
|
+
*/
|
|
92
|
+
/**
|
|
93
|
+
* Ask a yes/no question on an interactive terminal; `true` only for "y" or
|
|
94
|
+
* "yes".
|
|
95
|
+
*
|
|
96
|
+
* The `isTTY` guard is the contract, not an optimisation: non-interactive
|
|
97
|
+
* shells (CI, pipes, agents) can never answer, and `readline` on a non-TTY
|
|
98
|
+
* stdin resolves with whatever the pipe happens to contain, or never resolves
|
|
99
|
+
* at all. Returning false there is what makes an unattended `db push` abort
|
|
100
|
+
* instead of auto-confirming a destructive change. Callers decide first
|
|
101
|
+
* whether interactive confirmation is possible (`decidePushSafety` for a
|
|
102
|
+
* push); this is the backstop.
|
|
103
|
+
*
|
|
104
|
+
* Ctrl-C and Ctrl-D answer no. On a terminal readline reads Ctrl-C as a key,
|
|
105
|
+
* not as a signal, and with nothing listening it only pauses the input: the
|
|
106
|
+
* question never resolves, and the open database connections behind it keep
|
|
107
|
+
* the process alive, so the command hung instead of stopping. Answering no
|
|
108
|
+
* sends it down the path that says "Aborted" and cleans up.
|
|
109
|
+
*/
|
|
110
|
+
async function promptConfirm(question) {
|
|
111
|
+
if (!process.stdin.isTTY) return false;
|
|
112
|
+
const rl = readline.createInterface({
|
|
113
|
+
input: process.stdin,
|
|
114
|
+
output: process.stdout
|
|
115
|
+
});
|
|
116
|
+
try {
|
|
117
|
+
const answer = await new Promise((resolve) => {
|
|
118
|
+
rl.once("SIGINT", () => {
|
|
119
|
+
process.stdout.write("\n");
|
|
120
|
+
resolve("");
|
|
121
|
+
});
|
|
122
|
+
rl.once("close", () => resolve(""));
|
|
123
|
+
rl.question(question, resolve);
|
|
124
|
+
});
|
|
125
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
126
|
+
} finally {
|
|
127
|
+
rl.close();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
131
|
+
export { require_arg as n, promptConfirm as t };
|
|
86
132
|
|
|
87
|
-
//# sourceMappingURL=
|
|
133
|
+
//# sourceMappingURL=cli-prompt-egtNKkZl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-prompt-egtNKkZl.js","names":[],"sources":["../../../node_modules/.pnpm/arg@5.0.2/node_modules/arg/index.js","../src/cli-prompt.ts"],"sourcesContent":["const flagSymbol = Symbol('arg flag');\n\nclass ArgError extends Error {\n\tconstructor(msg, code) {\n\t\tsuper(msg);\n\t\tthis.name = 'ArgError';\n\t\tthis.code = code;\n\n\t\tObject.setPrototypeOf(this, ArgError.prototype);\n\t}\n}\n\nfunction arg(\n\topts,\n\t{\n\t\targv = process.argv.slice(2),\n\t\tpermissive = false,\n\t\tstopAtPositional = false\n\t} = {}\n) {\n\tif (!opts) {\n\t\tthrow new ArgError(\n\t\t\t'argument specification object is required',\n\t\t\t'ARG_CONFIG_NO_SPEC'\n\t\t);\n\t}\n\n\tconst result = { _: [] };\n\n\tconst aliases = {};\n\tconst handlers = {};\n\n\tfor (const key of Object.keys(opts)) {\n\t\tif (!key) {\n\t\t\tthrow new ArgError(\n\t\t\t\t'argument key cannot be an empty string',\n\t\t\t\t'ARG_CONFIG_EMPTY_KEY'\n\t\t\t);\n\t\t}\n\n\t\tif (key[0] !== '-') {\n\t\t\tthrow new ArgError(\n\t\t\t\t`argument key must start with '-' but found: '${key}'`,\n\t\t\t\t'ARG_CONFIG_NONOPT_KEY'\n\t\t\t);\n\t\t}\n\n\t\tif (key.length === 1) {\n\t\t\tthrow new ArgError(\n\t\t\t\t`argument key must have a name; singular '-' keys are not allowed: ${key}`,\n\t\t\t\t'ARG_CONFIG_NONAME_KEY'\n\t\t\t);\n\t\t}\n\n\t\tif (typeof opts[key] === 'string') {\n\t\t\taliases[key] = opts[key];\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet type = opts[key];\n\t\tlet isFlag = false;\n\n\t\tif (\n\t\t\tArray.isArray(type) &&\n\t\t\ttype.length === 1 &&\n\t\t\ttypeof type[0] === 'function'\n\t\t) {\n\t\t\tconst [fn] = type;\n\t\t\ttype = (value, name, prev = []) => {\n\t\t\t\tprev.push(fn(value, name, prev[prev.length - 1]));\n\t\t\t\treturn prev;\n\t\t\t};\n\t\t\tisFlag = fn === Boolean || fn[flagSymbol] === true;\n\t\t} else if (typeof type === 'function') {\n\t\t\tisFlag = type === Boolean || type[flagSymbol] === true;\n\t\t} else {\n\t\t\tthrow new ArgError(\n\t\t\t\t`type missing or not a function or valid array type: ${key}`,\n\t\t\t\t'ARG_CONFIG_VAD_TYPE'\n\t\t\t);\n\t\t}\n\n\t\tif (key[1] !== '-' && key.length > 2) {\n\t\t\tthrow new ArgError(\n\t\t\t\t`short argument keys (with a single hyphen) must have only one character: ${key}`,\n\t\t\t\t'ARG_CONFIG_SHORTOPT_TOOLONG'\n\t\t\t);\n\t\t}\n\n\t\thandlers[key] = [type, isFlag];\n\t}\n\n\tfor (let i = 0, len = argv.length; i < len; i++) {\n\t\tconst wholeArg = argv[i];\n\n\t\tif (stopAtPositional && result._.length > 0) {\n\t\t\tresult._ = result._.concat(argv.slice(i));\n\t\t\tbreak;\n\t\t}\n\n\t\tif (wholeArg === '--') {\n\t\t\tresult._ = result._.concat(argv.slice(i + 1));\n\t\t\tbreak;\n\t\t}\n\n\t\tif (wholeArg.length > 1 && wholeArg[0] === '-') {\n\t\t\t/* eslint-disable operator-linebreak */\n\t\t\tconst separatedArguments =\n\t\t\t\twholeArg[1] === '-' || wholeArg.length === 2\n\t\t\t\t\t? [wholeArg]\n\t\t\t\t\t: wholeArg\n\t\t\t\t\t\t\t.slice(1)\n\t\t\t\t\t\t\t.split('')\n\t\t\t\t\t\t\t.map((a) => `-${a}`);\n\t\t\t/* eslint-enable operator-linebreak */\n\n\t\t\tfor (let j = 0; j < separatedArguments.length; j++) {\n\t\t\t\tconst arg = separatedArguments[j];\n\t\t\t\tconst [originalArgName, argStr] =\n\t\t\t\t\targ[1] === '-' ? arg.split(/=(.*)/, 2) : [arg, undefined];\n\n\t\t\t\tlet argName = originalArgName;\n\t\t\t\twhile (argName in aliases) {\n\t\t\t\t\targName = aliases[argName];\n\t\t\t\t}\n\n\t\t\t\tif (!(argName in handlers)) {\n\t\t\t\t\tif (permissive) {\n\t\t\t\t\t\tresult._.push(arg);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new ArgError(\n\t\t\t\t\t\t\t`unknown or unexpected option: ${originalArgName}`,\n\t\t\t\t\t\t\t'ARG_UNKNOWN_OPTION'\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst [type, isFlag] = handlers[argName];\n\n\t\t\t\tif (!isFlag && j + 1 < separatedArguments.length) {\n\t\t\t\t\tthrow new ArgError(\n\t\t\t\t\t\t`option requires argument (but was followed by another short argument): ${originalArgName}`,\n\t\t\t\t\t\t'ARG_MISSING_REQUIRED_SHORTARG'\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (isFlag) {\n\t\t\t\t\tresult[argName] = type(true, argName, result[argName]);\n\t\t\t\t} else if (argStr === undefined) {\n\t\t\t\t\tif (\n\t\t\t\t\t\targv.length < i + 2 ||\n\t\t\t\t\t\t(argv[i + 1].length > 1 &&\n\t\t\t\t\t\t\targv[i + 1][0] === '-' &&\n\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\targv[i + 1].match(/^-?\\d*(\\.(?=\\d))?\\d*$/) &&\n\t\t\t\t\t\t\t\t(type === Number ||\n\t\t\t\t\t\t\t\t\t// eslint-disable-next-line no-undef\n\t\t\t\t\t\t\t\t\t(typeof BigInt !== 'undefined' && type === BigInt))\n\t\t\t\t\t\t\t))\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst extended =\n\t\t\t\t\t\t\toriginalArgName === argName ? '' : ` (alias for ${argName})`;\n\t\t\t\t\t\tthrow new ArgError(\n\t\t\t\t\t\t\t`option requires argument: ${originalArgName}${extended}`,\n\t\t\t\t\t\t\t'ARG_MISSING_REQUIRED_LONGARG'\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tresult[argName] = type(argv[i + 1], argName, result[argName]);\n\t\t\t\t\t++i;\n\t\t\t\t} else {\n\t\t\t\t\tresult[argName] = type(argStr, argName, result[argName]);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tresult._.push(wholeArg);\n\t\t}\n\t}\n\n\treturn result;\n}\n\narg.flag = (fn) => {\n\tfn[flagSymbol] = true;\n\treturn fn;\n};\n\n// Utility types\narg.COUNT = arg.flag((v, name, existingCount) => (existingCount || 0) + 1);\n\n// Expose error class\narg.ArgError = ArgError;\n\nmodule.exports = arg;\n","/**\n * The one yes/no question the driver CLI asks: before a destructive `db push`,\n * before a `db restore` without `--yes`, before `db branch prune` removes\n * anything, and before `schema introspect` samples rows.\n */\nimport readline from \"readline\";\n\n/**\n * Ask a yes/no question on an interactive terminal; `true` only for \"y\" or\n * \"yes\".\n *\n * The `isTTY` guard is the contract, not an optimisation: non-interactive\n * shells (CI, pipes, agents) can never answer, and `readline` on a non-TTY\n * stdin resolves with whatever the pipe happens to contain, or never resolves\n * at all. Returning false there is what makes an unattended `db push` abort\n * instead of auto-confirming a destructive change. Callers decide first\n * whether interactive confirmation is possible (`decidePushSafety` for a\n * push); this is the backstop.\n *\n * Ctrl-C and Ctrl-D answer no. On a terminal readline reads Ctrl-C as a key,\n * not as a signal, and with nothing listening it only pauses the input: the\n * question never resolves, and the open database connections behind it keep\n * the process alive, so the command hung instead of stopping. Answering no\n * sends it down the path that says \"Aborted\" and cleans up.\n */\nexport async function promptConfirm(question: string): Promise<boolean> {\n if (!process.stdin.isTTY) return false;\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n try {\n const answer = await new Promise<string>((resolve) => {\n rl.once(\"SIGINT\", () => {\n process.stdout.write(\"\\n\");\n resolve(\"\");\n });\n rl.once(\"close\", () => resolve(\"\"));\n rl.question(question, resolve);\n });\n return /^y(es)?$/i.test(answer.trim());\n } finally {\n rl.close();\n }\n}\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask a yes/no question on an interactive terminal; `true` only for "y" or
|
|
3
|
+
* "yes".
|
|
4
|
+
*
|
|
5
|
+
* The `isTTY` guard is the contract, not an optimisation: non-interactive
|
|
6
|
+
* shells (CI, pipes, agents) can never answer, and `readline` on a non-TTY
|
|
7
|
+
* stdin resolves with whatever the pipe happens to contain, or never resolves
|
|
8
|
+
* at all. Returning false there is what makes an unattended `db push` abort
|
|
9
|
+
* instead of auto-confirming a destructive change. Callers decide first
|
|
10
|
+
* whether interactive confirmation is possible (`decidePushSafety` for a
|
|
11
|
+
* push); this is the backstop.
|
|
12
|
+
*
|
|
13
|
+
* Ctrl-C and Ctrl-D answer no. On a terminal readline reads Ctrl-C as a key,
|
|
14
|
+
* not as a signal, and with nothing listening it only pauses the input: the
|
|
15
|
+
* question never resolves, and the open database connections behind it keep
|
|
16
|
+
* the process alive, so the command hung instead of stopping. Answering no
|
|
17
|
+
* sends it down the path that says "Aborted" and cleans up.
|
|
18
|
+
*/
|
|
19
|
+
export declare function promptConfirm(question: string): Promise<boolean>;
|
|
@@ -8,11 +8,17 @@
|
|
|
8
8
|
* `db push`: a `--dry-run` that left one behind while saying nothing was
|
|
9
9
|
* applied, and `db generate`, left one per target on the server.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* It is dropped on every way out of the command: success, a destructive push
|
|
12
|
+
* the user declined or that had no terminal to ask, and a crash. A crash that
|
|
13
|
+
* kept it left it for good, because the next push finds it already there and
|
|
14
|
+
* takes it for one made by hand.
|
|
15
|
+
*
|
|
16
|
+
* Two cases keep it. An Atlas run that failed while planning against it leaves
|
|
17
|
+
* the state Atlas was planning, which is the one thing worth inspecting. And
|
|
18
|
+
* one this process did not create (made by hand, the remedy for a role without
|
|
19
|
+
* `CREATEDB`) is the user's, and dropping it would put them back at the same
|
|
20
|
+
* refusal next time. An Atlas run that failed before planning (see
|
|
21
|
+
* {@link atlasFailedBeforePlanning}) left nothing in it, and it is dropped.
|
|
16
22
|
*/
|
|
17
23
|
export interface ScratchDatabaseOps {
|
|
18
24
|
/** Create it if it is missing; `true` only when this call created it. */
|
|
@@ -22,13 +28,46 @@ export interface ScratchDatabaseOps {
|
|
|
22
28
|
export declare class ScratchDatabase {
|
|
23
29
|
private readonly ops;
|
|
24
30
|
private created;
|
|
31
|
+
private keptAsEvidence;
|
|
25
32
|
constructor(ops: ScratchDatabaseOps);
|
|
26
33
|
/** Make sure it exists before an Atlas call that plans against it. */
|
|
27
34
|
ensure(databaseUrl: string, devDatabaseUrl: string): Promise<void>;
|
|
35
|
+
/** An Atlas run against it failed: keep it, whatever the command does next. */
|
|
36
|
+
keepAsEvidence(): void;
|
|
37
|
+
/**
|
|
38
|
+
* An Atlas run failed with `stderr`. Failing before it planned, it left
|
|
39
|
+
* nothing here to read, so the database is dropped now — before the
|
|
40
|
+
* command exits, which may not unwind through {@link around}. Otherwise
|
|
41
|
+
* it is kept as the evidence.
|
|
42
|
+
*/
|
|
43
|
+
afterAtlasFailure(stderr: string): Promise<void>;
|
|
28
44
|
/**
|
|
29
|
-
* Run a command, then drop the scratch database if the command created it
|
|
30
|
-
*
|
|
31
|
-
*
|
|
45
|
+
* Run a command, then drop the scratch database if the command created it,
|
|
46
|
+
* whether the command returned or threw. A throw after
|
|
47
|
+
* {@link keepAsEvidence} keeps it. A command that wants to stop with exit 1
|
|
48
|
+
* throws {@link CommandStopped} rather than calling `process.exit`, which
|
|
49
|
+
* would skip this.
|
|
32
50
|
*/
|
|
33
51
|
around<T>(command: () => Promise<T>): Promise<T>;
|
|
52
|
+
/** Drop it now if this process created it. Safe to call twice. */
|
|
53
|
+
release(): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Whether Atlas failed before it planned anything: on connecting, which it
|
|
57
|
+
* reports as `querying system variables: …` — SSL the server does not offer, a
|
|
58
|
+
* login refused, a socket that closed or never opened.
|
|
59
|
+
*/
|
|
60
|
+
export declare function atlasFailedBeforePlanning(stderr: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* A db command stopping with exit 1 after it has said why: a destructive push
|
|
63
|
+
* the user declined, or one with no terminal to ask on.
|
|
64
|
+
*
|
|
65
|
+
* Thrown instead of `process.exit(1)`, so it unwinds through
|
|
66
|
+
* {@link ScratchDatabase.around} and the scratch database is dropped on the way
|
|
67
|
+
* out. `alreadyReported` tells `reportCommandFailure` the explanation is on the
|
|
68
|
+
* terminal already; the entry point sets the exit code.
|
|
69
|
+
*/
|
|
70
|
+
export declare class CommandStopped extends Error {
|
|
71
|
+
readonly alreadyReported = true;
|
|
72
|
+
constructor(reason: string);
|
|
34
73
|
}
|