@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/index.es.js
CHANGED
|
@@ -80,16 +80,31 @@ async function promptForOptions(rawArgs) {
|
|
|
80
80
|
default: true
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
|
+
questions.push({
|
|
84
|
+
type: "input",
|
|
85
|
+
name: "databaseUrl",
|
|
86
|
+
message: "Enter your PostgreSQL database connection string (leave blank to use a local default):",
|
|
87
|
+
default: ""
|
|
88
|
+
});
|
|
89
|
+
questions.push({
|
|
90
|
+
type: "confirm",
|
|
91
|
+
name: "introspect",
|
|
92
|
+
message: "Would you like to introspect this database to automatically generate collections?",
|
|
93
|
+
default: true,
|
|
94
|
+
when: (answers2) => !!answers2.databaseUrl?.trim()
|
|
95
|
+
});
|
|
83
96
|
const answers = await inquirer.prompt(questions);
|
|
84
|
-
const
|
|
85
|
-
const
|
|
97
|
+
const targetDirectory = path.resolve(process.cwd(), nameArg || answers.projectName);
|
|
98
|
+
const projectName = path.basename(targetDirectory);
|
|
86
99
|
const templateDirectory = path.resolve(cliRoot, "templates", "template");
|
|
87
100
|
return {
|
|
88
101
|
projectName,
|
|
89
102
|
git: args["--git"] || answers.git || false,
|
|
90
103
|
installDeps: args["--install"] || answers.installDeps || false,
|
|
91
104
|
targetDirectory,
|
|
92
|
-
templateDirectory
|
|
105
|
+
templateDirectory,
|
|
106
|
+
databaseUrl: answers.databaseUrl?.trim() || void 0,
|
|
107
|
+
introspect: answers.introspect || false
|
|
93
108
|
};
|
|
94
109
|
}
|
|
95
110
|
async function createProject(options) {
|
|
@@ -122,27 +137,7 @@ async function createProject(options) {
|
|
|
122
137
|
process.exit(1);
|
|
123
138
|
}
|
|
124
139
|
await replacePlaceholders(options);
|
|
125
|
-
|
|
126
|
-
const envPath = path.join(options.targetDirectory, ".env");
|
|
127
|
-
if (fs.existsSync(envTemplatePath) && !fs.existsSync(envPath)) {
|
|
128
|
-
fs.renameSync(envTemplatePath, envPath);
|
|
129
|
-
const jwtSecret = crypto.randomBytes(32).toString("hex");
|
|
130
|
-
const dbPassword = crypto.randomBytes(16).toString("hex");
|
|
131
|
-
let envContent = fs.readFileSync(envPath, "utf-8");
|
|
132
|
-
envContent = envContent.replace(
|
|
133
|
-
"postgresql://rebase:password@localhost:5432/rebase",
|
|
134
|
-
`postgresql://rebase:${dbPassword}@localhost:5432/rebase`
|
|
135
|
-
);
|
|
136
|
-
envContent = envContent.replace(
|
|
137
|
-
"change-this-to-a-secure-random-string",
|
|
138
|
-
jwtSecret
|
|
139
|
-
);
|
|
140
|
-
envContent += `
|
|
141
|
-
# Docker Compose Database Password
|
|
142
|
-
POSTGRES_PASSWORD=${dbPassword}
|
|
143
|
-
`;
|
|
144
|
-
fs.writeFileSync(envPath, envContent, "utf-8");
|
|
145
|
-
}
|
|
140
|
+
configureEnvFile(options.targetDirectory, options.databaseUrl);
|
|
146
141
|
if (options.git) {
|
|
147
142
|
console.log(chalk.gray(" Initializing git repository..."));
|
|
148
143
|
try {
|
|
@@ -164,6 +159,26 @@ POSTGRES_PASSWORD=${dbPassword}
|
|
|
164
159
|
console.warn(chalk.yellow(" Warning: Failed to install dependencies. You may need to run `pnpm install` manually."));
|
|
165
160
|
}
|
|
166
161
|
}
|
|
162
|
+
if (options.introspect) {
|
|
163
|
+
console.log("");
|
|
164
|
+
if (options.installDeps) {
|
|
165
|
+
console.log(chalk.gray(" Introspecting database and generating collections..."));
|
|
166
|
+
console.log("");
|
|
167
|
+
try {
|
|
168
|
+
await execa("pnpm", ["exec", "rebase", "schema", "introspect", "--force"], {
|
|
169
|
+
cwd: options.targetDirectory,
|
|
170
|
+
stdio: "inherit"
|
|
171
|
+
});
|
|
172
|
+
console.log(chalk.green(" Database successfully introspected!"));
|
|
173
|
+
} catch {
|
|
174
|
+
console.warn(chalk.yellow(" Warning: Failed to introspect database automatically."));
|
|
175
|
+
console.warn(chalk.yellow(" You can run `pnpm exec rebase schema introspect` manually after setup."));
|
|
176
|
+
}
|
|
177
|
+
} else {
|
|
178
|
+
console.warn(chalk.yellow(" Skipping introspection because dependencies were not installed."));
|
|
179
|
+
console.warn(chalk.yellow(" Run `pnpm install` then `pnpm exec rebase schema introspect` manually."));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
167
182
|
console.log("");
|
|
168
183
|
console.log(`${chalk.green.bold("✓")} Project ${chalk.bold(options.projectName)} created successfully!`);
|
|
169
184
|
console.log("");
|
|
@@ -174,8 +189,15 @@ POSTGRES_PASSWORD=${dbPassword}
|
|
|
174
189
|
console.log(` ${chalk.cyan("pnpm install")}`);
|
|
175
190
|
}
|
|
176
191
|
console.log("");
|
|
177
|
-
|
|
178
|
-
|
|
192
|
+
if (options.databaseUrl) {
|
|
193
|
+
console.log(chalk.gray(" # Your database is configured! Start the dev server:"));
|
|
194
|
+
} else {
|
|
195
|
+
console.log(chalk.gray(" # A local database configuration has been generated in .env."));
|
|
196
|
+
console.log(chalk.gray(" # If using the included docker-compose.yml, start it with:"));
|
|
197
|
+
console.log(` ${chalk.cyan("docker compose up -d")}`);
|
|
198
|
+
console.log("");
|
|
199
|
+
console.log(chalk.gray(" # Then start the dev server:"));
|
|
200
|
+
}
|
|
179
201
|
console.log("");
|
|
180
202
|
console.log(` ${chalk.cyan("pnpm dev")}`);
|
|
181
203
|
console.log("");
|
|
@@ -193,14 +215,89 @@ async function replacePlaceholders(options) {
|
|
|
193
215
|
"config/package.json",
|
|
194
216
|
"frontend/index.html"
|
|
195
217
|
];
|
|
218
|
+
const packageJsonPath = path.resolve(cliRoot, "package.json");
|
|
219
|
+
let cliVersion = "latest";
|
|
220
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
221
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
222
|
+
cliVersion = pkg.version || "latest";
|
|
223
|
+
}
|
|
224
|
+
const versionCache = /* @__PURE__ */ new Map();
|
|
225
|
+
const getPackageVersion = async (pkgName) => {
|
|
226
|
+
if (versionCache.has(pkgName)) return versionCache.get(pkgName);
|
|
227
|
+
let versionToUse = cliVersion;
|
|
228
|
+
try {
|
|
229
|
+
const { stdout } = await execa("pnpm", ["view", `${pkgName}@${cliVersion}`, "version"]);
|
|
230
|
+
if (!stdout.trim()) throw new Error("Not found");
|
|
231
|
+
versionToUse = stdout.trim();
|
|
232
|
+
} catch {
|
|
233
|
+
try {
|
|
234
|
+
const tag = cliVersion.includes("canary") ? "canary" : "latest";
|
|
235
|
+
const { stdout } = await execa("pnpm", ["view", `${pkgName}@${tag}`, "version"]);
|
|
236
|
+
if (!stdout.trim()) throw new Error("Not found");
|
|
237
|
+
versionToUse = stdout.trim();
|
|
238
|
+
} catch {
|
|
239
|
+
try {
|
|
240
|
+
const { stdout } = await execa("pnpm", ["view", pkgName, "version"]);
|
|
241
|
+
versionToUse = stdout.trim() || "latest";
|
|
242
|
+
} catch {
|
|
243
|
+
versionToUse = "latest";
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
versionCache.set(pkgName, versionToUse);
|
|
248
|
+
return versionToUse;
|
|
249
|
+
};
|
|
250
|
+
const allPackages = /* @__PURE__ */ new Set();
|
|
251
|
+
const fileContents = /* @__PURE__ */ new Map();
|
|
196
252
|
for (const file of filesToProcess) {
|
|
197
253
|
const fullPath = path.resolve(options.targetDirectory, file);
|
|
198
254
|
if (!fs.existsSync(fullPath)) continue;
|
|
199
|
-
|
|
200
|
-
|
|
255
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
256
|
+
fileContents.set(fullPath, content);
|
|
257
|
+
const matches = [...content.matchAll(/"(@rebasepro\/[^"]+)":\s*"workspace:\*"/g)];
|
|
258
|
+
for (const match of matches) {
|
|
259
|
+
allPackages.add(match[1]);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
console.log(chalk.gray(" Resolving package versions..."));
|
|
263
|
+
await Promise.all(Array.from(allPackages).map(getPackageVersion));
|
|
264
|
+
for (const [fullPath, originalContent] of fileContents.entries()) {
|
|
265
|
+
let content = originalContent.replace(/\{\{PROJECT_NAME\}\}/g, options.projectName);
|
|
266
|
+
const matches = [...content.matchAll(/"(@rebasepro\/[^"]+)":\s*"workspace:\*"/g)];
|
|
267
|
+
for (const match of matches) {
|
|
268
|
+
const pkgName = match[1];
|
|
269
|
+
const resolvedVersion = versionCache.get(pkgName) || "latest";
|
|
270
|
+
content = content.replace(new RegExp(`"${pkgName}":\\s*"workspace:\\*"`, "g"), `"${pkgName}": "${resolvedVersion}"`);
|
|
271
|
+
}
|
|
201
272
|
fs.writeFileSync(fullPath, content, "utf-8");
|
|
202
273
|
}
|
|
203
274
|
}
|
|
275
|
+
function configureEnvFile(targetDirectory, databaseUrl) {
|
|
276
|
+
const envExamplePath = path.join(targetDirectory, ".env.example");
|
|
277
|
+
const envPath = path.join(targetDirectory, ".env");
|
|
278
|
+
if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
|
|
279
|
+
fs.copyFileSync(envExamplePath, envPath);
|
|
280
|
+
const jwtSecret = crypto.randomBytes(32).toString("hex");
|
|
281
|
+
const dbPassword = crypto.randomBytes(16).toString("hex");
|
|
282
|
+
let envContent = fs.readFileSync(envPath, "utf-8");
|
|
283
|
+
envContent = envContent.replace(
|
|
284
|
+
/^JWT_SECRET=.*$/m,
|
|
285
|
+
`JWT_SECRET=${jwtSecret}`
|
|
286
|
+
);
|
|
287
|
+
if (databaseUrl) {
|
|
288
|
+
envContent = envContent.replace(
|
|
289
|
+
/^DATABASE_URL=.*$/m,
|
|
290
|
+
`DATABASE_URL=${databaseUrl}`
|
|
291
|
+
);
|
|
292
|
+
} else {
|
|
293
|
+
envContent = envContent.replace(
|
|
294
|
+
/^DATABASE_URL=.*$/m,
|
|
295
|
+
`DATABASE_URL=postgresql://rebase:${dbPassword}@localhost:5432/rebase`
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
fs.writeFileSync(envPath, envContent, "utf-8");
|
|
299
|
+
}
|
|
300
|
+
}
|
|
204
301
|
async function loadCollections(collectionsDir) {
|
|
205
302
|
const absDir = path.resolve(collectionsDir);
|
|
206
303
|
if (!fs.existsSync(absDir)) {
|
|
@@ -371,6 +468,7 @@ function resolvePluginCliScript(backendDir, pluginName) {
|
|
|
371
468
|
path.join(backendDir, "node_modules", pluginName, "src", "cli.ts"),
|
|
372
469
|
path.join(backendDir, "node_modules", pluginName, "dist", "cli.js"),
|
|
373
470
|
// For monorepo dev mode:
|
|
471
|
+
path.resolve(backendDir, "..", "..", "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts"),
|
|
374
472
|
path.resolve(backendDir, "..", "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts"),
|
|
375
473
|
path.resolve(backendDir, "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts")
|
|
376
474
|
];
|
|
@@ -493,11 +591,15 @@ ${chalk.green.bold("Usage")}
|
|
|
493
591
|
${chalk.green.bold("Commands")}
|
|
494
592
|
${chalk.gray("(Commands are provided by your active database driver plugin)")}
|
|
495
593
|
${chalk.blue.bold("generate")} Generate Schema from collection definitions
|
|
594
|
+
${chalk.blue.bold("introspect")} Introspect an existing database to generate collection definitions
|
|
496
595
|
|
|
497
596
|
${chalk.green.bold("generate Options")}
|
|
498
597
|
${chalk.blue("--collections, -c")} Path to collections directory
|
|
499
598
|
${chalk.blue("--output, -o")} Output path for generated schema
|
|
500
599
|
${chalk.blue("--watch, -w")} Watch for changes and regenerate automatically
|
|
600
|
+
|
|
601
|
+
${chalk.green.bold("introspect Options")}
|
|
602
|
+
${chalk.blue("--output, -o")} Output directory for generated collection files
|
|
501
603
|
`);
|
|
502
604
|
}
|
|
503
605
|
async function dbCommand(subcommand, rawArgs) {
|
|
@@ -1170,6 +1272,7 @@ async function logout(env, _debug) {
|
|
|
1170
1272
|
}
|
|
1171
1273
|
export {
|
|
1172
1274
|
authCommand,
|
|
1275
|
+
configureEnvFile,
|
|
1173
1276
|
createRebaseApp,
|
|
1174
1277
|
dbCommand,
|
|
1175
1278
|
devCommand,
|