@rebasepro/cli 0.0.1-canary.1 → 0.0.1-canary.4d4fb3e
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/commands/auth.d.ts +1 -0
- package/dist/commands/db.d.ts +1 -0
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/generate_sdk.d.ts +18 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/schema.d.ts +1 -0
- package/dist/index.cjs +828 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.es.js +830 -20
- package/dist/index.es.js.map +1 -1
- package/dist/utils/project.d.ts +45 -0
- package/package.json +65 -57
- package/templates/template/.dockerignore +28 -0
- package/templates/template/.env.template +21 -11
- package/templates/template/README.md +73 -16
- package/templates/template/backend/Dockerfile +54 -9
- package/templates/template/backend/functions/hello.ts +34 -0
- package/templates/template/backend/package.json +30 -34
- package/templates/template/backend/src/index.ts +48 -86
- package/templates/template/docker-compose.yml +65 -16
- package/templates/template/frontend/Dockerfile +35 -13
- package/templates/template/frontend/nginx.conf +40 -0
- package/templates/template/frontend/package.json +9 -10
- package/templates/template/frontend/src/App.tsx +18 -24
- package/templates/template/frontend/src/index.css +15 -1
- package/templates/template/package.json +11 -16
- package/templates/template/pnpm-workspace.yaml +4 -0
- package/templates/template/shared/collections/posts.ts +1 -1
- package/templates/template/shared/package.json +25 -25
- package/templates/template/backend/scripts/db-generate.ts +0 -60
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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("util"), require("execa"), require("ncp"), require("url"), require("os")) : typeof define === "function" && define.amd ? define(["exports", "chalk", "arg", "inquirer", "path", "fs", "util", "execa", "ncp", "url", "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.os));
|
|
3
|
-
})(this, (function(exports2, chalk, arg, inquirer, path, fs, util, execa, ncp, url, os) {
|
|
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
4
|
"use strict";
|
|
5
5
|
var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
|
|
6
6
|
function _interopNamespaceDefault(e) {
|
|
@@ -46,7 +46,9 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
|
|
|
46
46
|
const args = arg(
|
|
47
47
|
{
|
|
48
48
|
"--git": Boolean,
|
|
49
|
-
"
|
|
49
|
+
"--install": Boolean,
|
|
50
|
+
"-g": "--git",
|
|
51
|
+
"-i": "--install"
|
|
50
52
|
},
|
|
51
53
|
{
|
|
52
54
|
argv: rawArgs.slice(3),
|
|
@@ -79,6 +81,14 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
|
|
|
79
81
|
default: true
|
|
80
82
|
});
|
|
81
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
|
+
}
|
|
82
92
|
const answers = await inquirer.prompt(questions);
|
|
83
93
|
const projectName = nameArg || answers.projectName;
|
|
84
94
|
const targetDirectory = path.resolve(process.cwd(), projectName);
|
|
@@ -86,6 +96,7 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
|
|
|
86
96
|
return {
|
|
87
97
|
projectName,
|
|
88
98
|
git: args["--git"] || answers.git || false,
|
|
99
|
+
installDeps: args["--install"] || answers.installDeps || false,
|
|
89
100
|
targetDirectory,
|
|
90
101
|
templateDirectory
|
|
91
102
|
};
|
|
@@ -106,19 +117,40 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
|
|
|
106
117
|
process.exit(1);
|
|
107
118
|
}
|
|
108
119
|
console.log(chalk.gray(" Copying project files..."));
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
+
}
|
|
117
133
|
await replacePlaceholders(options);
|
|
118
134
|
const envTemplatePath = path.join(options.targetDirectory, ".env.template");
|
|
119
135
|
const envPath = path.join(options.targetDirectory, ".env");
|
|
120
136
|
if (fs.existsSync(envTemplatePath) && !fs.existsSync(envPath)) {
|
|
121
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");
|
|
122
154
|
}
|
|
123
155
|
if (options.git) {
|
|
124
156
|
console.log(chalk.gray(" Initializing git repository..."));
|
|
@@ -128,13 +160,28 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
|
|
|
128
160
|
console.warn(chalk.yellow(" Warning: Failed to initialize git repository"));
|
|
129
161
|
}
|
|
130
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
|
+
}
|
|
131
176
|
console.log("");
|
|
132
177
|
console.log(`${chalk.green.bold("✓")} Project ${chalk.bold(options.projectName)} created successfully!`);
|
|
133
178
|
console.log("");
|
|
134
179
|
console.log(chalk.bold("Next steps:"));
|
|
135
180
|
console.log("");
|
|
136
181
|
console.log(` ${chalk.cyan("cd")} ${options.projectName}`);
|
|
137
|
-
|
|
182
|
+
if (!options.installDeps) {
|
|
183
|
+
console.log(` ${chalk.cyan("pnpm install")}`);
|
|
184
|
+
}
|
|
138
185
|
console.log("");
|
|
139
186
|
console.log(chalk.gray(" # Set up your database connection in .env"));
|
|
140
187
|
console.log(chalk.gray(" # Then run:"));
|
|
@@ -144,7 +191,7 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
|
|
|
144
191
|
console.log(chalk.gray("This starts both the backend (Express + PostgreSQL)") + chalk.gray(" and the frontend (Vite + React) concurrently."));
|
|
145
192
|
console.log("");
|
|
146
193
|
console.log(chalk.gray("Docs: https://rebase.pro/docs"));
|
|
147
|
-
console.log(chalk.gray("GitHub: https://github.com/
|
|
194
|
+
console.log(chalk.gray("GitHub: https://github.com/rebasepro/rebase"));
|
|
148
195
|
console.log("");
|
|
149
196
|
}
|
|
150
197
|
async function replacePlaceholders(options) {
|
|
@@ -163,6 +210,696 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
|
|
|
163
210
|
fs.writeFileSync(fullPath, content, "utf-8");
|
|
164
211
|
}
|
|
165
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, "shared"))) {
|
|
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 = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
366
|
+
for (const dep of Object.keys(deps)) {
|
|
367
|
+
if (dep.startsWith("@rebasepro/server-") && dep !== "@rebasepro/server-core") {
|
|
368
|
+
return dep;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
} catch {
|
|
372
|
+
}
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
function resolvePluginCliScript(backendDir, pluginName) {
|
|
376
|
+
const candidates = [
|
|
377
|
+
path.join(backendDir, "node_modules", pluginName, "src", "cli.ts"),
|
|
378
|
+
path.join(backendDir, "node_modules", pluginName, "dist", "cli.js"),
|
|
379
|
+
// For monorepo dev mode:
|
|
380
|
+
path.resolve(backendDir, "..", "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts"),
|
|
381
|
+
path.resolve(backendDir, "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts")
|
|
382
|
+
];
|
|
383
|
+
for (const candidate of candidates) {
|
|
384
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
385
|
+
}
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
function findFrontendDir(projectRoot) {
|
|
389
|
+
const frontendDir = path.join(projectRoot, "frontend");
|
|
390
|
+
return fs.existsSync(frontendDir) ? frontendDir : null;
|
|
391
|
+
}
|
|
392
|
+
function findEnvFile(projectRoot) {
|
|
393
|
+
const candidates = [
|
|
394
|
+
path.join(projectRoot, ".env"),
|
|
395
|
+
path.join(projectRoot, "backend", ".env")
|
|
396
|
+
];
|
|
397
|
+
for (const candidate of candidates) {
|
|
398
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
399
|
+
}
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
function resolveLocalBin(projectRoot, binName) {
|
|
403
|
+
const candidates = [
|
|
404
|
+
path.join(projectRoot, "backend", "node_modules", ".bin", binName),
|
|
405
|
+
path.join(projectRoot, "node_modules", ".bin", binName)
|
|
406
|
+
];
|
|
407
|
+
let parent = path.dirname(projectRoot);
|
|
408
|
+
const rootDir = path.parse(parent).root;
|
|
409
|
+
while (parent !== rootDir) {
|
|
410
|
+
candidates.push(path.join(parent, "node_modules", ".bin", binName));
|
|
411
|
+
parent = path.dirname(parent);
|
|
412
|
+
}
|
|
413
|
+
for (const candidate of candidates) {
|
|
414
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
const globalPath = child_process.execSync(`which ${binName}`, { encoding: "utf-8" }).trim();
|
|
418
|
+
if (globalPath && fs.existsSync(globalPath)) return globalPath;
|
|
419
|
+
} catch {
|
|
420
|
+
}
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
function resolveTsx(projectRoot) {
|
|
424
|
+
return resolveLocalBin(projectRoot, "tsx");
|
|
425
|
+
}
|
|
426
|
+
function requireProjectRoot() {
|
|
427
|
+
const root = findProjectRoot();
|
|
428
|
+
if (!root) {
|
|
429
|
+
console.error(chalk.red("✗ Could not find a Rebase project root."));
|
|
430
|
+
console.error(chalk.gray(" Make sure you are inside a Rebase project directory"));
|
|
431
|
+
console.error(chalk.gray(" (one with backend/, frontend/, and shared/ directories)."));
|
|
432
|
+
process.exit(1);
|
|
433
|
+
}
|
|
434
|
+
return root;
|
|
435
|
+
}
|
|
436
|
+
function requireBackendDir(projectRoot) {
|
|
437
|
+
const backendDir = findBackendDir(projectRoot);
|
|
438
|
+
if (!backendDir) {
|
|
439
|
+
console.error(chalk.red("✗ Could not find a backend/ directory."));
|
|
440
|
+
console.error(chalk.gray(` Expected at: ${path.join(projectRoot, "backend")}`));
|
|
441
|
+
process.exit(1);
|
|
442
|
+
}
|
|
443
|
+
return backendDir;
|
|
444
|
+
}
|
|
445
|
+
async function schemaCommand(subcommand, rawArgs) {
|
|
446
|
+
if (!subcommand || subcommand === "--help") {
|
|
447
|
+
printSchemaHelp();
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
const projectRoot = requireProjectRoot();
|
|
451
|
+
const backendDir = requireBackendDir(projectRoot);
|
|
452
|
+
const activePlugin = getActiveBackendPlugin(backendDir);
|
|
453
|
+
if (!activePlugin) {
|
|
454
|
+
console.error(chalk.red("✗ Could not detect an active database plugin."));
|
|
455
|
+
console.error(chalk.gray(" Make sure a package like @rebasepro/server-postgresql is installed in backend/package.json."));
|
|
456
|
+
process.exit(1);
|
|
457
|
+
}
|
|
458
|
+
const pluginCli = resolvePluginCliScript(backendDir, activePlugin);
|
|
459
|
+
if (!pluginCli) {
|
|
460
|
+
console.error(chalk.red(`✗ Could not find CLI entry point for ${activePlugin}.`));
|
|
461
|
+
process.exit(1);
|
|
462
|
+
}
|
|
463
|
+
const envFile = findEnvFile(projectRoot);
|
|
464
|
+
const env = { ...process.env };
|
|
465
|
+
if (envFile) {
|
|
466
|
+
env.DOTENV_CONFIG_PATH = envFile;
|
|
467
|
+
}
|
|
468
|
+
try {
|
|
469
|
+
const isTs = pluginCli.endsWith(".ts");
|
|
470
|
+
if (isTs) {
|
|
471
|
+
const tsxBin = resolveTsx(projectRoot);
|
|
472
|
+
if (!tsxBin) {
|
|
473
|
+
console.error(chalk.red("✗ Could not find tsx binary."));
|
|
474
|
+
process.exit(1);
|
|
475
|
+
}
|
|
476
|
+
await execa(tsxBin, [pluginCli, "schema", subcommand, ...rawArgs.slice(2)], {
|
|
477
|
+
cwd: backendDir,
|
|
478
|
+
stdio: "inherit",
|
|
479
|
+
env
|
|
480
|
+
});
|
|
481
|
+
} else {
|
|
482
|
+
await execa("node", [pluginCli, "schema", subcommand, ...rawArgs.slice(2)], {
|
|
483
|
+
cwd: backendDir,
|
|
484
|
+
stdio: "inherit",
|
|
485
|
+
env
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
} catch (err) {
|
|
489
|
+
process.exit(1);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function printSchemaHelp() {
|
|
493
|
+
console.log(`
|
|
494
|
+
${chalk.bold("rebase schema")} — Schema management commands
|
|
495
|
+
|
|
496
|
+
${chalk.green.bold("Usage")}
|
|
497
|
+
rebase schema ${chalk.blue("<command>")} [options]
|
|
498
|
+
|
|
499
|
+
${chalk.green.bold("Commands")}
|
|
500
|
+
${chalk.gray("(Commands are provided by your active database driver plugin)")}
|
|
501
|
+
${chalk.blue.bold("generate")} Generate Schema from collection definitions
|
|
502
|
+
|
|
503
|
+
${chalk.green.bold("generate Options")}
|
|
504
|
+
${chalk.blue("--collections, -c")} Path to collections directory
|
|
505
|
+
${chalk.blue("--output, -o")} Output path for generated schema
|
|
506
|
+
${chalk.blue("--watch, -w")} Watch for changes and regenerate automatically
|
|
507
|
+
`);
|
|
508
|
+
}
|
|
509
|
+
async function dbCommand(subcommand, rawArgs) {
|
|
510
|
+
if (!subcommand || subcommand === "--help") {
|
|
511
|
+
printDbHelp();
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
const projectRoot = requireProjectRoot();
|
|
515
|
+
const backendDir = requireBackendDir(projectRoot);
|
|
516
|
+
const activePlugin = getActiveBackendPlugin(backendDir);
|
|
517
|
+
if (!activePlugin) {
|
|
518
|
+
console.error(chalk.red("✗ Could not detect an active database plugin."));
|
|
519
|
+
console.error(chalk.gray(" Make sure a package like @rebasepro/server-postgresql is installed in backend/package.json."));
|
|
520
|
+
process.exit(1);
|
|
521
|
+
}
|
|
522
|
+
const pluginCli = resolvePluginCliScript(backendDir, activePlugin);
|
|
523
|
+
if (!pluginCli) {
|
|
524
|
+
console.error(chalk.red(`✗ Could not find CLI entry point for ${activePlugin}.`));
|
|
525
|
+
process.exit(1);
|
|
526
|
+
}
|
|
527
|
+
const envFile = findEnvFile(projectRoot);
|
|
528
|
+
const env = { ...process.env };
|
|
529
|
+
if (envFile) {
|
|
530
|
+
env.DOTENV_CONFIG_PATH = envFile;
|
|
531
|
+
}
|
|
532
|
+
try {
|
|
533
|
+
const isTs = pluginCli.endsWith(".ts");
|
|
534
|
+
if (isTs) {
|
|
535
|
+
const tsxBin = resolveTsx(projectRoot);
|
|
536
|
+
if (!tsxBin) {
|
|
537
|
+
console.error(chalk.red("✗ Could not find tsx binary."));
|
|
538
|
+
process.exit(1);
|
|
539
|
+
}
|
|
540
|
+
await execa(tsxBin, [pluginCli, "db", subcommand, ...rawArgs.slice(2)], {
|
|
541
|
+
cwd: backendDir,
|
|
542
|
+
stdio: "inherit",
|
|
543
|
+
env
|
|
544
|
+
});
|
|
545
|
+
} else {
|
|
546
|
+
await execa("node", [pluginCli, "db", subcommand, ...rawArgs.slice(2)], {
|
|
547
|
+
cwd: backendDir,
|
|
548
|
+
stdio: "inherit",
|
|
549
|
+
env
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
} catch (err) {
|
|
553
|
+
process.exit(1);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function printDbHelp() {
|
|
557
|
+
console.log(`
|
|
558
|
+
${chalk.bold("rebase db")} — Database management commands
|
|
559
|
+
|
|
560
|
+
${chalk.green.bold("Usage")}
|
|
561
|
+
rebase db ${chalk.blue("<command>")} [options]
|
|
562
|
+
|
|
563
|
+
${chalk.green.bold("Commands")}
|
|
564
|
+
${chalk.gray("(Commands are provided by your active database driver plugin)")}
|
|
565
|
+
${chalk.blue.bold("push")} Apply schema directly to database (development)
|
|
566
|
+
${chalk.blue.bold("pull")} Introspect database → Schema
|
|
567
|
+
${chalk.blue.bold("generate")} Generate migration files
|
|
568
|
+
${chalk.blue.bold("migrate")} Run pending migrations
|
|
569
|
+
${chalk.blue.bold("studio")} Open Studio viewer
|
|
570
|
+
${chalk.blue.bold("branch")} Database branching (create, list, delete, info)
|
|
571
|
+
|
|
572
|
+
${chalk.green.bold("Examples")}
|
|
573
|
+
${chalk.gray("# Quick development workflow")}
|
|
574
|
+
rebase schema generate && rebase db push
|
|
575
|
+
|
|
576
|
+
${chalk.gray("# Production migration workflow")}
|
|
577
|
+
rebase db generate
|
|
578
|
+
rebase db migrate
|
|
579
|
+
|
|
580
|
+
${chalk.gray("# Create a database branch")}
|
|
581
|
+
rebase db branch create feature_auth
|
|
582
|
+
`);
|
|
583
|
+
}
|
|
584
|
+
async function devCommand(rawArgs) {
|
|
585
|
+
const args = arg(
|
|
586
|
+
{
|
|
587
|
+
"--backend-only": Boolean,
|
|
588
|
+
"--frontend-only": Boolean,
|
|
589
|
+
"--port": Number,
|
|
590
|
+
"--help": Boolean,
|
|
591
|
+
"-b": "--backend-only",
|
|
592
|
+
"-f": "--frontend-only",
|
|
593
|
+
"-p": "--port",
|
|
594
|
+
"-h": "--help"
|
|
595
|
+
},
|
|
596
|
+
{
|
|
597
|
+
argv: rawArgs.slice(3),
|
|
598
|
+
// skip "node rebase dev"
|
|
599
|
+
permissive: true
|
|
600
|
+
}
|
|
601
|
+
);
|
|
602
|
+
if (args["--help"]) {
|
|
603
|
+
printDevHelp();
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
const projectRoot = requireProjectRoot();
|
|
607
|
+
const backendDir = findBackendDir(projectRoot);
|
|
608
|
+
const frontendDir = findFrontendDir(projectRoot);
|
|
609
|
+
const backendOnly = args["--backend-only"] || false;
|
|
610
|
+
const frontendOnly = args["--frontend-only"] || false;
|
|
611
|
+
console.log("");
|
|
612
|
+
console.log(chalk.bold(" 🚀 Rebase Dev Server"));
|
|
613
|
+
console.log("");
|
|
614
|
+
const children = [];
|
|
615
|
+
let frontendUrl = "";
|
|
616
|
+
let backendUrl = "";
|
|
617
|
+
let debounceSummary = null;
|
|
618
|
+
let bannerPrinted = false;
|
|
619
|
+
const stripAnsi = (str) => str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
|
|
620
|
+
function printSummary() {
|
|
621
|
+
if (!frontendUrl || !backendUrl) return;
|
|
622
|
+
if (debounceSummary) clearTimeout(debounceSummary);
|
|
623
|
+
debounceSummary = setTimeout(() => {
|
|
624
|
+
if (bannerPrinted) return;
|
|
625
|
+
console.log("");
|
|
626
|
+
console.log(chalk.cyan("┌────────────────────────────────────────────────────────────┐"));
|
|
627
|
+
console.log(chalk.cyan("│ │"));
|
|
628
|
+
console.log(chalk.cyan("│ ✨ Rebase Admin App is ready! │"));
|
|
629
|
+
const cleanUrl = stripAnsi(frontendUrl);
|
|
630
|
+
const paddedUrl = cleanUrl.padEnd(40);
|
|
631
|
+
console.log(chalk.cyan(`│ 👉 Frontend URL: `) + chalk.white(paddedUrl) + chalk.cyan(`│`));
|
|
632
|
+
console.log(chalk.cyan("│ │"));
|
|
633
|
+
console.log(chalk.cyan("└────────────────────────────────────────────────────────────┘"));
|
|
634
|
+
console.log("");
|
|
635
|
+
bannerPrinted = true;
|
|
636
|
+
}, 500);
|
|
637
|
+
}
|
|
638
|
+
const cleanup = () => {
|
|
639
|
+
children.forEach((child) => {
|
|
640
|
+
if (!child.killed) {
|
|
641
|
+
child.kill("SIGTERM");
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
process.exit(0);
|
|
645
|
+
};
|
|
646
|
+
process.on("SIGINT", cleanup);
|
|
647
|
+
process.on("SIGTERM", cleanup);
|
|
648
|
+
if (!frontendOnly && backendDir) {
|
|
649
|
+
const tsxBin = resolveTsx(projectRoot);
|
|
650
|
+
if (!tsxBin) {
|
|
651
|
+
console.error(chalk.red(" ✗ Could not find tsx binary for backend."));
|
|
652
|
+
console.error(chalk.gray(" Install it with: pnpm add -D tsx"));
|
|
653
|
+
process.exit(1);
|
|
654
|
+
}
|
|
655
|
+
const envFile = findEnvFile(projectRoot);
|
|
656
|
+
const env = { ...process.env };
|
|
657
|
+
if (envFile) {
|
|
658
|
+
env.DOTENV_CONFIG_PATH = envFile;
|
|
659
|
+
}
|
|
660
|
+
if (args["--port"]) {
|
|
661
|
+
env.PORT = String(args["--port"]);
|
|
662
|
+
}
|
|
663
|
+
path.join(backendDir, "src", "index.ts");
|
|
664
|
+
const watchDirs = [
|
|
665
|
+
`--watch="${path.join("..", "shared", "**", "*")}"`
|
|
666
|
+
];
|
|
667
|
+
console.log(` ${chalk.cyan("▶")} Backend: ${chalk.gray(backendDir)}`);
|
|
668
|
+
const backendChild = execa(
|
|
669
|
+
tsxBin,
|
|
670
|
+
["watch", ...watchDirs, "--conditions", "development", "src/index.ts"],
|
|
671
|
+
{
|
|
672
|
+
cwd: backendDir,
|
|
673
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
674
|
+
env,
|
|
675
|
+
shell: true
|
|
676
|
+
}
|
|
677
|
+
);
|
|
678
|
+
backendChild.catch(() => {
|
|
679
|
+
});
|
|
680
|
+
backendChild.stdout?.on("data", (data) => {
|
|
681
|
+
const lines = data.toString().split("\n").filter(Boolean);
|
|
682
|
+
lines.forEach((line) => {
|
|
683
|
+
console.log(`${chalk.cyan.bold("[backend]")} ${line}`);
|
|
684
|
+
const cleanLine = stripAnsi(line);
|
|
685
|
+
if (cleanLine.includes("Server running at http://")) {
|
|
686
|
+
backendUrl = "started";
|
|
687
|
+
printSummary();
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
backendChild.stderr?.on("data", (data) => {
|
|
692
|
+
const lines = data.toString().split("\n").filter(Boolean);
|
|
693
|
+
lines.forEach((line) => {
|
|
694
|
+
console.log(`${chalk.cyan.bold("[backend]")} ${line}`);
|
|
695
|
+
});
|
|
696
|
+
});
|
|
697
|
+
children.push(backendChild);
|
|
698
|
+
} else if (!frontendOnly && !backendDir) {
|
|
699
|
+
console.warn(chalk.yellow(" ⚠ No backend/ directory found, skipping backend."));
|
|
700
|
+
}
|
|
701
|
+
if (!backendOnly && frontendDir) {
|
|
702
|
+
console.log(` ${chalk.magenta("▶")} Frontend: ${chalk.gray(frontendDir)}`);
|
|
703
|
+
const frontendChild = execa(
|
|
704
|
+
"pnpm",
|
|
705
|
+
["run", "dev"],
|
|
706
|
+
{
|
|
707
|
+
cwd: frontendDir,
|
|
708
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
709
|
+
env: process.env,
|
|
710
|
+
shell: true
|
|
711
|
+
}
|
|
712
|
+
);
|
|
713
|
+
frontendChild.catch(() => {
|
|
714
|
+
});
|
|
715
|
+
frontendChild.stdout?.on("data", (data) => {
|
|
716
|
+
const lines = data.toString().split("\n").filter(Boolean);
|
|
717
|
+
lines.forEach((line) => {
|
|
718
|
+
console.log(`${chalk.magenta.bold("[frontend]")} ${line}`);
|
|
719
|
+
const cleanLine = stripAnsi(line);
|
|
720
|
+
const urlMatch = cleanLine.match(/(http:\/\/(?:localhost|127\.0\.0\.1):\d+)/);
|
|
721
|
+
if (cleanLine.includes("Local:") && urlMatch) {
|
|
722
|
+
frontendUrl = urlMatch[1];
|
|
723
|
+
printSummary();
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
frontendChild.stderr?.on("data", (data) => {
|
|
728
|
+
const lines = data.toString().split("\n").filter(Boolean);
|
|
729
|
+
lines.forEach((line) => {
|
|
730
|
+
console.log(`${chalk.magenta.bold("[frontend]")} ${line}`);
|
|
731
|
+
});
|
|
732
|
+
});
|
|
733
|
+
children.push(frontendChild);
|
|
734
|
+
} else if (!backendOnly && !frontendDir) {
|
|
735
|
+
console.warn(chalk.yellow(" ⚠ No frontend/ directory found, skipping frontend."));
|
|
736
|
+
}
|
|
737
|
+
if (children.length === 0) {
|
|
738
|
+
console.error(chalk.red(" ✗ Nothing to start. Check your project structure."));
|
|
739
|
+
process.exit(1);
|
|
740
|
+
}
|
|
741
|
+
console.log("");
|
|
742
|
+
console.log(chalk.gray(" Press Ctrl+C to stop all servers."));
|
|
743
|
+
console.log("");
|
|
744
|
+
await Promise.all(
|
|
745
|
+
children.map(
|
|
746
|
+
(child) => new Promise((resolve) => {
|
|
747
|
+
child.finally(() => resolve());
|
|
748
|
+
})
|
|
749
|
+
)
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
function printDevHelp() {
|
|
753
|
+
console.log(`
|
|
754
|
+
${chalk.bold("rebase dev")} — Start the development server
|
|
755
|
+
|
|
756
|
+
${chalk.green.bold("Usage")}
|
|
757
|
+
rebase dev [options]
|
|
758
|
+
|
|
759
|
+
${chalk.green.bold("Options")}
|
|
760
|
+
${chalk.blue("--backend-only, -b")} Only start the backend server
|
|
761
|
+
${chalk.blue("--frontend-only, -f")} Only start the frontend server
|
|
762
|
+
${chalk.blue("--port, -p")} Backend port (default: 3001)
|
|
763
|
+
|
|
764
|
+
${chalk.green.bold("Description")}
|
|
765
|
+
Starts both the backend (tsx watch + Express) and frontend (Vite)
|
|
766
|
+
dev servers concurrently with color-coded output prefixes.
|
|
767
|
+
`);
|
|
768
|
+
}
|
|
769
|
+
async function authCommand(subcommand, rawArgs) {
|
|
770
|
+
if (!subcommand || subcommand === "--help") {
|
|
771
|
+
printAuthHelp();
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
switch (subcommand) {
|
|
775
|
+
case "reset-password":
|
|
776
|
+
await resetPassword(rawArgs);
|
|
777
|
+
break;
|
|
778
|
+
default:
|
|
779
|
+
console.error(chalk.red(`Unknown auth command: ${subcommand}`));
|
|
780
|
+
console.log("");
|
|
781
|
+
printAuthHelp();
|
|
782
|
+
process.exit(1);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
async function resetPassword(rawArgs) {
|
|
786
|
+
const args = arg(
|
|
787
|
+
{
|
|
788
|
+
"--email": String,
|
|
789
|
+
"--password": String,
|
|
790
|
+
"-e": "--email",
|
|
791
|
+
"-p": "--password"
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
argv: rawArgs.slice(4),
|
|
795
|
+
// skip "node rebase auth reset-password"
|
|
796
|
+
permissive: true
|
|
797
|
+
}
|
|
798
|
+
);
|
|
799
|
+
const email = args["--email"] || args._[0];
|
|
800
|
+
const newPassword = args["--password"] || args._[1];
|
|
801
|
+
if (!email) {
|
|
802
|
+
console.error(chalk.red("✗ Email is required."));
|
|
803
|
+
console.log("");
|
|
804
|
+
console.log(chalk.gray(" Usage: rebase auth reset-password <email> [new-password]"));
|
|
805
|
+
console.log(chalk.gray(" rebase auth reset-password --email user@example.com --password NewPass123!"));
|
|
806
|
+
process.exit(1);
|
|
807
|
+
}
|
|
808
|
+
const projectRoot = requireProjectRoot();
|
|
809
|
+
const backendDir = requireBackendDir(projectRoot);
|
|
810
|
+
const tsxBin = resolveTsx(projectRoot);
|
|
811
|
+
if (!tsxBin) {
|
|
812
|
+
console.error(chalk.red("✗ Could not find tsx binary."));
|
|
813
|
+
process.exit(1);
|
|
814
|
+
}
|
|
815
|
+
const envFile = findEnvFile(projectRoot);
|
|
816
|
+
const env = { ...process.env };
|
|
817
|
+
if (envFile) {
|
|
818
|
+
env.DOTENV_CONFIG_PATH = envFile;
|
|
819
|
+
}
|
|
820
|
+
const scriptContent = `
|
|
821
|
+
import { createPostgresDatabaseConnection } from "@rebasepro/server-core";
|
|
822
|
+
import { hashPassword } from "@rebasepro/server-core/src/auth/password";
|
|
823
|
+
import { eq } from "drizzle-orm";
|
|
824
|
+
import { users } from "@rebasepro/server-core/src/db/auth-schema";
|
|
825
|
+
import * as dotenv from "dotenv";
|
|
826
|
+
import path from "path";
|
|
827
|
+
|
|
828
|
+
dotenv.config({ path: "${envFile || path.join(projectRoot, ".env")}" });
|
|
829
|
+
|
|
830
|
+
const email = "${email}";
|
|
831
|
+
const newPassword = "${newPassword || "NewPassword123!"}";
|
|
832
|
+
|
|
833
|
+
async function resetPassword() {
|
|
834
|
+
const { db } = createPostgresDatabaseConnection(process.env.DATABASE_URL!);
|
|
835
|
+
const hash = await hashPassword(newPassword);
|
|
836
|
+
|
|
837
|
+
const result = await db.update(users)
|
|
838
|
+
.set({ passwordHash: hash })
|
|
839
|
+
.where(eq(users.email, email))
|
|
840
|
+
.returning({
|
|
841
|
+
id: users.id,
|
|
842
|
+
email: users.email
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
if (result.length > 0) {
|
|
846
|
+
console.log("✅ Password reset for: " + result[0].email);
|
|
847
|
+
${!newPassword ? 'console.log(" New password: " + newPassword);' : ""}
|
|
848
|
+
} else {
|
|
849
|
+
console.log("✗ User not found: " + email);
|
|
850
|
+
}
|
|
851
|
+
process.exit(0);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
resetPassword().catch(console.error);
|
|
855
|
+
`;
|
|
856
|
+
const tmpScriptPath = path.join(backendDir, ".tmp-reset-password.ts");
|
|
857
|
+
fs.writeFileSync(tmpScriptPath, scriptContent, "utf-8");
|
|
858
|
+
console.log("");
|
|
859
|
+
console.log(chalk.bold(" 🔑 Rebase Auth — Reset Password"));
|
|
860
|
+
console.log("");
|
|
861
|
+
console.log(` ${chalk.gray("Email:")} ${email}`);
|
|
862
|
+
if (newPassword) {
|
|
863
|
+
console.log(` ${chalk.gray("Password:")} ${"*".repeat(newPassword.length)}`);
|
|
864
|
+
}
|
|
865
|
+
console.log("");
|
|
866
|
+
const child = child_process.spawn(tsxBin, [tmpScriptPath], {
|
|
867
|
+
cwd: backendDir,
|
|
868
|
+
stdio: "inherit",
|
|
869
|
+
env
|
|
870
|
+
});
|
|
871
|
+
return new Promise((resolve) => {
|
|
872
|
+
child.on("close", (code) => {
|
|
873
|
+
try {
|
|
874
|
+
fs.unlinkSync(tmpScriptPath);
|
|
875
|
+
} catch {
|
|
876
|
+
}
|
|
877
|
+
if (code !== 0) {
|
|
878
|
+
process.exit(code ?? 1);
|
|
879
|
+
}
|
|
880
|
+
resolve();
|
|
881
|
+
});
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
function printAuthHelp() {
|
|
885
|
+
console.log(`
|
|
886
|
+
${chalk.bold("rebase auth")} — Authentication management commands
|
|
887
|
+
|
|
888
|
+
${chalk.green.bold("Usage")}
|
|
889
|
+
rebase auth ${chalk.blue("<command>")} [options]
|
|
890
|
+
|
|
891
|
+
${chalk.green.bold("Commands")}
|
|
892
|
+
${chalk.blue.bold("reset-password")} Reset a user's password
|
|
893
|
+
|
|
894
|
+
${chalk.green.bold("reset-password Options")}
|
|
895
|
+
${chalk.blue("--email, -e")} User's email address
|
|
896
|
+
${chalk.blue("--password, -p")} New password (default: NewPassword123!)
|
|
897
|
+
|
|
898
|
+
${chalk.green.bold("Examples")}
|
|
899
|
+
rebase auth reset-password user@example.com
|
|
900
|
+
rebase auth reset-password --email user@example.com --password MyNewPass!
|
|
901
|
+
`);
|
|
902
|
+
}
|
|
166
903
|
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);
|
|
167
904
|
const __dirname$1 = path.dirname(__filename$1);
|
|
168
905
|
function getVersion() {
|
|
@@ -193,16 +930,52 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
|
|
|
193
930
|
return;
|
|
194
931
|
}
|
|
195
932
|
const command = parsedArgs._[0];
|
|
196
|
-
|
|
933
|
+
const subcommand = parsedArgs._[1];
|
|
934
|
+
const namespacedCommands = ["schema", "db", "dev", "auth"];
|
|
935
|
+
if (!command || parsedArgs["--help"] && !namespacedCommands.includes(command)) {
|
|
197
936
|
printHelp();
|
|
198
937
|
return;
|
|
199
938
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
939
|
+
const effectiveSubcommand = parsedArgs["--help"] ? "--help" : subcommand;
|
|
940
|
+
switch (command) {
|
|
941
|
+
case "init":
|
|
942
|
+
await createRebaseApp(args);
|
|
943
|
+
break;
|
|
944
|
+
case "generate-sdk":
|
|
945
|
+
const sdkArgs = arg(
|
|
946
|
+
{
|
|
947
|
+
"--collections-dir": String,
|
|
948
|
+
"--output": String,
|
|
949
|
+
"-c": "--collections-dir",
|
|
950
|
+
"-o": "--output"
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
argv: args.slice(3),
|
|
954
|
+
permissive: true
|
|
955
|
+
}
|
|
956
|
+
);
|
|
957
|
+
await generateSdkCommand({
|
|
958
|
+
collectionsDir: sdkArgs["--collections-dir"] || "./shared/collections",
|
|
959
|
+
output: sdkArgs["--output"] || "./generated/sdk",
|
|
960
|
+
cwd: process.cwd()
|
|
961
|
+
});
|
|
962
|
+
break;
|
|
963
|
+
case "schema":
|
|
964
|
+
await schemaCommand(effectiveSubcommand, args);
|
|
965
|
+
break;
|
|
966
|
+
case "db":
|
|
967
|
+
await dbCommand(effectiveSubcommand, args);
|
|
968
|
+
break;
|
|
969
|
+
case "dev":
|
|
970
|
+
await devCommand(args);
|
|
971
|
+
break;
|
|
972
|
+
case "auth":
|
|
973
|
+
await authCommand(effectiveSubcommand, args);
|
|
974
|
+
break;
|
|
975
|
+
default:
|
|
976
|
+
console.log(chalk.red(`Unknown command: ${command}`));
|
|
977
|
+
console.log("");
|
|
978
|
+
printHelp();
|
|
206
979
|
}
|
|
207
980
|
}
|
|
208
981
|
function printHelp() {
|
|
@@ -213,7 +986,27 @@ ${chalk.green.bold("Usage")}
|
|
|
213
986
|
rebase ${chalk.blue("<command>")} [options]
|
|
214
987
|
|
|
215
988
|
${chalk.green.bold("Commands")}
|
|
216
|
-
${chalk.blue.bold("init")}
|
|
989
|
+
${chalk.blue.bold("init")} Create a new Rebase project
|
|
990
|
+
${chalk.blue.bold("dev")} Start the development server
|
|
991
|
+
|
|
992
|
+
${chalk.green.bold("Schema")}
|
|
993
|
+
${chalk.blue.bold("schema generate")} Generate Drizzle schema from collections
|
|
994
|
+
${chalk.blue.bold("schema")} ${chalk.gray("--help")} Show schema command help
|
|
995
|
+
|
|
996
|
+
${chalk.green.bold("Database")}
|
|
997
|
+
${chalk.blue.bold("db push")} Apply schema directly to database ${chalk.gray("(dev)")}
|
|
998
|
+
${chalk.blue.bold("db pull")} Introspect database → Drizzle schema
|
|
999
|
+
${chalk.blue.bold("db generate")} Generate SQL migration files
|
|
1000
|
+
${chalk.blue.bold("db migrate")} Run pending migrations
|
|
1001
|
+
${chalk.blue.bold("db studio")} Open Drizzle Studio
|
|
1002
|
+
${chalk.blue.bold("db")} ${chalk.gray("--help")} Show database command help
|
|
1003
|
+
|
|
1004
|
+
${chalk.green.bold("SDK")}
|
|
1005
|
+
${chalk.blue.bold("generate-sdk")} Generate a typed JS SDK from collections
|
|
1006
|
+
|
|
1007
|
+
${chalk.green.bold("Auth")}
|
|
1008
|
+
${chalk.blue.bold("auth reset-password")} Reset a user's password
|
|
1009
|
+
${chalk.blue.bold("auth")} ${chalk.gray("--help")} Show auth command help
|
|
217
1010
|
|
|
218
1011
|
${chalk.green.bold("Options")}
|
|
219
1012
|
${chalk.blue("--version, -v")} Show version number
|
|
@@ -265,13 +1058,27 @@ ${chalk.gray("Documentation: https://rebase.pro/docs")}
|
|
|
265
1058
|
console.log("You are not logged in.");
|
|
266
1059
|
}
|
|
267
1060
|
}
|
|
1061
|
+
exports2.authCommand = authCommand;
|
|
268
1062
|
exports2.createRebaseApp = createRebaseApp;
|
|
1063
|
+
exports2.dbCommand = dbCommand;
|
|
1064
|
+
exports2.devCommand = devCommand;
|
|
269
1065
|
exports2.entry = entry;
|
|
1066
|
+
exports2.findBackendDir = findBackendDir;
|
|
1067
|
+
exports2.findEnvFile = findEnvFile;
|
|
1068
|
+
exports2.findFrontendDir = findFrontendDir;
|
|
1069
|
+
exports2.findProjectRoot = findProjectRoot;
|
|
1070
|
+
exports2.getActiveBackendPlugin = getActiveBackendPlugin;
|
|
270
1071
|
exports2.getTokens = getTokens;
|
|
271
1072
|
exports2.login = login;
|
|
272
1073
|
exports2.logout = logout;
|
|
273
1074
|
exports2.parseJwt = parseJwt;
|
|
274
1075
|
exports2.refreshCredentials = refreshCredentials;
|
|
1076
|
+
exports2.requireBackendDir = requireBackendDir;
|
|
1077
|
+
exports2.requireProjectRoot = requireProjectRoot;
|
|
1078
|
+
exports2.resolveLocalBin = resolveLocalBin;
|
|
1079
|
+
exports2.resolvePluginCliScript = resolvePluginCliScript;
|
|
1080
|
+
exports2.resolveTsx = resolveTsx;
|
|
1081
|
+
exports2.schemaCommand = schemaCommand;
|
|
275
1082
|
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
276
1083
|
}));
|
|
277
1084
|
//# sourceMappingURL=index.cjs.map
|