@rebasepro/cli 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -583,7 +583,7 @@ async function configureEnvFile(targetDirectory, databaseUrl) {
583
583
  * Dynamically load collection definitions from a directory.
584
584
  *
585
585
  * Expects the directory to have an index.ts/index.js that exports a default
586
- * array of EntityCollection objects (matching the app/config/collections pattern).
586
+ * array of CollectionConfig objects (matching the app/config/collections pattern).
587
587
  */
588
588
  async function loadCollections(collectionsDir) {
589
589
  const absDir = path.resolve(collectionsDir);
@@ -640,7 +640,7 @@ async function loadCollections(collectionsDir) {
640
640
  for (const value of Object.values(exported)) if (value && typeof value === "object" && "slug" in value) collections.push(value);
641
641
  if (collections.length > 0) return collections;
642
642
  }
643
- throw new Error(`Could not extract collections from ${indexPath}.\nExpected a default export of EntityCollection[] or an object with named collection exports.`);
643
+ throw new Error(`Could not extract collections from ${indexPath}.\nExpected a default export of CollectionConfig[] or an object with named collection exports.`);
644
644
  }
645
645
  /**
646
646
  * Write generated files to the output directory.
@@ -812,6 +812,41 @@ function resolveTsx(projectRoot) {
812
812
  return resolveLocalBin(projectRoot, "tsx");
813
813
  }
814
814
  /**
815
+ * Validate that a resolved tsx binary actually has an intact installation.
816
+ *
817
+ * `resolveLocalBin` only checks whether `node_modules/.bin/tsx` (a symlink)
818
+ * exists. If the pnpm content-addressable store was cleaned or a previous
819
+ * install was interrupted, the symlink can exist while critical files inside
820
+ * the tsx package (e.g. `dist/preflight.cjs`) are missing — causing a
821
+ * confusing MODULE_NOT_FOUND error at runtime.
822
+ *
823
+ * This function follows the symlink, walks up to find the tsx package root
824
+ * (`package.json` with `name: "tsx"`), and verifies that `dist/preflight.cjs`
825
+ * is present. Returns `null` when the installation looks healthy, or an
826
+ * error description string when it appears corrupted.
827
+ */
828
+ function validateTsxInstallation(tsxBinPath) {
829
+ try {
830
+ const realPath = fs.realpathSync(tsxBinPath);
831
+ let dir = path.dirname(realPath);
832
+ const fsRoot = path.parse(dir).root;
833
+ for (let depth = 0; depth < 10 && dir !== fsRoot; depth++) {
834
+ const pkgPath = path.join(dir, "package.json");
835
+ if (fs.existsSync(pkgPath)) try {
836
+ if (JSON.parse(fs.readFileSync(pkgPath, "utf-8")).name === "tsx") {
837
+ const preflightPath = path.join(dir, "dist", "preflight.cjs");
838
+ if (!fs.existsSync(preflightPath)) return `tsx package at ${dir} is missing dist/preflight.cjs`;
839
+ return null;
840
+ }
841
+ } catch {}
842
+ dir = path.dirname(dir);
843
+ }
844
+ return null;
845
+ } catch (err) {
846
+ return `tsx binary symlink is broken: ${err instanceof Error ? err.message : String(err)}`;
847
+ }
848
+ }
849
+ /**
815
850
  * Require the project root or exit with a helpful error.
816
851
  */
817
852
  function requireProjectRoot() {
@@ -1156,12 +1191,35 @@ async function devCommand(rawArgs) {
1156
1191
  console.error(chalk.gray(` Install it with: ${addCmd}`));
1157
1192
  process.exit(1);
1158
1193
  }
1194
+ const tsxValidationError = validateTsxInstallation(tsxBin);
1195
+ if (tsxValidationError) {
1196
+ const installCmd = getPMCommands(detectPackageManager(projectRoot)).install.join(" ");
1197
+ console.error(chalk.red(" ✗ tsx installation appears corrupted."));
1198
+ console.error(chalk.gray(` ${tsxValidationError}`));
1199
+ console.error("");
1200
+ console.error(chalk.gray(" To fix, run:"));
1201
+ console.error(chalk.cyan(` rm -rf node_modules && ${installCmd}`));
1202
+ process.exit(1);
1203
+ }
1159
1204
  const envFile = findEnvFile(projectRoot);
1160
1205
  const env = { ...process.env };
1161
1206
  if (envFile) env.DOTENV_CONFIG_PATH = envFile;
1162
1207
  env.PORT = String(startPort);
1163
1208
  console.log(` ${chalk.cyan("▶")} Backend: ${chalk.gray(backendDir)}`);
1164
1209
  console.log(` ${chalk.gray("↳ PORT")} = ${chalk.white(String(startPort))}`);
1210
+ if (envFile) try {
1211
+ const envText = fs.readFileSync(envFile, "utf-8");
1212
+ const readEnvKey = (key) => {
1213
+ const m = envText.match(new RegExp(`^\\s*${key}\\s*=\\s*(.+?)\\s*$`, "m"));
1214
+ return m ? m[1].replace(/^["']|["']$/g, "") : void 0;
1215
+ };
1216
+ const envPort = readEnvKey("PORT");
1217
+ const envApiUrl = readEnvKey("VITE_API_URL");
1218
+ const overridden = [];
1219
+ if (envPort && envPort !== String(startPort)) overridden.push("PORT");
1220
+ if (envApiUrl && envApiUrl !== `http://localhost:${startPort}`) overridden.push("VITE_API_URL");
1221
+ if (overridden.length > 0) console.log(chalk.yellow(` ⚠ dev uses a derived per-project port (${startPort}); your .env ${overridden.join(" / ")} ${overridden.length > 1 ? "are" : "is"} ignored here (avoids cross-project collisions). Pass ${chalk.white("--port")} to pin a port.`));
1222
+ } catch {}
1165
1223
  /** Whether the frontend has been launched (we only launch it once). */
1166
1224
  let frontendLaunched = false;
1167
1225
  if (shouldGenerate) {
@@ -1286,9 +1344,28 @@ async function devCommand(rawArgs) {
1286
1344
  }
1287
1345
  });
1288
1346
  });
1347
+ /** Whether we've already shown a corrupted-modules recovery hint. */
1348
+ let corruptedModulesWarned = false;
1289
1349
  backendChild.stderr?.on("data", (data) => {
1290
1350
  data.toString().split("\n").filter(Boolean).forEach((line) => {
1291
1351
  console.log(`${chalk.cyan.bold("[backend]")} ${line}`);
1352
+ if (!corruptedModulesWarned) {
1353
+ const cleanLine = stripAnsi(line);
1354
+ if (cleanLine.includes("Cannot find module") && cleanLine.includes("node_modules/.pnpm/")) {
1355
+ corruptedModulesWarned = true;
1356
+ setTimeout(() => {
1357
+ const installCmd = getPMCommands(detectPackageManager(projectRoot)).install.join(" ");
1358
+ console.error("");
1359
+ console.error(chalk.red(" ✗ node_modules appears corrupted — a required file is missing."));
1360
+ console.error(chalk.gray(" This usually happens when a previous install was interrupted"));
1361
+ console.error(chalk.gray(" or the package manager store was cleaned."));
1362
+ console.error("");
1363
+ console.error(chalk.gray(" To fix, stop the dev server and run:"));
1364
+ console.error(chalk.cyan(` rm -rf node_modules && ${installCmd}`));
1365
+ console.error("");
1366
+ }, 200);
1367
+ }
1368
+ }
1292
1369
  });
1293
1370
  });
1294
1371
  children.push(backendChild);
@@ -2243,6 +2320,6 @@ ${chalk.gray("Documentation: https://rebase.pro/docs")}
2243
2320
  `);
2244
2321
  }
2245
2322
  //#endregion
2246
- export { authCommand, buildCommand, buildInitQuestions, configureEnvFile, createRebaseApp, dbCommand, detectPackageManager, devCommand, doctorCommand, entry, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, generateSdkCommand, getActiveBackendPlugin, getPMCommands, requireBackendDir, requireProjectRoot, resolveLocalBin, resolvePluginCliScript, resolveTsx, schemaCommand, startCommand };
2323
+ export { authCommand, buildCommand, buildInitQuestions, configureEnvFile, createRebaseApp, dbCommand, detectPackageManager, devCommand, doctorCommand, entry, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, generateSdkCommand, getActiveBackendPlugin, getPMCommands, requireBackendDir, requireProjectRoot, resolveLocalBin, resolvePluginCliScript, resolveTsx, schemaCommand, startCommand, validateTsxInstallation };
2247
2324
 
2248
2325
  //# sourceMappingURL=index.es.js.map