@kozojs/cli 0.1.10 → 0.1.12
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/lib/index.js +160 -46
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -35,15 +35,15 @@ var import_execa = require("execa");
|
|
|
35
35
|
var import_fs_extra = __toESM(require("fs-extra"));
|
|
36
36
|
var import_node_path = __toESM(require("path"));
|
|
37
37
|
async function scaffoldProject(options) {
|
|
38
|
-
const { projectName, runtime, database, packageSource, template, frontend, extras } = options;
|
|
38
|
+
const { projectName, runtime, database, dbPort, auth, packageSource, template, frontend, extras } = options;
|
|
39
39
|
const projectDir = import_node_path.default.resolve(process.cwd(), projectName);
|
|
40
40
|
const kozoCoreDep = packageSource === "local" ? "workspace:*" : "^0.2.0";
|
|
41
41
|
if (frontend !== "none") {
|
|
42
|
-
await scaffoldFullstackProject(projectDir, projectName, kozoCoreDep, runtime, database, frontend, extras, template);
|
|
42
|
+
await scaffoldFullstackProject(projectDir, projectName, kozoCoreDep, runtime, database, dbPort, auth, frontend, extras, template);
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
if (template === "complete") {
|
|
46
|
-
await scaffoldCompleteTemplate(projectDir, projectName, kozoCoreDep, runtime);
|
|
46
|
+
await scaffoldCompleteTemplate(projectDir, projectName, kozoCoreDep, runtime, database, dbPort, auth);
|
|
47
47
|
if (extras.includes("docker")) await createDockerfile(projectDir, runtime);
|
|
48
48
|
if (extras.includes("github-actions")) await createGitHubActions(projectDir);
|
|
49
49
|
return;
|
|
@@ -411,7 +411,7 @@ export default async ({ body, services: { db } }: HandlerContext<Body>) => {
|
|
|
411
411
|
`;
|
|
412
412
|
await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "routes", "users", "post.ts"), postUsersRoute);
|
|
413
413
|
}
|
|
414
|
-
async function scaffoldCompleteTemplate(projectDir, projectName, kozoCoreDep, runtime) {
|
|
414
|
+
async function scaffoldCompleteTemplate(projectDir, projectName, kozoCoreDep, runtime, database = "none", dbPort, auth = true) {
|
|
415
415
|
await import_fs_extra.default.ensureDir(projectDir);
|
|
416
416
|
await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src"));
|
|
417
417
|
await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "schemas"));
|
|
@@ -422,6 +422,15 @@ async function scaffoldCompleteTemplate(projectDir, projectName, kozoCoreDep, ru
|
|
|
422
422
|
await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "middleware"));
|
|
423
423
|
await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "utils"));
|
|
424
424
|
await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "data"));
|
|
425
|
+
const hasDb = database !== "none";
|
|
426
|
+
if (hasDb) {
|
|
427
|
+
await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "db"));
|
|
428
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "db", "schema.ts"), getDatabaseSchema(database));
|
|
429
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "db", "index.ts"), getDatabaseIndex(database));
|
|
430
|
+
if (database === "sqlite") {
|
|
431
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "db", "seed.ts"), getSQLiteSeed());
|
|
432
|
+
}
|
|
433
|
+
}
|
|
425
434
|
const packageJson = {
|
|
426
435
|
name: projectName,
|
|
427
436
|
version: "1.0.0",
|
|
@@ -430,19 +439,30 @@ async function scaffoldCompleteTemplate(projectDir, projectName, kozoCoreDep, ru
|
|
|
430
439
|
dev: "tsx watch src/index.ts",
|
|
431
440
|
build: "tsc",
|
|
432
441
|
start: "node dist/index.js",
|
|
433
|
-
"type-check": "tsc --noEmit"
|
|
442
|
+
"type-check": "tsc --noEmit",
|
|
443
|
+
...hasDb && {
|
|
444
|
+
"db:generate": "drizzle-kit generate",
|
|
445
|
+
"db:push": "drizzle-kit push",
|
|
446
|
+
"db:studio": "drizzle-kit studio"
|
|
447
|
+
}
|
|
434
448
|
},
|
|
435
449
|
dependencies: {
|
|
436
450
|
"@kozojs/core": kozoCoreDep,
|
|
437
|
-
"@kozojs/auth": kozoCoreDep,
|
|
451
|
+
...auth && { "@kozojs/auth": kozoCoreDep },
|
|
438
452
|
"@hono/node-server": "^1.13.0",
|
|
439
453
|
hono: "^4.6.0",
|
|
440
|
-
zod: "^3.23.0"
|
|
454
|
+
zod: "^3.23.0",
|
|
455
|
+
...hasDb && { "drizzle-orm": "^0.36.0" },
|
|
456
|
+
...database === "postgresql" && { postgres: "^3.4.0" },
|
|
457
|
+
...database === "mysql" && { mysql2: "^3.11.0" },
|
|
458
|
+
...database === "sqlite" && { "better-sqlite3": "^11.0.0" }
|
|
441
459
|
},
|
|
442
460
|
devDependencies: {
|
|
443
461
|
"@types/node": "^22.0.0",
|
|
444
462
|
tsx: "^4.19.0",
|
|
445
|
-
typescript: "^5.6.0"
|
|
463
|
+
typescript: "^5.6.0",
|
|
464
|
+
...hasDb && { "drizzle-kit": "^0.28.0" },
|
|
465
|
+
...database === "sqlite" && { "@types/better-sqlite3": "^7.6.0" }
|
|
446
466
|
}
|
|
447
467
|
};
|
|
448
468
|
await import_fs_extra.default.writeJSON(import_node_path.default.join(projectDir, "package.json"), packageJson, { spaces: 2 });
|
|
@@ -471,13 +491,18 @@ dist/
|
|
|
471
491
|
*.log
|
|
472
492
|
`;
|
|
473
493
|
await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".gitignore"), gitignore);
|
|
494
|
+
const pgPort = dbPort ?? 5436;
|
|
495
|
+
const dbUrl = database === "postgresql" ? `postgresql://postgres:postgres@localhost:${pgPort}/${projectName}` : database === "mysql" ? `mysql://root:root@localhost:3306/${projectName}` : void 0;
|
|
474
496
|
const envExample = `# Server
|
|
475
497
|
PORT=3000
|
|
476
498
|
NODE_ENV=development
|
|
477
|
-
|
|
478
|
-
#
|
|
499
|
+
${database !== "none" && dbUrl ? `
|
|
500
|
+
# Database
|
|
501
|
+
DATABASE_URL=${dbUrl}
|
|
502
|
+
` : ""}
|
|
503
|
+
${auth ? `# JWT Authentication
|
|
479
504
|
JWT_SECRET=change-me-to-a-random-secret-at-least-32-chars
|
|
480
|
-
|
|
505
|
+
` : ""}
|
|
481
506
|
# CORS
|
|
482
507
|
CORS_ORIGIN=http://localhost:5173
|
|
483
508
|
|
|
@@ -487,17 +512,34 @@ RATE_LIMIT_WINDOW=60000
|
|
|
487
512
|
`;
|
|
488
513
|
await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".env.example"), envExample);
|
|
489
514
|
await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".env"), envExample);
|
|
515
|
+
if (hasDb) {
|
|
516
|
+
const dialect = database === "postgresql" ? "postgresql" : database === "mysql" ? "mysql" : "sqlite";
|
|
517
|
+
const drizzleConfig = `import { defineConfig } from 'drizzle-kit';
|
|
518
|
+
import 'dotenv/config';
|
|
519
|
+
|
|
520
|
+
export default defineConfig({
|
|
521
|
+
schema: './src/db/schema.ts',
|
|
522
|
+
out: './drizzle',
|
|
523
|
+
dialect: '${dialect}',
|
|
524
|
+
dbCredentials: {
|
|
525
|
+
${database === "sqlite" ? "url: './data.db'" : "url: process.env.DATABASE_URL!"}
|
|
526
|
+
},
|
|
527
|
+
});
|
|
528
|
+
`;
|
|
529
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "drizzle.config.ts"), drizzleConfig);
|
|
530
|
+
}
|
|
490
531
|
const indexTs = `import { createKozo, cors, logger, rateLimit } from '@kozojs/core';
|
|
491
|
-
import { authenticateJWT } from '@kozojs/auth';
|
|
492
|
-
import { registerAuthRoutes } from './routes/auth/index.js';
|
|
532
|
+
${auth ? "import { authenticateJWT } from '@kozojs/auth';" : ""}
|
|
533
|
+
${auth ? "import { registerAuthRoutes } from './routes/auth/index.js';" : ""}
|
|
493
534
|
import { registerUserRoutes } from './routes/users/index.js';
|
|
494
535
|
import { registerPostRoutes } from './routes/posts/index.js';
|
|
495
536
|
import { registerHealthRoute } from './routes/health.js';
|
|
496
537
|
import { registerStatsRoute } from './routes/stats.js';
|
|
538
|
+
${hasDb ? "import { db } from './db/index.js';" : ""}
|
|
497
539
|
|
|
498
540
|
// \u2500\u2500\u2500 Config \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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
499
541
|
const PORT = Number(process.env.PORT) || 3000;
|
|
500
|
-
const JWT_SECRET = process.env.JWT_SECRET || 'change-me-to-a-random-secret';
|
|
542
|
+
${auth ? "const JWT_SECRET = process.env.JWT_SECRET || 'change-me-to-a-random-secret';" : ""}
|
|
501
543
|
const CORS_ORIGIN = process.env.CORS_ORIGIN || '*';
|
|
502
544
|
const RATE_LIMIT_MAX = Number(process.env.RATE_LIMIT_MAX) || 100;
|
|
503
545
|
const RATE_LIMIT_WINDOW = Number(process.env.RATE_LIMIT_WINDOW) || 60_000;
|
|
@@ -509,13 +551,11 @@ const app = createKozo({ port: PORT });
|
|
|
509
551
|
app.getApp().use('*', logger());
|
|
510
552
|
app.getApp().use('*', cors({ origin: CORS_ORIGIN }));
|
|
511
553
|
app.getApp().use('/api/*', rateLimit({ max: RATE_LIMIT_MAX, windowMs: RATE_LIMIT_WINDOW }));
|
|
512
|
-
app.getApp().use('/api/*', authenticateJWT(JWT_SECRET, {
|
|
513
|
-
prefix: '/api',
|
|
514
|
-
}));
|
|
554
|
+
${auth ? `app.getApp().use('/api/*', authenticateJWT(JWT_SECRET, { prefix: '/api' }));` : ""}
|
|
515
555
|
|
|
516
556
|
// \u2500\u2500\u2500 Routes (native compiled \u2014 zero overhead) \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
|
|
517
557
|
registerHealthRoute(app);
|
|
518
|
-
registerAuthRoutes(app);
|
|
558
|
+
${auth ? "registerAuthRoutes(app);" : ""}
|
|
519
559
|
registerUserRoutes(app);
|
|
520
560
|
registerPostRoutes(app);
|
|
521
561
|
registerStatsRoute(app);
|
|
@@ -1257,9 +1297,11 @@ jobs:
|
|
|
1257
1297
|
`;
|
|
1258
1298
|
await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".github", "workflows", "ci.yml"), workflow);
|
|
1259
1299
|
}
|
|
1260
|
-
async function scaffoldFullstackProject(projectDir, projectName, kozoCoreDep, runtime, database, frontend, extras, template) {
|
|
1300
|
+
async function scaffoldFullstackProject(projectDir, projectName, kozoCoreDep, runtime, database, dbPort, auth, frontend, extras, template) {
|
|
1301
|
+
const hasDb = database !== "none";
|
|
1261
1302
|
await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "apps", "api", "src", "routes"));
|
|
1262
|
-
await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "apps", "api", "src", "data"));
|
|
1303
|
+
if (!hasDb) await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "apps", "api", "src", "data"));
|
|
1304
|
+
if (hasDb) await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "apps", "api", "src", "db"));
|
|
1263
1305
|
await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "apps", "web", "src", "lib"));
|
|
1264
1306
|
await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, ".vscode"));
|
|
1265
1307
|
const rootPackageJson = {
|
|
@@ -1275,32 +1317,81 @@ async function scaffoldFullstackProject(projectDir, projectName, kozoCoreDep, ru
|
|
|
1275
1317
|
- 'apps/*'
|
|
1276
1318
|
`);
|
|
1277
1319
|
await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".gitignore"), "node_modules/\ndist/\n.env\n*.log\n");
|
|
1278
|
-
await scaffoldFullstackApi(projectDir, projectName, kozoCoreDep, runtime);
|
|
1320
|
+
await scaffoldFullstackApi(projectDir, projectName, kozoCoreDep, runtime, database, dbPort, auth);
|
|
1279
1321
|
await scaffoldFullstackWeb(projectDir, projectName, frontend);
|
|
1280
1322
|
await scaffoldFullstackReadme(projectDir, projectName);
|
|
1281
1323
|
if (extras.includes("docker")) await createDockerfile(import_node_path.default.join(projectDir, "apps", "api"), runtime);
|
|
1282
1324
|
if (extras.includes("github-actions")) await createGitHubActions(projectDir);
|
|
1283
1325
|
}
|
|
1284
|
-
async function scaffoldFullstackApi(projectDir, projectName, kozoCoreDep, runtime) {
|
|
1326
|
+
async function scaffoldFullstackApi(projectDir, projectName, kozoCoreDep, runtime, database = "none", dbPort, auth = true) {
|
|
1285
1327
|
const apiDir = import_node_path.default.join(projectDir, "apps", "api");
|
|
1328
|
+
const hasDb = database !== "none";
|
|
1329
|
+
if (hasDb) {
|
|
1330
|
+
await import_fs_extra.default.ensureDir(import_node_path.default.join(apiDir, "src", "db"));
|
|
1331
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "db", "schema.ts"), getDatabaseSchema(database));
|
|
1332
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "db", "index.ts"), getDatabaseIndex(database));
|
|
1333
|
+
if (database === "sqlite") {
|
|
1334
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "db", "seed.ts"), getSQLiteSeed());
|
|
1335
|
+
}
|
|
1336
|
+
const dialect = database === "postgresql" ? "postgresql" : database === "mysql" ? "mysql" : "sqlite";
|
|
1337
|
+
const pgPort = dbPort ?? 5436;
|
|
1338
|
+
const dbUrl = database === "postgresql" ? `postgresql://postgres:postgres@localhost:${pgPort}/${projectName}` : database === "mysql" ? `mysql://root:root@localhost:3306/${projectName}` : void 0;
|
|
1339
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "drizzle.config.ts"), `import { defineConfig } from 'drizzle-kit';
|
|
1340
|
+
import 'dotenv/config';
|
|
1341
|
+
|
|
1342
|
+
export default defineConfig({
|
|
1343
|
+
schema: './src/db/schema.ts',
|
|
1344
|
+
out: './drizzle',
|
|
1345
|
+
dialect: '${dialect}',
|
|
1346
|
+
dbCredentials: {
|
|
1347
|
+
${database === "sqlite" ? "url: './data.db'" : "url: process.env.DATABASE_URL!"}
|
|
1348
|
+
},
|
|
1349
|
+
});
|
|
1350
|
+
`);
|
|
1351
|
+
const envContent = `PORT=3000
|
|
1352
|
+
NODE_ENV=development
|
|
1353
|
+
${dbUrl ? `DATABASE_URL=${dbUrl}
|
|
1354
|
+
` : ""}${auth ? "JWT_SECRET=change-me-to-a-random-secret-at-least-32-chars\n" : ""}`;
|
|
1355
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, ".env"), envContent);
|
|
1356
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, ".env.example"), envContent);
|
|
1357
|
+
} else {
|
|
1358
|
+
const envContent = `PORT=3000
|
|
1359
|
+
NODE_ENV=development
|
|
1360
|
+
${auth ? "JWT_SECRET=change-me-to-a-random-secret-at-least-32-chars\n" : ""}`;
|
|
1361
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, ".env"), envContent);
|
|
1362
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, ".env.example"), envContent);
|
|
1363
|
+
}
|
|
1286
1364
|
const apiPackageJson = {
|
|
1287
1365
|
name: `@${projectName}/api`,
|
|
1288
1366
|
version: "1.0.0",
|
|
1289
1367
|
type: "module",
|
|
1290
1368
|
scripts: {
|
|
1291
1369
|
dev: runtime === "bun" ? "bun --watch src/index.ts" : "tsx watch src/index.ts",
|
|
1292
|
-
build: "tsc"
|
|
1370
|
+
build: "tsc",
|
|
1371
|
+
...hasDb && {
|
|
1372
|
+
"db:generate": "drizzle-kit generate",
|
|
1373
|
+
"db:push": "drizzle-kit push",
|
|
1374
|
+
"db:studio": "drizzle-kit studio"
|
|
1375
|
+
}
|
|
1293
1376
|
},
|
|
1294
1377
|
dependencies: {
|
|
1295
1378
|
"@kozojs/core": kozoCoreDep,
|
|
1379
|
+
...auth && { "@kozojs/auth": kozoCoreDep },
|
|
1296
1380
|
hono: "^4.6.0",
|
|
1297
1381
|
zod: "^3.23.0",
|
|
1298
|
-
|
|
1382
|
+
dotenv: "^16.4.0",
|
|
1383
|
+
...runtime === "node" && { "@hono/node-server": "^1.13.0" },
|
|
1384
|
+
...hasDb && { "drizzle-orm": "^0.36.0" },
|
|
1385
|
+
...database === "postgresql" && { postgres: "^3.4.0" },
|
|
1386
|
+
...database === "mysql" && { mysql2: "^3.11.0" },
|
|
1387
|
+
...database === "sqlite" && { "better-sqlite3": "^11.0.0" }
|
|
1299
1388
|
},
|
|
1300
1389
|
devDependencies: {
|
|
1301
1390
|
"@types/node": "^22.0.0",
|
|
1302
1391
|
...runtime !== "bun" && { tsx: "^4.19.0" },
|
|
1303
|
-
typescript: "^5.6.0"
|
|
1392
|
+
typescript: "^5.6.0",
|
|
1393
|
+
...hasDb && { "drizzle-kit": "^0.28.0" },
|
|
1394
|
+
...database === "sqlite" && { "@types/better-sqlite3": "^7.6.0" }
|
|
1304
1395
|
}
|
|
1305
1396
|
};
|
|
1306
1397
|
await import_fs_extra.default.writeJSON(import_node_path.default.join(apiDir, "package.json"), apiPackageJson, { spaces: 2 });
|
|
@@ -1319,11 +1410,23 @@ async function scaffoldFullstackApi(projectDir, projectName, kozoCoreDep, runtim
|
|
|
1319
1410
|
exclude: ["node_modules", "dist"]
|
|
1320
1411
|
};
|
|
1321
1412
|
await import_fs_extra.default.writeJSON(import_node_path.default.join(apiDir, "tsconfig.json"), tsconfig, { spaces: 2 });
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1413
|
+
const dbImport = hasDb ? `import { createDb } from './db/index.js';
|
|
1414
|
+
` : "";
|
|
1415
|
+
const authImport = auth ? `import { authenticateJWT } from '@kozojs/auth';
|
|
1416
|
+
` : "";
|
|
1417
|
+
const servicesSetup = hasDb ? `
|
|
1418
|
+
const db = await createDb();
|
|
1419
|
+
const services = { db };
|
|
1420
|
+
` : "\nconst services = {};\n";
|
|
1421
|
+
const authMiddleware = auth ? `
|
|
1422
|
+
app.use('*', authenticateJWT({ secret: process.env.JWT_SECRET || 'change-me' }));
|
|
1423
|
+
` : "";
|
|
1424
|
+
await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "index.ts"), `import 'dotenv/config';
|
|
1425
|
+
import { createKozo } from '@kozojs/core';
|
|
1426
|
+
${dbImport}${authImport}import { registerRoutes } from './routes/index.js';
|
|
1427
|
+
${servicesSetup}
|
|
1428
|
+
const app = createKozo({ port: 3000, services });
|
|
1429
|
+
${authMiddleware}
|
|
1327
1430
|
registerRoutes(app);
|
|
1328
1431
|
|
|
1329
1432
|
export type AppType = typeof app;
|
|
@@ -2275,6 +2378,7 @@ function printLogo() {
|
|
|
2275
2378
|
async function newCommand(projectName) {
|
|
2276
2379
|
printLogo();
|
|
2277
2380
|
p.intro(import_picocolors2.default.bold(import_picocolors2.default.red("\u{1F525} Create a new Kozo project")));
|
|
2381
|
+
const isLocalWorkspace = process.env.KOZO_LOCAL === "true";
|
|
2278
2382
|
const project = await p.group(
|
|
2279
2383
|
{
|
|
2280
2384
|
name: () => {
|
|
@@ -2312,18 +2416,35 @@ async function newCommand(projectName) {
|
|
|
2312
2416
|
]
|
|
2313
2417
|
}),
|
|
2314
2418
|
database: ({ results }) => {
|
|
2315
|
-
if (results.template === "
|
|
2419
|
+
if (results.template === "api-only") {
|
|
2316
2420
|
return Promise.resolve("none");
|
|
2317
2421
|
}
|
|
2318
2422
|
return p.select({
|
|
2319
2423
|
message: "Database",
|
|
2320
2424
|
options: [
|
|
2321
|
-
{ value: "
|
|
2322
|
-
{ value: "
|
|
2323
|
-
{ value: "
|
|
2425
|
+
{ value: "postgresql", label: "PostgreSQL + Drizzle", hint: "Standard \u2014 recommended for production" },
|
|
2426
|
+
{ value: "mysql", label: "MySQL + Drizzle", hint: "PlanetScale compatible" },
|
|
2427
|
+
{ value: "sqlite", label: "SQLite + Drizzle", hint: "Zero setup, great for local dev" },
|
|
2428
|
+
{ value: "none", label: "None", hint: "In-memory store (demo only)" }
|
|
2324
2429
|
]
|
|
2325
2430
|
});
|
|
2326
2431
|
},
|
|
2432
|
+
dbPort: ({ results }) => {
|
|
2433
|
+
if (results.database !== "postgresql") return Promise.resolve(void 0);
|
|
2434
|
+
return p.text({
|
|
2435
|
+
message: "PostgreSQL port",
|
|
2436
|
+
placeholder: "5436",
|
|
2437
|
+
initialValue: "5436",
|
|
2438
|
+
validate: (v) => v && isNaN(Number(v)) ? "Must be a valid port number" : void 0
|
|
2439
|
+
});
|
|
2440
|
+
},
|
|
2441
|
+
auth: ({ results }) => {
|
|
2442
|
+
if (results.template === "api-only") return Promise.resolve(false);
|
|
2443
|
+
return p.confirm({
|
|
2444
|
+
message: "Include JWT authentication?",
|
|
2445
|
+
initialValue: true
|
|
2446
|
+
});
|
|
2447
|
+
},
|
|
2327
2448
|
frontend: () => p.select({
|
|
2328
2449
|
message: "Frontend",
|
|
2329
2450
|
options: [
|
|
@@ -2338,19 +2459,10 @@ async function newCommand(projectName) {
|
|
|
2338
2459
|
message: "Extras",
|
|
2339
2460
|
options: [
|
|
2340
2461
|
{ value: "docker", label: "Docker", hint: "Multi-stage Dockerfile" },
|
|
2341
|
-
{ value: "github-actions", label: "GitHub Actions", hint: "CI/CD pipeline" }
|
|
2342
|
-
{ value: "auth", label: "Authentication", hint: "JWT middleware + login routes" }
|
|
2462
|
+
{ value: "github-actions", label: "GitHub Actions", hint: "CI/CD pipeline" }
|
|
2343
2463
|
],
|
|
2344
2464
|
required: false
|
|
2345
2465
|
}),
|
|
2346
|
-
packageSource: () => p.select({
|
|
2347
|
-
message: "Package source",
|
|
2348
|
-
options: [
|
|
2349
|
-
{ value: "npm", label: "npm registry", hint: "Published version (recommended)" },
|
|
2350
|
-
{ value: "local", label: "Local workspace", hint: "Link to monorepo (dev only)" }
|
|
2351
|
-
],
|
|
2352
|
-
initialValue: "npm"
|
|
2353
|
-
}),
|
|
2354
2466
|
install: () => Promise.resolve(true)
|
|
2355
2467
|
},
|
|
2356
2468
|
{
|
|
@@ -2367,10 +2479,12 @@ async function newCommand(projectName) {
|
|
|
2367
2479
|
projectName: project.name,
|
|
2368
2480
|
runtime: project.runtime,
|
|
2369
2481
|
template: project.template,
|
|
2370
|
-
database: project.database,
|
|
2482
|
+
database: project.database ?? "none",
|
|
2483
|
+
dbPort: project.dbPort ? Number(project.dbPort) : void 0,
|
|
2484
|
+
auth: project.auth,
|
|
2371
2485
|
frontend: project.frontend,
|
|
2372
2486
|
extras: project.extras,
|
|
2373
|
-
packageSource:
|
|
2487
|
+
packageSource: isLocalWorkspace ? "local" : "npm"
|
|
2374
2488
|
});
|
|
2375
2489
|
s.stop("Project structure created!");
|
|
2376
2490
|
} catch (err) {
|