@rebasepro/cli 0.19.1-canary.g5a92fa9 → 0.19.1-canary.g9b6d85f
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/commands/db.d.ts +30 -0
- package/dist/index.es.js +198 -214
- package/dist/index.es.js.map +1 -1
- package/package.json +7 -7
package/dist/commands/db.d.ts
CHANGED
|
@@ -112,6 +112,36 @@ export declare function refuseAtlasOnManagedDatabase(rawArgs: string[], kind: st
|
|
|
112
112
|
* cover. It does now.
|
|
113
113
|
*/
|
|
114
114
|
export declare function refuseBranchOnManagedDatabase(rawArgs: string[], kind: string): void;
|
|
115
|
+
/**
|
|
116
|
+
* The one place this CLI spawns the driver's own CLI.
|
|
117
|
+
*
|
|
118
|
+
* There were three, each with its own copy of "tsx for a `.ts` entry, `node`
|
|
119
|
+
* otherwise". That rule was right only while the driver shipped `src/`; once it
|
|
120
|
+
* shipped `dist/cli.js` all three quietly switched to plain `node`, and the
|
|
121
|
+
* driver loads the PROJECT's TypeScript in process:
|
|
122
|
+
*
|
|
123
|
+
* - `schema stale` reads the collections, could not resolve `./authors` onto
|
|
124
|
+
* `authors.ts`, and answered "⏭ Not checked" while exiting 0;
|
|
125
|
+
* - `db push` does the same in `ensureAuthTables`, so `rebase.users` was never
|
|
126
|
+
* created and the push died at "Applying RLS policies" with
|
|
127
|
+
* `relation "rebase.users" does not exist` — on a virgin database, which is
|
|
128
|
+
* the documented bring-your-own-Postgres first run.
|
|
129
|
+
*
|
|
130
|
+
* Two were fixed and the third was missed, because three copies of a decision
|
|
131
|
+
* are three chances to miss one. There is one now, and a gate holds it at one.
|
|
132
|
+
*
|
|
133
|
+
* tsx whenever it is installed — a devDependency of every scaffold, for exactly
|
|
134
|
+
* this reason. Without it a `.ts` entry cannot run at all; a built entry still
|
|
135
|
+
* runs, and the subcommands that never touch the project's TypeScript still work.
|
|
136
|
+
*/
|
|
137
|
+
export declare function spawnDriverCli(resolved: {
|
|
138
|
+
projectRoot: string;
|
|
139
|
+
backendDir: string;
|
|
140
|
+
pluginCli: string;
|
|
141
|
+
env: Record<string, string>;
|
|
142
|
+
}, childArgs: string[], options?: {
|
|
143
|
+
quiet?: boolean;
|
|
144
|
+
}): Promise<void>;
|
|
115
145
|
/**
|
|
116
146
|
* Run a `schema` subcommand through the active driver's CLI.
|
|
117
147
|
*
|
package/dist/index.es.js
CHANGED
|
@@ -2452,6 +2452,19 @@ async function configureEnvFile(targetDirectory, databaseUrl) {
|
|
|
2452
2452
|
`# DATABASE_URL=postgresql://rebase_app:${dbPassword}@127.0.0.1:${dbPort}/rebase?options=-c%20search_path%3Dpublic&sslmode=disable`,
|
|
2453
2453
|
`DATABASE_PASSWORD=${dbPassword}`
|
|
2454
2454
|
].join("\n"));
|
|
2455
|
+
const envExampleReference = path.join(targetDirectory, ".env.example");
|
|
2456
|
+
if (fs.existsSync(envExampleReference)) {
|
|
2457
|
+
let exampleContent = fs.readFileSync(envExampleReference, "utf-8");
|
|
2458
|
+
exampleContent = exampleContent.replace(/^DATABASE_URL=postgresql:\/\/[^\n]*$/m, [
|
|
2459
|
+
"# Commented out on purpose — that is what selects the managed database.",
|
|
2460
|
+
"# To use the docker-compose Postgres this project ships instead:",
|
|
2461
|
+
"# docker compose up -d db, then uncomment the line below in .env",
|
|
2462
|
+
"# (with DATABASE_PASSWORD from that file, not the placeholder here).",
|
|
2463
|
+
`# DATABASE_URL=postgresql://rebase_app:changeme@127.0.0.1:${dbPort}/rebase?options=-c%20search_path%3Dpublic&sslmode=disable`
|
|
2464
|
+
].join("\n"));
|
|
2465
|
+
exampleContent = exampleContent.replaceAll("@localhost:5432/rebase", `@127.0.0.1:${dbPort}/rebase`);
|
|
2466
|
+
fs.writeFileSync(envExampleReference, exampleContent, "utf-8");
|
|
2467
|
+
}
|
|
2455
2468
|
const dockerComposePath = path.join(targetDirectory, "docker-compose.yml");
|
|
2456
2469
|
if (fs.existsSync(dockerComposePath)) {
|
|
2457
2470
|
let dockerComposeContent = fs.readFileSync(dockerComposePath, "utf-8");
|
|
@@ -2844,62 +2857,6 @@ function reportSpawnFailure(error) {
|
|
|
2844
2857
|
if (message) console.error(chalk.red(`✗ ${message}`));
|
|
2845
2858
|
}
|
|
2846
2859
|
//#endregion
|
|
2847
|
-
//#region src/utils/command-words.ts
|
|
2848
|
-
/**
|
|
2849
|
-
* The words that name a command, with the flags taken back out.
|
|
2850
|
-
*
|
|
2851
|
-
* `rawArgs` is the whole of `process.argv`, and reading the command's words at
|
|
2852
|
-
* fixed indices off it assumes nothing precedes them. Something routinely does:
|
|
2853
|
-
* `--debug` is what `bin/rebase.js` prints after every failure as the thing to
|
|
2854
|
-
* re-run with, so it is the single most likely token to appear before a command
|
|
2855
|
-
* word, and it shifted every index by one.
|
|
2856
|
-
*
|
|
2857
|
-
* What that cost is not a bad error message. `rebase db branch switch feature`
|
|
2858
|
-
* writes a per-checkout pointer that the CLI owns; the driver, running as a
|
|
2859
|
-
* child process, cannot persist it and does not try. The dispatch found
|
|
2860
|
-
* `switch` by position, so `rebase --debug db branch switch feature` missed the
|
|
2861
|
-
* CLI's branch and handed the line to the driver — which reported success and
|
|
2862
|
-
* left the checkout on the main database. Every subsequent `dev`, `push` and
|
|
2863
|
-
* `backup` then ran against the wrong database, believing it was the branch,
|
|
2864
|
-
* which is the exact failure branching exists to prevent.
|
|
2865
|
-
*
|
|
2866
|
-
* The words are anchored on the command name rather than taken from position
|
|
2867
|
-
* zero, because a flag written in the space form (`--database-url <url>`) leaves
|
|
2868
|
-
* its value behind as a bare token and no parser at this level knows which
|
|
2869
|
-
* flags take values. Anchoring survives that: the value would have to be the
|
|
2870
|
-
* literal command name to fool it.
|
|
2871
|
-
*
|
|
2872
|
-
* Returns `[]` when the command name is not on the line at all.
|
|
2873
|
-
*/
|
|
2874
|
-
function commandWords(rawArgs, command) {
|
|
2875
|
-
const words = rawArgs.slice(2).filter((token) => !token.startsWith("-"));
|
|
2876
|
-
const start = words.indexOf(command);
|
|
2877
|
-
return start === -1 ? [] : words.slice(start);
|
|
2878
|
-
}
|
|
2879
|
-
/**
|
|
2880
|
-
* The line to hand a spawned driver, starting at the command word.
|
|
2881
|
-
*
|
|
2882
|
-
* The same defect one layer down, and it does not degrade gracefully: the
|
|
2883
|
-
* driver reads its domain from `args[0]`, so `rebase --debug db push` spawned
|
|
2884
|
-
* it with `["--debug", "db", "push"]` and it answered "Unknown domain command:
|
|
2885
|
-
* --debug" — for a flag the CLI itself tells you to add after any failure.
|
|
2886
|
-
*
|
|
2887
|
-
* Tokens written *before* the command word are moved after it rather than
|
|
2888
|
-
* dropped. Dropping them would be the same class of bug in the other direction:
|
|
2889
|
-
* `rebase --database-url postgres://… db push` would silently lose the flag that
|
|
2890
|
-
* says which database to touch. Appending keeps each flag next to its value, and
|
|
2891
|
-
* `arg` reads flags wherever they appear.
|
|
2892
|
-
*
|
|
2893
|
-
* Falls back to `rawArgs.slice(2)` when the command word is not on the line,
|
|
2894
|
-
* which is what an internally synthesised argv looks like.
|
|
2895
|
-
*/
|
|
2896
|
-
function argsFromCommand(rawArgs, command) {
|
|
2897
|
-
const tail = rawArgs.slice(2);
|
|
2898
|
-
const start = tail.findIndex((token) => token === command);
|
|
2899
|
-
if (start <= 0) return [...tail];
|
|
2900
|
-
return [...tail.slice(start), ...tail.slice(0, start)];
|
|
2901
|
-
}
|
|
2902
|
-
//#endregion
|
|
2903
2860
|
//#region src/utils/unknown-command.ts
|
|
2904
2861
|
/**
|
|
2905
2862
|
* What every command family says when it does not recognise a subcommand.
|
|
@@ -2994,6 +2951,62 @@ function unknownCommand(typed, known, family = "") {
|
|
|
2994
2951
|
process.exit(1);
|
|
2995
2952
|
}
|
|
2996
2953
|
//#endregion
|
|
2954
|
+
//#region src/utils/command-words.ts
|
|
2955
|
+
/**
|
|
2956
|
+
* The words that name a command, with the flags taken back out.
|
|
2957
|
+
*
|
|
2958
|
+
* `rawArgs` is the whole of `process.argv`, and reading the command's words at
|
|
2959
|
+
* fixed indices off it assumes nothing precedes them. Something routinely does:
|
|
2960
|
+
* `--debug` is what `bin/rebase.js` prints after every failure as the thing to
|
|
2961
|
+
* re-run with, so it is the single most likely token to appear before a command
|
|
2962
|
+
* word, and it shifted every index by one.
|
|
2963
|
+
*
|
|
2964
|
+
* What that cost is not a bad error message. `rebase db branch switch feature`
|
|
2965
|
+
* writes a per-checkout pointer that the CLI owns; the driver, running as a
|
|
2966
|
+
* child process, cannot persist it and does not try. The dispatch found
|
|
2967
|
+
* `switch` by position, so `rebase --debug db branch switch feature` missed the
|
|
2968
|
+
* CLI's branch and handed the line to the driver — which reported success and
|
|
2969
|
+
* left the checkout on the main database. Every subsequent `dev`, `push` and
|
|
2970
|
+
* `backup` then ran against the wrong database, believing it was the branch,
|
|
2971
|
+
* which is the exact failure branching exists to prevent.
|
|
2972
|
+
*
|
|
2973
|
+
* The words are anchored on the command name rather than taken from position
|
|
2974
|
+
* zero, because a flag written in the space form (`--database-url <url>`) leaves
|
|
2975
|
+
* its value behind as a bare token and no parser at this level knows which
|
|
2976
|
+
* flags take values. Anchoring survives that: the value would have to be the
|
|
2977
|
+
* literal command name to fool it.
|
|
2978
|
+
*
|
|
2979
|
+
* Returns `[]` when the command name is not on the line at all.
|
|
2980
|
+
*/
|
|
2981
|
+
function commandWords(rawArgs, command) {
|
|
2982
|
+
const words = rawArgs.slice(2).filter((token) => !token.startsWith("-"));
|
|
2983
|
+
const start = words.indexOf(command);
|
|
2984
|
+
return start === -1 ? [] : words.slice(start);
|
|
2985
|
+
}
|
|
2986
|
+
/**
|
|
2987
|
+
* The line to hand a spawned driver, starting at the command word.
|
|
2988
|
+
*
|
|
2989
|
+
* The same defect one layer down, and it does not degrade gracefully: the
|
|
2990
|
+
* driver reads its domain from `args[0]`, so `rebase --debug db push` spawned
|
|
2991
|
+
* it with `["--debug", "db", "push"]` and it answered "Unknown domain command:
|
|
2992
|
+
* --debug" — for a flag the CLI itself tells you to add after any failure.
|
|
2993
|
+
*
|
|
2994
|
+
* Tokens written *before* the command word are moved after it rather than
|
|
2995
|
+
* dropped. Dropping them would be the same class of bug in the other direction:
|
|
2996
|
+
* `rebase --database-url postgres://… db push` would silently lose the flag that
|
|
2997
|
+
* says which database to touch. Appending keeps each flag next to its value, and
|
|
2998
|
+
* `arg` reads flags wherever they appear.
|
|
2999
|
+
*
|
|
3000
|
+
* Falls back to `rawArgs.slice(2)` when the command word is not on the line,
|
|
3001
|
+
* which is what an internally synthesised argv looks like.
|
|
3002
|
+
*/
|
|
3003
|
+
function argsFromCommand(rawArgs, command) {
|
|
3004
|
+
const tail = rawArgs.slice(2);
|
|
3005
|
+
const start = tail.findIndex((token) => token === command);
|
|
3006
|
+
if (start <= 0) return [...tail];
|
|
3007
|
+
return [...tail.slice(start), ...tail.slice(0, start)];
|
|
3008
|
+
}
|
|
3009
|
+
//#endregion
|
|
2997
3010
|
//#region src/dev-db/prepare.ts
|
|
2998
3011
|
/**
|
|
2999
3012
|
* The one place a command asks "which database, and how do I reach it?".
|
|
@@ -3179,122 +3192,6 @@ function managedNotices(prepared) {
|
|
|
3179
3192
|
return lines;
|
|
3180
3193
|
}
|
|
3181
3194
|
//#endregion
|
|
3182
|
-
//#region src/commands/schema.ts
|
|
3183
|
-
/**
|
|
3184
|
-
* CLI command: rebase schema <action>
|
|
3185
|
-
*/
|
|
3186
|
-
async function schemaCommand(subcommand, rawArgs) {
|
|
3187
|
-
if (!subcommand || subcommand === "--help" || wantsHelp(rawArgs)) {
|
|
3188
|
-
printSchemaHelp(subcommand === "--help" ? void 0 : subcommand);
|
|
3189
|
-
return;
|
|
3190
|
-
}
|
|
3191
|
-
if (!SCHEMA_ACTION_HELP[subcommand]) unknownCommand(subcommand, Object.keys(SCHEMA_ACTION_HELP), "schema");
|
|
3192
|
-
const projectRoot = requireProjectRoot();
|
|
3193
|
-
recordEvent("cli.schema", { subcommand: subcommand ?? "none" }, { projectRoot });
|
|
3194
|
-
const backendDir = requireBackendDir(projectRoot);
|
|
3195
|
-
const activePlugin = getActiveBackendPlugin(backendDir);
|
|
3196
|
-
if (!activePlugin) {
|
|
3197
|
-
console.error(chalk.red("✗ Could not detect an active database plugin."));
|
|
3198
|
-
console.error(chalk.gray(" Make sure a package like @rebasepro/server-postgres is installed in backend/package.json."));
|
|
3199
|
-
process.exit(1);
|
|
3200
|
-
}
|
|
3201
|
-
const pluginCli = resolvePluginCliScript(backendDir, activePlugin);
|
|
3202
|
-
if (!pluginCli) exitDependenciesNotInstalled(projectRoot);
|
|
3203
|
-
const envFile = findEnvFile(projectRoot);
|
|
3204
|
-
const env = { ...process.env };
|
|
3205
|
-
if (envFile) env.DOTENV_CONFIG_PATH = envFile;
|
|
3206
|
-
env[DEV_DATABASE_KIND_ENV] = devDatabaseKind(projectRoot) ?? "";
|
|
3207
|
-
try {
|
|
3208
|
-
/**
|
|
3209
|
-
* tsx, whether the driver CLI is source or built.
|
|
3210
|
-
*
|
|
3211
|
-
* This chose the interpreter from the file extension — tsx for a `.ts`
|
|
3212
|
-
* entry, `node` for a built one — which was right only for as long as
|
|
3213
|
-
* the driver shipped `src/`. Once it shipped `dist/cli.js`, the built
|
|
3214
|
-
* CLI ran under plain `node`, and some of its subcommands load the
|
|
3215
|
-
* PROJECT's collections in process. `schema stale` does: on the stock
|
|
3216
|
-
* scaffold, whose collections import each other, Node could not resolve
|
|
3217
|
-
* `./authors` onto `authors.ts` and the command reported "⏭ Not
|
|
3218
|
-
* checked" — answering "is the generated schema stale?" with nothing,
|
|
3219
|
-
* and exiting 0.
|
|
3220
|
-
*
|
|
3221
|
-
* The same rule lives in `execDriverCli` (commands/db.ts). Two copies of
|
|
3222
|
-
* one decision is how they came to disagree; this one is kept because
|
|
3223
|
-
* `schema` deliberately does NOT resolve a database, and `execDriverCli`
|
|
3224
|
-
* is reached through a path that does.
|
|
3225
|
-
*/
|
|
3226
|
-
const tsxBin = resolveTsx(projectRoot);
|
|
3227
|
-
if (!tsxBin && pluginCli.endsWith(".ts")) exitDependenciesNotInstalled(projectRoot);
|
|
3228
|
-
await execa(tsxBin ?? "node", [pluginCli, ...argsFromCommand(rawArgs, "schema")], {
|
|
3229
|
-
cwd: backendDir,
|
|
3230
|
-
stdio: "inherit",
|
|
3231
|
-
env
|
|
3232
|
-
});
|
|
3233
|
-
} catch (error) {
|
|
3234
|
-
reportSpawnFailure(error);
|
|
3235
|
-
process.exit(1);
|
|
3236
|
-
}
|
|
3237
|
-
}
|
|
3238
|
-
/** One page per subcommand, so `rebase schema <action> --help` says something. */
|
|
3239
|
-
var SCHEMA_ACTION_HELP = {
|
|
3240
|
-
generate: {
|
|
3241
|
-
usage: "rebase schema generate [--collections <dir>] [--output <file>] [--watch]",
|
|
3242
|
-
summary: "Generate the Drizzle schema from the collection definitions.",
|
|
3243
|
-
notes: ["--watch regenerates on every change to a collection file."]
|
|
3244
|
-
},
|
|
3245
|
-
introspect: {
|
|
3246
|
-
usage: "rebase schema introspect [--collections <dir>] [--output <dir>] [--schema <name>] [--force]",
|
|
3247
|
-
summary: "Read an existing database and write Rebase collection definitions from it.",
|
|
3248
|
-
notes: ["--force overwrites collection files that are already there."]
|
|
3249
|
-
},
|
|
3250
|
-
stale: {
|
|
3251
|
-
usage: "rebase schema stale [--collections <dir>] [--output <file>] [--fix]",
|
|
3252
|
-
summary: "Report generated schema files that no longer match the collections.",
|
|
3253
|
-
notes: ["--fix regenerates them instead of only reporting."]
|
|
3254
|
-
}
|
|
3255
|
-
};
|
|
3256
|
-
function printSchemaHelp(action) {
|
|
3257
|
-
const entry = action ? SCHEMA_ACTION_HELP[action] : void 0;
|
|
3258
|
-
if (entry) {
|
|
3259
|
-
console.log(`
|
|
3260
|
-
${chalk.bold(`rebase schema ${action}`)}
|
|
3261
|
-
|
|
3262
|
-
${entry.summary}
|
|
3263
|
-
|
|
3264
|
-
${chalk.green.bold("Usage")}
|
|
3265
|
-
${chalk.blue(entry.usage)}
|
|
3266
|
-
${entry.notes?.length ? `\n${chalk.green.bold("Notes")}\n${entry.notes.map((n) => ` ${chalk.gray(`• ${n}`)}`).join("\n")}\n` : ""}
|
|
3267
|
-
${chalk.gray("Run `rebase schema --help` for every subcommand.")}
|
|
3268
|
-
`);
|
|
3269
|
-
return;
|
|
3270
|
-
}
|
|
3271
|
-
console.log(`
|
|
3272
|
-
${chalk.bold("rebase schema")} — Schema management commands
|
|
3273
|
-
|
|
3274
|
-
${chalk.green.bold("Usage")}
|
|
3275
|
-
rebase schema ${chalk.blue("<command>")} [options]
|
|
3276
|
-
|
|
3277
|
-
${chalk.green.bold("Commands")}
|
|
3278
|
-
${chalk.gray("(Commands are provided by your active database driver plugin)")}
|
|
3279
|
-
${chalk.blue.bold("generate")} Generate Schema from collection definitions
|
|
3280
|
-
${chalk.blue.bold("introspect")} Introspect an existing database to generate collection definitions
|
|
3281
|
-
${chalk.blue.bold("stale")} Report generated schema files that no longer match the collections
|
|
3282
|
-
|
|
3283
|
-
${chalk.green.bold("generate Options")}
|
|
3284
|
-
${chalk.blue("--collections, -c")} Path to collections directory
|
|
3285
|
-
${chalk.blue("--output, -o")} Output path for generated schema
|
|
3286
|
-
${chalk.blue("--watch, -w")} Watch for changes and regenerate automatically
|
|
3287
|
-
|
|
3288
|
-
${chalk.green.bold("introspect Options")}
|
|
3289
|
-
${chalk.blue("--output, -o")} Output directory for generated collection files
|
|
3290
|
-
${chalk.blue("--schema")} Postgres schema to read (default: public)
|
|
3291
|
-
${chalk.blue("--force, -f")} Overwrite collection files that already exist
|
|
3292
|
-
|
|
3293
|
-
${chalk.green.bold("stale Options")}
|
|
3294
|
-
${chalk.blue("--fix")} Regenerate the stale files instead of only reporting them
|
|
3295
|
-
`);
|
|
3296
|
-
}
|
|
3297
|
-
//#endregion
|
|
3298
3195
|
//#region src/commands/db.ts
|
|
3299
3196
|
/**
|
|
3300
3197
|
* CLI command: rebase db <action>
|
|
@@ -3588,42 +3485,41 @@ async function resolveDriverCli() {
|
|
|
3588
3485
|
env
|
|
3589
3486
|
};
|
|
3590
3487
|
}
|
|
3591
|
-
/**
|
|
3592
|
-
|
|
3488
|
+
/**
|
|
3489
|
+
* The one place this CLI spawns the driver's own CLI.
|
|
3490
|
+
*
|
|
3491
|
+
* There were three, each with its own copy of "tsx for a `.ts` entry, `node`
|
|
3492
|
+
* otherwise". That rule was right only while the driver shipped `src/`; once it
|
|
3493
|
+
* shipped `dist/cli.js` all three quietly switched to plain `node`, and the
|
|
3494
|
+
* driver loads the PROJECT's TypeScript in process:
|
|
3495
|
+
*
|
|
3496
|
+
* - `schema stale` reads the collections, could not resolve `./authors` onto
|
|
3497
|
+
* `authors.ts`, and answered "⏭ Not checked" while exiting 0;
|
|
3498
|
+
* - `db push` does the same in `ensureAuthTables`, so `rebase.users` was never
|
|
3499
|
+
* created and the push died at "Applying RLS policies" with
|
|
3500
|
+
* `relation "rebase.users" does not exist` — on a virgin database, which is
|
|
3501
|
+
* the documented bring-your-own-Postgres first run.
|
|
3502
|
+
*
|
|
3503
|
+
* Two were fixed and the third was missed, because three copies of a decision
|
|
3504
|
+
* are three chances to miss one. There is one now, and a gate holds it at one.
|
|
3505
|
+
*
|
|
3506
|
+
* tsx whenever it is installed — a devDependency of every scaffold, for exactly
|
|
3507
|
+
* this reason. Without it a `.ts` entry cannot run at all; a built entry still
|
|
3508
|
+
* runs, and the subcommands that never touch the project's TypeScript still work.
|
|
3509
|
+
*/
|
|
3510
|
+
async function spawnDriverCli(resolved, childArgs, options = {}) {
|
|
3593
3511
|
const { projectRoot, backendDir, pluginCli, env } = resolved;
|
|
3594
3512
|
const stdio = options.quiet ? "pipe" : "inherit";
|
|
3595
|
-
/**
|
|
3596
|
-
* tsx, whether the driver CLI is source or built.
|
|
3597
|
-
*
|
|
3598
|
-
* It used to be tsx only for a `.ts` entry, which happened to be right for
|
|
3599
|
-
* as long as the driver shipped `src/`. Once it shipped `dist/cli.js`
|
|
3600
|
-
* instead, this ran the built CLI under plain `node` — and some of its
|
|
3601
|
-
* subcommands load the PROJECT's collections in process. `schema stale`
|
|
3602
|
-
* does, so on every scaffold whose collections import each other (the stock
|
|
3603
|
-
* one does) it failed to resolve them and reported "⏭ Not checked": a
|
|
3604
|
-
* command that answers "is the generated schema stale?" with nothing at all,
|
|
3605
|
-
* exiting 0, on the default project.
|
|
3606
|
-
*
|
|
3607
|
-
* Node cannot load a `.ts` file, and cannot resolve `./authors` or
|
|
3608
|
-
* `./authors.js` onto `authors.ts`. tsx does both. It is a devDependency of
|
|
3609
|
-
* every scaffold for exactly this reason.
|
|
3610
|
-
*/
|
|
3611
3513
|
const tsxBin = resolveTsx(projectRoot);
|
|
3612
|
-
if (tsxBin)
|
|
3613
|
-
|
|
3614
|
-
cwd: backendDir,
|
|
3615
|
-
stdio,
|
|
3616
|
-
env
|
|
3617
|
-
});
|
|
3618
|
-
return;
|
|
3619
|
-
}
|
|
3620
|
-
if (pluginCli.endsWith(".ts")) throw new Error(dependenciesNotInstalled(projectRoot));
|
|
3621
|
-
await execa("node", [pluginCli, ...childArgs], {
|
|
3514
|
+
if (!tsxBin && pluginCli.endsWith(".ts")) throw new Error(dependenciesNotInstalled(projectRoot));
|
|
3515
|
+
await execa(tsxBin ?? "node", [pluginCli, ...childArgs], {
|
|
3622
3516
|
cwd: backendDir,
|
|
3623
3517
|
stdio,
|
|
3624
3518
|
env
|
|
3625
3519
|
});
|
|
3626
3520
|
}
|
|
3521
|
+
/** @deprecated Use {@link spawnDriverCli}. Kept as the internal name callers use. */
|
|
3522
|
+
var execDriverCli = spawnDriverCli;
|
|
3627
3523
|
/**
|
|
3628
3524
|
* Run a `schema` subcommand through the active driver's CLI.
|
|
3629
3525
|
*
|
|
@@ -3666,21 +3562,12 @@ async function runDriverDbCommand(rawArgs, options = {}) {
|
|
|
3666
3562
|
if (!options.quiet) for (const line of managedNotices(prepared)) console.log(chalk.gray(` ${line}`));
|
|
3667
3563
|
refuseAtlasOnManagedDatabase(rawArgs, prepared.database.kind);
|
|
3668
3564
|
const childArgs = absolutizeLocalPathArgs(argsFromCommand(rawArgs, "db"), process.cwd());
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
cwd: backendDir,
|
|
3674
|
-
stdio: "inherit",
|
|
3675
|
-
env
|
|
3676
|
-
});
|
|
3677
|
-
return;
|
|
3678
|
-
}
|
|
3679
|
-
await execa("node", [pluginCli, ...childArgs], {
|
|
3680
|
-
cwd: backendDir,
|
|
3681
|
-
stdio: "inherit",
|
|
3565
|
+
await spawnDriverCli({
|
|
3566
|
+
projectRoot,
|
|
3567
|
+
backendDir,
|
|
3568
|
+
pluginCli,
|
|
3682
3569
|
env
|
|
3683
|
-
});
|
|
3570
|
+
}, childArgs, options);
|
|
3684
3571
|
}
|
|
3685
3572
|
async function dbCommand$1(subcommand, rawArgs) {
|
|
3686
3573
|
if (!subcommand || subcommand === "--help" || rawArgs.includes("--help") || rawArgs.includes("-h")) {
|
|
@@ -4348,6 +4235,103 @@ function dbExamples(kind) {
|
|
|
4348
4235
|
`;
|
|
4349
4236
|
}
|
|
4350
4237
|
//#endregion
|
|
4238
|
+
//#region src/commands/schema.ts
|
|
4239
|
+
/**
|
|
4240
|
+
* CLI command: rebase schema <action>
|
|
4241
|
+
*/
|
|
4242
|
+
async function schemaCommand(subcommand, rawArgs) {
|
|
4243
|
+
if (!subcommand || subcommand === "--help" || wantsHelp(rawArgs)) {
|
|
4244
|
+
printSchemaHelp(subcommand === "--help" ? void 0 : subcommand);
|
|
4245
|
+
return;
|
|
4246
|
+
}
|
|
4247
|
+
if (!SCHEMA_ACTION_HELP[subcommand]) unknownCommand(subcommand, Object.keys(SCHEMA_ACTION_HELP), "schema");
|
|
4248
|
+
const projectRoot = requireProjectRoot();
|
|
4249
|
+
recordEvent("cli.schema", { subcommand: subcommand ?? "none" }, { projectRoot });
|
|
4250
|
+
const backendDir = requireBackendDir(projectRoot);
|
|
4251
|
+
const activePlugin = getActiveBackendPlugin(backendDir);
|
|
4252
|
+
if (!activePlugin) {
|
|
4253
|
+
console.error(chalk.red("✗ Could not detect an active database plugin."));
|
|
4254
|
+
console.error(chalk.gray(" Make sure a package like @rebasepro/server-postgres is installed in backend/package.json."));
|
|
4255
|
+
process.exit(1);
|
|
4256
|
+
}
|
|
4257
|
+
const pluginCli = resolvePluginCliScript(backendDir, activePlugin);
|
|
4258
|
+
if (!pluginCli) exitDependenciesNotInstalled(projectRoot);
|
|
4259
|
+
const envFile = findEnvFile(projectRoot);
|
|
4260
|
+
const env = { ...process.env };
|
|
4261
|
+
if (envFile) env.DOTENV_CONFIG_PATH = envFile;
|
|
4262
|
+
env[DEV_DATABASE_KIND_ENV] = devDatabaseKind(projectRoot) ?? "";
|
|
4263
|
+
try {
|
|
4264
|
+
await spawnDriverCli({
|
|
4265
|
+
projectRoot,
|
|
4266
|
+
backendDir,
|
|
4267
|
+
pluginCli,
|
|
4268
|
+
env
|
|
4269
|
+
}, argsFromCommand(rawArgs, "schema"));
|
|
4270
|
+
} catch (error) {
|
|
4271
|
+
reportSpawnFailure(error);
|
|
4272
|
+
process.exit(1);
|
|
4273
|
+
}
|
|
4274
|
+
}
|
|
4275
|
+
/** One page per subcommand, so `rebase schema <action> --help` says something. */
|
|
4276
|
+
var SCHEMA_ACTION_HELP = {
|
|
4277
|
+
generate: {
|
|
4278
|
+
usage: "rebase schema generate [--collections <dir>] [--output <file>] [--watch]",
|
|
4279
|
+
summary: "Generate the Drizzle schema from the collection definitions.",
|
|
4280
|
+
notes: ["--watch regenerates on every change to a collection file."]
|
|
4281
|
+
},
|
|
4282
|
+
introspect: {
|
|
4283
|
+
usage: "rebase schema introspect [--collections <dir>] [--output <dir>] [--schema <name>] [--force]",
|
|
4284
|
+
summary: "Read an existing database and write Rebase collection definitions from it.",
|
|
4285
|
+
notes: ["--force overwrites collection files that are already there."]
|
|
4286
|
+
},
|
|
4287
|
+
stale: {
|
|
4288
|
+
usage: "rebase schema stale [--collections <dir>] [--output <file>] [--fix]",
|
|
4289
|
+
summary: "Report generated schema files that no longer match the collections.",
|
|
4290
|
+
notes: ["--fix regenerates them instead of only reporting."]
|
|
4291
|
+
}
|
|
4292
|
+
};
|
|
4293
|
+
function printSchemaHelp(action) {
|
|
4294
|
+
const entry = action ? SCHEMA_ACTION_HELP[action] : void 0;
|
|
4295
|
+
if (entry) {
|
|
4296
|
+
console.log(`
|
|
4297
|
+
${chalk.bold(`rebase schema ${action}`)}
|
|
4298
|
+
|
|
4299
|
+
${entry.summary}
|
|
4300
|
+
|
|
4301
|
+
${chalk.green.bold("Usage")}
|
|
4302
|
+
${chalk.blue(entry.usage)}
|
|
4303
|
+
${entry.notes?.length ? `\n${chalk.green.bold("Notes")}\n${entry.notes.map((n) => ` ${chalk.gray(`• ${n}`)}`).join("\n")}\n` : ""}
|
|
4304
|
+
${chalk.gray("Run `rebase schema --help` for every subcommand.")}
|
|
4305
|
+
`);
|
|
4306
|
+
return;
|
|
4307
|
+
}
|
|
4308
|
+
console.log(`
|
|
4309
|
+
${chalk.bold("rebase schema")} — Schema management commands
|
|
4310
|
+
|
|
4311
|
+
${chalk.green.bold("Usage")}
|
|
4312
|
+
rebase schema ${chalk.blue("<command>")} [options]
|
|
4313
|
+
|
|
4314
|
+
${chalk.green.bold("Commands")}
|
|
4315
|
+
${chalk.gray("(Commands are provided by your active database driver plugin)")}
|
|
4316
|
+
${chalk.blue.bold("generate")} Generate Schema from collection definitions
|
|
4317
|
+
${chalk.blue.bold("introspect")} Introspect an existing database to generate collection definitions
|
|
4318
|
+
${chalk.blue.bold("stale")} Report generated schema files that no longer match the collections
|
|
4319
|
+
|
|
4320
|
+
${chalk.green.bold("generate Options")}
|
|
4321
|
+
${chalk.blue("--collections, -c")} Path to collections directory
|
|
4322
|
+
${chalk.blue("--output, -o")} Output path for generated schema
|
|
4323
|
+
${chalk.blue("--watch, -w")} Watch for changes and regenerate automatically
|
|
4324
|
+
|
|
4325
|
+
${chalk.green.bold("introspect Options")}
|
|
4326
|
+
${chalk.blue("--output, -o")} Output directory for generated collection files
|
|
4327
|
+
${chalk.blue("--schema")} Postgres schema to read (default: public)
|
|
4328
|
+
${chalk.blue("--force, -f")} Overwrite collection files that already exist
|
|
4329
|
+
|
|
4330
|
+
${chalk.green.bold("stale Options")}
|
|
4331
|
+
${chalk.blue("--fix")} Regenerate the stale files instead of only reporting them
|
|
4332
|
+
`);
|
|
4333
|
+
}
|
|
4334
|
+
//#endregion
|
|
4351
4335
|
//#region src/manifest.ts
|
|
4352
4336
|
/**
|
|
4353
4337
|
* Loading, validating and synthesizing `rebase.json`.
|