@rebasepro/cli 0.12.1-canary.g181d0fe → 0.12.1-canary.g389e9b2
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/bin/rebase.js +27 -1
- package/dist/bundle.d.ts +36 -0
- package/dist/index.es.js +154 -7
- package/dist/index.es.js.map +1 -1
- package/package.json +7 -7
- package/templates/template/config/collections/index.ts +9 -1
package/bin/rebase.js
CHANGED
|
@@ -88,4 +88,30 @@ if (!existsSync(distEntry)) {
|
|
|
88
88
|
|
|
89
89
|
const { entry } = await import("../dist/index.es.js");
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
/**
|
|
92
|
+
* The CLI's last line of defence.
|
|
93
|
+
*
|
|
94
|
+
* `entry()` returns a promise and nothing was awaiting it, so anything a
|
|
95
|
+
* command threw surfaced as an unhandled rejection: Node's own stack trace,
|
|
96
|
+
* rooted in `dist/index.es.js`, with the CLI's bundled line numbers and no
|
|
97
|
+
* exit code of its own. "Collections directory not found" is a sentence a
|
|
98
|
+
* developer can act on; the same sentence under ten frames of bundle internals
|
|
99
|
+
* reads as a crash in Rebase.
|
|
100
|
+
*
|
|
101
|
+
* The message is the error's own — commands that already print something
|
|
102
|
+
* friendly and exit never reach here. The stack is available behind
|
|
103
|
+
* `--debug`/`REBASE_DEBUG`, because when the message is *not* enough that is
|
|
104
|
+
* the only thing that helps.
|
|
105
|
+
*/
|
|
106
|
+
const wantsStack = process.argv.includes("--debug") || process.env.REBASE_DEBUG === "1";
|
|
107
|
+
|
|
108
|
+
entry(process.argv).catch((error) => {
|
|
109
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
110
|
+
process.stderr.write(`\x1b[31m✗ ${message}\x1b[0m\n`);
|
|
111
|
+
if (wantsStack && error instanceof Error && error.stack) {
|
|
112
|
+
process.stderr.write(`\n${error.stack}\n`);
|
|
113
|
+
} else {
|
|
114
|
+
process.stderr.write("\x1b[90m Re-run with --debug for the stack trace.\x1b[0m\n");
|
|
115
|
+
}
|
|
116
|
+
process.exit(1);
|
|
117
|
+
});
|
package/dist/bundle.d.ts
CHANGED
|
@@ -68,6 +68,41 @@ export declare function detectNativeDependencies(projectRoot: string, declared:
|
|
|
68
68
|
* own config package already travels inside the bundle.
|
|
69
69
|
*/
|
|
70
70
|
export declare function collectDeclaredDependencies(projectRoot: string): Record<string, string>;
|
|
71
|
+
/** One `@rebasepro/*` dependency as some package.json in the project declares it. */
|
|
72
|
+
export interface DeclaredFrameworkDep {
|
|
73
|
+
name: string;
|
|
74
|
+
range: string;
|
|
75
|
+
/** Project-relative package.json it was declared in. */
|
|
76
|
+
file: string;
|
|
77
|
+
}
|
|
78
|
+
export interface FrameworkDepDrift {
|
|
79
|
+
/** Declared at a version that can never reach the CLI's own. */
|
|
80
|
+
behind: DeclaredFrameworkDep[];
|
|
81
|
+
/**
|
|
82
|
+
* The distinct lower bounds found across all declared `@rebasepro/*`, when
|
|
83
|
+
* there is more than one — the project is pinning mixed-era framework
|
|
84
|
+
* packages against each other.
|
|
85
|
+
*/
|
|
86
|
+
disagreeing: string[];
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Find `@rebasepro/*` dependencies pinned to a version older than this CLI.
|
|
90
|
+
*
|
|
91
|
+
* This is the only place a developer can be told. In development, every
|
|
92
|
+
* `@rebasepro/*` resolves through pnpm's `link:`/`workspace:` overrides to the
|
|
93
|
+
* checkout, so the version STRINGS in package.json are never exercised — the
|
|
94
|
+
* project runs fine locally on whatever is on disk, and the declared numbers are
|
|
95
|
+
* first honoured when the runtime npm-installs them from a bundle in the cloud.
|
|
96
|
+
* A project scaffolded at 0.10.0 therefore keeps working on a developer's
|
|
97
|
+
* machine indefinitely while being, in the cloud, a 0.10.0 driver.
|
|
98
|
+
*
|
|
99
|
+
* That matters because the image supplies only `@rebasepro/server`; the database
|
|
100
|
+
* driver comes from these declarations and a newer runtime never updates it.
|
|
101
|
+
* Every package.json is scanned, `dependencies` and `devDependencies` both,
|
|
102
|
+
* because they have to be bumped together and the one that gets forgotten is the
|
|
103
|
+
* one nobody looks at.
|
|
104
|
+
*/
|
|
105
|
+
export declare function detectFrameworkDepDrift(projectRoot: string, cliVersion: string): FrameworkDepDrift;
|
|
71
106
|
/**
|
|
72
107
|
* Rewrite relative import specifiers in emitted JavaScript so Node can resolve them.
|
|
73
108
|
*
|
|
@@ -182,3 +217,4 @@ export declare function buildStaticBundle(options: {
|
|
|
182
217
|
manifest: RebaseBundleManifest;
|
|
183
218
|
fileCount: number;
|
|
184
219
|
};
|
|
220
|
+
export declare function resolveCliVersion(): string;
|
package/dist/index.es.js
CHANGED
|
@@ -533,7 +533,7 @@ async function requireClient(rawArgs) {
|
|
|
533
533
|
* the ingress and the console read — see saas/backend/src/utils/tenant-domain.ts).
|
|
534
534
|
*
|
|
535
535
|
* The CLI cannot know this value: it is per-deployment configuration (production
|
|
536
|
-
* serves tenants at `
|
|
536
|
+
* serves tenants at `rebase.website`, a dev control plane at `localhost`). It
|
|
537
537
|
* used to be hardcoded to `rebase.pro`, so `cloud projects create` congratulated
|
|
538
538
|
* the user with a URL that resolves nowhere near their app.
|
|
539
539
|
*
|
|
@@ -1573,7 +1573,9 @@ async function configureEnvFile(targetDirectory, databaseUrl) {
|
|
|
1573
1573
|
envContent = /^#?\s*REBASE_VERSION=.*$/m.test(envContent) ? envContent.replace(/^#?\s*REBASE_VERSION=.*$/m, `REBASE_VERSION=${runtimeVersion}`) : `${envContent.trimEnd()}\n\n# The Rebase runtime image tag docker-compose.yml pulls.\n# Change this and restart to upgrade; your project bundle is untouched.\nREBASE_VERSION=${runtimeVersion}\n`;
|
|
1574
1574
|
if (databaseUrl) {
|
|
1575
1575
|
if (/[\r\n]/.test(databaseUrl)) throw new Error("Invalid DATABASE_URL: multiline values are not allowed.");
|
|
1576
|
-
|
|
1576
|
+
const { pinSearchPath } = await import("@rebasepro/server-postgres");
|
|
1577
|
+
const pinnedUrl = pinSearchPath(databaseUrl);
|
|
1578
|
+
envContent = envContent.replace(/^DATABASE_URL=.*$/m, `DATABASE_URL=${pinnedUrl}\nDATABASE_PASSWORD=${dbPassword}`);
|
|
1577
1579
|
} else {
|
|
1578
1580
|
const dbPort = await findAvailablePort(5432);
|
|
1579
1581
|
envContent = envContent.replace(/^DATABASE_URL=.*$/m, `DATABASE_URL=postgresql://rebase:${dbPassword}@localhost:${dbPort}/rebase?options=-c%20search_path=public&sslmode=disable\nDATABASE_PASSWORD=${dbPassword}`);
|
|
@@ -3513,6 +3515,139 @@ function collectDeclaredDependencies(projectRoot) {
|
|
|
3513
3515
|
return declared;
|
|
3514
3516
|
}
|
|
3515
3517
|
/**
|
|
3518
|
+
* Lowest version a range could resolve to, or null if it is not a range.
|
|
3519
|
+
*
|
|
3520
|
+
* Kept deliberately tiny and local. The published range grammar here is a caret,
|
|
3521
|
+
* a tilde, an exact version or a `>=` floor, and the alternative — a semver
|
|
3522
|
+
* dependency in the CLI — buys breadth this does not need.
|
|
3523
|
+
*/
|
|
3524
|
+
function lowerBoundOf(range) {
|
|
3525
|
+
const raw = range.trim().replace(/^[\^~]/, "").replace(/^>=\s*/, "").replace(/^v/, "");
|
|
3526
|
+
if (!/^\d+(\.\d+){0,2}$/.test(raw)) return null;
|
|
3527
|
+
const [major, minor = 0, patch = 0] = raw.split(".").map(Number);
|
|
3528
|
+
return [
|
|
3529
|
+
major,
|
|
3530
|
+
minor,
|
|
3531
|
+
patch
|
|
3532
|
+
];
|
|
3533
|
+
}
|
|
3534
|
+
/** Highest version a range could resolve to (exclusive), or null. */
|
|
3535
|
+
function upperBoundOf(range) {
|
|
3536
|
+
const trimmed = range.trim();
|
|
3537
|
+
const min = lowerBoundOf(trimmed);
|
|
3538
|
+
if (!min) return null;
|
|
3539
|
+
if (trimmed.startsWith(">=")) return null;
|
|
3540
|
+
const [major, minor, patch] = min;
|
|
3541
|
+
if (trimmed.startsWith("^")) {
|
|
3542
|
+
if (major > 0) return [
|
|
3543
|
+
major + 1,
|
|
3544
|
+
0,
|
|
3545
|
+
0
|
|
3546
|
+
];
|
|
3547
|
+
if (minor > 0) return [
|
|
3548
|
+
0,
|
|
3549
|
+
minor + 1,
|
|
3550
|
+
0
|
|
3551
|
+
];
|
|
3552
|
+
return [
|
|
3553
|
+
0,
|
|
3554
|
+
0,
|
|
3555
|
+
patch + 1
|
|
3556
|
+
];
|
|
3557
|
+
}
|
|
3558
|
+
if (trimmed.startsWith("~")) return trimmed.replace(/^~v?/, "").split(".").length >= 2 ? [
|
|
3559
|
+
major,
|
|
3560
|
+
minor + 1,
|
|
3561
|
+
0
|
|
3562
|
+
] : [
|
|
3563
|
+
major + 1,
|
|
3564
|
+
0,
|
|
3565
|
+
0
|
|
3566
|
+
];
|
|
3567
|
+
const parts = trimmed.replace(/^v/, "").split(".").length;
|
|
3568
|
+
if (parts === 1) return [
|
|
3569
|
+
major + 1,
|
|
3570
|
+
0,
|
|
3571
|
+
0
|
|
3572
|
+
];
|
|
3573
|
+
if (parts === 2) return [
|
|
3574
|
+
major,
|
|
3575
|
+
minor + 1,
|
|
3576
|
+
0
|
|
3577
|
+
];
|
|
3578
|
+
return [
|
|
3579
|
+
major,
|
|
3580
|
+
minor,
|
|
3581
|
+
patch + 1
|
|
3582
|
+
];
|
|
3583
|
+
}
|
|
3584
|
+
function compareTriples(a, b) {
|
|
3585
|
+
for (let i = 0; i < 3; i++) if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1;
|
|
3586
|
+
return 0;
|
|
3587
|
+
}
|
|
3588
|
+
/**
|
|
3589
|
+
* Whether a declared range could EVER resolve at or above `target`.
|
|
3590
|
+
*
|
|
3591
|
+
* The same question the control plane asks at intake, asked here first. Only a
|
|
3592
|
+
* range whose entire span sits below the target is reported — `^0.10.0` can
|
|
3593
|
+
* never cross to 0.12 whatever npm publishes — because a false alarm on a build
|
|
3594
|
+
* that would have worked trains people to ignore the warning that matters.
|
|
3595
|
+
*/
|
|
3596
|
+
function canReach(range, target) {
|
|
3597
|
+
const ceiling = upperBoundOf(range);
|
|
3598
|
+
const floor = lowerBoundOf(target);
|
|
3599
|
+
if (!floor || !lowerBoundOf(range)) return null;
|
|
3600
|
+
if (!ceiling) return true;
|
|
3601
|
+
return compareTriples(ceiling, floor) > 0;
|
|
3602
|
+
}
|
|
3603
|
+
/**
|
|
3604
|
+
* Find `@rebasepro/*` dependencies pinned to a version older than this CLI.
|
|
3605
|
+
*
|
|
3606
|
+
* This is the only place a developer can be told. In development, every
|
|
3607
|
+
* `@rebasepro/*` resolves through pnpm's `link:`/`workspace:` overrides to the
|
|
3608
|
+
* checkout, so the version STRINGS in package.json are never exercised — the
|
|
3609
|
+
* project runs fine locally on whatever is on disk, and the declared numbers are
|
|
3610
|
+
* first honoured when the runtime npm-installs them from a bundle in the cloud.
|
|
3611
|
+
* A project scaffolded at 0.10.0 therefore keeps working on a developer's
|
|
3612
|
+
* machine indefinitely while being, in the cloud, a 0.10.0 driver.
|
|
3613
|
+
*
|
|
3614
|
+
* That matters because the image supplies only `@rebasepro/server`; the database
|
|
3615
|
+
* driver comes from these declarations and a newer runtime never updates it.
|
|
3616
|
+
* Every package.json is scanned, `dependencies` and `devDependencies` both,
|
|
3617
|
+
* because they have to be bumped together and the one that gets forgotten is the
|
|
3618
|
+
* one nobody looks at.
|
|
3619
|
+
*/
|
|
3620
|
+
function detectFrameworkDepDrift(projectRoot, cliVersion) {
|
|
3621
|
+
const found = [];
|
|
3622
|
+
for (const relative of [
|
|
3623
|
+
"package.json",
|
|
3624
|
+
"backend/package.json",
|
|
3625
|
+
"config/package.json",
|
|
3626
|
+
"frontend/package.json"
|
|
3627
|
+
]) {
|
|
3628
|
+
const file = path.join(projectRoot, relative);
|
|
3629
|
+
if (!fs.existsSync(file)) continue;
|
|
3630
|
+
try {
|
|
3631
|
+
const pkg = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
3632
|
+
for (const block of [pkg.dependencies, pkg.devDependencies]) for (const [name, range] of Object.entries(block ?? {})) {
|
|
3633
|
+
if (!name.startsWith("@rebasepro/")) continue;
|
|
3634
|
+
if (typeof range !== "string") continue;
|
|
3635
|
+
found.push({
|
|
3636
|
+
name,
|
|
3637
|
+
range,
|
|
3638
|
+
file: relative
|
|
3639
|
+
});
|
|
3640
|
+
}
|
|
3641
|
+
} catch {}
|
|
3642
|
+
}
|
|
3643
|
+
const behind = found.filter((d) => canReach(d.range, cliVersion) === false);
|
|
3644
|
+
const bounds = new Set(found.map((d) => lowerBoundOf(d.range)).filter((b) => b != null).map((b) => b.join(".")));
|
|
3645
|
+
return {
|
|
3646
|
+
behind,
|
|
3647
|
+
disagreeing: bounds.size > 1 ? [...bounds].sort() : []
|
|
3648
|
+
};
|
|
3649
|
+
}
|
|
3650
|
+
/**
|
|
3516
3651
|
* Rewrite relative import specifiers in emitted JavaScript so Node can resolve them.
|
|
3517
3652
|
*
|
|
3518
3653
|
* TypeScript deliberately does not touch specifiers: `moduleResolution: "bundler"`
|
|
@@ -4210,6 +4345,16 @@ async function buildCommand(rawArgs = []) {
|
|
|
4210
4345
|
console.log(chalk.yellow(` ⚠ native dependencies detected: ${names}`));
|
|
4211
4346
|
console.log(chalk.dim(" These cannot run on the managed runtime. See `rebase doctor`."));
|
|
4212
4347
|
}
|
|
4348
|
+
const drift = detectFrameworkDepDrift(projectRoot, resolveCliVersion());
|
|
4349
|
+
if (drift.behind.length > 0) {
|
|
4350
|
+
console.log(chalk.yellow(` ⚠ framework dependencies older than this CLI (${resolveCliVersion()}):`));
|
|
4351
|
+
for (const dep of drift.behind) console.log(chalk.dim(` ${dep.name}@${dep.range} (${dep.file})`));
|
|
4352
|
+
console.log(chalk.dim(" The image supplies the server, but your bundle supplies the database"));
|
|
4353
|
+
console.log(chalk.dim(" driver — a newer runtime does not update it. Bump these and rebuild."));
|
|
4354
|
+
} else if (drift.disagreeing.length > 0) {
|
|
4355
|
+
console.log(chalk.yellow(` ⚠ mixed @rebasepro versions declared: ${drift.disagreeing.join(", ")}`));
|
|
4356
|
+
console.log(chalk.dim(" These are published together and expect to run together; pin them alike."));
|
|
4357
|
+
}
|
|
4213
4358
|
if (!args["--no-static"]) {
|
|
4214
4359
|
const folded = await foldFrontendIntoBundle({
|
|
4215
4360
|
projectRoot,
|
|
@@ -5068,7 +5213,7 @@ function parseAgentFlags(rawArgs) {
|
|
|
5068
5213
|
return requested;
|
|
5069
5214
|
}
|
|
5070
5215
|
async function skillsInstall(rawArgs = []) {
|
|
5071
|
-
const projectDir = process.cwd();
|
|
5216
|
+
const projectDir = findProjectRoot() ?? process.cwd();
|
|
5072
5217
|
let skillsDir;
|
|
5073
5218
|
try {
|
|
5074
5219
|
skillsDir = getSkillsSourceDir();
|
|
@@ -5112,7 +5257,8 @@ async function skillsInstall(rawArgs = []) {
|
|
|
5112
5257
|
for (const agentKey of agents) {
|
|
5113
5258
|
const agent = AGENTS[agentKey];
|
|
5114
5259
|
const count = installForAgent(agentKey, skills, projectDir);
|
|
5115
|
-
|
|
5260
|
+
const shown = path.relative(process.cwd(), path.join(projectDir, agent.targetDir)) || agent.targetDir;
|
|
5261
|
+
console.log(` ${chalk.green("✓")} ${chalk.bold(agent.label)} — ${count} skills installed to ${chalk.gray(shown)}`);
|
|
5116
5262
|
}
|
|
5117
5263
|
console.log("");
|
|
5118
5264
|
console.log(chalk.gray(" Skills are project-local. Commit them to share with your team."));
|
|
@@ -9883,9 +10029,10 @@ async function entry(args) {
|
|
|
9883
10029
|
argv: args.slice(3),
|
|
9884
10030
|
permissive: true
|
|
9885
10031
|
});
|
|
10032
|
+
const sdkRoot = sdkArgs["--help"] ? process.cwd() : requireProjectRoot();
|
|
9886
10033
|
await generateSdkCommand({
|
|
9887
|
-
collectionsDir: sdkArgs["--collections-dir"] || "
|
|
9888
|
-
output: sdkArgs["--output"] || "
|
|
10034
|
+
collectionsDir: sdkArgs["--collections-dir"] || path.join(sdkRoot, "config/collections"),
|
|
10035
|
+
output: sdkArgs["--output"] || path.join(sdkRoot, "generated/sdk"),
|
|
9889
10036
|
from: sdkArgs["--from"],
|
|
9890
10037
|
token: sdkArgs["--token"],
|
|
9891
10038
|
help: sdkArgs["--help"],
|
|
@@ -9995,6 +10142,6 @@ ${chalk.gray("Documentation: https://rebase.pro/docs")}
|
|
|
9995
10142
|
`);
|
|
9996
10143
|
}
|
|
9997
10144
|
//#endregion
|
|
9998
|
-
export { CURRENT_RUNTIME_RANGE, DEFAULT_BUNDLE_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CRONS_DIR, DEFAULT_FUNCTIONS_DIR, DEFAULT_SCHEMA_FILE, MANIFEST_FILENAME, ManifestError, TEMPLATE_PLACEHOLDER_FILES, appsCommand, assessManagedCompatibility, authCommand, buildBundle, buildCommand, buildInitQuestions, buildStaticBundle, buildableApps, cloudCommand, collectDeclaredDependencies, configureEnvFile, createRebaseApp, dbCommand, detectNativeDependencies, detectPackageManager, detectStorageAuthorize, devCommand, doctorCommand, ejectCommand, entry, findBackendApp, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, findUnusedServerEntry, foldStaticIntoBundle, formatCdTarget, generateSdkCommand, getActiveBackendPlugin, getPMCommands, isIdentifierLike, isPnpmAvailable, loadManifest, manifestExists, manifestPath, normalizeEsmSpecifiers, pnpmAvailabilityFromProbe, printInitHelp, requireBackendDir, requireProjectRoot, resetPnpmAvailabilityCache, resolveBackendPaths, resolveExampleBaseUrl, resolveLocalBin, resolvePluginCliScript, resolveTsx, schemaCommand, startCommand, synthesizeManifest, validateManifest, validateProjectName, validateTsxInstallation, writeManifest };
|
|
10145
|
+
export { CURRENT_RUNTIME_RANGE, DEFAULT_BUNDLE_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CRONS_DIR, DEFAULT_FUNCTIONS_DIR, DEFAULT_SCHEMA_FILE, MANIFEST_FILENAME, ManifestError, TEMPLATE_PLACEHOLDER_FILES, appsCommand, assessManagedCompatibility, authCommand, buildBundle, buildCommand, buildInitQuestions, buildStaticBundle, buildableApps, cloudCommand, collectDeclaredDependencies, configureEnvFile, createRebaseApp, dbCommand, detectFrameworkDepDrift, detectNativeDependencies, detectPackageManager, detectStorageAuthorize, devCommand, doctorCommand, ejectCommand, entry, findBackendApp, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, findUnusedServerEntry, foldStaticIntoBundle, formatCdTarget, generateSdkCommand, getActiveBackendPlugin, getPMCommands, isIdentifierLike, isPnpmAvailable, loadManifest, manifestExists, manifestPath, normalizeEsmSpecifiers, pnpmAvailabilityFromProbe, printInitHelp, requireBackendDir, requireProjectRoot, resetPnpmAvailabilityCache, resolveBackendPaths, resolveCliVersion, resolveExampleBaseUrl, resolveLocalBin, resolvePluginCliScript, resolveTsx, schemaCommand, startCommand, synthesizeManifest, validateManifest, validateProjectName, validateTsxInstallation, writeManifest };
|
|
9999
10146
|
|
|
10000
10147
|
//# sourceMappingURL=index.es.js.map
|