@rebasepro/cli 0.0.1-canary.dbf160a → 0.0.1-canary.e17585f

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
@@ -11,6 +11,45 @@ import crypto from "crypto";
11
11
  import { generateSDK } from "@rebasepro/sdk-generator";
12
12
  import { execSync, spawn } from "child_process";
13
13
  import * as os from "os";
14
+ function detectPackageManager(targetDir) {
15
+ const userAgent = process.env.npm_config_user_agent ?? "";
16
+ if (userAgent.startsWith("npm/")) return "npm";
17
+ if (userAgent.startsWith("pnpm/")) return "pnpm";
18
+ if (targetDir) {
19
+ if (fs.existsSync(path.join(targetDir, "package-lock.json"))) return "npm";
20
+ if (fs.existsSync(path.join(targetDir, "pnpm-lock.yaml"))) return "pnpm";
21
+ }
22
+ const cwd = process.cwd();
23
+ if (cwd !== targetDir) {
24
+ if (fs.existsSync(path.join(cwd, "package-lock.json"))) return "npm";
25
+ if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
26
+ }
27
+ return "pnpm";
28
+ }
29
+ function getPMCommands(pm) {
30
+ if (pm === "npm") {
31
+ return {
32
+ name: "npm",
33
+ install: ["npm", "install"],
34
+ run: (script) => ["npm", "run", script],
35
+ exec: (bin, args) => ["npx", bin, ...args],
36
+ view: (pkg, field) => ["npm", "view", pkg, field],
37
+ runAll: (script) => ["npm", "run", script, "--workspaces", "--if-present"],
38
+ runWorkspace: (workspace, script) => ["npm", "run", script, "-w", workspace],
39
+ workspaceProtocol: "*"
40
+ };
41
+ }
42
+ return {
43
+ name: "pnpm",
44
+ install: ["pnpm", "install"],
45
+ run: (script) => ["pnpm", "run", script],
46
+ exec: (bin, args) => ["pnpm", "exec", bin, ...args],
47
+ view: (pkg, field) => ["pnpm", "view", pkg, field],
48
+ runAll: (script) => ["pnpm", "-r", "run", script],
49
+ runWorkspace: (workspace, script) => ["pnpm", "--filter", workspace, script],
50
+ workspaceProtocol: "workspace:*"
51
+ };
52
+ }
14
53
  const access = promisify(fs.access);
15
54
  const copy = promisify(ncp);
16
55
  const __filename$2 = fileURLToPath(import.meta.url);
@@ -30,10 +69,11 @@ async function createRebaseApp(rawArgs) {
30
69
  console.log(`
31
70
  ${chalk.bold("Rebase")} — Create a new project šŸš€
32
71
  `);
33
- const options = await promptForOptions(rawArgs);
72
+ const pm = detectPackageManager();
73
+ const options = await promptForOptions(rawArgs, pm);
34
74
  await createProject(options);
35
75
  }
36
- async function promptForOptions(rawArgs) {
76
+ async function promptForOptions(rawArgs, pm) {
37
77
  const args = arg(
38
78
  {
39
79
  "--git": Boolean,
@@ -76,7 +116,7 @@ async function promptForOptions(rawArgs) {
76
116
  questions.push({
77
117
  type: "confirm",
78
118
  name: "installDeps",
79
- message: "Install dependencies with pnpm?",
119
+ message: `Install dependencies with ${pm}?`,
80
120
  default: true
81
121
  });
82
122
  }
@@ -97,6 +137,7 @@ async function promptForOptions(rawArgs) {
97
137
  const targetDirectory = path.resolve(process.cwd(), nameArg || answers.projectName);
98
138
  const projectName = path.basename(targetDirectory);
99
139
  const templateDirectory = path.resolve(cliRoot, "templates", "template");
140
+ const pmCommands = getPMCommands(pm);
100
141
  return {
101
142
  projectName,
102
143
  git: args["--git"] || answers.git || false,
@@ -104,7 +145,9 @@ async function promptForOptions(rawArgs) {
104
145
  targetDirectory,
105
146
  templateDirectory,
106
147
  databaseUrl: answers.databaseUrl?.trim() || void 0,
107
- introspect: answers.introspect || false
148
+ introspect: answers.introspect || false,
149
+ pm,
150
+ pmCommands
108
151
  };
109
152
  }
110
153
  async function createProject(options) {
@@ -137,34 +180,7 @@ async function createProject(options) {
137
180
  process.exit(1);
138
181
  }
139
182
  await replacePlaceholders(options);
140
- const envTemplatePath = path.join(options.targetDirectory, ".env.template");
141
- const envPath = path.join(options.targetDirectory, ".env");
142
- if (fs.existsSync(envTemplatePath) && !fs.existsSync(envPath)) {
143
- fs.renameSync(envTemplatePath, envPath);
144
- const jwtSecret = crypto.randomBytes(32).toString("hex");
145
- let envContent = fs.readFileSync(envPath, "utf-8");
146
- envContent = envContent.replace(
147
- "change-this-to-a-secure-random-string",
148
- jwtSecret
149
- );
150
- if (options.databaseUrl) {
151
- envContent = envContent.replace(
152
- "postgresql://rebase:password@localhost:5432/rebase",
153
- options.databaseUrl
154
- );
155
- } else {
156
- const dbPassword = crypto.randomBytes(16).toString("hex");
157
- envContent = envContent.replace(
158
- "postgresql://rebase:password@localhost:5432/rebase",
159
- `postgresql://rebase:${dbPassword}@localhost:5432/rebase`
160
- );
161
- envContent += `
162
- # Docker Compose Database Password
163
- POSTGRES_PASSWORD=${dbPassword}
164
- `;
165
- }
166
- fs.writeFileSync(envPath, envContent, "utf-8");
167
- }
183
+ configureEnvFile(options.targetDirectory, options.databaseUrl);
168
184
  if (options.git) {
169
185
  console.log(chalk.gray(" Initializing git repository..."));
170
186
  try {
@@ -173,17 +189,20 @@ POSTGRES_PASSWORD=${dbPassword}
173
189
  console.warn(chalk.yellow(" Warning: Failed to initialize git repository"));
174
190
  }
175
191
  }
192
+ const { pm, pmCommands } = options;
193
+ const installCmd = pmCommands.install;
194
+ const execCmd = pmCommands.exec("rebase", ["schema", "introspect", "--force"]);
176
195
  if (options.installDeps) {
177
196
  console.log("");
178
- console.log(chalk.gray(" Installing dependencies with pnpm..."));
197
+ console.log(chalk.gray(` Installing dependencies with ${pm}...`));
179
198
  console.log("");
180
199
  try {
181
- await execa("pnpm", ["install"], {
200
+ await execa(installCmd[0], installCmd.slice(1), {
182
201
  cwd: options.targetDirectory,
183
202
  stdio: "inherit"
184
203
  });
185
204
  } catch {
186
- console.warn(chalk.yellow(" Warning: Failed to install dependencies. You may need to run `pnpm install` manually."));
205
+ console.warn(chalk.yellow(` Warning: Failed to install dependencies. You may need to run \`${installCmd.join(" ")}\` manually.`));
187
206
  }
188
207
  }
189
208
  if (options.introspect) {
@@ -192,18 +211,18 @@ POSTGRES_PASSWORD=${dbPassword}
192
211
  console.log(chalk.gray(" Introspecting database and generating collections..."));
193
212
  console.log("");
194
213
  try {
195
- await execa("pnpm", ["exec", "rebase", "schema", "introspect"], {
214
+ await execa(execCmd[0], execCmd.slice(1), {
196
215
  cwd: options.targetDirectory,
197
216
  stdio: "inherit"
198
217
  });
199
218
  console.log(chalk.green(" Database successfully introspected!"));
200
219
  } catch {
201
220
  console.warn(chalk.yellow(" Warning: Failed to introspect database automatically."));
202
- console.warn(chalk.yellow(" You can run `pnpm exec rebase schema introspect` manually after setup."));
221
+ console.warn(chalk.yellow(` You can run \`${execCmd.join(" ")}\` manually after setup.`));
203
222
  }
204
223
  } else {
205
224
  console.warn(chalk.yellow(" Skipping introspection because dependencies were not installed."));
206
- console.warn(chalk.yellow(" Run `pnpm install` then `pnpm exec rebase schema introspect` manually."));
225
+ console.warn(chalk.yellow(` Run \`${installCmd.join(" ")}\` then \`${execCmd.join(" ")}\` manually.`));
207
226
  }
208
227
  }
209
228
  console.log("");
@@ -211,22 +230,23 @@ POSTGRES_PASSWORD=${dbPassword}
211
230
  console.log("");
212
231
  console.log(chalk.bold("Next steps:"));
213
232
  console.log("");
233
+ const runDev = pmCommands.run("dev");
214
234
  console.log(` ${chalk.cyan("cd")} ${options.projectName}`);
215
235
  if (!options.installDeps) {
216
- console.log(` ${chalk.cyan("pnpm install")}`);
236
+ console.log(` ${chalk.cyan(installCmd.join(" "))}`);
217
237
  }
218
238
  console.log("");
219
239
  if (options.databaseUrl) {
220
240
  console.log(chalk.gray(" # Your database is configured! Start the dev server:"));
221
241
  } else {
222
- console.log(chalk.gray(" # A local database configuration has been generated in .env"));
242
+ console.log(chalk.gray(" # A local database configuration has been generated in .env."));
223
243
  console.log(chalk.gray(" # If using the included docker-compose.yml, start it with:"));
224
244
  console.log(` ${chalk.cyan("docker compose up -d")}`);
225
245
  console.log("");
226
246
  console.log(chalk.gray(" # Then start the dev server:"));
227
247
  }
228
248
  console.log("");
229
- console.log(` ${chalk.cyan("pnpm dev")}`);
249
+ console.log(` ${chalk.cyan(runDev.join(" "))}`);
230
250
  console.log("");
231
251
  console.log(chalk.gray("This starts both the backend (Hono + PostgreSQL)") + chalk.gray(" and the frontend (Vite + React) concurrently."));
232
252
  console.log("");
@@ -240,7 +260,8 @@ async function replacePlaceholders(options) {
240
260
  "frontend/package.json",
241
261
  "backend/package.json",
242
262
  "config/package.json",
243
- "frontend/index.html"
263
+ "frontend/index.html",
264
+ "README.md"
244
265
  ];
245
266
  const packageJsonPath = path.resolve(cliRoot, "package.json");
246
267
  let cliVersion = "latest";
@@ -249,22 +270,23 @@ async function replacePlaceholders(options) {
249
270
  cliVersion = pkg.version || "latest";
250
271
  }
251
272
  const versionCache = /* @__PURE__ */ new Map();
273
+ const viewBin = "npm";
252
274
  const getPackageVersion = async (pkgName) => {
253
275
  if (versionCache.has(pkgName)) return versionCache.get(pkgName);
254
276
  let versionToUse = cliVersion;
255
277
  try {
256
- const { stdout } = await execa("npm", ["--loglevel", "error", "info", `${pkgName}@${cliVersion}`, "version"]);
278
+ const { stdout } = await execa(viewBin, ["view", `${pkgName}@${cliVersion}`, "version"]);
257
279
  if (!stdout.trim()) throw new Error("Not found");
258
280
  versionToUse = stdout.trim();
259
281
  } catch {
260
282
  try {
261
283
  const tag = cliVersion.includes("canary") ? "canary" : "latest";
262
- const { stdout } = await execa("npm", ["--loglevel", "error", "info", `${pkgName}@${tag}`, "version"]);
284
+ const { stdout } = await execa(viewBin, ["view", `${pkgName}@${tag}`, "version"]);
263
285
  if (!stdout.trim()) throw new Error("Not found");
264
286
  versionToUse = stdout.trim();
265
287
  } catch {
266
288
  try {
267
- const { stdout } = await execa("npm", ["--loglevel", "error", "info", pkgName, "version"]);
289
+ const { stdout } = await execa(viewBin, ["view", pkgName, "version"]);
268
290
  versionToUse = stdout.trim() || "latest";
269
291
  } catch {
270
292
  versionToUse = "latest";
@@ -299,6 +321,32 @@ async function replacePlaceholders(options) {
299
321
  fs.writeFileSync(fullPath, content, "utf-8");
300
322
  }
301
323
  }
324
+ function configureEnvFile(targetDirectory, databaseUrl) {
325
+ const envExamplePath = path.join(targetDirectory, ".env.example");
326
+ const envPath = path.join(targetDirectory, ".env");
327
+ if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
328
+ fs.copyFileSync(envExamplePath, envPath);
329
+ const jwtSecret = crypto.randomBytes(32).toString("hex");
330
+ const dbPassword = crypto.randomBytes(16).toString("hex");
331
+ let envContent = fs.readFileSync(envPath, "utf-8");
332
+ envContent = envContent.replace(
333
+ /^JWT_SECRET=.*$/m,
334
+ `JWT_SECRET=${jwtSecret}`
335
+ );
336
+ if (databaseUrl) {
337
+ envContent = envContent.replace(
338
+ /^DATABASE_URL=.*$/m,
339
+ `DATABASE_URL=${databaseUrl}`
340
+ );
341
+ } else {
342
+ envContent = envContent.replace(
343
+ /^DATABASE_URL=.*$/m,
344
+ `DATABASE_URL=postgresql://rebase:${dbPassword}@localhost:5432/rebase`
345
+ );
346
+ }
347
+ fs.writeFileSync(envPath, envContent, "utf-8");
348
+ }
349
+ }
302
350
  async function loadCollections(collectionsDir) {
303
351
  const absDir = path.resolve(collectionsDir);
304
352
  if (!fs.existsSync(absDir)) {
@@ -451,15 +499,20 @@ function getActiveBackendPlugin(backendDir) {
451
499
  if (!fs.existsSync(pkgPath)) return null;
452
500
  try {
453
501
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
454
- const deps = {
455
- ...pkg.dependencies,
456
- ...pkg.devDependencies
457
- };
458
- for (const dep of Object.keys(deps)) {
459
- if (dep.startsWith("@rebasepro/server-") && dep !== "@rebasepro/server-core") {
460
- return dep;
502
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
503
+ const candidates = Object.keys(deps).filter(
504
+ (dep) => dep.startsWith("@rebasepro/server-") && dep !== "@rebasepro/server-core"
505
+ );
506
+ if (candidates.length === 0) return null;
507
+ if (candidates.includes("@rebasepro/server-postgresql")) {
508
+ return "@rebasepro/server-postgresql";
509
+ }
510
+ for (const candidate of candidates) {
511
+ if (resolvePluginCliScript(backendDir, candidate)) {
512
+ return candidate;
461
513
  }
462
514
  }
515
+ return candidates[0];
463
516
  } catch {
464
517
  }
465
518
  return null;
@@ -660,7 +713,6 @@ ${chalk.green.bold("Usage")}
660
713
  ${chalk.green.bold("Commands")}
661
714
  ${chalk.gray("(Commands are provided by your active database driver plugin)")}
662
715
  ${chalk.blue.bold("push")} Apply schema directly to database (development)
663
- ${chalk.blue.bold("pull")} Introspect database → Schema
664
716
  ${chalk.blue.bold("generate")} Generate migration files
665
717
  ${chalk.blue.bold("migrate")} Run pending migrations
666
718
  ${chalk.blue.bold("studio")} Open Studio viewer
@@ -791,9 +843,12 @@ async function devCommand(rawArgs) {
791
843
  frontendEnv.VITE_API_URL = `http://localhost:${backendPort}`;
792
844
  console.log(` ${chalk.gray("↳ VITE_API_URL")} = ${chalk.white(`http://localhost:${backendPort}`)}`);
793
845
  }
846
+ const pm = detectPackageManager(projectRoot);
847
+ const pmCmds = getPMCommands(pm);
848
+ const runDevCmd = pmCmds.run("dev");
794
849
  const frontendChild = execa(
795
- "pnpm",
796
- ["run", "dev"],
850
+ runDevCmd[0],
851
+ runDevCmd.slice(1),
797
852
  {
798
853
  cwd: frontendDir,
799
854
  stdio: ["inherit", "pipe", "pipe"],
@@ -827,8 +882,10 @@ async function devCommand(rawArgs) {
827
882
  if (!frontendOnly && backendDir) {
828
883
  const tsxBin = resolveTsx(projectRoot);
829
884
  if (!tsxBin) {
885
+ const pmName = detectPackageManager(projectRoot);
886
+ const addCmd = pmName === "npm" ? "npm install -D tsx" : "pnpm add -D tsx";
830
887
  console.error(chalk.red(" āœ— Could not find tsx binary for backend."));
831
- console.error(chalk.gray(" Install it with: pnpm add -D tsx"));
888
+ console.error(chalk.gray(` Install it with: ${addCmd}`));
832
889
  process.exit(1);
833
890
  }
834
891
  const envFile = findEnvFile(projectRoot);
@@ -929,6 +986,46 @@ ${chalk.green.bold("Description")}
929
986
  backend is ready, and VITE_API_URL is injected automatically.
930
987
  `);
931
988
  }
989
+ async function buildCommand() {
990
+ const projectRoot = requireProjectRoot();
991
+ const pm = detectPackageManager(projectRoot);
992
+ const cmds = getPMCommands(pm);
993
+ const buildCmd = cmds.runAll("build");
994
+ console.log(`${chalk.bold("Rebase")} — Building all workspaces with ${chalk.cyan(pm)}...
995
+ `);
996
+ try {
997
+ await execa(buildCmd[0], buildCmd.slice(1), {
998
+ cwd: projectRoot,
999
+ stdio: "inherit"
1000
+ });
1001
+ } catch {
1002
+ console.error(chalk.red("\nāœ— Build failed."));
1003
+ process.exit(1);
1004
+ }
1005
+ }
1006
+ async function startCommand() {
1007
+ const projectRoot = requireProjectRoot();
1008
+ const pm = detectPackageManager(projectRoot);
1009
+ const cmds = getPMCommands(pm);
1010
+ const startCmd = cmds.runWorkspace("backend", "start");
1011
+ const envFile = findEnvFile(projectRoot);
1012
+ const env = { ...process.env };
1013
+ if (envFile) {
1014
+ env.DOTENV_CONFIG_PATH = envFile;
1015
+ }
1016
+ console.log(`${chalk.bold("Rebase")} — Starting backend server...
1017
+ `);
1018
+ try {
1019
+ await execa(startCmd[0], startCmd.slice(1), {
1020
+ cwd: projectRoot,
1021
+ stdio: "inherit",
1022
+ env
1023
+ });
1024
+ } catch {
1025
+ console.error(chalk.red("\nāœ— Failed to start server."));
1026
+ process.exit(1);
1027
+ }
1028
+ }
932
1029
  async function authCommand(subcommand, rawArgs) {
933
1030
  if (!subcommand || subcommand === "--help") {
934
1031
  printAuthHelp();
@@ -1137,7 +1234,7 @@ async function entry(args) {
1137
1234
  }
1138
1235
  const command = parsedArgs._[0];
1139
1236
  const subcommand = parsedArgs._[1];
1140
- const namespacedCommands = ["schema", "db", "dev", "auth", "doctor"];
1237
+ const namespacedCommands = ["schema", "db", "dev", "build", "start", "auth", "doctor"];
1141
1238
  if (!command || parsedArgs["--help"] && !namespacedCommands.includes(command)) {
1142
1239
  printHelp();
1143
1240
  return;
@@ -1176,6 +1273,12 @@ async function entry(args) {
1176
1273
  case "dev":
1177
1274
  await devCommand(args);
1178
1275
  break;
1276
+ case "build":
1277
+ await buildCommand();
1278
+ break;
1279
+ case "start":
1280
+ await startCommand();
1281
+ break;
1179
1282
  case "auth":
1180
1283
  await authCommand(effectiveSubcommand, args);
1181
1284
  break;
@@ -1198,14 +1301,16 @@ ${chalk.green.bold("Usage")}
1198
1301
  ${chalk.green.bold("Commands")}
1199
1302
  ${chalk.blue.bold("init")} Create a new Rebase project
1200
1303
  ${chalk.blue.bold("dev")} Start the development server
1304
+ ${chalk.blue.bold("build")} Build all workspace packages
1305
+ ${chalk.blue.bold("start")} Start the backend server ${chalk.gray("(production)")}
1201
1306
 
1202
1307
  ${chalk.green.bold("Schema")}
1203
1308
  ${chalk.blue.bold("schema generate")} Generate Drizzle schema from collections
1309
+ ${chalk.blue.bold("schema introspect")} Introspect database → Rebase collections
1204
1310
  ${chalk.blue.bold("schema")} ${chalk.gray("--help")} Show schema command help
1205
1311
 
1206
1312
  ${chalk.green.bold("Database")}
1207
1313
  ${chalk.blue.bold("db push")} Apply schema directly to database ${chalk.gray("(dev)")}
1208
- ${chalk.blue.bold("db pull")} Introspect database → Drizzle schema
1209
1314
  ${chalk.blue.bold("db generate")} Generate SQL migration files
1210
1315
  ${chalk.blue.bold("db migrate")} Run pending migrations
1211
1316
  ${chalk.blue.bold("db studio")} Open Drizzle Studio
@@ -1273,6 +1378,8 @@ async function logout(env, _debug) {
1273
1378
  }
1274
1379
  export {
1275
1380
  authCommand,
1381
+ buildCommand,
1382
+ configureEnvFile,
1276
1383
  createRebaseApp,
1277
1384
  dbCommand,
1278
1385
  devCommand,
@@ -1292,6 +1399,7 @@ export {
1292
1399
  resolveLocalBin,
1293
1400
  resolvePluginCliScript,
1294
1401
  resolveTsx,
1295
- schemaCommand
1402
+ schemaCommand,
1403
+ startCommand
1296
1404
  };
1297
1405
  //# sourceMappingURL=index.es.js.map