katax-cli 1.4.2 → 1.4.4
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/README.md +28 -1
- package/dist/commands/add-endpoint.d.ts +29 -0
- package/dist/commands/add-endpoint.d.ts.map +1 -1
- package/dist/commands/add-endpoint.js +154 -51
- package/dist/commands/add-endpoint.js.map +1 -1
- package/dist/commands/generate-crud.d.ts +29 -0
- package/dist/commands/generate-crud.d.ts.map +1 -1
- package/dist/commands/generate-crud.js +157 -50
- package/dist/commands/generate-crud.js.map +1 -1
- package/dist/commands/generate-repository.d.ts +42 -0
- package/dist/commands/generate-repository.d.ts.map +1 -0
- package/dist/commands/generate-repository.js +451 -0
- package/dist/commands/generate-repository.js.map +1 -0
- package/dist/commands/init.d.ts +17 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +456 -114
- package/dist/commands/init.js.map +1 -1
- package/dist/generators/validator-generator.d.ts.map +1 -1
- package/dist/generators/validator-generator.improved.d.ts +1 -1
- package/dist/generators/validator-generator.improved.js +55 -55
- package/dist/generators/validator-generator.improved.js.map +1 -1
- package/dist/generators/validator-generator.js +8 -31
- package/dist/generators/validator-generator.js.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/services/project-structure-generator.js +1 -1
- package/dist/services/project-structure-generator.js.map +1 -1
- package/dist/templates/generators/auth-utils-template.d.ts.map +1 -1
- package/dist/templates/generators/auth-utils-template.js +3 -10
- package/dist/templates/generators/auth-utils-template.js.map +1 -1
- package/dist/templates/generators/stream-utils-template.d.ts.map +1 -1
- package/dist/templates/generators/stream-utils-template.js +4 -5
- package/dist/templates/generators/stream-utils-template.js.map +1 -1
- package/dist/types/index.d.ts +6 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +4 -2
package/dist/commands/init.js
CHANGED
|
@@ -8,6 +8,46 @@ import { directoryExists, ensureDir, writeFile, } from "../utils/file-utils.js";
|
|
|
8
8
|
import { generateSwaggerSetup } from "../templates/generators/swagger-template.js";
|
|
9
9
|
import { generateStreamUtils } from "../templates/generators/stream-utils-template.js";
|
|
10
10
|
import { generateAuthUtils } from "../templates/generators/auth-utils-template.js";
|
|
11
|
+
const KATAX_SERVICE_MANAGER_PEERS = [
|
|
12
|
+
"dotenv",
|
|
13
|
+
"mongodb",
|
|
14
|
+
"mysql2",
|
|
15
|
+
"node-cron",
|
|
16
|
+
"pg",
|
|
17
|
+
"pino-pretty",
|
|
18
|
+
"redis",
|
|
19
|
+
"socket.io",
|
|
20
|
+
];
|
|
21
|
+
function getPackageManager(pm) {
|
|
22
|
+
return pm === "npm" ? "npm" : "pnpm";
|
|
23
|
+
}
|
|
24
|
+
function getInstallCommand(packageManager, packages = [], ignoreScripts = false) {
|
|
25
|
+
const args = [];
|
|
26
|
+
if (packageManager === "pnpm") {
|
|
27
|
+
if (packages.length > 0) {
|
|
28
|
+
args.push("add", ...packages);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
args.push("install");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
args.push("install", ...packages);
|
|
36
|
+
}
|
|
37
|
+
if (ignoreScripts) {
|
|
38
|
+
args.push("--ignore-scripts");
|
|
39
|
+
}
|
|
40
|
+
return { cmd: packageManager, args };
|
|
41
|
+
}
|
|
42
|
+
async function writeIgnoreScriptsNpmrc(projectPath) {
|
|
43
|
+
const npmrcContent = [
|
|
44
|
+
"# Generated by katax-cli",
|
|
45
|
+
"# Prevent lifecycle scripts during install for safer bootstrapping",
|
|
46
|
+
"ignore-scripts=true",
|
|
47
|
+
"",
|
|
48
|
+
].join("\n");
|
|
49
|
+
await writeFile(path.join(projectPath, ".npmrc"), npmrcContent);
|
|
50
|
+
}
|
|
11
51
|
export async function initCommand(projectName, options = {}) {
|
|
12
52
|
title("🚀 Katax CLI - Initialize API Project");
|
|
13
53
|
let finalProjectName = projectName || "";
|
|
@@ -146,6 +186,21 @@ export async function initCommand(projectName, options = {}) {
|
|
|
146
186
|
default: false,
|
|
147
187
|
when: (answers) => answers.useKataxServiceManager,
|
|
148
188
|
},
|
|
189
|
+
{
|
|
190
|
+
type: "list",
|
|
191
|
+
name: "peerDependenciesMode",
|
|
192
|
+
message: "Install katax-service-manager peer dependencies now?",
|
|
193
|
+
choices: [
|
|
194
|
+
{ name: "No (install later as needed)", value: "none" },
|
|
195
|
+
{
|
|
196
|
+
name: "Yes, install peers for selected integrations",
|
|
197
|
+
value: "selected",
|
|
198
|
+
},
|
|
199
|
+
{ name: "Yes, install all optional peers", value: "all" },
|
|
200
|
+
],
|
|
201
|
+
default: "selected",
|
|
202
|
+
when: (answers) => answers.useKataxServiceManager,
|
|
203
|
+
},
|
|
149
204
|
{
|
|
150
205
|
type: "confirm",
|
|
151
206
|
name: "useSeparateSocketPort",
|
|
@@ -186,6 +241,29 @@ export async function initCommand(projectName, options = {}) {
|
|
|
186
241
|
message: "Initialize git repository?",
|
|
187
242
|
default: true,
|
|
188
243
|
},
|
|
244
|
+
{
|
|
245
|
+
type: "list",
|
|
246
|
+
name: "packageManager",
|
|
247
|
+
message: "Package manager for install commands:",
|
|
248
|
+
choices: [
|
|
249
|
+
{ name: "npm", value: "npm" },
|
|
250
|
+
{ name: "pnpm", value: "pnpm" },
|
|
251
|
+
],
|
|
252
|
+
default: getPackageManager(options.pm),
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
type: "confirm",
|
|
256
|
+
name: "ignoreScripts",
|
|
257
|
+
message: "Install dependencies with --ignore-scripts?",
|
|
258
|
+
default: options.ignoreScripts ?? false,
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
type: "confirm",
|
|
262
|
+
name: "writeNpmrc",
|
|
263
|
+
message: "Create .npmrc with ignore-scripts=true?",
|
|
264
|
+
default: options.writeNpmrc ?? true,
|
|
265
|
+
when: (answers) => answers.ignoreScripts,
|
|
266
|
+
},
|
|
189
267
|
]);
|
|
190
268
|
let dbConfig = {};
|
|
191
269
|
if (answers.database !== "none") {
|
|
@@ -310,7 +388,15 @@ export async function initCommand(projectName, options = {}) {
|
|
|
310
388
|
useRegistry: answers.useRegistry || false,
|
|
311
389
|
registryMode: answers.useRegistry ? answers.registryMode || "url" : "none",
|
|
312
390
|
registryUrl: answers.registryUrl,
|
|
391
|
+
peerDependenciesMode: answers.useKataxServiceManager
|
|
392
|
+
? answers.peerDependenciesMode || "selected"
|
|
393
|
+
: "none",
|
|
313
394
|
useLifecycleHooks: answers.useLifecycleHooks || false,
|
|
395
|
+
packageManager: getPackageManager(answers.packageManager),
|
|
396
|
+
ignoreInstallScripts: answers.ignoreScripts || false,
|
|
397
|
+
createNpmrcForIgnoreScripts: answers.ignoreScripts
|
|
398
|
+
? (answers.writeNpmrc ?? true)
|
|
399
|
+
: false,
|
|
314
400
|
initGit: answers.initGit,
|
|
315
401
|
redisConfig,
|
|
316
402
|
dbConfig,
|
|
@@ -337,19 +423,30 @@ export async function initCommand(projectName, options = {}) {
|
|
|
337
423
|
if (config.useKataxServiceManager) {
|
|
338
424
|
gray(` Katax Mode: ${config.kataxMode === "instance" ? "Instance (new Katax())" : "Singleton"}`);
|
|
339
425
|
gray(` Registry: ${config.useRegistry ? (config.registryMode === "url" ? `URL (${config.registryUrl})` : "Callback handler") : "No"}`);
|
|
426
|
+
gray(` Peer Deps: ${config.peerDependenciesMode || "none"}`);
|
|
340
427
|
gray(` Lifecycle Hooks: ${config.useLifecycleHooks ? "Yes" : "No"}`);
|
|
341
428
|
gray(` Redis Cache: ${config.useRedis ? "Yes" : "No"}`);
|
|
342
429
|
gray(` WebSocket: ${config.useWebSocket ? (config.useSeparateSocketPort ? `Yes (port ${config.socketPort})` : "Yes (shared port)") : "No"}`);
|
|
343
430
|
}
|
|
344
431
|
gray(` Git: ${config.initGit ? "Yes" : "No"}`);
|
|
432
|
+
gray(` Package Manager: ${config.packageManager}`);
|
|
433
|
+
gray(` Ignore Install Scripts: ${config.ignoreInstallScripts ? "Yes" : "No"}`);
|
|
434
|
+
gray(` Write .npmrc: ${config.createNpmrcForIgnoreScripts ? "Yes" : "No"}`);
|
|
345
435
|
gray(` Port: ${config.port}\n`);
|
|
346
436
|
const spinner = ora("Creating project structure...").start();
|
|
347
437
|
try {
|
|
348
438
|
await createProjectStructure(projectPath, config, generateJwtSecrets);
|
|
349
439
|
spinner.succeed("Project structure created");
|
|
440
|
+
if (config.createNpmrcForIgnoreScripts) {
|
|
441
|
+
spinner.start("Writing .npmrc...");
|
|
442
|
+
await writeIgnoreScriptsNpmrc(projectPath);
|
|
443
|
+
spinner.succeed(".npmrc created (ignore-scripts=true)");
|
|
444
|
+
}
|
|
350
445
|
spinner.start("Installing dependencies...");
|
|
351
|
-
await installDependencies(projectPath);
|
|
352
|
-
spinner.succeed(
|
|
446
|
+
const installedPeerDeps = await installDependencies(projectPath, config);
|
|
447
|
+
spinner.succeed(installedPeerDeps.length > 0
|
|
448
|
+
? `Dependencies installed (+ ${installedPeerDeps.length} peer deps)`
|
|
449
|
+
: "Dependencies installed");
|
|
353
450
|
if (config.initGit) {
|
|
354
451
|
spinner.start("Initializing git repository...");
|
|
355
452
|
await initGitRepository(projectPath);
|
|
@@ -358,11 +455,16 @@ export async function initCommand(projectName, options = {}) {
|
|
|
358
455
|
success(`\n✨ Project "${finalProjectName}" created successfully!\n`);
|
|
359
456
|
info("Next steps:");
|
|
360
457
|
gray(` cd ${finalProjectName}`);
|
|
361
|
-
gray(` npm
|
|
458
|
+
gray(` ${config.packageManager === "pnpm" ? "pnpm install" : "npm install"}`);
|
|
459
|
+
gray(` ${config.packageManager === "pnpm" ? "pnpm dev" : "npm run dev"}\n`);
|
|
362
460
|
info("Available commands:");
|
|
363
461
|
gray(` katax add endpoint <name> - Add a new endpoint`);
|
|
364
462
|
gray(` katax generate crud <name> - Generate CRUD resource`);
|
|
365
463
|
gray(` katax info - Show project structure\n`);
|
|
464
|
+
if (installedPeerDeps.length > 0) {
|
|
465
|
+
info("Installed peer dependencies:");
|
|
466
|
+
gray(` ${installedPeerDeps.join(", ")}\n`);
|
|
467
|
+
}
|
|
366
468
|
if (config.swagger) {
|
|
367
469
|
info("📖 API Documentation:");
|
|
368
470
|
gray(` Open http://localhost:${config.port}/docs after starting the server`);
|
|
@@ -375,11 +477,44 @@ export async function initCommand(projectName, options = {}) {
|
|
|
375
477
|
process.exit(1);
|
|
376
478
|
}
|
|
377
479
|
}
|
|
378
|
-
async function installDependencies(projectPath) {
|
|
379
|
-
|
|
480
|
+
async function installDependencies(projectPath, config) {
|
|
481
|
+
const packageManager = config.packageManager || "npm";
|
|
482
|
+
const ignoreScripts = config.ignoreInstallScripts || false;
|
|
483
|
+
const baseInstall = getInstallCommand(packageManager, [], ignoreScripts);
|
|
484
|
+
await execa(baseInstall.cmd, baseInstall.args, {
|
|
380
485
|
cwd: projectPath,
|
|
381
486
|
stdio: "ignore",
|
|
382
487
|
});
|
|
488
|
+
const peers = resolvePeerDependencies(config);
|
|
489
|
+
if (peers.length === 0) {
|
|
490
|
+
return [];
|
|
491
|
+
}
|
|
492
|
+
const peerInstall = getInstallCommand(packageManager, peers, ignoreScripts);
|
|
493
|
+
await execa(peerInstall.cmd, peerInstall.args, {
|
|
494
|
+
cwd: projectPath,
|
|
495
|
+
stdio: "ignore",
|
|
496
|
+
});
|
|
497
|
+
return peers;
|
|
498
|
+
}
|
|
499
|
+
function resolvePeerDependencies(config) {
|
|
500
|
+
if (!config.useKataxServiceManager) {
|
|
501
|
+
return [];
|
|
502
|
+
}
|
|
503
|
+
const mode = config.peerDependenciesMode || "none";
|
|
504
|
+
if (mode === "none") {
|
|
505
|
+
return [];
|
|
506
|
+
}
|
|
507
|
+
if (mode === "all") {
|
|
508
|
+
return [...KATAX_SERVICE_MANAGER_PEERS];
|
|
509
|
+
}
|
|
510
|
+
const selected = new Set();
|
|
511
|
+
if (config.useRedis) {
|
|
512
|
+
selected.add("redis");
|
|
513
|
+
}
|
|
514
|
+
if (config.useWebSocket) {
|
|
515
|
+
selected.add("socket.io");
|
|
516
|
+
}
|
|
517
|
+
return [...selected];
|
|
383
518
|
}
|
|
384
519
|
async function initGitRepository(projectPath) {
|
|
385
520
|
await execa("git", ["init"], {
|
|
@@ -567,9 +702,12 @@ async function createProjectStructure(projectPath, config, generateJwtSecrets) {
|
|
|
567
702
|
dependencies: {
|
|
568
703
|
express: "^4.18.2",
|
|
569
704
|
cors: "^2.8.5",
|
|
705
|
+
helmet: "^8.1.0",
|
|
706
|
+
"cookie-parser": "^1.4.7",
|
|
707
|
+
"express-rate-limit": "^8.3.2",
|
|
570
708
|
dotenv: "^16.3.1",
|
|
571
709
|
...(config.useKataxServiceManager
|
|
572
|
-
? { "katax-service-manager": "
|
|
710
|
+
? { "katax-service-manager": "latest", "pino-pretty": "^10.3.1" }
|
|
573
711
|
: { pino: "^8.17.2", "pino-pretty": "^10.3.1" }),
|
|
574
712
|
...(config.validation === "katax-core" && { "katax-core": "latest" }),
|
|
575
713
|
...(config.authentication === "jwt" && {
|
|
@@ -585,6 +723,7 @@ async function createProjectStructure(projectPath, config, generateJwtSecrets) {
|
|
|
585
723
|
devDependencies: {
|
|
586
724
|
"@types/express": "^4.17.21",
|
|
587
725
|
"@types/cors": "^2.8.17",
|
|
726
|
+
"@types/cookie-parser": "^1.4.9",
|
|
588
727
|
"@types/node": "^22.10.5",
|
|
589
728
|
...(config.authentication === "jwt" && {
|
|
590
729
|
"@types/jsonwebtoken": "^9.0.5",
|
|
@@ -607,7 +746,7 @@ async function createProjectStructure(projectPath, config, generateJwtSecrets) {
|
|
|
607
746
|
target: "ES2022",
|
|
608
747
|
module: "ESNext",
|
|
609
748
|
lib: ["ES2022"],
|
|
610
|
-
moduleResolution: "
|
|
749
|
+
moduleResolution: "bundler",
|
|
611
750
|
esModuleInterop: true,
|
|
612
751
|
allowSyntheticDefaultImports: true,
|
|
613
752
|
forceConsistentCasingInFileNames: true,
|
|
@@ -921,7 +1060,7 @@ ${listenCode}
|
|
|
921
1060
|
|
|
922
1061
|
// Register custom shutdown hooks (optional)
|
|
923
1062
|
katax.onShutdown(async () => {
|
|
924
|
-
katax.logger.info('Running custom cleanup...');
|
|
1063
|
+
katax.logger.info({ message: 'Running custom cleanup...' });
|
|
925
1064
|
// Add your custom cleanup logic here
|
|
926
1065
|
});
|
|
927
1066
|
|
|
@@ -949,19 +1088,19 @@ validateEnvironment();
|
|
|
949
1088
|
const PORT = process.env.PORT || ${config.port};
|
|
950
1089
|
|
|
951
1090
|
app.listen(PORT, () => {
|
|
952
|
-
logger.info(\`Server running on http://localhost:\${PORT}\`);
|
|
953
|
-
logger.info(\`API endpoints available at http://localhost:\${PORT}/api\`);
|
|
954
|
-
logger.info(\`Health check: http://localhost:\${PORT}/api/health\`);
|
|
1091
|
+
logger.info({ message: \`Server running on http://localhost:\${PORT}\` });
|
|
1092
|
+
logger.info({ message: \`API endpoints available at http://localhost:\${PORT}/api\` });
|
|
1093
|
+
logger.info({ message: \`Health check: http://localhost:\${PORT}/api/health\` });
|
|
955
1094
|
});
|
|
956
1095
|
|
|
957
1096
|
// Graceful shutdown handlers
|
|
958
1097
|
process.on('SIGTERM', () => {
|
|
959
|
-
logger.info('SIGTERM received, shutting down...');
|
|
1098
|
+
logger.info({ message: 'SIGTERM received, shutting down...' });
|
|
960
1099
|
process.exit(0);
|
|
961
1100
|
});
|
|
962
1101
|
|
|
963
1102
|
process.on('SIGINT', () => {
|
|
964
|
-
logger.info('SIGINT received, shutting down...');
|
|
1103
|
+
logger.info({ message: 'SIGINT received, shutting down...' });
|
|
965
1104
|
process.exit(0);
|
|
966
1105
|
});
|
|
967
1106
|
`;
|
|
@@ -976,6 +1115,9 @@ export const katax = new Katax();
|
|
|
976
1115
|
}
|
|
977
1116
|
const appContent = `import express from 'express';
|
|
978
1117
|
import cors from 'cors';
|
|
1118
|
+
import helmet from 'helmet';
|
|
1119
|
+
import cookieParser from 'cookie-parser';
|
|
1120
|
+
import { rateLimit } from 'express-rate-limit';
|
|
979
1121
|
import router from './api/routes.js';
|
|
980
1122
|
import { errorMiddleware } from './middleware/error.middleware.js';
|
|
981
1123
|
import { requestLogger } from './middleware/logger.middleware.js';
|
|
@@ -983,10 +1125,24 @@ import { corsOptions } from './config/cors.config.js';${config.swagger ? "\nimpo
|
|
|
983
1125
|
|
|
984
1126
|
const app = express();
|
|
985
1127
|
|
|
1128
|
+
const apiLimiter = rateLimit({
|
|
1129
|
+
windowMs: 15 * 60 * 1000,
|
|
1130
|
+
max: 200,
|
|
1131
|
+
standardHeaders: true,
|
|
1132
|
+
legacyHeaders: false,
|
|
1133
|
+
message: {
|
|
1134
|
+
success: false,
|
|
1135
|
+
message: 'Too many requests, please try again later.',
|
|
1136
|
+
error: 'RATE_LIMIT_EXCEEDED'
|
|
1137
|
+
}
|
|
1138
|
+
});
|
|
1139
|
+
|
|
986
1140
|
// Middleware
|
|
1141
|
+
app.use(helmet());
|
|
987
1142
|
app.use(cors(corsOptions));
|
|
988
|
-
app.use(
|
|
989
|
-
app.use(express.
|
|
1143
|
+
app.use(cookieParser());
|
|
1144
|
+
app.use(express.json({ limit: '1mb' }));
|
|
1145
|
+
app.use(express.urlencoded({ extended: true, limit: '1mb' }));
|
|
990
1146
|
app.use(requestLogger);
|
|
991
1147
|
|
|
992
1148
|
${config.swagger ? "// API Documentation\nsetupSwagger(app);\n\n" : ""}// Routes
|
|
@@ -999,6 +1155,7 @@ app.get('/', (req, res) => {
|
|
|
999
1155
|
});
|
|
1000
1156
|
});
|
|
1001
1157
|
|
|
1158
|
+
app.use('/api', apiLimiter);
|
|
1002
1159
|
app.use('/api', router);
|
|
1003
1160
|
|
|
1004
1161
|
// Error handling
|
|
@@ -1022,7 +1179,42 @@ router.use('/hello', helloRouter);
|
|
|
1022
1179
|
export default router;
|
|
1023
1180
|
`;
|
|
1024
1181
|
await writeFile(path.join(projectPath, "src/api/routes.ts"), routesContent);
|
|
1025
|
-
const errorMiddlewareContent =
|
|
1182
|
+
const errorMiddlewareContent = config.useKataxServiceManager
|
|
1183
|
+
? `import { Request, Response, NextFunction } from 'express';
|
|
1184
|
+
import { katax } from '${kataxImportSourceShared}';
|
|
1185
|
+
|
|
1186
|
+
export interface ApiError extends Error {
|
|
1187
|
+
statusCode?: number;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
export function errorMiddleware(
|
|
1191
|
+
err: ApiError,
|
|
1192
|
+
req: Request,
|
|
1193
|
+
res: Response,
|
|
1194
|
+
next: NextFunction
|
|
1195
|
+
): void {
|
|
1196
|
+
const statusCode = err.statusCode || 500;
|
|
1197
|
+
const message = err.message || 'Internal Server Error';
|
|
1198
|
+
|
|
1199
|
+
katax.logger.error({
|
|
1200
|
+
err,
|
|
1201
|
+
req: {
|
|
1202
|
+
method: req.method,
|
|
1203
|
+
url: req.url,
|
|
1204
|
+
headers: req.headers
|
|
1205
|
+
},
|
|
1206
|
+
statusCode,
|
|
1207
|
+
message
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
res.status(statusCode).json({
|
|
1211
|
+
success: false,
|
|
1212
|
+
message,
|
|
1213
|
+
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
`
|
|
1217
|
+
: `import { Request, Response, NextFunction } from 'express';
|
|
1026
1218
|
import { logger } from '../shared/logger.utils.js';
|
|
1027
1219
|
|
|
1028
1220
|
export interface ApiError extends Error {
|
|
@@ -1061,14 +1253,24 @@ export function errorMiddleware(
|
|
|
1061
1253
|
await createDatabaseConnection(projectPath, config);
|
|
1062
1254
|
}
|
|
1063
1255
|
if (config.validation === "katax-core") {
|
|
1256
|
+
const apiUtilsLoggerImport = config.useKataxServiceManager
|
|
1257
|
+
? `import { katax } from '${kataxImportSourceShared}';`
|
|
1258
|
+
: "import { logger } from './logger.utils.js';";
|
|
1259
|
+
const apiUtilsWarnLogger = config.useKataxServiceManager
|
|
1260
|
+
? "katax.logger.warn"
|
|
1261
|
+
: "logger.warn";
|
|
1262
|
+
const apiUtilsErrorLogger = config.useKataxServiceManager
|
|
1263
|
+
? "katax.logger.error"
|
|
1264
|
+
: "logger.error";
|
|
1064
1265
|
const apiUtilsContent = `import { Request, Response } from 'express';
|
|
1065
|
-
|
|
1266
|
+
${apiUtilsLoggerImport}
|
|
1066
1267
|
|
|
1067
1268
|
export interface ControllerResult<T = any> {
|
|
1068
1269
|
success: boolean;
|
|
1069
1270
|
message: string;
|
|
1070
1271
|
data?: T;
|
|
1071
1272
|
error?: string;
|
|
1273
|
+
details?: unknown;
|
|
1072
1274
|
statusCode?: number;
|
|
1073
1275
|
currentPage?: number;
|
|
1074
1276
|
totalPages?: number;
|
|
@@ -1077,6 +1279,93 @@ export interface ControllerResult<T = any> {
|
|
|
1077
1279
|
hasMorePages?: boolean;
|
|
1078
1280
|
}
|
|
1079
1281
|
|
|
1282
|
+
type PaginationMeta = Pick<
|
|
1283
|
+
ControllerResult,
|
|
1284
|
+
'currentPage' | 'totalPages' | 'totalItems' | 'totalCount' | 'hasMorePages'
|
|
1285
|
+
>;
|
|
1286
|
+
|
|
1287
|
+
export const createResponse = {
|
|
1288
|
+
success<T>(
|
|
1289
|
+
message: string,
|
|
1290
|
+
data?: T,
|
|
1291
|
+
statusCode = 200,
|
|
1292
|
+
pagination?: PaginationMeta
|
|
1293
|
+
): ControllerResult<T> {
|
|
1294
|
+
return {
|
|
1295
|
+
success: true,
|
|
1296
|
+
message,
|
|
1297
|
+
statusCode,
|
|
1298
|
+
...(pagination ?? {}),
|
|
1299
|
+
data
|
|
1300
|
+
};
|
|
1301
|
+
},
|
|
1302
|
+
|
|
1303
|
+
error(
|
|
1304
|
+
message: string,
|
|
1305
|
+
error: string = 'Request error',
|
|
1306
|
+
statusCode = 400,
|
|
1307
|
+
details?: unknown
|
|
1308
|
+
): ControllerResult {
|
|
1309
|
+
return {
|
|
1310
|
+
success: false,
|
|
1311
|
+
message,
|
|
1312
|
+
error,
|
|
1313
|
+
statusCode,
|
|
1314
|
+
details
|
|
1315
|
+
};
|
|
1316
|
+
},
|
|
1317
|
+
|
|
1318
|
+
unauthorized(
|
|
1319
|
+
message = 'Unauthorized',
|
|
1320
|
+
error = 'Authentication required'
|
|
1321
|
+
): ControllerResult {
|
|
1322
|
+
return {
|
|
1323
|
+
success: false,
|
|
1324
|
+
message,
|
|
1325
|
+
error,
|
|
1326
|
+
statusCode: 401
|
|
1327
|
+
};
|
|
1328
|
+
},
|
|
1329
|
+
|
|
1330
|
+
forbidden(
|
|
1331
|
+
message = 'Forbidden',
|
|
1332
|
+
error = 'Insufficient permissions'
|
|
1333
|
+
): ControllerResult {
|
|
1334
|
+
return {
|
|
1335
|
+
success: false,
|
|
1336
|
+
message,
|
|
1337
|
+
error,
|
|
1338
|
+
statusCode: 403
|
|
1339
|
+
};
|
|
1340
|
+
},
|
|
1341
|
+
|
|
1342
|
+
notFound(resource = 'Resource'): ControllerResult {
|
|
1343
|
+
return {
|
|
1344
|
+
success: false,
|
|
1345
|
+
message: resource + ' not found',
|
|
1346
|
+
error: 'NOT_FOUND',
|
|
1347
|
+
statusCode: 404
|
|
1348
|
+
};
|
|
1349
|
+
},
|
|
1350
|
+
|
|
1351
|
+
validation(
|
|
1352
|
+
errors: ValidationError[] = [],
|
|
1353
|
+
message = 'Validation failed'
|
|
1354
|
+
): ControllerResult {
|
|
1355
|
+
return {
|
|
1356
|
+
success: false,
|
|
1357
|
+
message,
|
|
1358
|
+
error: 'VALIDATION_ERROR',
|
|
1359
|
+
statusCode: 422,
|
|
1360
|
+
details: errors
|
|
1361
|
+
};
|
|
1362
|
+
},
|
|
1363
|
+
|
|
1364
|
+
custom<T>(result: ControllerResult<T>): ControllerResult<T> {
|
|
1365
|
+
return result;
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1368
|
+
|
|
1080
1369
|
export function createSuccessResult<T>(
|
|
1081
1370
|
message: string,
|
|
1082
1371
|
data?: T,
|
|
@@ -1088,18 +1377,19 @@ export function createSuccessResult<T>(
|
|
|
1088
1377
|
totalCount?: number,
|
|
1089
1378
|
hasMorePages?: boolean
|
|
1090
1379
|
): ControllerResult<T> {
|
|
1091
|
-
|
|
1092
|
-
success: true,
|
|
1093
|
-
message,
|
|
1094
|
-
error,
|
|
1095
|
-
statusCode,
|
|
1380
|
+
const response = createResponse.success(message, data, statusCode, {
|
|
1096
1381
|
currentPage,
|
|
1097
1382
|
totalPages,
|
|
1098
1383
|
totalItems,
|
|
1099
1384
|
totalCount,
|
|
1100
|
-
hasMorePages
|
|
1101
|
-
|
|
1102
|
-
|
|
1385
|
+
hasMorePages
|
|
1386
|
+
});
|
|
1387
|
+
|
|
1388
|
+
if (error) {
|
|
1389
|
+
response.error = error;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
return response;
|
|
1103
1393
|
}
|
|
1104
1394
|
|
|
1105
1395
|
export function createErrorResult(
|
|
@@ -1107,13 +1397,34 @@ export function createErrorResult(
|
|
|
1107
1397
|
error?: string,
|
|
1108
1398
|
statusCode = 400
|
|
1109
1399
|
): ControllerResult {
|
|
1110
|
-
return
|
|
1400
|
+
return createResponse.error(message, error, statusCode);
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
export interface ValidationError {
|
|
1404
|
+
field: string;
|
|
1405
|
+
message: string;
|
|
1111
1406
|
}
|
|
1112
1407
|
|
|
1113
|
-
export interface ValidationResult<T =
|
|
1408
|
+
export interface ValidationResult<T = unknown> {
|
|
1114
1409
|
isValid: boolean;
|
|
1115
1410
|
data?: T;
|
|
1116
|
-
errors?:
|
|
1411
|
+
errors?: ValidationError[];
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
type KataxIssue = {
|
|
1415
|
+
path: (string | number)[];
|
|
1416
|
+
message: string;
|
|
1417
|
+
};
|
|
1418
|
+
|
|
1419
|
+
type KataxSafeParseResult<T> =
|
|
1420
|
+
| { success: true; data: T }
|
|
1421
|
+
| { success: false; issues: KataxIssue[] };
|
|
1422
|
+
|
|
1423
|
+
export interface KataxSchema<T = unknown> {
|
|
1424
|
+
safeParse(input: unknown): KataxSafeParseResult<T>;
|
|
1425
|
+
safeParseAsync(input: unknown): Promise<KataxSafeParseResult<T>>;
|
|
1426
|
+
hasAsyncValidation?: () => boolean;
|
|
1427
|
+
_asyncValidators?: unknown[];
|
|
1117
1428
|
}
|
|
1118
1429
|
|
|
1119
1430
|
/**
|
|
@@ -1125,13 +1436,16 @@ export interface ValidationResult<T = any> {
|
|
|
1125
1436
|
* @returns ValidationResult con datos validados o errores
|
|
1126
1437
|
*/
|
|
1127
1438
|
export async function validateSchema<T>(
|
|
1128
|
-
schema:
|
|
1439
|
+
schema: KataxSchema<T>,
|
|
1129
1440
|
data: unknown
|
|
1130
1441
|
): Promise<ValidationResult<T>> {
|
|
1131
1442
|
// Detectar si el schema tiene validadores asíncronos
|
|
1132
|
-
const hasAsyncValidators =
|
|
1443
|
+
const hasAsyncValidators =
|
|
1444
|
+
typeof schema.hasAsyncValidation === 'function'
|
|
1445
|
+
? schema.hasAsyncValidation()
|
|
1446
|
+
: !!(schema._asyncValidators && schema._asyncValidators.length > 0);
|
|
1133
1447
|
|
|
1134
|
-
let result:
|
|
1448
|
+
let result: KataxSafeParseResult<T>;
|
|
1135
1449
|
|
|
1136
1450
|
try {
|
|
1137
1451
|
if (hasAsyncValidators) {
|
|
@@ -1155,10 +1469,10 @@ export async function validateSchema<T>(
|
|
|
1155
1469
|
}
|
|
1156
1470
|
|
|
1157
1471
|
if (!result.success) {
|
|
1158
|
-
const errors = result.issues
|
|
1472
|
+
const errors = result.issues.map((issue) => ({
|
|
1159
1473
|
field: issue.path.join('.') || 'root',
|
|
1160
1474
|
message: issue.message
|
|
1161
|
-
}))
|
|
1475
|
+
}));
|
|
1162
1476
|
|
|
1163
1477
|
return {
|
|
1164
1478
|
isValid: false,
|
|
@@ -1172,7 +1486,7 @@ export async function validateSchema<T>(
|
|
|
1172
1486
|
};
|
|
1173
1487
|
}
|
|
1174
1488
|
|
|
1175
|
-
export async function sendResponse<TValidation =
|
|
1489
|
+
export async function sendResponse<TValidation = unknown, TResponse = unknown>(
|
|
1176
1490
|
req: Request,
|
|
1177
1491
|
res: Response,
|
|
1178
1492
|
validator: () => Promise<ValidationResult<TValidation>>,
|
|
@@ -1184,19 +1498,18 @@ export async function sendResponse<TValidation = any, TResponse = any>(
|
|
|
1184
1498
|
|
|
1185
1499
|
if (!validationResult.isValid) {
|
|
1186
1500
|
// Validation error
|
|
1187
|
-
|
|
1501
|
+
${apiUtilsWarnLogger}({
|
|
1188
1502
|
method: req.method,
|
|
1189
1503
|
path: req.path,
|
|
1190
1504
|
errors: validationResult.errors,
|
|
1191
1505
|
message:'Validation failed'}
|
|
1192
1506
|
);
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
});
|
|
1507
|
+
|
|
1508
|
+
const validationResponse = createResponse.validation(
|
|
1509
|
+
validationResult.errors || [],
|
|
1510
|
+
'Invalid data'
|
|
1511
|
+
);
|
|
1512
|
+
res.status(validationResponse.statusCode || 422).json(validationResponse);
|
|
1200
1513
|
return;
|
|
1201
1514
|
}
|
|
1202
1515
|
|
|
@@ -1206,7 +1519,18 @@ export async function sendResponse<TValidation = any, TResponse = any>(
|
|
|
1206
1519
|
// 3. Build HTTP response
|
|
1207
1520
|
const statusCode = controllerResult.statusCode || (controllerResult.success ? 200 : 400);
|
|
1208
1521
|
|
|
1209
|
-
|
|
1522
|
+
interface ResponsePayload {
|
|
1523
|
+
success: boolean;
|
|
1524
|
+
message: string;
|
|
1525
|
+
error?: string;
|
|
1526
|
+
totalItems?: number;
|
|
1527
|
+
currentPage?: number;
|
|
1528
|
+
totalPages?: number;
|
|
1529
|
+
hasMorePages?: boolean;
|
|
1530
|
+
data?: TResponse;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
const response: ResponsePayload = {
|
|
1210
1534
|
success: controllerResult.success,
|
|
1211
1535
|
message: controllerResult.message
|
|
1212
1536
|
};
|
|
@@ -1239,7 +1563,7 @@ export async function sendResponse<TValidation = any, TResponse = any>(
|
|
|
1239
1563
|
|
|
1240
1564
|
} catch (error) {
|
|
1241
1565
|
// Internal server error
|
|
1242
|
-
|
|
1566
|
+
${apiUtilsErrorLogger}({
|
|
1243
1567
|
err: error,
|
|
1244
1568
|
method: req.method,
|
|
1245
1569
|
path: req.path,
|
|
@@ -1247,9 +1571,11 @@ export async function sendResponse<TValidation = any, TResponse = any>(
|
|
|
1247
1571
|
});
|
|
1248
1572
|
|
|
1249
1573
|
res.status(500).json({
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1574
|
+
...createResponse.error(
|
|
1575
|
+
'Internal server error',
|
|
1576
|
+
error instanceof Error ? error.message : 'Unknown error',
|
|
1577
|
+
500
|
|
1578
|
+
)
|
|
1253
1579
|
});
|
|
1254
1580
|
}
|
|
1255
1581
|
}
|
|
@@ -1258,13 +1584,14 @@ export async function sendResponse<TValidation = any, TResponse = any>(
|
|
|
1258
1584
|
}
|
|
1259
1585
|
if (config.authentication === "jwt") {
|
|
1260
1586
|
const jwtUtilsContent = `import jwt from 'jsonwebtoken';
|
|
1587
|
+
import type { SignOptions } from 'jsonwebtoken';
|
|
1261
1588
|
import { Request, Response, NextFunction } from 'express';
|
|
1262
1589
|
|
|
1263
1590
|
const JWT_SECRET = process.env.JWT_SECRET || 'your-super-secret-jwt-key-change-in-production';
|
|
1264
1591
|
const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET || 'your-refresh-secret-key';
|
|
1265
1592
|
|
|
1266
|
-
const ACCESS_TOKEN_EXPIRY = '15m'
|
|
1267
|
-
const REFRESH_TOKEN_EXPIRY = '7d'
|
|
1593
|
+
const ACCESS_TOKEN_EXPIRY = (process.env.JWT_EXPIRES_IN || '15m') as SignOptions['expiresIn'];
|
|
1594
|
+
const REFRESH_TOKEN_EXPIRY = (process.env.JWT_REFRESH_EXPIRES_IN || '7d') as SignOptions['expiresIn'];
|
|
1268
1595
|
|
|
1269
1596
|
// ==================== INTERFACES ====================
|
|
1270
1597
|
|
|
@@ -1413,33 +1740,8 @@ export function requireRole(...roles: string[]) {
|
|
|
1413
1740
|
await writeFile(path.join(projectPath, "src/shared/jwt.utils.ts"), jwtUtilsContent);
|
|
1414
1741
|
await writeFile(path.join(projectPath, "src/shared/auth.utils.ts"), generateAuthUtils());
|
|
1415
1742
|
}
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
loggerUtilsContent = `import { katax } from '${kataxImportSourceShared}';
|
|
1419
|
-
|
|
1420
|
-
/**
|
|
1421
|
-
* Re-export logger for convenience
|
|
1422
|
-
* katax.logger is always available (creates a default logger if not initialized)
|
|
1423
|
-
* Advanced features (broadcast, transports) require katax.init()
|
|
1424
|
-
*/
|
|
1425
|
-
export const logger = katax.logger;
|
|
1426
|
-
|
|
1427
|
-
/**
|
|
1428
|
-
* Log HTTP request helper
|
|
1429
|
-
*/
|
|
1430
|
-
export function logRequest(method: string, url: string, statusCode: number, duration: number): void {
|
|
1431
|
-
logger.info({
|
|
1432
|
-
message: \`\${method} \${url} - \${statusCode} (\${duration}ms)\`,
|
|
1433
|
-
method,
|
|
1434
|
-
url,
|
|
1435
|
-
statusCode,
|
|
1436
|
-
duration: \`\${duration}ms\`
|
|
1437
|
-
});
|
|
1438
|
-
}
|
|
1439
|
-
`;
|
|
1440
|
-
}
|
|
1441
|
-
else {
|
|
1442
|
-
loggerUtilsContent = `import pino from 'pino';
|
|
1743
|
+
if (!config.useKataxServiceManager) {
|
|
1744
|
+
const loggerUtilsContent = `import pino from 'pino';
|
|
1443
1745
|
|
|
1444
1746
|
const isDevelopment = process.env.NODE_ENV !== 'production';
|
|
1445
1747
|
|
|
@@ -1482,38 +1784,68 @@ export function logRequest(method: string, url: string, statusCode: number, dura
|
|
|
1482
1784
|
/**
|
|
1483
1785
|
* Log error with context
|
|
1484
1786
|
*/
|
|
1485
|
-
export function logError(error: Error, context?: Record<string,
|
|
1787
|
+
export function logError(error: Error, context?: Record<string, unknown>): void {
|
|
1486
1788
|
logger.error({
|
|
1789
|
+
message: error.message,
|
|
1487
1790
|
err: error,
|
|
1488
1791
|
...context
|
|
1489
|
-
}
|
|
1792
|
+
});
|
|
1490
1793
|
}
|
|
1491
1794
|
|
|
1492
1795
|
/**
|
|
1493
1796
|
* Log info message
|
|
1494
1797
|
*/
|
|
1495
|
-
export function logInfo(message: string, data?: Record<string,
|
|
1496
|
-
logger.info(
|
|
1798
|
+
export function logInfo(message: string, data?: Record<string, unknown>): void {
|
|
1799
|
+
logger.info({ message, ...(data || {}) });
|
|
1497
1800
|
}
|
|
1498
1801
|
|
|
1499
1802
|
/**
|
|
1500
1803
|
* Log warning message
|
|
1501
1804
|
*/
|
|
1502
|
-
export function logWarning(message: string, data?: Record<string,
|
|
1503
|
-
logger.warn(
|
|
1805
|
+
export function logWarning(message: string, data?: Record<string, unknown>): void {
|
|
1806
|
+
logger.warn({ message, ...(data || {}) });
|
|
1504
1807
|
}
|
|
1505
1808
|
|
|
1506
1809
|
/**
|
|
1507
1810
|
* Log debug message (only in development)
|
|
1508
1811
|
*/
|
|
1509
|
-
export function logDebug(message: string, data?: Record<string,
|
|
1510
|
-
logger.debug(
|
|
1812
|
+
export function logDebug(message: string, data?: Record<string, unknown>): void {
|
|
1813
|
+
logger.debug({ message, ...(data || {}) });
|
|
1511
1814
|
}
|
|
1512
1815
|
`;
|
|
1816
|
+
await writeFile(path.join(projectPath, "src/shared/logger.utils.ts"), loggerUtilsContent);
|
|
1513
1817
|
}
|
|
1514
|
-
await writeFile(path.join(projectPath, "src/shared/logger.utils.ts"), loggerUtilsContent);
|
|
1515
1818
|
await writeFile(path.join(projectPath, "src/shared/stream.utils.ts"), generateStreamUtils());
|
|
1516
|
-
const loggerMiddlewareContent =
|
|
1819
|
+
const loggerMiddlewareContent = config.useKataxServiceManager
|
|
1820
|
+
? `import { Request, Response, NextFunction } from 'express';
|
|
1821
|
+
import { katax } from '${kataxImportSourceShared}';
|
|
1822
|
+
|
|
1823
|
+
function logRequest(method: string, url: string, statusCode: number, duration: number): void {
|
|
1824
|
+
katax.logger.info({
|
|
1825
|
+
message: \`\${method} \${url} - \${statusCode} (\${duration}ms)\`,
|
|
1826
|
+
method,
|
|
1827
|
+
url,
|
|
1828
|
+
statusCode,
|
|
1829
|
+
duration
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
/**
|
|
1834
|
+
* Express middleware to log all HTTP requests
|
|
1835
|
+
*/
|
|
1836
|
+
export function requestLogger(req: Request, res: Response, next: NextFunction): void {
|
|
1837
|
+
const startTime = Date.now();
|
|
1838
|
+
|
|
1839
|
+
// Log response when it finishes
|
|
1840
|
+
res.on('finish', () => {
|
|
1841
|
+
const duration = Date.now() - startTime;
|
|
1842
|
+
logRequest(req.method, req.url, res.statusCode, duration);
|
|
1843
|
+
});
|
|
1844
|
+
|
|
1845
|
+
next();
|
|
1846
|
+
}
|
|
1847
|
+
`
|
|
1848
|
+
: `import { Request, Response, NextFunction } from 'express';
|
|
1517
1849
|
import { logRequest } from '../shared/logger.utils.js';
|
|
1518
1850
|
|
|
1519
1851
|
/**
|
|
@@ -1557,7 +1889,16 @@ export const corsOptions: CorsOptions = {
|
|
|
1557
1889
|
};
|
|
1558
1890
|
`;
|
|
1559
1891
|
await writeFile(path.join(projectPath, "src/config/cors.config.ts"), corsConfigContent);
|
|
1560
|
-
const
|
|
1892
|
+
const envLoggerImport = config.useKataxServiceManager
|
|
1893
|
+
? `import { katax } from '${kataxImportSourceShared}';`
|
|
1894
|
+
: "import { logger } from '../shared/logger.utils.js';";
|
|
1895
|
+
const envErrorLogger = config.useKataxServiceManager
|
|
1896
|
+
? "katax.logger.error"
|
|
1897
|
+
: "logger.error";
|
|
1898
|
+
const envInfoLogger = config.useKataxServiceManager
|
|
1899
|
+
? "katax.logger.info"
|
|
1900
|
+
: "logger.info";
|
|
1901
|
+
const envValidatorContent = `${envLoggerImport}
|
|
1561
1902
|
|
|
1562
1903
|
interface RequiredEnvVars {
|
|
1563
1904
|
[key: string]: string;
|
|
@@ -1582,11 +1923,11 @@ ${config.database !== "none" ? ` // Database variables\n required.DATABASE_URL
|
|
|
1582
1923
|
}
|
|
1583
1924
|
|
|
1584
1925
|
if (missing.length > 0) {
|
|
1585
|
-
|
|
1586
|
-
|
|
1926
|
+
${envErrorLogger}({message:\`Missing required environment variables: \${missing.join(', ')}\`});
|
|
1927
|
+
${envErrorLogger}({message:'Please check your .env file'});
|
|
1587
1928
|
}
|
|
1588
1929
|
|
|
1589
|
-
|
|
1930
|
+
${envInfoLogger}({message:'Environment variables validated successfully'});
|
|
1590
1931
|
}
|
|
1591
1932
|
`;
|
|
1592
1933
|
await writeFile(path.join(projectPath, "src/config/env.validator.ts"), envValidatorContent);
|
|
@@ -1839,10 +2180,21 @@ MIT
|
|
|
1839
2180
|
}
|
|
1840
2181
|
async function createHelloEndpoint(projectPath, config) {
|
|
1841
2182
|
const helloPath = path.join(projectPath, "src/api/hello");
|
|
2183
|
+
const helloLoggerImport = config.useKataxServiceManager
|
|
2184
|
+
? config.kataxMode === "instance"
|
|
2185
|
+
? "import { katax } from '../../config/katax.instance.js';"
|
|
2186
|
+
: "import { katax } from 'katax-service-manager';"
|
|
2187
|
+
: "import { logger } from '../../shared/logger.utils.js';";
|
|
2188
|
+
const helloDebugLogger = config.useKataxServiceManager
|
|
2189
|
+
? "katax.logger.debug"
|
|
2190
|
+
: "logger.debug";
|
|
2191
|
+
const helloErrorLogger = config.useKataxServiceManager
|
|
2192
|
+
? "katax.logger.error"
|
|
2193
|
+
: "logger.error";
|
|
1842
2194
|
const controllerContent = [
|
|
1843
|
-
"import { ControllerResult,
|
|
2195
|
+
"import { ControllerResult, createResponse } from '../../shared/api.utils.js';",
|
|
1844
2196
|
"import { HelloQuery } from './hello.validator.js';",
|
|
1845
|
-
|
|
2197
|
+
helloLoggerImport,
|
|
1846
2198
|
"",
|
|
1847
2199
|
"/**",
|
|
1848
2200
|
" * Get hello message",
|
|
@@ -1850,9 +2202,9 @@ async function createHelloEndpoint(projectPath, config) {
|
|
|
1850
2202
|
"export async function getHello(queryData: HelloQuery): Promise<ControllerResult<{ message: string; timestamp: string }>> {",
|
|
1851
2203
|
" try {",
|
|
1852
2204
|
" const name = queryData.name || 'World';",
|
|
1853
|
-
|
|
2205
|
+
` ${helloDebugLogger}({ name, message: 'Processing hello request' });`,
|
|
1854
2206
|
" ",
|
|
1855
|
-
" return
|
|
2207
|
+
" return createResponse.success(",
|
|
1856
2208
|
" 'Hello endpoint working!',",
|
|
1857
2209
|
" {",
|
|
1858
2210
|
" message: `Hello ${name}! Welcome to your API 🚀`,",
|
|
@@ -1860,8 +2212,8 @@ async function createHelloEndpoint(projectPath, config) {
|
|
|
1860
2212
|
" }",
|
|
1861
2213
|
" );",
|
|
1862
2214
|
" } catch (error) {",
|
|
1863
|
-
|
|
1864
|
-
" return
|
|
2215
|
+
` ${helloErrorLogger}({ err: error, message: 'Error in getHello controller' });`,
|
|
2216
|
+
" return createResponse.error(",
|
|
1865
2217
|
" 'Failed to get hello message',",
|
|
1866
2218
|
" error instanceof Error ? error.message : 'Unknown error',",
|
|
1867
2219
|
" 500",
|
|
@@ -1914,6 +2266,7 @@ async function createHelloEndpoint(projectPath, config) {
|
|
|
1914
2266
|
if (config.validation === "katax-core") {
|
|
1915
2267
|
const validatorContent = [
|
|
1916
2268
|
"import { k, kataxInfer } from 'katax-core';",
|
|
2269
|
+
"import { validateSchema } from '../../shared/api.utils.js';",
|
|
1917
2270
|
"import type { ValidationResult } from '../../shared/api.utils.js';",
|
|
1918
2271
|
"",
|
|
1919
2272
|
"// ==================== SCHEMAS ====================",
|
|
@@ -1934,27 +2287,16 @@ async function createHelloEndpoint(projectPath, config) {
|
|
|
1934
2287
|
" * Validate hello query params",
|
|
1935
2288
|
" */",
|
|
1936
2289
|
"export async function validateHelloQuery(data: unknown): Promise<ValidationResult<HelloQuery>> {",
|
|
1937
|
-
"
|
|
1938
|
-
"",
|
|
1939
|
-
" if (!result.success) {",
|
|
1940
|
-
" const errors = result.issues.map(issue => ({",
|
|
1941
|
-
" field: issue.path.join('.'),",
|
|
1942
|
-
" message: issue.message",
|
|
1943
|
-
" }));",
|
|
1944
|
-
"",
|
|
1945
|
-
" return {",
|
|
1946
|
-
" isValid: false,",
|
|
1947
|
-
" errors",
|
|
1948
|
-
" };",
|
|
1949
|
-
" }",
|
|
1950
|
-
"",
|
|
1951
|
-
" return {",
|
|
1952
|
-
" isValid: true,",
|
|
1953
|
-
" data: result.data",
|
|
1954
|
-
" };",
|
|
2290
|
+
" return validateSchema(helloQuerySchema, data);",
|
|
1955
2291
|
"}",
|
|
1956
2292
|
].join("\n");
|
|
1957
2293
|
await writeFile(path.join(helloPath, "hello.validator.ts"), validatorContent);
|
|
1958
2294
|
}
|
|
1959
2295
|
}
|
|
2296
|
+
export const __initTestUtils = {
|
|
2297
|
+
getPackageManager,
|
|
2298
|
+
getInstallCommand,
|
|
2299
|
+
resolvePeerDependencies,
|
|
2300
|
+
KATAX_SERVICE_MANAGER_PEERS,
|
|
2301
|
+
};
|
|
1960
2302
|
//# sourceMappingURL=init.js.map
|