@rebasepro/cli 0.0.1-canary.eae7889 → 0.0.1-canary.f81da60
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/init.d.ts +3 -0
- package/dist/index.cjs +131 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +131 -28
- package/dist/index.es.js.map +1 -1
- package/package.json +4 -5
- package/templates/template/.dockerignore +1 -1
- package/templates/template/.env.example +96 -0
- package/templates/template/README.md +14 -4
- package/templates/template/backend/drizzle.config.ts +24 -4
- package/templates/template/backend/package.json +3 -3
- package/templates/template/config/collections/posts.ts +3 -3
- package/templates/template/docker-compose.yml +12 -37
- package/templates/template/frontend/package.json +1 -1
- package/templates/template/frontend/src/App.tsx +19 -98
- package/templates/template/frontend/vite.config.ts +32 -2
- package/templates/template/package.json +5 -4
- package/templates/template/.env.template +0 -62
package/dist/commands/init.d.ts
CHANGED
|
@@ -4,5 +4,8 @@ export interface InitOptions {
|
|
|
4
4
|
installDeps: boolean;
|
|
5
5
|
targetDirectory: string;
|
|
6
6
|
templateDirectory: string;
|
|
7
|
+
databaseUrl?: string;
|
|
8
|
+
introspect?: boolean;
|
|
7
9
|
}
|
|
8
10
|
export declare function createRebaseApp(rawArgs: string[]): Promise<void>;
|
|
11
|
+
export declare function configureEnvFile(targetDirectory: string, databaseUrl?: string): void;
|
package/dist/index.cjs
CHANGED
|
@@ -89,16 +89,31 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
|
|
|
89
89
|
default: true
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
|
+
questions.push({
|
|
93
|
+
type: "input",
|
|
94
|
+
name: "databaseUrl",
|
|
95
|
+
message: "Enter your PostgreSQL database connection string (leave blank to use a local default):",
|
|
96
|
+
default: ""
|
|
97
|
+
});
|
|
98
|
+
questions.push({
|
|
99
|
+
type: "confirm",
|
|
100
|
+
name: "introspect",
|
|
101
|
+
message: "Would you like to introspect this database to automatically generate collections?",
|
|
102
|
+
default: true,
|
|
103
|
+
when: (answers2) => !!answers2.databaseUrl?.trim()
|
|
104
|
+
});
|
|
92
105
|
const answers = await inquirer.prompt(questions);
|
|
93
|
-
const
|
|
94
|
-
const
|
|
106
|
+
const targetDirectory = path.resolve(process.cwd(), nameArg || answers.projectName);
|
|
107
|
+
const projectName = path.basename(targetDirectory);
|
|
95
108
|
const templateDirectory = path.resolve(cliRoot, "templates", "template");
|
|
96
109
|
return {
|
|
97
110
|
projectName,
|
|
98
111
|
git: args["--git"] || answers.git || false,
|
|
99
112
|
installDeps: args["--install"] || answers.installDeps || false,
|
|
100
113
|
targetDirectory,
|
|
101
|
-
templateDirectory
|
|
114
|
+
templateDirectory,
|
|
115
|
+
databaseUrl: answers.databaseUrl?.trim() || void 0,
|
|
116
|
+
introspect: answers.introspect || false
|
|
102
117
|
};
|
|
103
118
|
}
|
|
104
119
|
async function createProject(options) {
|
|
@@ -131,27 +146,7 @@ ${chalk.bold("Rebase")} — Create a new project 🚀
|
|
|
131
146
|
process.exit(1);
|
|
132
147
|
}
|
|
133
148
|
await replacePlaceholders(options);
|
|
134
|
-
|
|
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
|
-
}
|
|
149
|
+
configureEnvFile(options.targetDirectory, options.databaseUrl);
|
|
155
150
|
if (options.git) {
|
|
156
151
|
console.log(chalk.gray(" Initializing git repository..."));
|
|
157
152
|
try {
|
|
@@ -173,6 +168,26 @@ POSTGRES_PASSWORD=${dbPassword}
|
|
|
173
168
|
console.warn(chalk.yellow(" Warning: Failed to install dependencies. You may need to run `pnpm install` manually."));
|
|
174
169
|
}
|
|
175
170
|
}
|
|
171
|
+
if (options.introspect) {
|
|
172
|
+
console.log("");
|
|
173
|
+
if (options.installDeps) {
|
|
174
|
+
console.log(chalk.gray(" Introspecting database and generating collections..."));
|
|
175
|
+
console.log("");
|
|
176
|
+
try {
|
|
177
|
+
await execa("pnpm", ["exec", "rebase", "schema", "introspect", "--force"], {
|
|
178
|
+
cwd: options.targetDirectory,
|
|
179
|
+
stdio: "inherit"
|
|
180
|
+
});
|
|
181
|
+
console.log(chalk.green(" Database successfully introspected!"));
|
|
182
|
+
} catch {
|
|
183
|
+
console.warn(chalk.yellow(" Warning: Failed to introspect database automatically."));
|
|
184
|
+
console.warn(chalk.yellow(" You can run `pnpm exec rebase schema introspect` manually after setup."));
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
console.warn(chalk.yellow(" Skipping introspection because dependencies were not installed."));
|
|
188
|
+
console.warn(chalk.yellow(" Run `pnpm install` then `pnpm exec rebase schema introspect` manually."));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
176
191
|
console.log("");
|
|
177
192
|
console.log(`${chalk.green.bold("✓")} Project ${chalk.bold(options.projectName)} created successfully!`);
|
|
178
193
|
console.log("");
|
|
@@ -183,8 +198,15 @@ POSTGRES_PASSWORD=${dbPassword}
|
|
|
183
198
|
console.log(` ${chalk.cyan("pnpm install")}`);
|
|
184
199
|
}
|
|
185
200
|
console.log("");
|
|
186
|
-
|
|
187
|
-
|
|
201
|
+
if (options.databaseUrl) {
|
|
202
|
+
console.log(chalk.gray(" # Your database is configured! Start the dev server:"));
|
|
203
|
+
} else {
|
|
204
|
+
console.log(chalk.gray(" # A local database configuration has been generated in .env."));
|
|
205
|
+
console.log(chalk.gray(" # If using the included docker-compose.yml, start it with:"));
|
|
206
|
+
console.log(` ${chalk.cyan("docker compose up -d")}`);
|
|
207
|
+
console.log("");
|
|
208
|
+
console.log(chalk.gray(" # Then start the dev server:"));
|
|
209
|
+
}
|
|
188
210
|
console.log("");
|
|
189
211
|
console.log(` ${chalk.cyan("pnpm dev")}`);
|
|
190
212
|
console.log("");
|
|
@@ -202,14 +224,89 @@ POSTGRES_PASSWORD=${dbPassword}
|
|
|
202
224
|
"config/package.json",
|
|
203
225
|
"frontend/index.html"
|
|
204
226
|
];
|
|
227
|
+
const packageJsonPath = path.resolve(cliRoot, "package.json");
|
|
228
|
+
let cliVersion = "latest";
|
|
229
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
230
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
231
|
+
cliVersion = pkg.version || "latest";
|
|
232
|
+
}
|
|
233
|
+
const versionCache = /* @__PURE__ */ new Map();
|
|
234
|
+
const getPackageVersion = async (pkgName) => {
|
|
235
|
+
if (versionCache.has(pkgName)) return versionCache.get(pkgName);
|
|
236
|
+
let versionToUse = cliVersion;
|
|
237
|
+
try {
|
|
238
|
+
const { stdout } = await execa("pnpm", ["view", `${pkgName}@${cliVersion}`, "version"]);
|
|
239
|
+
if (!stdout.trim()) throw new Error("Not found");
|
|
240
|
+
versionToUse = stdout.trim();
|
|
241
|
+
} catch {
|
|
242
|
+
try {
|
|
243
|
+
const tag = cliVersion.includes("canary") ? "canary" : "latest";
|
|
244
|
+
const { stdout } = await execa("pnpm", ["view", `${pkgName}@${tag}`, "version"]);
|
|
245
|
+
if (!stdout.trim()) throw new Error("Not found");
|
|
246
|
+
versionToUse = stdout.trim();
|
|
247
|
+
} catch {
|
|
248
|
+
try {
|
|
249
|
+
const { stdout } = await execa("pnpm", ["view", pkgName, "version"]);
|
|
250
|
+
versionToUse = stdout.trim() || "latest";
|
|
251
|
+
} catch {
|
|
252
|
+
versionToUse = "latest";
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
versionCache.set(pkgName, versionToUse);
|
|
257
|
+
return versionToUse;
|
|
258
|
+
};
|
|
259
|
+
const allPackages = /* @__PURE__ */ new Set();
|
|
260
|
+
const fileContents = /* @__PURE__ */ new Map();
|
|
205
261
|
for (const file of filesToProcess) {
|
|
206
262
|
const fullPath = path.resolve(options.targetDirectory, file);
|
|
207
263
|
if (!fs.existsSync(fullPath)) continue;
|
|
208
|
-
|
|
209
|
-
|
|
264
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
265
|
+
fileContents.set(fullPath, content);
|
|
266
|
+
const matches = [...content.matchAll(/"(@rebasepro\/[^"]+)":\s*"workspace:\*"/g)];
|
|
267
|
+
for (const match of matches) {
|
|
268
|
+
allPackages.add(match[1]);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
console.log(chalk.gray(" Resolving package versions..."));
|
|
272
|
+
await Promise.all(Array.from(allPackages).map(getPackageVersion));
|
|
273
|
+
for (const [fullPath, originalContent] of fileContents.entries()) {
|
|
274
|
+
let content = originalContent.replace(/\{\{PROJECT_NAME\}\}/g, options.projectName);
|
|
275
|
+
const matches = [...content.matchAll(/"(@rebasepro\/[^"]+)":\s*"workspace:\*"/g)];
|
|
276
|
+
for (const match of matches) {
|
|
277
|
+
const pkgName = match[1];
|
|
278
|
+
const resolvedVersion = versionCache.get(pkgName) || "latest";
|
|
279
|
+
content = content.replace(new RegExp(`"${pkgName}":\\s*"workspace:\\*"`, "g"), `"${pkgName}": "${resolvedVersion}"`);
|
|
280
|
+
}
|
|
210
281
|
fs.writeFileSync(fullPath, content, "utf-8");
|
|
211
282
|
}
|
|
212
283
|
}
|
|
284
|
+
function configureEnvFile(targetDirectory, databaseUrl) {
|
|
285
|
+
const envExamplePath = path.join(targetDirectory, ".env.example");
|
|
286
|
+
const envPath = path.join(targetDirectory, ".env");
|
|
287
|
+
if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
|
|
288
|
+
fs.copyFileSync(envExamplePath, envPath);
|
|
289
|
+
const jwtSecret = crypto.randomBytes(32).toString("hex");
|
|
290
|
+
const dbPassword = crypto.randomBytes(16).toString("hex");
|
|
291
|
+
let envContent = fs.readFileSync(envPath, "utf-8");
|
|
292
|
+
envContent = envContent.replace(
|
|
293
|
+
/^JWT_SECRET=.*$/m,
|
|
294
|
+
`JWT_SECRET=${jwtSecret}`
|
|
295
|
+
);
|
|
296
|
+
if (databaseUrl) {
|
|
297
|
+
envContent = envContent.replace(
|
|
298
|
+
/^DATABASE_URL=.*$/m,
|
|
299
|
+
`DATABASE_URL=${databaseUrl}`
|
|
300
|
+
);
|
|
301
|
+
} else {
|
|
302
|
+
envContent = envContent.replace(
|
|
303
|
+
/^DATABASE_URL=.*$/m,
|
|
304
|
+
`DATABASE_URL=postgresql://rebase:${dbPassword}@localhost:5432/rebase`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
fs.writeFileSync(envPath, envContent, "utf-8");
|
|
308
|
+
}
|
|
309
|
+
}
|
|
213
310
|
async function loadCollections(collectionsDir) {
|
|
214
311
|
const absDir = path.resolve(collectionsDir);
|
|
215
312
|
if (!fs.existsSync(absDir)) {
|
|
@@ -380,6 +477,7 @@ Expected a default export of EntityCollection[] or an object with named collecti
|
|
|
380
477
|
path.join(backendDir, "node_modules", pluginName, "src", "cli.ts"),
|
|
381
478
|
path.join(backendDir, "node_modules", pluginName, "dist", "cli.js"),
|
|
382
479
|
// For monorepo dev mode:
|
|
480
|
+
path.resolve(backendDir, "..", "..", "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts"),
|
|
383
481
|
path.resolve(backendDir, "..", "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts"),
|
|
384
482
|
path.resolve(backendDir, "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts")
|
|
385
483
|
];
|
|
@@ -502,11 +600,15 @@ ${chalk.green.bold("Usage")}
|
|
|
502
600
|
${chalk.green.bold("Commands")}
|
|
503
601
|
${chalk.gray("(Commands are provided by your active database driver plugin)")}
|
|
504
602
|
${chalk.blue.bold("generate")} Generate Schema from collection definitions
|
|
603
|
+
${chalk.blue.bold("introspect")} Introspect an existing database to generate collection definitions
|
|
505
604
|
|
|
506
605
|
${chalk.green.bold("generate Options")}
|
|
507
606
|
${chalk.blue("--collections, -c")} Path to collections directory
|
|
508
607
|
${chalk.blue("--output, -o")} Output path for generated schema
|
|
509
608
|
${chalk.blue("--watch, -w")} Watch for changes and regenerate automatically
|
|
609
|
+
|
|
610
|
+
${chalk.green.bold("introspect Options")}
|
|
611
|
+
${chalk.blue("--output, -o")} Output directory for generated collection files
|
|
510
612
|
`);
|
|
511
613
|
}
|
|
512
614
|
async function dbCommand(subcommand, rawArgs) {
|
|
@@ -1178,6 +1280,7 @@ ${chalk.gray("Documentation: https://rebase.pro/docs")}
|
|
|
1178
1280
|
}
|
|
1179
1281
|
}
|
|
1180
1282
|
exports2.authCommand = authCommand;
|
|
1283
|
+
exports2.configureEnvFile = configureEnvFile;
|
|
1181
1284
|
exports2.createRebaseApp = createRebaseApp;
|
|
1182
1285
|
exports2.dbCommand = dbCommand;
|
|
1183
1286
|
exports2.devCommand = devCommand;
|