zuro-cli 0.0.2-beta.4 → 0.0.2-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +91 -66
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +91 -66
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -202,18 +202,23 @@ async function ensurePackageManagerAvailable(pm) {
|
|
|
202
202
|
);
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
|
-
async function initPackageJson(cwd, force = false, packageName = "zuro-app", srcDir = "src") {
|
|
205
|
+
async function initPackageJson(cwd, force = false, packageName = "zuro-app", srcDir = "src", options = {}) {
|
|
206
206
|
const pkgPath = import_path.default.join(cwd, "package.json");
|
|
207
207
|
if (force || !await import_fs_extra.default.pathExists(pkgPath)) {
|
|
208
|
+
const scripts = {
|
|
209
|
+
"dev": `tsx watch ${srcDir}/server.ts`,
|
|
210
|
+
"build": "tsc",
|
|
211
|
+
"start": "node dist/server.js"
|
|
212
|
+
};
|
|
213
|
+
if (options.enablePrettier) {
|
|
214
|
+
scripts["format"] = "prettier --write .";
|
|
215
|
+
scripts["format:check"] = "prettier --check .";
|
|
216
|
+
}
|
|
208
217
|
await import_fs_extra.default.writeJson(pkgPath, {
|
|
209
218
|
name: normalizePackageName(packageName),
|
|
210
219
|
version: "0.0.1",
|
|
211
220
|
private: true,
|
|
212
|
-
scripts
|
|
213
|
-
"dev": `tsx watch ${srcDir}/server.ts`,
|
|
214
|
-
"build": "tsc",
|
|
215
|
-
"start": "node dist/server.js"
|
|
216
|
-
}
|
|
221
|
+
scripts
|
|
217
222
|
}, { spaces: 2 });
|
|
218
223
|
}
|
|
219
224
|
}
|
|
@@ -402,6 +407,13 @@ function showNonZuroProjectMessage() {
|
|
|
402
407
|
console.log("- a fresh/empty directory, or");
|
|
403
408
|
console.log("- an existing project already managed by Zuro CLI.");
|
|
404
409
|
}
|
|
410
|
+
function showInitFirstMessage() {
|
|
411
|
+
console.log(import_chalk.default.yellow("No Zuro project found in this directory."));
|
|
412
|
+
console.log("");
|
|
413
|
+
console.log(import_chalk.default.yellow("Run init first, then add modules."));
|
|
414
|
+
console.log("");
|
|
415
|
+
console.log(import_chalk.default.cyan("npx zuro-cli init"));
|
|
416
|
+
}
|
|
405
417
|
|
|
406
418
|
// src/commands/init.ts
|
|
407
419
|
function resolveSafeTargetPath(projectRoot, srcDir, file) {
|
|
@@ -431,6 +443,33 @@ async function ensureSafeTargetDirectory(targetDir, cwd, projectName) {
|
|
|
431
443
|
});
|
|
432
444
|
return response.proceed === true;
|
|
433
445
|
}
|
|
446
|
+
async function setupPrettier(targetDir) {
|
|
447
|
+
const prettierConfigPath = import_path4.default.join(targetDir, ".prettierrc");
|
|
448
|
+
const prettierIgnorePath = import_path4.default.join(targetDir, ".prettierignore");
|
|
449
|
+
if (!await import_fs_extra4.default.pathExists(prettierConfigPath)) {
|
|
450
|
+
const prettierConfig = {
|
|
451
|
+
semi: true,
|
|
452
|
+
singleQuote: false,
|
|
453
|
+
trailingComma: "es5",
|
|
454
|
+
printWidth: 100,
|
|
455
|
+
tabWidth: 2
|
|
456
|
+
};
|
|
457
|
+
await import_fs_extra4.default.writeJson(prettierConfigPath, prettierConfig, { spaces: 2 });
|
|
458
|
+
}
|
|
459
|
+
if (!await import_fs_extra4.default.pathExists(prettierIgnorePath)) {
|
|
460
|
+
const ignoreContent = `node_modules
|
|
461
|
+
dist
|
|
462
|
+
build
|
|
463
|
+
coverage
|
|
464
|
+
.next
|
|
465
|
+
pnpm-lock.yaml
|
|
466
|
+
package-lock.json
|
|
467
|
+
bun.lock
|
|
468
|
+
bun.lockb
|
|
469
|
+
`;
|
|
470
|
+
await import_fs_extra4.default.writeFile(prettierIgnorePath, ignoreContent);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
434
473
|
async function init() {
|
|
435
474
|
const cwd = process.cwd();
|
|
436
475
|
const isExistingProject = await import_fs_extra4.default.pathExists(import_path4.default.join(cwd, "package.json"));
|
|
@@ -443,6 +482,7 @@ async function init() {
|
|
|
443
482
|
let pm = "npm";
|
|
444
483
|
let srcDir = "src";
|
|
445
484
|
let projectName = import_path4.default.basename(cwd);
|
|
485
|
+
let enablePrettier = false;
|
|
446
486
|
if (isExistingProject) {
|
|
447
487
|
console.log(import_chalk2.default.blue("\u2139 Existing project detected."));
|
|
448
488
|
projectName = import_path4.default.basename(cwd);
|
|
@@ -480,6 +520,12 @@ async function init() {
|
|
|
480
520
|
{ title: "bun", value: "bun" }
|
|
481
521
|
],
|
|
482
522
|
initial: 0
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
type: "confirm",
|
|
526
|
+
name: "prettier",
|
|
527
|
+
message: "Setup Prettier?",
|
|
528
|
+
initial: true
|
|
483
529
|
}
|
|
484
530
|
]);
|
|
485
531
|
if (response.pm === void 0) {
|
|
@@ -487,6 +533,7 @@ async function init() {
|
|
|
487
533
|
return;
|
|
488
534
|
}
|
|
489
535
|
pm = response.pm;
|
|
536
|
+
enablePrettier = response.prettier === true;
|
|
490
537
|
srcDir = "src";
|
|
491
538
|
if (!response.path || response.path.trim() === "") {
|
|
492
539
|
projectName = import_path4.default.basename(cwd);
|
|
@@ -525,7 +572,7 @@ async function init() {
|
|
|
525
572
|
spinner.text = "Initializing project...";
|
|
526
573
|
const hasPackageJson = await import_fs_extra4.default.pathExists(import_path4.default.join(targetDir, "package.json"));
|
|
527
574
|
if (!hasPackageJson) {
|
|
528
|
-
await initPackageJson(targetDir, true, projectName, srcDir);
|
|
575
|
+
await initPackageJson(targetDir, true, projectName, srcDir, { enablePrettier });
|
|
529
576
|
}
|
|
530
577
|
currentStep = "dependency installation";
|
|
531
578
|
spinner.text = `Installing dependencies using ${pm}...`;
|
|
@@ -542,6 +589,9 @@ async function init() {
|
|
|
542
589
|
}
|
|
543
590
|
await installDependencies(pm, runtimeDeps, targetDir);
|
|
544
591
|
await installDependencies(pm, devDeps, targetDir, { dev: true });
|
|
592
|
+
if (enablePrettier) {
|
|
593
|
+
await installDependencies(pm, ["prettier"], targetDir, { dev: true });
|
|
594
|
+
}
|
|
545
595
|
currentStep = "module file generation";
|
|
546
596
|
spinner.text = "Fetching core module files...";
|
|
547
597
|
for (const file of coreModule.files) {
|
|
@@ -567,6 +617,10 @@ async function init() {
|
|
|
567
617
|
}
|
|
568
618
|
currentStep = "environment file setup";
|
|
569
619
|
await createInitialEnv(targetDir);
|
|
620
|
+
if (enablePrettier) {
|
|
621
|
+
currentStep = "prettier setup";
|
|
622
|
+
await setupPrettier(targetDir);
|
|
623
|
+
}
|
|
570
624
|
currentStep = "config write";
|
|
571
625
|
await writeZuroConfig(targetDir, zuroConfig);
|
|
572
626
|
spinner.succeed(import_chalk2.default.green("Project initialized successfully!"));
|
|
@@ -751,6 +805,12 @@ function getDatabaseSetupHint(moduleName, dbUrl) {
|
|
|
751
805
|
return moduleName === "database-pg" ? "createdb <database_name>" : `mysql -e "CREATE DATABASE IF NOT EXISTS <database_name>;"`;
|
|
752
806
|
}
|
|
753
807
|
}
|
|
808
|
+
function getModuleDocsPath(moduleName) {
|
|
809
|
+
if (isDatabaseModule(moduleName)) {
|
|
810
|
+
return "database";
|
|
811
|
+
}
|
|
812
|
+
return moduleName;
|
|
813
|
+
}
|
|
754
814
|
function escapeRegex(value) {
|
|
755
815
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
756
816
|
}
|
|
@@ -763,6 +823,11 @@ async function hasEnvVariable(projectRoot, key) {
|
|
|
763
823
|
const pattern = new RegExp(`^${escapeRegex(key)}=`, "m");
|
|
764
824
|
return pattern.test(content);
|
|
765
825
|
}
|
|
826
|
+
async function isLikelyEmptyDirectory(cwd) {
|
|
827
|
+
const entries = await import_fs_extra6.default.readdir(cwd);
|
|
828
|
+
const ignored = /* @__PURE__ */ new Set([".ds_store", "thumbs.db"]);
|
|
829
|
+
return entries.filter((entry) => !ignored.has(entry.toLowerCase())).length === 0;
|
|
830
|
+
}
|
|
766
831
|
async function injectErrorHandler(projectRoot, srcDir) {
|
|
767
832
|
const appPath = import_path6.default.join(projectRoot, srcDir, "app.ts");
|
|
768
833
|
if (!import_fs_extra6.default.existsSync(appPath)) {
|
|
@@ -878,6 +943,10 @@ var add = async (moduleName) => {
|
|
|
878
943
|
const projectRoot = process.cwd();
|
|
879
944
|
const projectConfig = await readZuroConfig(projectRoot);
|
|
880
945
|
if (!projectConfig) {
|
|
946
|
+
if (await isLikelyEmptyDirectory(projectRoot)) {
|
|
947
|
+
showInitFirstMessage();
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
881
950
|
showNonZuroProjectMessage();
|
|
882
951
|
return;
|
|
883
952
|
}
|
|
@@ -1052,71 +1121,27 @@ var add = async (moduleName) => {
|
|
|
1052
1121
|
console.log(import_chalk4.default.blue(`\u2139 Backup created at: ${databaseBackupPath}
|
|
1053
1122
|
`));
|
|
1054
1123
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
} else {
|
|
1060
|
-
console.log(import_chalk4.default.yellow("1. Review your auth env values in .env."));
|
|
1061
|
-
}
|
|
1062
|
-
console.log(import_chalk4.default.dim(" Make sure BETTER_AUTH_URL matches your API origin (for example http://localhost:3000).\n"));
|
|
1063
|
-
console.log(import_chalk4.default.yellow("2. Run database migrations:"));
|
|
1064
|
-
console.log(import_chalk4.default.cyan(" npx drizzle-kit generate"));
|
|
1065
|
-
console.log(import_chalk4.default.cyan(" npx drizzle-kit migrate\n"));
|
|
1066
|
-
console.log(import_chalk4.default.yellow("3. Available endpoints:"));
|
|
1067
|
-
console.log(import_chalk4.default.dim(" POST /auth/sign-up/email - Register"));
|
|
1068
|
-
console.log(import_chalk4.default.dim(" POST /auth/sign-in/email - Login"));
|
|
1069
|
-
console.log(import_chalk4.default.dim(" POST /auth/sign-out - Logout"));
|
|
1070
|
-
console.log(import_chalk4.default.dim(" GET /api/users/me - Current user\n"));
|
|
1071
|
-
} else if (resolvedModuleName === "error-handler") {
|
|
1072
|
-
console.log(import_chalk4.default.bold("\u{1F4CB} Usage:\n"));
|
|
1073
|
-
console.log(import_chalk4.default.yellow("Throw errors in your controllers:"));
|
|
1074
|
-
console.log(import_chalk4.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1075
|
-
console.log(import_chalk4.default.white(` import { UnauthorizedError, NotFoundError } from "./lib/errors";`));
|
|
1076
|
-
console.log("");
|
|
1077
|
-
console.log(import_chalk4.default.white(` throw new UnauthorizedError("Invalid credentials");`));
|
|
1078
|
-
console.log(import_chalk4.default.white(` throw new NotFoundError("User not found");`));
|
|
1079
|
-
console.log(import_chalk4.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n"));
|
|
1080
|
-
console.log(import_chalk4.default.yellow("Available error classes:"));
|
|
1081
|
-
console.log(import_chalk4.default.dim(" BadRequestError (400)"));
|
|
1082
|
-
console.log(import_chalk4.default.dim(" UnauthorizedError (401)"));
|
|
1083
|
-
console.log(import_chalk4.default.dim(" ForbiddenError (403)"));
|
|
1084
|
-
console.log(import_chalk4.default.dim(" NotFoundError (404)"));
|
|
1085
|
-
console.log(import_chalk4.default.dim(" ConflictError (409)"));
|
|
1086
|
-
console.log(import_chalk4.default.dim(" ValidationError (422)"));
|
|
1087
|
-
console.log(import_chalk4.default.dim(" InternalServerError (500)\n"));
|
|
1088
|
-
console.log(import_chalk4.default.yellow("Wrap async handlers:"));
|
|
1089
|
-
console.log(import_chalk4.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1090
|
-
console.log(import_chalk4.default.white(` import { asyncHandler } from "./middleware/error-handler";`));
|
|
1091
|
-
console.log("");
|
|
1092
|
-
console.log(import_chalk4.default.white(` router.get("/users", asyncHandler(async (req, res) => {`));
|
|
1093
|
-
console.log(import_chalk4.default.white(" // errors auto-caught"));
|
|
1094
|
-
console.log(import_chalk4.default.white(" }));"));
|
|
1095
|
-
console.log(import_chalk4.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n"));
|
|
1096
|
-
} else if (isDatabaseModule(resolvedModuleName)) {
|
|
1097
|
-
console.log(import_chalk4.default.bold("\u{1F4CB} Next Steps:\n"));
|
|
1098
|
-
let stepNum = 1;
|
|
1124
|
+
const docsPath = getModuleDocsPath(resolvedModuleName);
|
|
1125
|
+
const docsUrl = `https://zuro-cli.devbybriyan.com/docs/${docsPath}`;
|
|
1126
|
+
console.log(import_chalk4.default.blue(`\u2139 Docs: ${docsUrl}`));
|
|
1127
|
+
if (isDatabaseModule(resolvedModuleName)) {
|
|
1099
1128
|
if (usedDefaultDbUrl) {
|
|
1100
|
-
console.log(import_chalk4.default.yellow(
|
|
1101
|
-
console.log(
|
|
1102
|
-
import_chalk4.default.dim(" We added a local default. Update it if your DB host/user/password differ.\n")
|
|
1103
|
-
);
|
|
1104
|
-
stepNum++;
|
|
1129
|
+
console.log(import_chalk4.default.yellow("\u2139 Review DATABASE_URL in .env if your local DB config differs."));
|
|
1105
1130
|
}
|
|
1106
|
-
console.log(import_chalk4.default.yellow(`${stepNum}. Create schemas in ${srcDir}/db/schema/:`));
|
|
1107
|
-
console.log(import_chalk4.default.dim(" Add table files and export from index.ts\n"));
|
|
1108
|
-
stepNum++;
|
|
1109
1131
|
const setupHint = getDatabaseSetupHint(
|
|
1110
1132
|
resolvedModuleName,
|
|
1111
1133
|
customDbUrl || DEFAULT_DATABASE_URLS[resolvedModuleName]
|
|
1112
1134
|
);
|
|
1113
|
-
console.log(import_chalk4.default.yellow(
|
|
1114
|
-
console.log(import_chalk4.default.
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1135
|
+
console.log(import_chalk4.default.yellow(`\u2139 Ensure DB exists: ${setupHint}`));
|
|
1136
|
+
console.log(import_chalk4.default.yellow("\u2139 Run migrations: npx drizzle-kit generate && npx drizzle-kit migrate"));
|
|
1137
|
+
}
|
|
1138
|
+
if (resolvedModuleName === "auth") {
|
|
1139
|
+
if (generatedAuthSecret) {
|
|
1140
|
+
console.log(import_chalk4.default.yellow("\u2139 BETTER_AUTH_SECRET was generated automatically."));
|
|
1141
|
+
} else {
|
|
1142
|
+
console.log(import_chalk4.default.yellow("\u2139 Review BETTER_AUTH_SECRET and BETTER_AUTH_URL in .env."));
|
|
1143
|
+
}
|
|
1144
|
+
console.log(import_chalk4.default.yellow("\u2139 Run migrations: npx drizzle-kit generate && npx drizzle-kit migrate"));
|
|
1120
1145
|
}
|
|
1121
1146
|
} catch (error) {
|
|
1122
1147
|
spinner.fail(import_chalk4.default.red(`Failed during ${currentStep}.`));
|