@rebasepro/cli 0.2.3 → 0.2.5

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/README.md CHANGED
@@ -1,52 +1,56 @@
1
1
  ## Rebase CLI
2
2
 
3
- This CLI tool allows you to create new Rebase projects and to deploy them to Rebase Cloud.
4
- **IMPORTANT**: You should not be using this tool directly, but `rebase` instead.
3
+ Developer tools for scaffolding, running, and managing Rebase projects.
5
4
 
6
- ### CLI
5
+ ### Installation
7
6
 
8
- You can use the following commands:
7
+ The CLI is bundled with every Rebase project. You can also install it globally:
9
8
 
10
9
  ```bash
11
- rebase login
10
+ pnpm add -g @rebasepro/cli
12
11
  ```
13
12
 
14
- ```bash
15
- rebase init
16
- ```
13
+ ### Commands
14
+
15
+ | Command | Description |
16
+ |---------|-------------|
17
+ | `rebase init` | Scaffold a new Rebase project |
18
+ | `rebase dev` | Start the development server (backend + frontend) |
19
+ | `rebase build` | Build all workspace packages |
20
+ | `rebase start` | Start the backend server (production) |
21
+ | `rebase schema generate` | Generate Drizzle schema from collection definitions |
22
+ | `rebase schema introspect` | Introspect an existing database to generate collections |
23
+ | `rebase db push` | Apply schema directly to database (development) |
24
+ | `rebase db generate` | Generate SQL migration files |
25
+ | `rebase db migrate` | Run pending migrations |
26
+ | `rebase db studio` | Open Drizzle Studio |
27
+ | `rebase generate-sdk` | Generate a typed JS SDK from collections |
28
+ | `rebase auth reset-password` | Reset a user's password |
29
+ | `rebase doctor` | Detect schema drift between collections, schema, and DB |
30
+
31
+ ### Quick Start
17
32
 
18
33
  ```bash
19
- rebase deploy
34
+ rebase init my-app
35
+ cd my-app
36
+ docker compose up -d db
37
+ pnpm run db:push
38
+ pnpm run dev
20
39
  ```
21
40
 
22
- ### Using different templates
23
-
24
- You can initialize a new project using different templates. Please not that these templates can't
25
- be deployed to Rebase Cloud. For example:
41
+ ### Help
26
42
 
27
- For Rebase Cloud
43
+ Run `rebase --help` or `rebase <command> --help` for detailed usage information.
28
44
 
29
- ```bash
30
- rebase init
31
- ```
45
+ ### Development
32
46
 
33
- For Rebase PRO:
47
+ For local development of the CLI itself, link the package:
34
48
 
35
49
  ```bash
36
- rebase init --pro
50
+ pnpm link --global
37
51
  ```
38
52
 
39
- #### To run locally
40
-
41
- For development purposes, you can link the package locally.
42
-
43
- ```bash
44
- npm link rebase
45
- ```
46
-
47
- ### Development only
48
-
49
- You can change the environment when deploying to Rebase Cloud by defining the --env variable.
53
+ You can change the environment when deploying to Rebase Cloud by defining the `--env` variable.
50
54
  Possible values are `prod` (default) and `dev`.
51
55
 
52
56
  ```bash
package/dist/index.cjs CHANGED
@@ -1,25 +1,8 @@
1
1
  (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("chalk"), require("arg"), require("inquirer"), require("path"), require("fs"), require("net"), require("util"), require("execa"), require("fs/promises"), require("url"), require("crypto"), require("@rebasepro/sdk-generator"), require("child_process"), require("os")) : typeof define === "function" && define.amd ? define(["exports", "chalk", "arg", "inquirer", "path", "fs", "net", "util", "execa", "fs/promises", "url", "crypto", "@rebasepro/sdk-generator", "child_process", "os"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["Rebase CLI"] = {}, global.chalk, global.arg, global.inquirer, global.path, global.fs, global.net, global.util, global.execa, global.promises, global.url, global.crypto, global.sdkGenerator, global.child_process, global.os));
3
- })(this, (function(exports2, chalk, arg, inquirer, path, fs, net, util, execa, promises, url, crypto, sdkGenerator, child_process, os) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("chalk"), require("arg"), require("inquirer"), require("path"), require("fs"), require("net"), require("util"), require("execa"), require("fs/promises"), require("url"), require("crypto"), require("@rebasepro/sdk-generator"), require("child_process")) : typeof define === "function" && define.amd ? define(["exports", "chalk", "arg", "inquirer", "path", "fs", "net", "util", "execa", "fs/promises", "url", "crypto", "@rebasepro/sdk-generator", "child_process"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["Rebase CLI"] = {}, global.chalk, global.arg, global.inquirer, global.path, global.fs, global.net, global.util, global.execa, global.promises, global.url, global.crypto, global.sdkGenerator, global.child_process));
3
+ })(this, (function(exports2, chalk, arg, inquirer, path, fs, net, util, execa, promises, url, crypto, sdkGenerator, child_process) {
4
4
  "use strict";
5
5
  var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
6
- function _interopNamespaceDefault(e) {
7
- const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
8
- if (e) {
9
- for (const k in e) {
10
- if (k !== "default") {
11
- const d = Object.getOwnPropertyDescriptor(e, k);
12
- Object.defineProperty(n, k, d.get ? d : {
13
- enumerable: true,
14
- get: () => e[k]
15
- });
16
- }
17
- }
18
- }
19
- n.default = e;
20
- return Object.freeze(n);
21
- }
22
- const os__namespace = /* @__PURE__ */ _interopNamespaceDefault(os);
23
6
  function detectPackageManager(targetDir) {
24
7
  const userAgent = process.env.npm_config_user_agent ?? "";
25
8
  if (userAgent.startsWith("npm/")) return "npm";
@@ -154,7 +137,13 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
154
137
  type: "input",
155
138
  name: "databaseUrl",
156
139
  message: "Enter your PostgreSQL database connection string (leave blank to use a local default):",
157
- default: ""
140
+ default: "",
141
+ validate: (input) => {
142
+ if (input.trim() && /[\r\n]/.test(input)) {
143
+ return "Database URL cannot contain newline characters.";
144
+ }
145
+ return true;
146
+ }
158
147
  });
159
148
  questions.push({
160
149
  type: "confirm",
@@ -260,23 +249,37 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
260
249
  console.log(chalk.bold("Next steps:"));
261
250
  console.log("");
262
251
  const runDev = pmCommands.run("dev");
252
+ const runDbPush = pmCommands.run("db:push");
263
253
  console.log(` ${chalk.cyan("cd")} ${options.projectName}`);
264
254
  if (!options.installDeps) {
265
255
  console.log(` ${chalk.cyan(installCmd.join(" "))}`);
266
256
  }
267
257
  console.log("");
268
258
  if (options.databaseUrl) {
269
- console.log(chalk.gray(" # Your database is configured! Start the dev server:"));
259
+ if (options.introspect) {
260
+ console.log(chalk.gray(" # Database has been introspected & collections generated!"));
261
+ console.log(chalk.gray(" # Start the development server (frontend + backend):"));
262
+ console.log(` ${chalk.cyan(runDev.join(" "))}`);
263
+ } else {
264
+ console.log(chalk.gray(" # Your custom database is configured in .env."));
265
+ console.log(chalk.gray(" # If the database is empty, push the Rebase schema to initialize it:"));
266
+ console.log(` ${chalk.cyan(runDbPush.join(" "))}`);
267
+ console.log("");
268
+ console.log(chalk.gray(" # Then start the development server:"));
269
+ console.log(` ${chalk.cyan(runDev.join(" "))}`);
270
+ }
270
271
  } else {
271
272
  console.log(chalk.gray(" # A local database configuration has been generated in .env."));
272
- console.log(chalk.gray(" # If using the included docker-compose.yml, start the database with:"));
273
+ console.log(chalk.gray(" # 1. Start the PostgreSQL database container:"));
273
274
  console.log(` ${chalk.cyan("docker compose up -d db")}`);
274
275
  console.log("");
275
- console.log(chalk.gray(" # Then start the dev server:"));
276
+ console.log(chalk.gray(" # 2. Push the Rebase schema to initialize database tables:"));
277
+ console.log(` ${chalk.cyan(runDbPush.join(" "))}`);
278
+ console.log("");
279
+ console.log(chalk.gray(" # 3. Start the development server (frontend + backend):"));
280
+ console.log(` ${chalk.cyan(runDev.join(" "))}`);
276
281
  }
277
282
  console.log("");
278
- console.log(` ${chalk.cyan(runDev.join(" "))}`);
279
- console.log("");
280
283
  console.log(chalk.gray("This starts both the backend (Hono + PostgreSQL)") + chalk.gray(" and the frontend (Vite + React) concurrently."));
281
284
  console.log("");
282
285
  console.log(chalk.gray("Docs: https://rebase.pro/docs"));
@@ -387,6 +390,9 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
387
390
  `JWT_SECRET=${jwtSecret}`
388
391
  );
389
392
  if (databaseUrl) {
393
+ if (/[\r\n]/.test(databaseUrl)) {
394
+ throw new Error("Invalid DATABASE_URL: multiline values are not allowed.");
395
+ }
390
396
  envContent = envContent.replace(
391
397
  /^DATABASE_URL=.*$/m,
392
398
  `DATABASE_URL=${databaseUrl}`
@@ -696,7 +702,7 @@ Expected a default export of EntityCollection[] or an object with named collecti
696
702
  env
697
703
  });
698
704
  }
699
- } catch (err) {
705
+ } catch {
700
706
  process.exit(1);
701
707
  }
702
708
  }
@@ -764,7 +770,7 @@ ${chalk.green.bold("introspect Options")}
764
770
  env
765
771
  });
766
772
  }
767
- } catch (err) {
773
+ } catch {
768
774
  process.exit(1);
769
775
  }
770
776
  }
@@ -984,7 +990,7 @@ ${chalk.green.bold("Examples")}
984
990
  });
985
991
  console.log(chalk.green(" ✓ Initial schema and SDK generated successfully.\n"));
986
992
  } catch (err) {
987
- console.error(chalk.red(` ✗ Initial schema/SDK generation failed: ${err.message || err}
993
+ console.error(chalk.red(` ✗ Initial schema/SDK generation failed: ${err instanceof Error ? err.message : err}
988
994
  `));
989
995
  }
990
996
  const collectionsDir = path.join(projectRoot, "config", "collections");
@@ -1013,7 +1019,7 @@ ${chalk.green.bold("Examples")}
1013
1019
  });
1014
1020
  console.log(chalk.green(" ✓ Schema & SDK regenerated successfully. Hono will reload."));
1015
1021
  } catch (err) {
1016
- console.error(chalk.red(` ✗ Failed to regenerate schema/SDK: ${err.message || err}`));
1022
+ console.error(chalk.red(` ✗ Failed to regenerate schema/SDK: ${err instanceof Error ? err.message : err}`));
1017
1023
  }
1018
1024
  }, 300);
1019
1025
  });
@@ -1208,6 +1214,9 @@ ${chalk.green.bold("Description")}
1208
1214
  if (envFile) {
1209
1215
  env.DOTENV_CONFIG_PATH = envFile;
1210
1216
  }
1217
+ env.REBASE_RESET_EMAIL = email;
1218
+ env.REBASE_RESET_PASSWORD = newPassword || "NewPassword123!";
1219
+ env.REBASE_ENV_FILE_PATH = envFile || path.join(projectRoot, ".env");
1211
1220
  const scriptContent = `
1212
1221
  import { createPostgresDatabaseConnection } from "@rebasepro/server-postgresql";
1213
1222
  import { hashPassword } from "@rebasepro/server-core";
@@ -1216,10 +1225,10 @@ import * as dotenv from "dotenv";
1216
1225
  import path from "path";
1217
1226
  import fs from "fs";
1218
1227
 
1219
- dotenv.config({ path: "${envFile || path.join(projectRoot, ".env")}" });
1228
+ dotenv.config({ path: process.env.REBASE_ENV_FILE_PATH });
1220
1229
 
1221
- const email = "${email}";
1222
- const newPassword = "${newPassword || "NewPassword123!"}";
1230
+ const email = process.env.REBASE_RESET_EMAIL!;
1231
+ const newPassword = process.env.REBASE_RESET_PASSWORD!;
1223
1232
 
1224
1233
  async function resetPassword() {
1225
1234
  const { db } = createPostgresDatabaseConnection(process.env.DATABASE_URL!);
@@ -1482,66 +1491,22 @@ ${chalk.green.bold("Options")}
1482
1491
  ${chalk.gray("Documentation: https://rebase.pro/docs")}
1483
1492
  `);
1484
1493
  }
1485
- const TOKEN_DIR = path.join(os__namespace.homedir(), ".rebase");
1486
- function tokenPath(env) {
1487
- return path.join(TOKEN_DIR, (env === "dev" ? "staging." : "") + "tokens.json");
1488
- }
1489
- async function getTokens(env, _debug) {
1490
- const fp = tokenPath(env);
1491
- if (!fs.existsSync(fp)) return null;
1492
- try {
1493
- const data = fs.readFileSync(fp, "utf-8");
1494
- return JSON.parse(data);
1495
- } catch {
1496
- return null;
1497
- }
1498
- }
1499
- function parseJwt(token) {
1500
- if (!token) throw new Error("No JWT token");
1501
- const base64Url = token.split(".")[1];
1502
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
1503
- const buffer = Buffer.from(base64, "base64");
1504
- return JSON.parse(buffer.toString());
1505
- }
1506
- async function refreshCredentials(env, credentials, _onErr) {
1507
- if (!credentials) return null;
1508
- const expiryDate = new Date(credentials["expiry_date"]);
1509
- if (expiryDate.getTime() > Date.now()) {
1510
- return credentials;
1511
- }
1512
- return null;
1513
- }
1514
- async function login(env, _debug) {
1515
- console.log(
1516
- "Interactive login is not yet implemented in @rebasepro/cli.\nPlease authenticate via the Rebase dashboard and copy your tokens to " + tokenPath(env)
1517
- );
1518
- }
1519
- async function logout(env, _debug) {
1520
- const fp = tokenPath(env);
1521
- if (fs.existsSync(fp)) {
1522
- fs.unlinkSync(fp);
1523
- console.log("You have been logged out.");
1524
- } else {
1525
- console.log("You are not logged in.");
1526
- }
1527
- }
1528
1494
  exports2.authCommand = authCommand;
1529
1495
  exports2.buildCommand = buildCommand;
1530
1496
  exports2.configureEnvFile = configureEnvFile;
1531
1497
  exports2.createRebaseApp = createRebaseApp;
1532
1498
  exports2.dbCommand = dbCommand;
1499
+ exports2.detectPackageManager = detectPackageManager;
1533
1500
  exports2.devCommand = devCommand;
1501
+ exports2.doctorCommand = doctorCommand;
1534
1502
  exports2.entry = entry;
1535
1503
  exports2.findBackendDir = findBackendDir;
1536
1504
  exports2.findEnvFile = findEnvFile;
1537
1505
  exports2.findFrontendDir = findFrontendDir;
1538
1506
  exports2.findProjectRoot = findProjectRoot;
1507
+ exports2.generateSdkCommand = generateSdkCommand;
1539
1508
  exports2.getActiveBackendPlugin = getActiveBackendPlugin;
1540
- exports2.getTokens = getTokens;
1541
- exports2.login = login;
1542
- exports2.logout = logout;
1543
- exports2.parseJwt = parseJwt;
1544
- exports2.refreshCredentials = refreshCredentials;
1509
+ exports2.getPMCommands = getPMCommands;
1545
1510
  exports2.requireBackendDir = requireBackendDir;
1546
1511
  exports2.requireProjectRoot = requireProjectRoot;
1547
1512
  exports2.resolveLocalBin = resolveLocalBin;