@rebasepro/cli 0.13.1-canary.gcef69d4 → 0.13.1-canary.gef9608c
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/index.es.js +111 -5
- package/dist/index.es.js.map +1 -1
- package/dist/utils/collection-drift.d.ts +27 -0
- package/package.json +7 -7
package/dist/index.es.js
CHANGED
|
@@ -14,7 +14,7 @@ import os from "os";
|
|
|
14
14
|
import { createRebaseClient } from "@rebasepro/client";
|
|
15
15
|
import dotenv from "dotenv";
|
|
16
16
|
import { createRequire } from "module";
|
|
17
|
-
import { BUNDLE_FORMAT_VERSION, RUNTIME_CONTRACT_VERSION, computeSchemaVersion, deserializeCollections, findStorageSuffixCollision, normalizeStorageSources, storageEnvSuffix } from "@rebasepro/types";
|
|
17
|
+
import { BUNDLE_FORMAT_VERSION, DEFAULT_DATA_SOURCE_KEY, RUNTIME_CONTRACT_VERSION, computeSchemaVersion, deserializeCollections, findStorageSuffixCollision, getDataSourceCapabilities, normalizeStorageSources, storageEnvSuffix } from "@rebasepro/types";
|
|
18
18
|
import { generateSDK } from "@rebasepro/codegen";
|
|
19
19
|
//#region src/utils/package-manager.ts
|
|
20
20
|
/**
|
|
@@ -3130,6 +3130,106 @@ function resolveBackendPaths(app, projectRoot) {
|
|
|
3130
3130
|
};
|
|
3131
3131
|
}
|
|
3132
3132
|
//#endregion
|
|
3133
|
+
//#region src/utils/collection-drift.ts
|
|
3134
|
+
/**
|
|
3135
|
+
* Which edits under `config/collections` can put the *SQL* schema out of date.
|
|
3136
|
+
*
|
|
3137
|
+
* `rebase dev` watches that directory and, on any change, either tells the
|
|
3138
|
+
* developer to run `rebase schema generate` / `rebase db push` or runs them.
|
|
3139
|
+
* The watcher is recursive and knows nothing about what it is watching, so it
|
|
3140
|
+
* said that about every file under the directory — including a
|
|
3141
|
+
* `collections/firestore/exercises.ts`, whose documents live in Firestore and
|
|
3142
|
+
* for which there is no Drizzle schema to regenerate and no database to push
|
|
3143
|
+
* to. Advice that is wrong on every edit is advice a developer learns to
|
|
3144
|
+
* ignore, which is worse than none: the same box is the only warning for the
|
|
3145
|
+
* Postgres collection next to it, where it is real.
|
|
3146
|
+
*
|
|
3147
|
+
* Two independent reasons a change cannot affect the SQL schema, both checked
|
|
3148
|
+
* here:
|
|
3149
|
+
*
|
|
3150
|
+
* 1. **The loader would never read the file.** `loadCollectionsFromDirectory`
|
|
3151
|
+
* reads the top level of the collections directory only — no recursion, no
|
|
3152
|
+
* `index`, no tests, no declarations. A file it does not read cannot change
|
|
3153
|
+
* what it returns, and the watcher must not claim otherwise.
|
|
3154
|
+
* 2. **Every collection in it is served by another engine.** A Firestore or
|
|
3155
|
+
* MongoDB collection has no table, no migration and no policies.
|
|
3156
|
+
*
|
|
3157
|
+
* The engine check reads the source text rather than importing the module: the
|
|
3158
|
+
* CLI runs as plain Node and cannot evaluate a project's TypeScript, and a
|
|
3159
|
+
* watcher must answer in the time between two keystrokes. Anything it cannot
|
|
3160
|
+
* read confidently counts as SQL-affecting — a spurious warning is a nuisance,
|
|
3161
|
+
* a suppressed one hides real drift.
|
|
3162
|
+
*/
|
|
3163
|
+
/**
|
|
3164
|
+
* Would `loadCollectionsFromDirectory` load this file?
|
|
3165
|
+
*
|
|
3166
|
+
* Mirrors that loader's own `isCollectionFile` plus its flat (non-recursive)
|
|
3167
|
+
* scan. `relativePath` is relative to the collections directory, as `fs.watch`
|
|
3168
|
+
* reports it.
|
|
3169
|
+
*/
|
|
3170
|
+
function isLoadedCollectionFile(relativePath) {
|
|
3171
|
+
const normalized = relativePath.split(path.sep).join("/");
|
|
3172
|
+
if (normalized.includes("/")) return false;
|
|
3173
|
+
const file = normalized;
|
|
3174
|
+
if (!file.endsWith(".ts") && !file.endsWith(".js")) return false;
|
|
3175
|
+
if (file.startsWith(".")) return false;
|
|
3176
|
+
if (file.includes(".test.")) return false;
|
|
3177
|
+
if (file.endsWith(".d.ts")) return false;
|
|
3178
|
+
if (file === "index.ts" || file === "index.js") return false;
|
|
3179
|
+
return true;
|
|
3180
|
+
}
|
|
3181
|
+
var ENGINE_LITERAL = /\bengine\s*:\s*["'`]([^"'`]+)["'`]/g;
|
|
3182
|
+
var DATA_SOURCE_LITERAL = /\bdataSource\s*:\s*["'`]([^"'`]+)["'`]/g;
|
|
3183
|
+
/**
|
|
3184
|
+
* Drop comments, so a `// engine: "firestore"` in a docblock cannot silence a
|
|
3185
|
+
* warning about the Postgres collection the file actually declares.
|
|
3186
|
+
*
|
|
3187
|
+
* Deliberately naive — it does not understand strings, so a `//` inside one
|
|
3188
|
+
* (a URL in a default value) eats the rest of that line. That only ever removes
|
|
3189
|
+
* text, and removing an engine literal makes this file *more* likely to warn,
|
|
3190
|
+
* which is the side to be wrong on.
|
|
3191
|
+
*/
|
|
3192
|
+
function stripComments(source) {
|
|
3193
|
+
return source.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/\/\/[^\n]*/g, " ");
|
|
3194
|
+
}
|
|
3195
|
+
function literals(source, pattern) {
|
|
3196
|
+
const found = [];
|
|
3197
|
+
for (const match of source.matchAll(pattern)) found.push(match[1]);
|
|
3198
|
+
return found;
|
|
3199
|
+
}
|
|
3200
|
+
/**
|
|
3201
|
+
* Does this collection source declare anything a SQL toolchain would own?
|
|
3202
|
+
*
|
|
3203
|
+
* The fallback order matches `resolveDataSource`: an explicit `engine` wins,
|
|
3204
|
+
* and a collection that only names a `dataSource` is resolved as if the key
|
|
3205
|
+
* were the engine — which is what that function does when no registry is
|
|
3206
|
+
* available, and the CLI has none. An engine nobody recognises counts as
|
|
3207
|
+
* relational, for the reason `isRelationalCollection` gives.
|
|
3208
|
+
*
|
|
3209
|
+
* A file declaring several collections is SQL-affecting if *any* of them is.
|
|
3210
|
+
*/
|
|
3211
|
+
function declaresRelationalCollection(rawSource) {
|
|
3212
|
+
const source = stripComments(rawSource);
|
|
3213
|
+
const engines = literals(source, ENGINE_LITERAL);
|
|
3214
|
+
const declared = engines.length > 0 ? engines : literals(source, DATA_SOURCE_LITERAL).filter((key) => key !== DEFAULT_DATA_SOURCE_KEY);
|
|
3215
|
+
if (declared.length === 0) return true;
|
|
3216
|
+
return declared.some((engine) => getDataSourceCapabilities(engine).supportsRelations);
|
|
3217
|
+
}
|
|
3218
|
+
/**
|
|
3219
|
+
* Can this edit have changed the generated SQL schema?
|
|
3220
|
+
*
|
|
3221
|
+
* Answers `true` when it cannot tell — an unreadable file is a reason to warn,
|
|
3222
|
+
* not a reason to go quiet.
|
|
3223
|
+
*/
|
|
3224
|
+
function affectsSqlSchema(collectionsDir, relativePath) {
|
|
3225
|
+
if (!isLoadedCollectionFile(relativePath)) return false;
|
|
3226
|
+
try {
|
|
3227
|
+
return declaresRelationalCollection(fs.readFileSync(path.join(collectionsDir, relativePath), "utf8"));
|
|
3228
|
+
} catch {
|
|
3229
|
+
return true;
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
//#endregion
|
|
3133
3233
|
//#region src/commands/dev.ts
|
|
3134
3234
|
/**
|
|
3135
3235
|
* CLI command: rebase dev
|
|
@@ -3442,14 +3542,18 @@ async function devCommand(rawArgs) {
|
|
|
3442
3542
|
const collectionsDir = path.join(projectRoot, "config", "collections");
|
|
3443
3543
|
if (fs.existsSync(collectionsDir)) {
|
|
3444
3544
|
let watchDebounce = null;
|
|
3545
|
+
let sqlSchemaAffected = false;
|
|
3445
3546
|
fs.watch(collectionsDir, { recursive: true }, (eventType, filename) => {
|
|
3446
3547
|
if (!filename || filename.startsWith(".") || filename.endsWith(".tmp")) return;
|
|
3548
|
+
sqlSchemaAffected = sqlSchemaAffected || affectsSqlSchema(collectionsDir, filename);
|
|
3447
3549
|
if (watchDebounce) clearTimeout(watchDebounce);
|
|
3448
3550
|
watchDebounce = setTimeout(async () => {
|
|
3449
|
-
|
|
3551
|
+
const regenerateSchema = sqlSchemaAffected;
|
|
3552
|
+
sqlSchemaAffected = false;
|
|
3553
|
+
console.log(chalk.yellow(`\n 🔄 Collection change detected (${filename}). Regenerating ${regenerateSchema ? "schema & SDK" : "SDK"}...`));
|
|
3450
3554
|
try {
|
|
3451
3555
|
const activePlugin = getActiveBackendPlugin(backendDir);
|
|
3452
|
-
const pluginCli = activePlugin ? resolvePluginCliScript(backendDir, activePlugin) : null;
|
|
3556
|
+
const pluginCli = regenerateSchema && activePlugin ? resolvePluginCliScript(backendDir, activePlugin) : null;
|
|
3453
3557
|
if (pluginCli) await execa(tsxBin, [
|
|
3454
3558
|
pluginCli,
|
|
3455
3559
|
"schema",
|
|
@@ -3465,7 +3569,7 @@ async function devCommand(rawArgs) {
|
|
|
3465
3569
|
stdio: "inherit",
|
|
3466
3570
|
env
|
|
3467
3571
|
});
|
|
3468
|
-
console.log(chalk.green(
|
|
3572
|
+
console.log(chalk.green(` ✓ ${regenerateSchema ? "Schema & SDK" : "SDK"} regenerated successfully. Hono will reload.`));
|
|
3469
3573
|
} catch (err) {
|
|
3470
3574
|
console.error(chalk.red(` ✗ Failed to regenerate schema/SDK: ${err instanceof Error ? err.message : err}`));
|
|
3471
3575
|
}
|
|
@@ -3490,12 +3594,14 @@ async function devCommand(rawArgs) {
|
|
|
3490
3594
|
let driftDebounce = null;
|
|
3491
3595
|
fs.watch(collectionsDir, { recursive: true }, (_eventType, filename) => {
|
|
3492
3596
|
if (!filename || filename.startsWith(".") || filename.endsWith(".tmp")) return;
|
|
3597
|
+
if (!affectsSqlSchema(collectionsDir, filename)) return;
|
|
3493
3598
|
if (driftDebounce) clearTimeout(driftDebounce);
|
|
3494
3599
|
driftDebounce = setTimeout(() => {
|
|
3600
|
+
const shown = filename.length > 31 ? `…${filename.slice(-30)}` : filename.padEnd(31);
|
|
3495
3601
|
console.log([
|
|
3496
3602
|
"",
|
|
3497
3603
|
chalk.yellow(" ┌──────────────────────────────────────────────────────────────┐"),
|
|
3498
|
-
chalk.yellow(" │ ⚠️ Collection file changed: ") + chalk.white(
|
|
3604
|
+
chalk.yellow(" │ ⚠️ Collection file changed: ") + chalk.white(shown) + chalk.yellow("│"),
|
|
3499
3605
|
chalk.yellow(" │ │"),
|
|
3500
3606
|
chalk.yellow(" │ Your schema may be out of sync. Run: │"),
|
|
3501
3607
|
chalk.yellow(" │ ") + chalk.cyan("rebase schema generate") + chalk.yellow(" regenerate Drizzle schema │"),
|