@rebasepro/cli 0.0.1-canary.eae7889 → 0.0.1-canary.eb08332

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.
Files changed (74) hide show
  1. package/LICENSE +17 -196
  2. package/README.md +57 -33
  3. package/dist/commands/api-keys.d.ts +1 -0
  4. package/dist/commands/build.d.ts +1 -0
  5. package/dist/commands/cloud/auth.d.ts +3 -0
  6. package/dist/commands/cloud/context.d.ts +61 -0
  7. package/dist/commands/cloud/databases.d.ts +1 -0
  8. package/dist/commands/cloud/deploy.d.ts +2 -0
  9. package/dist/commands/cloud/index.d.ts +1 -0
  10. package/dist/commands/cloud/link.d.ts +5 -0
  11. package/dist/commands/cloud/orgs.d.ts +1 -0
  12. package/dist/commands/cloud/projects.d.ts +13 -0
  13. package/dist/commands/cloud/resources.d.ts +6 -0
  14. package/dist/commands/generate_sdk.d.ts +1 -1
  15. package/dist/commands/init.d.ts +39 -0
  16. package/dist/commands/skills.d.ts +1 -0
  17. package/dist/commands/start.d.ts +1 -0
  18. package/dist/index.d.ts +6 -1
  19. package/dist/index.es.js +3785 -990
  20. package/dist/index.es.js.map +1 -1
  21. package/dist/utils/package-manager.d.ts +33 -0
  22. package/dist/utils/project.d.ts +16 -1
  23. package/package.json +26 -23
  24. package/templates/overlays/baas/README.md +37 -0
  25. package/templates/overlays/baas/backend/package.json +31 -0
  26. package/templates/overlays/baas/backend/src/index.ts +172 -0
  27. package/templates/overlays/baas/backend/tsconfig.json +18 -0
  28. package/templates/overlays/baas/package.json +42 -0
  29. package/templates/overlays/baas/pnpm-workspace.yaml +9 -0
  30. package/templates/template/.cursorrules +2 -0
  31. package/templates/template/.dockerignore +1 -1
  32. package/templates/template/.env.example +120 -0
  33. package/templates/template/.github/copilot-instructions.md +2 -0
  34. package/templates/template/.windsurfrules +2 -0
  35. package/templates/template/AGENTS.md +2 -0
  36. package/templates/template/CLAUDE.md +2 -0
  37. package/templates/template/README.md +20 -10
  38. package/templates/template/ai-instructions.md +17 -0
  39. package/templates/template/backend/Dockerfile +5 -4
  40. package/templates/template/backend/functions/hello.ts +36 -32
  41. package/templates/template/backend/package.json +11 -11
  42. package/templates/template/backend/src/env.ts +13 -42
  43. package/templates/template/backend/src/index.ts +54 -28
  44. package/templates/template/config/collections/authors.ts +2 -2
  45. package/templates/template/config/collections/index.ts +25 -4
  46. package/templates/template/config/collections/posts.ts +15 -35
  47. package/templates/template/config/collections/presets/blank/index.ts +3 -0
  48. package/templates/template/config/collections/presets/ecommerce/categories.ts +40 -0
  49. package/templates/template/config/collections/presets/ecommerce/index.ts +6 -0
  50. package/templates/template/config/collections/presets/ecommerce/orders.ts +66 -0
  51. package/templates/template/config/collections/presets/ecommerce/products.ts +64 -0
  52. package/templates/template/config/collections/tags.ts +3 -5
  53. package/templates/template/config/collections/users.ts +142 -0
  54. package/templates/template/config/index.ts +1 -1
  55. package/templates/template/docker-compose.yml +14 -39
  56. package/templates/template/frontend/Dockerfile +5 -3
  57. package/templates/template/frontend/package.json +8 -7
  58. package/templates/template/frontend/src/App.tsx +26 -105
  59. package/templates/template/frontend/src/main.tsx +4 -0
  60. package/templates/template/frontend/src/virtual.d.ts +6 -0
  61. package/templates/template/frontend/tsconfig.json +3 -2
  62. package/templates/template/frontend/vite.config.ts +47 -4
  63. package/templates/template/package.json +22 -8
  64. package/templates/template/pnpm-workspace.yaml +9 -0
  65. package/templates/template/scripts/example.ts +5 -2
  66. package/dist/auth.d.ts +0 -5
  67. package/dist/commands/cli.test.d.ts +0 -1
  68. package/dist/commands/dev.test.d.ts +0 -1
  69. package/dist/commands/init.test.d.ts +0 -1
  70. package/dist/index.cjs +0 -1203
  71. package/dist/index.cjs.map +0 -1
  72. package/dist/utils/project.test.d.ts +0 -1
  73. package/templates/template/.env.template +0 -62
  74. package/templates/template/backend/drizzle.config.ts +0 -22
package/dist/index.cjs DELETED
@@ -1,1203 +0,0 @@
1
- (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("chalk"), require("arg"), require("inquirer"), require("path"), require("fs"), require("util"), require("execa"), require("ncp"), 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", "util", "execa", "ncp", "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.util, global.execa, global.ncp, global.url, global.crypto, global.sdkGenerator, global.child_process, global.os));
3
- })(this, (function(exports2, chalk, arg, inquirer, path, fs, util, execa, ncp, url, crypto, sdkGenerator, child_process, os) {
4
- "use strict";
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
- const access = util.promisify(fs.access);
24
- const copy = util.promisify(ncp);
25
- const __filename$2 = url.fileURLToPath(typeof document === "undefined" && typeof location === "undefined" ? require("url").pathToFileURL(__filename).href : typeof document === "undefined" ? location.href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index.cjs", document.baseURI).href);
26
- const __dirname$2 = path.dirname(__filename$2);
27
- function findParentDir(currentDir, targetName) {
28
- const root = path.parse(currentDir).root;
29
- while (currentDir && currentDir !== root) {
30
- if (path.basename(currentDir) === targetName) {
31
- return currentDir;
32
- }
33
- currentDir = path.dirname(currentDir);
34
- }
35
- return null;
36
- }
37
- const cliRoot = findParentDir(__dirname$2, "cli");
38
- async function createRebaseApp(rawArgs) {
39
- console.log(`
40
- ${chalk.bold("Rebase")} — Create a new project 🚀
41
- `);
42
- const options = await promptForOptions(rawArgs);
43
- await createProject(options);
44
- }
45
- async function promptForOptions(rawArgs) {
46
- const args = arg(
47
- {
48
- "--git": Boolean,
49
- "--install": Boolean,
50
- "-g": "--git",
51
- "-i": "--install"
52
- },
53
- {
54
- argv: rawArgs.slice(3),
55
- // skip "node", "rebase", "init"
56
- permissive: true
57
- }
58
- );
59
- const nameArg = args._[0];
60
- const questions = [];
61
- if (!nameArg) {
62
- questions.push({
63
- type: "input",
64
- name: "projectName",
65
- message: "Project name:",
66
- default: "my-rebase-app",
67
- validate: (input) => {
68
- if (!input.trim()) return "Project name is required";
69
- if (!/^[a-z0-9][a-z0-9._-]*$/.test(input)) {
70
- return "Project name must start with a lowercase letter or number and contain only lowercase letters, numbers, hyphens, dots, or underscores";
71
- }
72
- return true;
73
- }
74
- });
75
- }
76
- if (!args["--git"]) {
77
- questions.push({
78
- type: "confirm",
79
- name: "git",
80
- message: "Initialize a git repository?",
81
- default: true
82
- });
83
- }
84
- if (!args["--install"]) {
85
- questions.push({
86
- type: "confirm",
87
- name: "installDeps",
88
- message: "Install dependencies with pnpm?",
89
- default: true
90
- });
91
- }
92
- const answers = await inquirer.prompt(questions);
93
- const projectName = nameArg || answers.projectName;
94
- const targetDirectory = path.resolve(process.cwd(), projectName);
95
- const templateDirectory = path.resolve(cliRoot, "templates", "template");
96
- return {
97
- projectName,
98
- git: args["--git"] || answers.git || false,
99
- installDeps: args["--install"] || answers.installDeps || false,
100
- targetDirectory,
101
- templateDirectory
102
- };
103
- }
104
- async function createProject(options) {
105
- if (fs.existsSync(options.targetDirectory)) {
106
- if (fs.readdirSync(options.targetDirectory).length !== 0) {
107
- console.error(`${chalk.red.bold("ERROR")} Directory "${options.projectName}" already exists and is not empty`);
108
- process.exit(1);
109
- }
110
- } else {
111
- fs.mkdirSync(options.targetDirectory, { recursive: true });
112
- }
113
- try {
114
- await access(options.templateDirectory, fs.constants.R_OK);
115
- } catch {
116
- console.error(`${chalk.red.bold("ERROR")} Template not found at ${options.templateDirectory}`);
117
- process.exit(1);
118
- }
119
- console.log(chalk.gray(" Copying project files..."));
120
- try {
121
- await copy(options.templateDirectory, options.targetDirectory, {
122
- clobber: false,
123
- dot: true,
124
- filter: (source) => {
125
- const basename = path.basename(source);
126
- return basename !== "node_modules" && basename !== ".DS_Store";
127
- }
128
- });
129
- } catch (err) {
130
- console.error(`${chalk.red.bold("ERROR")} Failed to copy template files: ${err instanceof Error ? err.message : String(err)}`);
131
- process.exit(1);
132
- }
133
- await replacePlaceholders(options);
134
- const envTemplatePath = path.join(options.targetDirectory, ".env.template");
135
- const envPath = path.join(options.targetDirectory, ".env");
136
- if (fs.existsSync(envTemplatePath) && !fs.existsSync(envPath)) {
137
- fs.renameSync(envTemplatePath, envPath);
138
- const jwtSecret = crypto.randomBytes(32).toString("hex");
139
- const dbPassword = crypto.randomBytes(16).toString("hex");
140
- let envContent = fs.readFileSync(envPath, "utf-8");
141
- envContent = envContent.replace(
142
- "postgresql://rebase:password@localhost:5432/rebase",
143
- `postgresql://rebase:${dbPassword}@localhost:5432/rebase`
144
- );
145
- envContent = envContent.replace(
146
- "change-this-to-a-secure-random-string",
147
- jwtSecret
148
- );
149
- envContent += `
150
- # Docker Compose Database Password
151
- POSTGRES_PASSWORD=${dbPassword}
152
- `;
153
- fs.writeFileSync(envPath, envContent, "utf-8");
154
- }
155
- if (options.git) {
156
- console.log(chalk.gray(" Initializing git repository..."));
157
- try {
158
- await execa("git", ["init"], { cwd: options.targetDirectory });
159
- } catch {
160
- console.warn(chalk.yellow(" Warning: Failed to initialize git repository"));
161
- }
162
- }
163
- if (options.installDeps) {
164
- console.log("");
165
- console.log(chalk.gray(" Installing dependencies with pnpm..."));
166
- console.log("");
167
- try {
168
- await execa("pnpm", ["install"], {
169
- cwd: options.targetDirectory,
170
- stdio: "inherit"
171
- });
172
- } catch {
173
- console.warn(chalk.yellow(" Warning: Failed to install dependencies. You may need to run `pnpm install` manually."));
174
- }
175
- }
176
- console.log("");
177
- console.log(`${chalk.green.bold("✓")} Project ${chalk.bold(options.projectName)} created successfully!`);
178
- console.log("");
179
- console.log(chalk.bold("Next steps:"));
180
- console.log("");
181
- console.log(` ${chalk.cyan("cd")} ${options.projectName}`);
182
- if (!options.installDeps) {
183
- console.log(` ${chalk.cyan("pnpm install")}`);
184
- }
185
- console.log("");
186
- console.log(chalk.gray(" # Set up your database connection in .env"));
187
- console.log(chalk.gray(" # Then run:"));
188
- console.log("");
189
- console.log(` ${chalk.cyan("pnpm dev")}`);
190
- console.log("");
191
- console.log(chalk.gray("This starts both the backend (Hono + PostgreSQL)") + chalk.gray(" and the frontend (Vite + React) concurrently."));
192
- console.log("");
193
- console.log(chalk.gray("Docs: https://rebase.pro/docs"));
194
- console.log(chalk.gray("GitHub: https://github.com/rebasepro/rebase"));
195
- console.log("");
196
- }
197
- async function replacePlaceholders(options) {
198
- const filesToProcess = [
199
- "package.json",
200
- "frontend/package.json",
201
- "backend/package.json",
202
- "config/package.json",
203
- "frontend/index.html"
204
- ];
205
- for (const file of filesToProcess) {
206
- const fullPath = path.resolve(options.targetDirectory, file);
207
- if (!fs.existsSync(fullPath)) continue;
208
- let content = fs.readFileSync(fullPath, "utf-8");
209
- content = content.replace(/\{\{PROJECT_NAME\}\}/g, options.projectName);
210
- fs.writeFileSync(fullPath, content, "utf-8");
211
- }
212
- }
213
- async function loadCollections(collectionsDir) {
214
- const absDir = path.resolve(collectionsDir);
215
- if (!fs.existsSync(absDir)) {
216
- throw new Error(`Collections directory not found: ${absDir}`);
217
- }
218
- let jiti;
219
- try {
220
- const jitiModule = await import("jiti");
221
- jiti = jitiModule.default || jitiModule;
222
- } catch {
223
- throw new Error(
224
- "Could not load 'jiti'. Install it with: pnpm add -D jiti\njiti is required to dynamically import TypeScript collection definitions."
225
- );
226
- }
227
- const jitiInstance = jiti(absDir, {
228
- interopDefault: true,
229
- esmResolve: true
230
- });
231
- const indexCandidates = ["index.ts", "index.js", "index.mjs"];
232
- let indexPath = null;
233
- for (const candidate of indexCandidates) {
234
- const p = path.join(absDir, candidate);
235
- if (fs.existsSync(p)) {
236
- indexPath = p;
237
- break;
238
- }
239
- }
240
- if (!indexPath) {
241
- console.log(chalk.yellow(" No index file found, scanning individual collection files..."));
242
- const collections = [];
243
- const files = fs.readdirSync(absDir).filter(
244
- (f) => (f.endsWith(".ts") || f.endsWith(".js")) && !f.startsWith(".")
245
- );
246
- for (const file of files) {
247
- try {
248
- const mod2 = jitiInstance(path.join(absDir, file));
249
- const exported2 = mod2.default || mod2;
250
- if (exported2 && typeof exported2 === "object" && "slug" in exported2) {
251
- collections.push(exported2);
252
- } else if (Array.isArray(exported2)) {
253
- collections.push(...exported2);
254
- }
255
- } catch (err) {
256
- console.warn(chalk.yellow(` ⚠ Skipping ${file}: ${err.message}`));
257
- }
258
- }
259
- return collections;
260
- }
261
- const mod = jitiInstance(indexPath);
262
- const exported = mod.default || mod;
263
- if (Array.isArray(exported)) {
264
- return exported;
265
- } else if (typeof exported === "object" && exported !== null) {
266
- if ("collections" in exported && Array.isArray(exported.collections)) {
267
- return exported.collections;
268
- }
269
- const collections = [];
270
- for (const value of Object.values(exported)) {
271
- if (value && typeof value === "object" && "slug" in value) {
272
- collections.push(value);
273
- }
274
- }
275
- if (collections.length > 0) return collections;
276
- }
277
- throw new Error(
278
- `Could not extract collections from ${indexPath}.
279
- Expected a default export of EntityCollection[] or an object with named collection exports.`
280
- );
281
- }
282
- function writeFiles(outputDir, files) {
283
- const absOutput = path.resolve(outputDir);
284
- fs.mkdirSync(absOutput, { recursive: true });
285
- for (const file of files) {
286
- const filePath = path.join(absOutput, file.path);
287
- const dir = path.dirname(filePath);
288
- if (!fs.existsSync(dir)) {
289
- fs.mkdirSync(dir, { recursive: true });
290
- }
291
- fs.writeFileSync(filePath, file.content, "utf-8");
292
- }
293
- }
294
- async function generateSdkCommand(args) {
295
- const { collectionsDir, output, cwd } = args;
296
- const resolvedCollectionsDir = path.isAbsolute(collectionsDir) ? collectionsDir : path.join(cwd, collectionsDir);
297
- const resolvedOutput = path.isAbsolute(output) ? output : path.join(cwd, output);
298
- console.log("");
299
- console.log(chalk.bold(" 🔧 Rebase SDK Generator"));
300
- console.log("");
301
- console.log(` ${chalk.gray("Collections:")} ${resolvedCollectionsDir}`);
302
- console.log(` ${chalk.gray("Output:")} ${resolvedOutput}`);
303
- console.log("");
304
- console.log(chalk.cyan(" → Loading collection definitions..."));
305
- const collections = await loadCollections(resolvedCollectionsDir);
306
- if (collections.length === 0) {
307
- console.log(chalk.red(" ✗ No collections found. Nothing to generate."));
308
- process.exit(1);
309
- }
310
- console.log(chalk.green(` ✓ Found ${collections.length} collection(s): ${collections.map((c) => c.slug).join(", ")}`));
311
- console.log("");
312
- console.log(chalk.cyan(" → Generating SDK files..."));
313
- const files = sdkGenerator.generateSDK(collections);
314
- console.log(chalk.green(` ✓ Generated ${files.length} file(s)`));
315
- console.log(chalk.cyan(` → Writing to ${resolvedOutput}...`));
316
- writeFiles(resolvedOutput, files);
317
- console.log("");
318
- console.log(chalk.green.bold(" ✓ SDK generated successfully!"));
319
- console.log("");
320
- console.log(chalk.gray(" Usage:"));
321
- console.log(chalk.gray(" import { createRebaseClient } from '@rebasepro/client';"));
322
- console.log(chalk.gray(` import type { Database } from './${path.relative(cwd, path.join(resolvedOutput, "database.types"))}';`));
323
- console.log("");
324
- console.log(chalk.gray(" const rebase = createRebaseClient<Database>({"));
325
- console.log(chalk.gray(" baseUrl: 'http://localhost:3001',"));
326
- console.log(chalk.gray(" // token: 'your-jwt-token',"));
327
- console.log(chalk.gray(" });"));
328
- console.log("");
329
- console.log(chalk.gray(` const { data } = await rebase.collection('${collections[0]?.slug || "my_collection"}').find();`));
330
- console.log("");
331
- }
332
- function findProjectRoot(startDir = process.cwd()) {
333
- let dir = path.resolve(startDir);
334
- const root = path.parse(dir).root;
335
- while (dir !== root) {
336
- const pkgPath = path.join(dir, "package.json");
337
- if (fs.existsSync(pkgPath)) {
338
- try {
339
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
340
- if (pkg.workspaces && Array.isArray(pkg.workspaces)) {
341
- const hasBackend = pkg.workspaces.some(
342
- (w) => w === "backend" || w.includes("backend")
343
- );
344
- if (hasBackend) return dir;
345
- }
346
- } catch {
347
- }
348
- if (fs.existsSync(path.join(dir, "backend")) && fs.existsSync(path.join(dir, "config"))) {
349
- return dir;
350
- }
351
- }
352
- dir = path.dirname(dir);
353
- }
354
- return null;
355
- }
356
- function findBackendDir(projectRoot) {
357
- const backendDir = path.join(projectRoot, "backend");
358
- return fs.existsSync(backendDir) ? backendDir : null;
359
- }
360
- function getActiveBackendPlugin(backendDir) {
361
- const pkgPath = path.join(backendDir, "package.json");
362
- if (!fs.existsSync(pkgPath)) return null;
363
- try {
364
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
365
- const deps = {
366
- ...pkg.dependencies,
367
- ...pkg.devDependencies
368
- };
369
- for (const dep of Object.keys(deps)) {
370
- if (dep.startsWith("@rebasepro/server-") && dep !== "@rebasepro/server-core") {
371
- return dep;
372
- }
373
- }
374
- } catch {
375
- }
376
- return null;
377
- }
378
- function resolvePluginCliScript(backendDir, pluginName) {
379
- const candidates = [
380
- path.join(backendDir, "node_modules", pluginName, "src", "cli.ts"),
381
- path.join(backendDir, "node_modules", pluginName, "dist", "cli.js"),
382
- // For monorepo dev mode:
383
- path.resolve(backendDir, "..", "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts"),
384
- path.resolve(backendDir, "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts")
385
- ];
386
- for (const candidate of candidates) {
387
- if (fs.existsSync(candidate)) return candidate;
388
- }
389
- return null;
390
- }
391
- function findFrontendDir(projectRoot) {
392
- const frontendDir = path.join(projectRoot, "frontend");
393
- return fs.existsSync(frontendDir) ? frontendDir : null;
394
- }
395
- function findEnvFile(projectRoot) {
396
- const candidates = [
397
- path.join(projectRoot, ".env"),
398
- path.join(projectRoot, "backend", ".env")
399
- ];
400
- for (const candidate of candidates) {
401
- if (fs.existsSync(candidate)) return candidate;
402
- }
403
- return null;
404
- }
405
- function resolveLocalBin(projectRoot, binName) {
406
- const candidates = [
407
- path.join(projectRoot, "backend", "node_modules", ".bin", binName),
408
- path.join(projectRoot, "node_modules", ".bin", binName)
409
- ];
410
- let parent = path.dirname(projectRoot);
411
- const rootDir = path.parse(parent).root;
412
- while (parent !== rootDir) {
413
- candidates.push(path.join(parent, "node_modules", ".bin", binName));
414
- parent = path.dirname(parent);
415
- }
416
- for (const candidate of candidates) {
417
- if (fs.existsSync(candidate)) return candidate;
418
- }
419
- try {
420
- const globalPath = child_process.execSync(`which ${binName}`, { encoding: "utf-8" }).trim();
421
- if (globalPath && fs.existsSync(globalPath)) return globalPath;
422
- } catch {
423
- }
424
- return null;
425
- }
426
- function resolveTsx(projectRoot) {
427
- return resolveLocalBin(projectRoot, "tsx");
428
- }
429
- function requireProjectRoot() {
430
- const root = findProjectRoot();
431
- if (!root) {
432
- console.error(chalk.red("✗ Could not find a Rebase project root."));
433
- console.error(chalk.gray(" Make sure you are inside a Rebase project directory"));
434
- console.error(chalk.gray(" (one with backend/, frontend/, and shared/ directories)."));
435
- process.exit(1);
436
- }
437
- return root;
438
- }
439
- function requireBackendDir(projectRoot) {
440
- const backendDir = findBackendDir(projectRoot);
441
- if (!backendDir) {
442
- console.error(chalk.red("✗ Could not find a backend/ directory."));
443
- console.error(chalk.gray(` Expected at: ${path.join(projectRoot, "backend")}`));
444
- process.exit(1);
445
- }
446
- return backendDir;
447
- }
448
- async function schemaCommand(subcommand, rawArgs) {
449
- if (!subcommand || subcommand === "--help") {
450
- printSchemaHelp();
451
- return;
452
- }
453
- const projectRoot = requireProjectRoot();
454
- const backendDir = requireBackendDir(projectRoot);
455
- const activePlugin = getActiveBackendPlugin(backendDir);
456
- if (!activePlugin) {
457
- console.error(chalk.red("✗ Could not detect an active database plugin."));
458
- console.error(chalk.gray(" Make sure a package like @rebasepro/server-postgresql is installed in backend/package.json."));
459
- process.exit(1);
460
- }
461
- const pluginCli = resolvePluginCliScript(backendDir, activePlugin);
462
- if (!pluginCli) {
463
- console.error(chalk.red(`✗ Could not find CLI entry point for ${activePlugin}.`));
464
- process.exit(1);
465
- }
466
- const envFile = findEnvFile(projectRoot);
467
- const env = { ...process.env };
468
- if (envFile) {
469
- env.DOTENV_CONFIG_PATH = envFile;
470
- }
471
- try {
472
- const isTs = pluginCli.endsWith(".ts");
473
- if (isTs) {
474
- const tsxBin = resolveTsx(projectRoot);
475
- if (!tsxBin) {
476
- console.error(chalk.red("✗ Could not find tsx binary."));
477
- process.exit(1);
478
- }
479
- await execa(tsxBin, [pluginCli, ...rawArgs.slice(2)], {
480
- cwd: backendDir,
481
- stdio: "inherit",
482
- env
483
- });
484
- } else {
485
- await execa("node", [pluginCli, ...rawArgs.slice(2)], {
486
- cwd: backendDir,
487
- stdio: "inherit",
488
- env
489
- });
490
- }
491
- } catch (err) {
492
- process.exit(1);
493
- }
494
- }
495
- function printSchemaHelp() {
496
- console.log(`
497
- ${chalk.bold("rebase schema")} — Schema management commands
498
-
499
- ${chalk.green.bold("Usage")}
500
- rebase schema ${chalk.blue("<command>")} [options]
501
-
502
- ${chalk.green.bold("Commands")}
503
- ${chalk.gray("(Commands are provided by your active database driver plugin)")}
504
- ${chalk.blue.bold("generate")} Generate Schema from collection definitions
505
-
506
- ${chalk.green.bold("generate Options")}
507
- ${chalk.blue("--collections, -c")} Path to collections directory
508
- ${chalk.blue("--output, -o")} Output path for generated schema
509
- ${chalk.blue("--watch, -w")} Watch for changes and regenerate automatically
510
- `);
511
- }
512
- async function dbCommand(subcommand, rawArgs) {
513
- if (!subcommand || subcommand === "--help") {
514
- printDbHelp();
515
- return;
516
- }
517
- const projectRoot = requireProjectRoot();
518
- const backendDir = requireBackendDir(projectRoot);
519
- const activePlugin = getActiveBackendPlugin(backendDir);
520
- if (!activePlugin) {
521
- console.error(chalk.red("✗ Could not detect an active database plugin."));
522
- console.error(chalk.gray(" Make sure a package like @rebasepro/server-postgresql is installed in backend/package.json."));
523
- process.exit(1);
524
- }
525
- const pluginCli = resolvePluginCliScript(backendDir, activePlugin);
526
- if (!pluginCli) {
527
- console.error(chalk.red(`✗ Could not find CLI entry point for ${activePlugin}.`));
528
- process.exit(1);
529
- }
530
- const envFile = findEnvFile(projectRoot);
531
- const env = { ...process.env };
532
- if (envFile) {
533
- env.DOTENV_CONFIG_PATH = envFile;
534
- }
535
- try {
536
- const isTs = pluginCli.endsWith(".ts");
537
- if (isTs) {
538
- const tsxBin = resolveTsx(projectRoot);
539
- if (!tsxBin) {
540
- console.error(chalk.red("✗ Could not find tsx binary."));
541
- process.exit(1);
542
- }
543
- await execa(tsxBin, [pluginCli, ...rawArgs.slice(2)], {
544
- cwd: backendDir,
545
- stdio: "inherit",
546
- env
547
- });
548
- } else {
549
- await execa("node", [pluginCli, ...rawArgs.slice(2)], {
550
- cwd: backendDir,
551
- stdio: "inherit",
552
- env
553
- });
554
- }
555
- } catch (err) {
556
- process.exit(1);
557
- }
558
- }
559
- function printDbHelp() {
560
- console.log(`
561
- ${chalk.bold("rebase db")} — Database management commands
562
-
563
- ${chalk.green.bold("Usage")}
564
- rebase db ${chalk.blue("<command>")} [options]
565
-
566
- ${chalk.green.bold("Commands")}
567
- ${chalk.gray("(Commands are provided by your active database driver plugin)")}
568
- ${chalk.blue.bold("push")} Apply schema directly to database (development)
569
- ${chalk.blue.bold("pull")} Introspect database → Schema
570
- ${chalk.blue.bold("generate")} Generate migration files
571
- ${chalk.blue.bold("migrate")} Run pending migrations
572
- ${chalk.blue.bold("studio")} Open Studio viewer
573
- ${chalk.blue.bold("branch")} Database branching (create, list, delete, info)
574
-
575
- ${chalk.green.bold("Examples")}
576
- ${chalk.gray("# Quick development workflow")}
577
- rebase schema generate && rebase db push
578
-
579
- ${chalk.gray("# Production migration workflow")}
580
- rebase db generate
581
- rebase db migrate
582
-
583
- ${chalk.gray("# Create a database branch")}
584
- rebase db branch create feature_auth
585
- `);
586
- }
587
- const DEV_PORT_FILENAME = ".rebase-dev-port";
588
- function getProjectPort(projectRoot) {
589
- let hash = 0;
590
- for (let i = 0; i < projectRoot.length; i++) {
591
- hash = (hash << 5) - hash + projectRoot.charCodeAt(i) | 0;
592
- }
593
- return 3001 + Math.abs(hash) % 999;
594
- }
595
- function resolveStartPort(projectRoot, explicitPort) {
596
- if (explicitPort) return explicitPort;
597
- if (process.env.PORT) return parseInt(process.env.PORT, 10);
598
- try {
599
- const portFile = path.join(projectRoot, DEV_PORT_FILENAME);
600
- if (fs.existsSync(portFile)) {
601
- const saved = parseInt(fs.readFileSync(portFile, "utf-8").trim(), 10);
602
- if (saved > 0 && saved < 65536) return saved;
603
- }
604
- } catch {
605
- }
606
- return getProjectPort(projectRoot);
607
- }
608
- async function devCommand(rawArgs) {
609
- const args = arg(
610
- {
611
- "--backend-only": Boolean,
612
- "--frontend-only": Boolean,
613
- "--port": Number,
614
- "--help": Boolean,
615
- "-b": "--backend-only",
616
- "-f": "--frontend-only",
617
- "-p": "--port",
618
- "-h": "--help"
619
- },
620
- {
621
- argv: rawArgs.slice(3),
622
- // skip "node rebase dev"
623
- permissive: true
624
- }
625
- );
626
- if (args["--help"]) {
627
- printDevHelp();
628
- return;
629
- }
630
- const projectRoot = requireProjectRoot();
631
- const backendDir = findBackendDir(projectRoot);
632
- const frontendDir = findFrontendDir(projectRoot);
633
- const backendOnly = args["--backend-only"] || false;
634
- const frontendOnly = args["--frontend-only"] || false;
635
- const startPort = resolveStartPort(projectRoot, args["--port"]);
636
- console.log("");
637
- console.log(chalk.bold(" 🚀 Rebase Dev Server"));
638
- console.log("");
639
- const children = [];
640
- let frontendUrl = "";
641
- let backendUrl = "";
642
- let debounceSummary = null;
643
- let bannerPrinted = false;
644
- let resolvedBackendPort = null;
645
- const stripAnsi = (str) => str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
646
- function printSummary() {
647
- if (!frontendUrl || !backendUrl) return;
648
- if (debounceSummary) clearTimeout(debounceSummary);
649
- debounceSummary = setTimeout(() => {
650
- if (bannerPrinted) return;
651
- console.log("");
652
- console.log(chalk.cyan("┌────────────────────────────────────────────────────────────┐"));
653
- console.log(chalk.cyan("│ │"));
654
- console.log(chalk.cyan("│ ✨ Rebase Admin App is ready! │"));
655
- const cleanUrl = stripAnsi(frontendUrl);
656
- const paddedUrl = cleanUrl.padEnd(40);
657
- console.log(chalk.cyan("│ 👉 Frontend URL: ") + chalk.white(paddedUrl) + chalk.cyan("│"));
658
- console.log(chalk.cyan("│ │"));
659
- console.log(chalk.cyan("└────────────────────────────────────────────────────────────┘"));
660
- console.log("");
661
- bannerPrinted = true;
662
- }, 500);
663
- }
664
- const cleanup = () => {
665
- try {
666
- const portFile = path.join(projectRoot, DEV_PORT_FILENAME);
667
- if (fs.existsSync(portFile)) fs.unlinkSync(portFile);
668
- const urlFile = path.join(projectRoot, ".rebase-dev-url");
669
- if (fs.existsSync(urlFile)) fs.unlinkSync(urlFile);
670
- } catch {
671
- }
672
- children.forEach((child) => {
673
- if (child.pid && !child.killed) {
674
- try {
675
- if (process.platform === "win32") {
676
- execa.commandSync(`taskkill /pid ${child.pid} /T /F`);
677
- } else {
678
- process.kill(-child.pid, "SIGKILL");
679
- }
680
- } catch (e) {
681
- try {
682
- child.kill("SIGKILL");
683
- } catch (err) {
684
- }
685
- }
686
- }
687
- });
688
- process.exit(0);
689
- };
690
- process.on("SIGINT", cleanup);
691
- process.on("SIGTERM", cleanup);
692
- function startFrontend(backendPort) {
693
- if (!frontendDir) return;
694
- console.log(` ${chalk.magenta("▶")} Frontend: ${chalk.gray(frontendDir)}`);
695
- const frontendEnv = { ...process.env };
696
- if (backendPort) {
697
- frontendEnv.VITE_API_URL = `http://localhost:${backendPort}`;
698
- console.log(` ${chalk.gray("↳ VITE_API_URL")} = ${chalk.white(`http://localhost:${backendPort}`)}`);
699
- }
700
- const frontendChild = execa(
701
- "pnpm",
702
- ["run", "dev"],
703
- {
704
- cwd: frontendDir,
705
- stdio: ["inherit", "pipe", "pipe"],
706
- env: frontendEnv,
707
- shell: true,
708
- detached: process.platform !== "win32"
709
- }
710
- );
711
- frontendChild.catch(() => {
712
- });
713
- frontendChild.stdout?.on("data", (data) => {
714
- const lines = data.toString().split("\n").filter(Boolean);
715
- lines.forEach((line) => {
716
- console.log(`${chalk.magenta.bold("[admin]")} ${line}`);
717
- const cleanLine = stripAnsi(line);
718
- const urlMatch = cleanLine.match(/(http:\/\/(?:localhost|127\.0\.0\.1):\d+)/);
719
- if (cleanLine.includes("Local:") && urlMatch) {
720
- frontendUrl = urlMatch[1];
721
- printSummary();
722
- }
723
- });
724
- });
725
- frontendChild.stderr?.on("data", (data) => {
726
- const lines = data.toString().split("\n").filter(Boolean);
727
- lines.forEach((line) => {
728
- console.log(`${chalk.magenta.bold("[admin]")} ${line}`);
729
- });
730
- });
731
- children.push(frontendChild);
732
- }
733
- if (!frontendOnly && backendDir) {
734
- const tsxBin = resolveTsx(projectRoot);
735
- if (!tsxBin) {
736
- console.error(chalk.red(" ✗ Could not find tsx binary for backend."));
737
- console.error(chalk.gray(" Install it with: pnpm add -D tsx"));
738
- process.exit(1);
739
- }
740
- const envFile = findEnvFile(projectRoot);
741
- const env = { ...process.env };
742
- if (envFile) {
743
- env.DOTENV_CONFIG_PATH = envFile;
744
- }
745
- env.PORT = String(startPort);
746
- console.log(` ${chalk.cyan("▶")} Backend: ${chalk.gray(backendDir)}`);
747
- console.log(` ${chalk.gray("↳ PORT")} = ${chalk.white(String(startPort))}`);
748
- let frontendLaunched = false;
749
- const backendChild = execa(
750
- tsxBin,
751
- ["watch", `--watch="${path.join("..", "config", "**", "*")}"`, "--conditions", "development", "src/index.ts"],
752
- {
753
- cwd: backendDir,
754
- stdio: ["inherit", "pipe", "pipe"],
755
- env,
756
- shell: true,
757
- detached: process.platform !== "win32"
758
- }
759
- );
760
- backendChild.catch(() => {
761
- });
762
- backendChild.stdout?.on("data", (data) => {
763
- const lines = data.toString().split("\n").filter(Boolean);
764
- lines.forEach((line) => {
765
- console.log(`${chalk.cyan.bold("[backend]")} ${line}`);
766
- const cleanLine = stripAnsi(line);
767
- const serverMatch = cleanLine.match(/Server running at http:\/\/(?:localhost|127\.0\.0\.1):(\d+)/);
768
- if (serverMatch) {
769
- resolvedBackendPort = parseInt(serverMatch[1], 10);
770
- backendUrl = "started";
771
- printSummary();
772
- const urlFile = path.join(projectRoot, ".rebase-dev-url");
773
- fs.writeFileSync(urlFile, `http://localhost:${resolvedBackendPort}`, "utf-8");
774
- const portFile = path.join(projectRoot, DEV_PORT_FILENAME);
775
- fs.writeFileSync(portFile, String(resolvedBackendPort), "utf-8");
776
- if (!backendOnly && frontendDir && !frontendLaunched) {
777
- frontendLaunched = true;
778
- startFrontend(resolvedBackendPort);
779
- }
780
- }
781
- });
782
- });
783
- backendChild.stderr?.on("data", (data) => {
784
- const lines = data.toString().split("\n").filter(Boolean);
785
- lines.forEach((line) => {
786
- console.log(`${chalk.cyan.bold("[backend]")} ${line}`);
787
- });
788
- });
789
- children.push(backendChild);
790
- } else if (!frontendOnly && !backendDir) {
791
- console.warn(chalk.yellow(" ⚠ No backend/ directory found, skipping backend."));
792
- }
793
- if (!backendOnly && frontendDir && (frontendOnly || !backendDir)) {
794
- startFrontend(null);
795
- } else if (!backendOnly && !frontendDir) {
796
- console.warn(chalk.yellow(" ⚠ No frontend/ directory found, skipping frontend."));
797
- }
798
- if (children.length === 0) {
799
- console.error(chalk.red(" ✗ Nothing to start. Check your project structure."));
800
- process.exit(1);
801
- }
802
- console.log("");
803
- console.log(chalk.gray(" Press Ctrl+C to stop all servers."));
804
- console.log("");
805
- await Promise.all(
806
- children.map(
807
- (child) => new Promise((resolve) => {
808
- child.finally(() => resolve());
809
- })
810
- )
811
- );
812
- }
813
- function printDevHelp() {
814
- console.log(`
815
- ${chalk.bold("rebase dev")} — Start the development server
816
-
817
- ${chalk.green.bold("Usage")}
818
- rebase dev [options]
819
-
820
- ${chalk.green.bold("Options")}
821
- ${chalk.blue("--backend-only, -b")} Only start the backend server
822
- ${chalk.blue("--frontend-only, -f")} Only start the frontend server
823
- ${chalk.blue("--port, -p")} Backend port (default: auto-detected per project)
824
-
825
- ${chalk.green.bold("Description")}
826
- Starts both the backend (tsx watch + Hono) and frontend (Vite)
827
- dev servers concurrently with color-coded output prefixes.
828
-
829
- Each project automatically receives a unique default port derived
830
- from its directory path, preventing collisions when running multiple
831
- Rebase instances simultaneously.
832
-
833
- If the assigned port is already in use, the server will automatically
834
- try the next available port. The frontend is started only after the
835
- backend is ready, and VITE_API_URL is injected automatically.
836
- `);
837
- }
838
- async function authCommand(subcommand, rawArgs) {
839
- if (!subcommand || subcommand === "--help") {
840
- printAuthHelp();
841
- return;
842
- }
843
- switch (subcommand) {
844
- case "reset-password":
845
- await resetPassword(rawArgs);
846
- break;
847
- default:
848
- console.error(chalk.red(`Unknown auth command: ${subcommand}`));
849
- console.log("");
850
- printAuthHelp();
851
- process.exit(1);
852
- }
853
- }
854
- async function resetPassword(rawArgs) {
855
- const args = arg(
856
- {
857
- "--email": String,
858
- "--password": String,
859
- "-e": "--email",
860
- "-p": "--password"
861
- },
862
- {
863
- argv: rawArgs.slice(4),
864
- // skip "node rebase auth reset-password"
865
- permissive: true
866
- }
867
- );
868
- const email = args["--email"] || args._[0];
869
- const newPassword = args["--password"] || args._[1];
870
- if (!email) {
871
- console.error(chalk.red("✗ Email is required."));
872
- console.log("");
873
- console.log(chalk.gray(" Usage: rebase auth reset-password <email> [new-password]"));
874
- console.log(chalk.gray(" rebase auth reset-password --email user@example.com --password NewPass123!"));
875
- process.exit(1);
876
- }
877
- const projectRoot = requireProjectRoot();
878
- const backendDir = requireBackendDir(projectRoot);
879
- const tsxBin = resolveTsx(projectRoot);
880
- if (!tsxBin) {
881
- console.error(chalk.red("✗ Could not find tsx binary."));
882
- process.exit(1);
883
- }
884
- const envFile = findEnvFile(projectRoot);
885
- const env = { ...process.env };
886
- if (envFile) {
887
- env.DOTENV_CONFIG_PATH = envFile;
888
- }
889
- const scriptContent = `
890
- import { createPostgresDatabaseConnection } from "@rebasepro/server-core";
891
- import { hashPassword } from "@rebasepro/server-core/src/auth/password";
892
- import { eq } from "drizzle-orm";
893
- import { users } from "@rebasepro/server-core/src/db/auth-schema";
894
- import * as dotenv from "dotenv";
895
- import path from "path";
896
-
897
- dotenv.config({ path: "${envFile || path.join(projectRoot, ".env")}" });
898
-
899
- const email = "${email}";
900
- const newPassword = "${newPassword || "NewPassword123!"}";
901
-
902
- async function resetPassword() {
903
- const { db } = createPostgresDatabaseConnection(process.env.DATABASE_URL!);
904
- const hash = await hashPassword(newPassword);
905
-
906
- const result = await db.update(users)
907
- .set({ passwordHash: hash })
908
- .where(eq(users.email, email))
909
- .returning({
910
- id: users.id,
911
- email: users.email
912
- });
913
-
914
- if (result.length > 0) {
915
- console.log("✅ Password reset for: " + result[0].email);
916
- ${!newPassword ? 'console.log(" New password: " + newPassword);' : ""}
917
- } else {
918
- console.log("✗ User not found: " + email);
919
- }
920
- process.exit(0);
921
- }
922
-
923
- resetPassword().catch(console.error);
924
- `;
925
- const tmpScriptPath = path.join(backendDir, ".tmp-reset-password.ts");
926
- fs.writeFileSync(tmpScriptPath, scriptContent, "utf-8");
927
- console.log("");
928
- console.log(chalk.bold(" 🔑 Rebase Auth — Reset Password"));
929
- console.log("");
930
- console.log(` ${chalk.gray("Email:")} ${email}`);
931
- if (newPassword) {
932
- console.log(` ${chalk.gray("Password:")} ${"*".repeat(newPassword.length)}`);
933
- }
934
- console.log("");
935
- const child = child_process.spawn(tsxBin, [tmpScriptPath], {
936
- cwd: backendDir,
937
- stdio: "inherit",
938
- env
939
- });
940
- return new Promise((resolve) => {
941
- child.on("close", (code) => {
942
- try {
943
- fs.unlinkSync(tmpScriptPath);
944
- } catch {
945
- }
946
- if (code !== 0) {
947
- process.exit(code ?? 1);
948
- }
949
- resolve();
950
- });
951
- });
952
- }
953
- function printAuthHelp() {
954
- console.log(`
955
- ${chalk.bold("rebase auth")} — Authentication management commands
956
-
957
- ${chalk.green.bold("Usage")}
958
- rebase auth ${chalk.blue("<command>")} [options]
959
-
960
- ${chalk.green.bold("Commands")}
961
- ${chalk.blue.bold("reset-password")} Reset a user's password
962
-
963
- ${chalk.green.bold("reset-password Options")}
964
- ${chalk.blue("--email, -e")} User's email address
965
- ${chalk.blue("--password, -p")} New password (default: NewPassword123!)
966
-
967
- ${chalk.green.bold("Examples")}
968
- rebase auth reset-password user@example.com
969
- rebase auth reset-password --email user@example.com --password MyNewPass!
970
- `);
971
- }
972
- async function doctorCommand(rawArgs) {
973
- const projectRoot = requireProjectRoot();
974
- const backendDir = requireBackendDir(projectRoot);
975
- const activePlugin = getActiveBackendPlugin(backendDir);
976
- if (!activePlugin) {
977
- console.error(chalk.red("✗ Could not detect an active database plugin."));
978
- console.error(chalk.gray(" Make sure a package like @rebasepro/server-postgresql is installed in backend/package.json."));
979
- process.exit(1);
980
- }
981
- const pluginCli = resolvePluginCliScript(backendDir, activePlugin);
982
- if (!pluginCli) {
983
- console.error(chalk.red(`✗ Could not find CLI entry point for ${activePlugin}.`));
984
- process.exit(1);
985
- }
986
- const envFile = findEnvFile(projectRoot);
987
- const env = { ...process.env };
988
- if (envFile) {
989
- env.DOTENV_CONFIG_PATH = envFile;
990
- }
991
- try {
992
- const isTs = pluginCli.endsWith(".ts");
993
- if (isTs) {
994
- const tsxBin = resolveTsx(projectRoot);
995
- if (!tsxBin) {
996
- console.error(chalk.red("✗ Could not find tsx binary."));
997
- process.exit(1);
998
- }
999
- await execa(tsxBin, [pluginCli, ...rawArgs.slice(2)], {
1000
- cwd: backendDir,
1001
- stdio: "inherit",
1002
- env
1003
- });
1004
- } else {
1005
- await execa("node", [pluginCli, ...rawArgs.slice(2)], {
1006
- cwd: backendDir,
1007
- stdio: "inherit",
1008
- env
1009
- });
1010
- }
1011
- } catch {
1012
- process.exit(1);
1013
- }
1014
- }
1015
- const __filename$1 = url.fileURLToPath(typeof document === "undefined" && typeof location === "undefined" ? require("url").pathToFileURL(__filename).href : typeof document === "undefined" ? location.href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index.cjs", document.baseURI).href);
1016
- const __dirname$1 = path.dirname(__filename$1);
1017
- function getVersion() {
1018
- try {
1019
- const pkgPath = path.resolve(__dirname$1, "../package.json");
1020
- if (fs.existsSync(pkgPath)) {
1021
- return JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version;
1022
- }
1023
- } catch {
1024
- }
1025
- return "unknown";
1026
- }
1027
- async function entry(args) {
1028
- const parsedArgs = arg(
1029
- {
1030
- "--version": Boolean,
1031
- "--help": Boolean,
1032
- "-v": "--version",
1033
- "-h": "--help"
1034
- },
1035
- {
1036
- argv: args.slice(2),
1037
- permissive: true
1038
- }
1039
- );
1040
- if (parsedArgs["--version"]) {
1041
- console.log(getVersion());
1042
- return;
1043
- }
1044
- const command = parsedArgs._[0];
1045
- const subcommand = parsedArgs._[1];
1046
- const namespacedCommands = ["schema", "db", "dev", "auth", "doctor"];
1047
- if (!command || parsedArgs["--help"] && !namespacedCommands.includes(command)) {
1048
- printHelp();
1049
- return;
1050
- }
1051
- const effectiveSubcommand = parsedArgs["--help"] ? "--help" : subcommand;
1052
- switch (command) {
1053
- case "init":
1054
- await createRebaseApp(args);
1055
- break;
1056
- case "generate-sdk": {
1057
- const sdkArgs = arg(
1058
- {
1059
- "--collections-dir": String,
1060
- "--output": String,
1061
- "-c": "--collections-dir",
1062
- "-o": "--output"
1063
- },
1064
- {
1065
- argv: args.slice(3),
1066
- permissive: true
1067
- }
1068
- );
1069
- await generateSdkCommand({
1070
- collectionsDir: sdkArgs["--collections-dir"] || "./config/collections",
1071
- output: sdkArgs["--output"] || "./generated/sdk",
1072
- cwd: process.cwd()
1073
- });
1074
- break;
1075
- }
1076
- case "schema":
1077
- await schemaCommand(effectiveSubcommand, args);
1078
- break;
1079
- case "db":
1080
- await dbCommand(effectiveSubcommand, args);
1081
- break;
1082
- case "dev":
1083
- await devCommand(args);
1084
- break;
1085
- case "auth":
1086
- await authCommand(effectiveSubcommand, args);
1087
- break;
1088
- case "doctor":
1089
- await doctorCommand(args);
1090
- break;
1091
- default:
1092
- console.log(chalk.red(`Unknown command: ${command}`));
1093
- console.log("");
1094
- printHelp();
1095
- }
1096
- }
1097
- function printHelp() {
1098
- console.log(`
1099
- ${chalk.bold("Rebase CLI")} — Developer tools for Rebase projects
1100
-
1101
- ${chalk.green.bold("Usage")}
1102
- rebase ${chalk.blue("<command>")} [options]
1103
-
1104
- ${chalk.green.bold("Commands")}
1105
- ${chalk.blue.bold("init")} Create a new Rebase project
1106
- ${chalk.blue.bold("dev")} Start the development server
1107
-
1108
- ${chalk.green.bold("Schema")}
1109
- ${chalk.blue.bold("schema generate")} Generate Drizzle schema from collections
1110
- ${chalk.blue.bold("schema")} ${chalk.gray("--help")} Show schema command help
1111
-
1112
- ${chalk.green.bold("Database")}
1113
- ${chalk.blue.bold("db push")} Apply schema directly to database ${chalk.gray("(dev)")}
1114
- ${chalk.blue.bold("db pull")} Introspect database → Drizzle schema
1115
- ${chalk.blue.bold("db generate")} Generate SQL migration files
1116
- ${chalk.blue.bold("db migrate")} Run pending migrations
1117
- ${chalk.blue.bold("db studio")} Open Drizzle Studio
1118
- ${chalk.blue.bold("db")} ${chalk.gray("--help")} Show database command help
1119
-
1120
- ${chalk.green.bold("SDK")}
1121
- ${chalk.blue.bold("generate-sdk")} Generate a typed JS SDK from collections
1122
-
1123
- ${chalk.green.bold("Auth")}
1124
- ${chalk.blue.bold("auth reset-password")} Reset a user's password
1125
- ${chalk.blue.bold("auth")} ${chalk.gray("--help")} Show auth command help
1126
-
1127
- ${chalk.green.bold("Diagnostics")}
1128
- ${chalk.blue.bold("doctor")} Detect schema drift between collections, schema, and DB
1129
-
1130
- ${chalk.green.bold("Options")}
1131
- ${chalk.blue("--version, -v")} Show version number
1132
- ${chalk.blue("--help, -h")} Show this help message
1133
-
1134
- ${chalk.gray("Documentation: https://rebase.pro/docs")}
1135
- `);
1136
- }
1137
- const TOKEN_DIR = path.join(os__namespace.homedir(), ".rebase");
1138
- function tokenPath(env) {
1139
- return path.join(TOKEN_DIR, (env === "dev" ? "staging." : "") + "tokens.json");
1140
- }
1141
- async function getTokens(env, _debug) {
1142
- const fp = tokenPath(env);
1143
- if (!fs.existsSync(fp)) return null;
1144
- try {
1145
- const data = fs.readFileSync(fp, "utf-8");
1146
- return JSON.parse(data);
1147
- } catch {
1148
- return null;
1149
- }
1150
- }
1151
- function parseJwt(token) {
1152
- if (!token) throw new Error("No JWT token");
1153
- const base64Url = token.split(".")[1];
1154
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
1155
- const buffer = Buffer.from(base64, "base64");
1156
- return JSON.parse(buffer.toString());
1157
- }
1158
- async function refreshCredentials(env, credentials, _onErr) {
1159
- if (!credentials) return null;
1160
- const expiryDate = new Date(credentials["expiry_date"]);
1161
- if (expiryDate.getTime() > Date.now()) {
1162
- return credentials;
1163
- }
1164
- return null;
1165
- }
1166
- async function login(env, _debug) {
1167
- console.log(
1168
- "Interactive login is not yet implemented in @rebasepro/cli.\nPlease authenticate via the Rebase dashboard and copy your tokens to " + tokenPath(env)
1169
- );
1170
- }
1171
- async function logout(env, _debug) {
1172
- const fp = tokenPath(env);
1173
- if (fs.existsSync(fp)) {
1174
- fs.unlinkSync(fp);
1175
- console.log("You have been logged out.");
1176
- } else {
1177
- console.log("You are not logged in.");
1178
- }
1179
- }
1180
- exports2.authCommand = authCommand;
1181
- exports2.createRebaseApp = createRebaseApp;
1182
- exports2.dbCommand = dbCommand;
1183
- exports2.devCommand = devCommand;
1184
- exports2.entry = entry;
1185
- exports2.findBackendDir = findBackendDir;
1186
- exports2.findEnvFile = findEnvFile;
1187
- exports2.findFrontendDir = findFrontendDir;
1188
- exports2.findProjectRoot = findProjectRoot;
1189
- exports2.getActiveBackendPlugin = getActiveBackendPlugin;
1190
- exports2.getTokens = getTokens;
1191
- exports2.login = login;
1192
- exports2.logout = logout;
1193
- exports2.parseJwt = parseJwt;
1194
- exports2.refreshCredentials = refreshCredentials;
1195
- exports2.requireBackendDir = requireBackendDir;
1196
- exports2.requireProjectRoot = requireProjectRoot;
1197
- exports2.resolveLocalBin = resolveLocalBin;
1198
- exports2.resolvePluginCliScript = resolvePluginCliScript;
1199
- exports2.resolveTsx = resolveTsx;
1200
- exports2.schemaCommand = schemaCommand;
1201
- Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
1202
- }));
1203
- //# sourceMappingURL=index.cjs.map