katax-cli 1.1.3 → 1.2.0

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.
Files changed (34) hide show
  1. package/dist/commands/add-endpoint.d.ts.map +1 -1
  2. package/dist/commands/add-endpoint.js +121 -97
  3. package/dist/commands/add-endpoint.js.map +1 -1
  4. package/dist/commands/deploy.d.ts +3 -0
  5. package/dist/commands/deploy.d.ts.map +1 -1
  6. package/dist/commands/deploy.js +287 -153
  7. package/dist/commands/deploy.js.map +1 -1
  8. package/dist/commands/generate-crud.d.ts.map +1 -1
  9. package/dist/commands/generate-crud.js +60 -56
  10. package/dist/commands/generate-crud.js.map +1 -1
  11. package/dist/commands/generate-docs.d.ts +8 -0
  12. package/dist/commands/generate-docs.d.ts.map +1 -0
  13. package/dist/commands/generate-docs.js +159 -0
  14. package/dist/commands/generate-docs.js.map +1 -0
  15. package/dist/commands/init.d.ts.map +1 -1
  16. package/dist/commands/init.js +506 -244
  17. package/dist/commands/init.js.map +1 -1
  18. package/dist/index.js +83 -69
  19. package/dist/index.js.map +1 -1
  20. package/dist/services/openapi-generator.service.d.ts +37 -0
  21. package/dist/services/openapi-generator.service.d.ts.map +1 -0
  22. package/dist/services/openapi-generator.service.js +333 -0
  23. package/dist/services/openapi-generator.service.js.map +1 -0
  24. package/dist/services/project-structure-generator.d.ts +1 -1
  25. package/dist/services/project-structure-generator.d.ts.map +1 -1
  26. package/dist/services/project-structure-generator.js +443 -445
  27. package/dist/services/project-structure-generator.js.map +1 -1
  28. package/dist/templates/generators/swagger-template.d.ts +3 -0
  29. package/dist/templates/generators/swagger-template.d.ts.map +1 -0
  30. package/dist/templates/generators/swagger-template.js +117 -0
  31. package/dist/templates/generators/swagger-template.js.map +1 -0
  32. package/dist/types/index.d.ts +19 -10
  33. package/dist/types/index.d.ts.map +1 -1
  34. package/package.json +1 -1
@@ -1,221 +1,284 @@
1
- import inquirer from 'inquirer';
2
- import ora from 'ora';
3
- import path from 'path';
4
- import crypto from 'crypto';
5
- import { execa } from 'execa';
6
- import { success, error, gray, title, info } from '../utils/logger.js';
7
- import { directoryExists, ensureDir, writeFile } from '../utils/file-utils.js';
1
+ import inquirer from "inquirer";
2
+ import ora from "ora";
3
+ import path from "path";
4
+ import crypto from "crypto";
5
+ import { execa } from "execa";
6
+ import { success, error, gray, title, info } from "../utils/logger.js";
7
+ import { directoryExists, ensureDir, writeFile, } from "../utils/file-utils.js";
8
+ import { generateSwaggerSetup } from "../templates/generators/swagger-template.js";
8
9
  export async function initCommand(projectName, options = {}) {
9
- title('🚀 Katax CLI - Initialize API Project');
10
- let finalProjectName = projectName || '';
10
+ title("🚀 Katax CLI - Initialize API Project");
11
+ let finalProjectName = projectName || "";
11
12
  if (!finalProjectName) {
12
13
  const answer = await inquirer.prompt([
13
14
  {
14
- type: 'input',
15
- name: 'projectName',
16
- message: 'Project name:',
17
- default: 'my-api',
15
+ type: "input",
16
+ name: "projectName",
17
+ message: "Project name:",
18
+ default: "my-api",
18
19
  validate: (input) => {
19
20
  if (!/^[a-z0-9-_]+$/i.test(input)) {
20
- return 'Project name can only contain letters, numbers, hyphens, and underscores';
21
+ return "Project name can only contain letters, numbers, hyphens, and underscores";
21
22
  }
22
23
  return true;
23
- }
24
- }
24
+ },
25
+ },
25
26
  ]);
26
27
  finalProjectName = answer.projectName;
27
28
  }
28
29
  const projectPath = path.join(process.cwd(), finalProjectName);
29
30
  if (directoryExists(projectPath) && !options.force) {
30
31
  error(`Directory "${finalProjectName}" already exists!`);
31
- gray('Use --force to overwrite\n');
32
+ gray("Use --force to overwrite\n");
32
33
  process.exit(1);
33
34
  }
34
35
  const answers = await inquirer.prompt([
35
36
  {
36
- type: 'input',
37
- name: 'description',
38
- message: 'Project description:',
39
- default: 'REST API built with Express and TypeScript'
37
+ type: "input",
38
+ name: "description",
39
+ message: "Project description:",
40
+ default: "REST API built with Express and TypeScript",
40
41
  },
41
42
  {
42
- type: 'list',
43
- name: 'database',
44
- message: 'Select database:',
43
+ type: "list",
44
+ name: "database",
45
+ message: "Select database:",
45
46
  choices: [
46
- { name: 'PostgreSQL', value: 'postgresql' },
47
- { name: 'MySQL', value: 'mysql' },
48
- { name: 'MongoDB', value: 'mongodb' },
49
- { name: 'None (no database)', value: 'none' }
47
+ { name: "PostgreSQL", value: "postgresql" },
48
+ { name: "MySQL", value: "mysql" },
49
+ { name: "MongoDB", value: "mongodb" },
50
+ { name: "None (no database)", value: "none" },
50
51
  ],
51
- default: 'postgresql'
52
+ default: "postgresql",
52
53
  },
53
54
  {
54
- type: 'list',
55
- name: 'authentication',
56
- message: 'Add authentication?',
55
+ type: "list",
56
+ name: "authentication",
57
+ message: "Add authentication?",
57
58
  choices: [
58
- { name: 'JWT Authentication', value: 'jwt' },
59
- { name: 'None', value: 'none' }
59
+ { name: "JWT Authentication", value: "jwt" },
60
+ { name: "None", value: "none" },
60
61
  ],
61
- default: 'jwt'
62
+ default: "jwt",
63
+ },
64
+ {
65
+ type: "confirm",
66
+ name: "validation",
67
+ message: "Use katax-core for validation?",
68
+ default: true,
69
+ },
70
+ {
71
+ type: "confirm",
72
+ name: "swagger",
73
+ message: "Install Swagger/OpenAPI documentation?",
74
+ default: true,
62
75
  },
63
76
  {
64
- type: 'confirm',
65
- name: 'validation',
66
- message: 'Use katax-core for validation?',
67
- default: true
77
+ type: "confirm",
78
+ name: "useKataxServiceManager",
79
+ message: "Use katax-service-manager for services? (logger, database, etc.)",
80
+ default: true,
68
81
  },
69
82
  {
70
- type: 'input',
71
- name: 'port',
72
- message: 'Server port:',
73
- default: '3000',
83
+ type: "confirm",
84
+ name: "useRedis",
85
+ message: "Add Redis cache support?",
86
+ default: false,
87
+ when: (answers) => answers.useKataxServiceManager,
88
+ },
89
+ {
90
+ type: "input",
91
+ name: "port",
92
+ message: "Server port:",
93
+ default: "3000",
74
94
  validate: (input) => {
75
95
  const port = parseInt(input);
76
96
  if (isNaN(port) || port < 1 || port > 65535) {
77
- return 'Port must be a number between 1 and 65535';
97
+ return "Port must be a number between 1 and 65535";
78
98
  }
79
99
  return true;
80
- }
81
- }
100
+ },
101
+ },
82
102
  ]);
83
103
  let dbConfig = {};
84
- if (answers.database !== 'none') {
104
+ if (answers.database !== "none") {
85
105
  const dbQuestions = [];
86
- if (answers.database === 'postgresql' || answers.database === 'mysql') {
106
+ if (answers.database === "postgresql" || answers.database === "mysql") {
87
107
  dbQuestions.push({
88
- type: 'input',
89
- name: 'host',
90
- message: `${answers.database === 'postgresql' ? 'PostgreSQL' : 'MySQL'} host:`,
91
- default: 'localhost'
108
+ type: "input",
109
+ name: "host",
110
+ message: `${answers.database === "postgresql" ? "PostgreSQL" : "MySQL"} host:`,
111
+ default: "localhost",
92
112
  }, {
93
- type: 'input',
94
- name: 'port',
95
- message: `${answers.database === 'postgresql' ? 'PostgreSQL' : 'MySQL'} port:`,
96
- default: answers.database === 'postgresql' ? '5432' : '3306'
113
+ type: "input",
114
+ name: "port",
115
+ message: `${answers.database === "postgresql" ? "PostgreSQL" : "MySQL"} port:`,
116
+ default: answers.database === "postgresql" ? "5432" : "3306",
97
117
  }, {
98
- type: 'input',
99
- name: 'user',
100
- message: 'Database user:',
101
- default: 'postgres'
118
+ type: "input",
119
+ name: "user",
120
+ message: "Database user:",
121
+ default: "postgres",
102
122
  }, {
103
- type: 'password',
104
- name: 'password',
105
- message: 'Database password:',
106
- default: 'password'
123
+ type: "password",
124
+ name: "password",
125
+ message: "Database password:",
126
+ default: "password",
107
127
  }, {
108
- type: 'input',
109
- name: 'database',
110
- message: 'Database name:',
111
- default: finalProjectName.toLowerCase().replace(/-/g, '_')
128
+ type: "input",
129
+ name: "database",
130
+ message: "Database name:",
131
+ default: finalProjectName.toLowerCase().replace(/-/g, "_"),
112
132
  });
113
133
  }
114
- else if (answers.database === 'mongodb') {
134
+ else if (answers.database === "mongodb") {
115
135
  dbQuestions.push({
116
- type: 'input',
117
- name: 'host',
118
- message: 'MongoDB host:',
119
- default: 'localhost'
136
+ type: "input",
137
+ name: "host",
138
+ message: "MongoDB host:",
139
+ default: "localhost",
120
140
  }, {
121
- type: 'input',
122
- name: 'port',
123
- message: 'MongoDB port:',
124
- default: '27017'
141
+ type: "input",
142
+ name: "port",
143
+ message: "MongoDB port:",
144
+ default: "27017",
125
145
  }, {
126
- type: 'input',
127
- name: 'database',
128
- message: 'Database name:',
129
- default: finalProjectName.toLowerCase().replace(/-/g, '_')
146
+ type: "input",
147
+ name: "database",
148
+ message: "Database name:",
149
+ default: finalProjectName.toLowerCase().replace(/-/g, "_"),
130
150
  }, {
131
- type: 'confirm',
132
- name: 'useAuth',
133
- message: 'Use authentication?',
134
- default: false
151
+ type: "confirm",
152
+ name: "useAuth",
153
+ message: "Use authentication?",
154
+ default: false,
135
155
  });
136
156
  }
137
157
  dbConfig = await inquirer.prompt(dbQuestions);
138
- if (answers.database === 'mongodb' && dbConfig.useAuth) {
158
+ if (answers.database === "mongodb" && dbConfig.useAuth) {
139
159
  const authConfig = await inquirer.prompt([
140
160
  {
141
- type: 'input',
142
- name: 'user',
143
- message: 'MongoDB user:',
144
- default: 'admin'
161
+ type: "input",
162
+ name: "user",
163
+ message: "MongoDB user:",
164
+ default: "admin",
145
165
  },
146
166
  {
147
- type: 'password',
148
- name: 'password',
149
- message: 'MongoDB password:',
150
- default: 'password'
151
- }
167
+ type: "password",
168
+ name: "password",
169
+ message: "MongoDB password:",
170
+ default: "password",
171
+ },
152
172
  ]);
153
173
  dbConfig.user = authConfig.user;
154
174
  dbConfig.password = authConfig.password;
155
175
  }
156
176
  }
177
+ let redisConfig = {};
178
+ if (answers.useRedis) {
179
+ redisConfig = await inquirer.prompt([
180
+ {
181
+ type: "input",
182
+ name: "host",
183
+ message: "Redis host:",
184
+ default: "localhost",
185
+ },
186
+ {
187
+ type: "input",
188
+ name: "port",
189
+ message: "Redis port:",
190
+ default: "6379",
191
+ },
192
+ {
193
+ type: "password",
194
+ name: "password",
195
+ message: "Redis password (leave empty for no password):",
196
+ default: "",
197
+ },
198
+ {
199
+ type: "input",
200
+ name: "db",
201
+ message: "Redis database number:",
202
+ default: "0",
203
+ },
204
+ ]);
205
+ }
157
206
  const config = {
158
207
  name: finalProjectName,
159
208
  description: answers.description,
160
- type: 'rest-api',
209
+ type: "rest-api",
161
210
  typescript: true,
162
211
  database: answers.database,
163
212
  authentication: answers.authentication,
164
- validation: answers.validation ? 'katax-core' : 'none',
165
- orm: 'none',
213
+ validation: answers.validation ? "katax-core" : "none",
214
+ swagger: answers.swagger,
215
+ orm: "none",
166
216
  port: parseInt(answers.port),
167
- dbConfig
217
+ useKataxServiceManager: answers.useKataxServiceManager,
218
+ useRedis: answers.useRedis || false,
219
+ redisConfig,
220
+ dbConfig,
168
221
  };
169
222
  let generateJwtSecrets = false;
170
- if (config.authentication === 'jwt') {
223
+ if (config.authentication === "jwt") {
171
224
  const jwtAnswer = await inquirer.prompt([
172
225
  {
173
- type: 'confirm',
174
- name: 'generate',
175
- message: 'Generate JWT secrets automatically?',
176
- default: true
177
- }
226
+ type: "confirm",
227
+ name: "generate",
228
+ message: "Generate JWT secrets automatically?",
229
+ default: true,
230
+ },
178
231
  ]);
179
232
  generateJwtSecrets = jwtAnswer.generate;
180
233
  }
181
- gray('\n📋 Project Configuration:');
234
+ gray("\n📋 Project Configuration:");
182
235
  gray(` Name: ${config.name}`);
183
236
  gray(` Database: ${config.database}`);
184
237
  gray(` Auth: ${config.authentication}`);
185
238
  gray(` Validation: ${config.validation}`);
239
+ gray(` Swagger: ${config.swagger ? "Yes" : "No"}`);
240
+ gray(` Service Manager: ${config.useKataxServiceManager ? "katax-service-manager" : "manual"}`);
241
+ if (config.useKataxServiceManager) {
242
+ gray(` Redis Cache: ${config.useRedis ? "Yes" : "No"}`);
243
+ }
186
244
  gray(` Port: ${config.port}\n`);
187
- const spinner = ora('Creating project structure...').start();
245
+ const spinner = ora("Creating project structure...").start();
188
246
  try {
189
247
  await createProjectStructure(projectPath, config, generateJwtSecrets);
190
- spinner.succeed('Project structure created');
191
- spinner.start('Installing dependencies...');
248
+ spinner.succeed("Project structure created");
249
+ spinner.start("Installing dependencies...");
192
250
  await installDependencies(projectPath);
193
- spinner.succeed('Dependencies installed');
251
+ spinner.succeed("Dependencies installed");
194
252
  success(`\n✨ Project "${finalProjectName}" created successfully!\n`);
195
- info('Next steps:');
253
+ info("Next steps:");
196
254
  gray(` cd ${finalProjectName}`);
197
255
  gray(` npm run dev\n`);
198
- info('Available commands:');
256
+ info("Available commands:");
199
257
  gray(` katax add endpoint <name> - Add a new endpoint`);
200
258
  gray(` katax generate crud <name> - Generate CRUD resource`);
201
259
  gray(` katax info - Show project structure\n`);
260
+ if (config.swagger) {
261
+ info("📖 API Documentation:");
262
+ gray(` Open http://localhost:${config.port}/docs after starting the server`);
263
+ gray(` Swagger UI is pre-configured and ready to use!\n`);
264
+ }
202
265
  }
203
266
  catch (err) {
204
- spinner.fail('Failed to create project');
205
- error(err instanceof Error ? err.message : 'Unknown error');
267
+ spinner.fail("Failed to create project");
268
+ error(err instanceof Error ? err.message : "Unknown error");
206
269
  process.exit(1);
207
270
  }
208
271
  }
209
272
  async function installDependencies(projectPath) {
210
- await execa('npm', ['install'], {
273
+ await execa("npm", ["install"], {
211
274
  cwd: projectPath,
212
- stdio: 'ignore'
275
+ stdio: "ignore",
213
276
  });
214
277
  }
215
278
  async function createDatabaseConnection(projectPath, config) {
216
- const destPath = path.join(projectPath, 'src/database/connection.ts');
217
- let content = '';
218
- if (config.database === 'postgresql') {
279
+ const destPath = path.join(projectPath, "src/database/connection.ts");
280
+ let content = "";
281
+ if (config.database === "postgresql") {
219
282
  content = [
220
283
  "import { Pool } from 'pg';",
221
284
  "import dotenv from 'dotenv';",
@@ -268,10 +331,10 @@ async function createDatabaseConnection(projectPath, config) {
268
331
  " };",
269
332
  " ",
270
333
  " return client;",
271
- "}"
272
- ].join('\n');
334
+ "}",
335
+ ].join("\n");
273
336
  }
274
- else if (config.database === 'mysql') {
337
+ else if (config.database === "mysql") {
275
338
  content = [
276
339
  "import mysql from 'mysql2/promise';",
277
340
  "",
@@ -294,10 +357,10 @@ async function createDatabaseConnection(projectPath, config) {
294
357
  "",
295
358
  "export async function getConnection() {",
296
359
  " return await pool.getConnection();",
297
- "}"
298
- ].join('\n');
360
+ "}",
361
+ ].join("\n");
299
362
  }
300
- else if (config.database === 'mongodb') {
363
+ else if (config.database === "mongodb") {
301
364
  content = [
302
365
  "import { MongoClient, Db } from 'mongodb';",
303
366
  "",
@@ -344,103 +407,105 @@ async function createDatabaseConnection(projectPath, config) {
344
407
  " return db;",
345
408
  "}",
346
409
  "",
347
- "export default { connect, disconnect, getDb };"
348
- ].join('\n');
410
+ "export default { connect, disconnect, getDb };",
411
+ ].join("\n");
349
412
  }
350
413
  await writeFile(destPath, content);
351
414
  }
352
415
  async function createProjectStructure(projectPath, config, generateJwtSecrets) {
353
416
  const dirs = [
354
- 'src',
355
- 'src/api',
356
- 'src/config',
357
- 'src/middleware',
358
- 'src/shared',
359
- 'src/types'
417
+ "src",
418
+ "src/api",
419
+ "src/config",
420
+ "src/middleware",
421
+ "src/shared",
422
+ "src/types",
360
423
  ];
361
- if (config.database !== 'none') {
362
- dirs.push('src/database');
424
+ if (config.database !== "none") {
425
+ dirs.push("src/database");
363
426
  }
364
- dirs.push('src/api/hello');
427
+ dirs.push("src/api/hello");
365
428
  for (const dir of dirs) {
366
429
  await ensureDir(path.join(projectPath, dir));
367
430
  }
368
431
  const packageJson = {
369
432
  name: config.name,
370
- version: '1.0.0',
433
+ version: "1.0.0",
371
434
  description: config.description,
372
- type: 'module',
373
- main: 'dist/index.js',
435
+ type: "module",
436
+ main: "dist/index.js",
374
437
  scripts: {
375
- dev: 'nodemon --watch src --exec tsx src/index.ts',
376
- build: 'tsc',
377
- start: 'node dist/index.js',
378
- lint: 'eslint . --ext .ts',
379
- format: 'prettier --write "src/**/*.ts"'
438
+ dev: "nodemon --watch src --exec tsx src/index.ts",
439
+ build: "tsc",
440
+ start: "node dist/index.js",
441
+ lint: "eslint . --ext .ts",
442
+ format: 'prettier --write "src/**/*.ts"',
380
443
  },
381
- keywords: ['api', 'express', 'typescript'],
382
- author: '',
383
- license: 'MIT',
444
+ keywords: ["api", "express", "typescript"],
445
+ author: "",
446
+ license: "MIT",
384
447
  dependencies: {
385
- express: '^4.18.2',
386
- cors: '^2.8.5',
387
- dotenv: '^16.3.1',
388
- pino: '^8.17.2',
389
- 'pino-pretty': '^10.3.1',
390
- ...(config.validation === 'katax-core' && { 'katax-core': '^1.5.0' }),
391
- ...(config.authentication === 'jwt' && {
392
- jsonwebtoken: '^9.0.2',
393
- bcrypt: '^5.1.1'
448
+ express: "^4.18.2",
449
+ cors: "^2.8.5",
450
+ dotenv: "^16.3.1",
451
+ ...(config.useKataxServiceManager
452
+ ? { "katax-service-manager": "^0.1.0" }
453
+ : { pino: "^8.17.2", "pino-pretty": "^10.3.1" }),
454
+ ...(config.validation === "katax-core" && { "katax-core": "^1.5.0" }),
455
+ ...(config.authentication === "jwt" && {
456
+ jsonwebtoken: "^9.0.2",
457
+ bcrypt: "^5.1.1",
394
458
  }),
395
- ...(config.database === 'postgresql' && { pg: '^8.11.3' }),
396
- ...(config.database === 'mysql' && { mysql2: '^3.6.5' }),
397
- ...(config.database === 'mongodb' && { mongodb: '^6.3.0' })
459
+ ...(config.swagger && { "swagger-ui-express": "^5.0.0" }),
460
+ ...(config.database === "postgresql" && { pg: "^8.11.3" }),
461
+ ...(config.database === "mysql" && { mysql2: "^3.6.5" }),
462
+ ...(config.database === "mongodb" && { mongodb: "^6.3.0" }),
463
+ ...(config.useRedis && { ioredis: "^5.3.2" }),
398
464
  },
399
465
  devDependencies: {
400
- '@types/express': '^4.17.21',
401
- '@types/cors': '^2.8.17',
402
- '@types/node': '^22.10.5',
403
- ...(config.authentication === 'jwt' && {
404
- '@types/jsonwebtoken': '^9.0.5',
405
- '@types/bcrypt': '^5.0.2'
466
+ "@types/express": "^4.17.21",
467
+ "@types/cors": "^2.8.17",
468
+ "@types/node": "^22.10.5",
469
+ ...(config.authentication === "jwt" && {
470
+ "@types/jsonwebtoken": "^9.0.5",
471
+ "@types/bcrypt": "^5.0.2",
406
472
  }),
407
- ...(config.database === 'postgresql' && { '@types/pg': '^8.10.9' }),
408
- typescript: '^5.3.3',
409
- tsx: '^4.7.0',
410
- nodemon: '^3.0.2',
411
- eslint: '^8.56.0',
412
- '@typescript-eslint/eslint-plugin': '^6.19.0',
413
- '@typescript-eslint/parser': '^6.19.0',
414
- prettier: '^3.2.4'
415
- }
473
+ ...(config.swagger && { "@types/swagger-ui-express": "^4.1.6" }),
474
+ ...(config.database === "postgresql" && { "@types/pg": "^8.10.9" }),
475
+ typescript: "^5.3.3",
476
+ tsx: "^4.7.0",
477
+ nodemon: "^3.0.2",
478
+ eslint: "^8.56.0",
479
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
480
+ "@typescript-eslint/parser": "^6.19.0",
481
+ prettier: "^3.2.4",
482
+ },
416
483
  };
417
- await writeFile(path.join(projectPath, 'package.json'), JSON.stringify(packageJson, null, 2));
484
+ await writeFile(path.join(projectPath, "package.json"), JSON.stringify(packageJson, null, 2));
418
485
  const tsConfig = {
419
486
  compilerOptions: {
420
- target: 'ES2022',
421
- module: 'ESNext',
422
- lib: ['ES2022'],
423
- moduleResolution: 'node',
487
+ target: "ES2022",
488
+ module: "ESNext",
489
+ lib: ["ES2022"],
490
+ moduleResolution: "node",
424
491
  esModuleInterop: true,
425
492
  allowSyntheticDefaultImports: true,
426
493
  forceConsistentCasingInFileNames: true,
427
494
  strict: true,
428
495
  skipLibCheck: true,
429
496
  resolveJsonModule: true,
430
- declaration: true,
431
- declarationMap: true,
432
497
  sourceMap: true,
433
498
  removeComments: true,
434
- outDir: './dist',
435
- rootDir: './src'
499
+ outDir: "./dist",
500
+ rootDir: "./src",
436
501
  },
437
- include: ['src/**/*'],
438
- exclude: ['node_modules', 'dist']
502
+ include: ["src/**/*"],
503
+ exclude: ["node_modules", "dist"],
439
504
  };
440
- await writeFile(path.join(projectPath, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
441
- let databaseUrl = '';
442
- let dbEnvVars = '';
443
- if (config.database === 'postgresql' && config.dbConfig) {
505
+ await writeFile(path.join(projectPath, "tsconfig.json"), JSON.stringify(tsConfig, null, 2));
506
+ let databaseUrl = "";
507
+ let dbEnvVars = "";
508
+ if (config.database === "postgresql" && config.dbConfig) {
444
509
  const { host, port, user, password, database } = config.dbConfig;
445
510
  databaseUrl = `DATABASE_URL=postgresql://${user}:${password}@${host}:${port}/${database}`;
446
511
  dbEnvVars = `DB_HOST=${host}
@@ -449,7 +514,7 @@ DB_NAME=${database}
449
514
  DB_USER=${user}
450
515
  DB_PASSWORD=${password}`;
451
516
  }
452
- else if (config.database === 'mysql' && config.dbConfig) {
517
+ else if (config.database === "mysql" && config.dbConfig) {
453
518
  const { host, port, user, password, database } = config.dbConfig;
454
519
  databaseUrl = `DATABASE_URL=mysql://${user}:${password}@${host}:${port}/${database}`;
455
520
  dbEnvVars = `DB_HOST=${host}
@@ -458,7 +523,7 @@ DB_NAME=${database}
458
523
  DB_USER=${user}
459
524
  DB_PASSWORD=${password}`;
460
525
  }
461
- else if (config.database === 'mongodb' && config.dbConfig) {
526
+ else if (config.database === "mongodb" && config.dbConfig) {
462
527
  const { host, port, database, user, password } = config.dbConfig;
463
528
  if (user && password) {
464
529
  databaseUrl = `DATABASE_URL=mongodb://${user}:${password}@${host}:${port}/${database}`;
@@ -475,11 +540,11 @@ DB_PORT=${port}
475
540
  DB_NAME=${database}`;
476
541
  }
477
542
  }
478
- let jwtConfig = '';
479
- if (config.authentication === 'jwt') {
543
+ let jwtConfig = "";
544
+ if (config.authentication === "jwt") {
480
545
  if (generateJwtSecrets) {
481
- const jwtSecret = crypto.randomBytes(64).toString('hex');
482
- const jwtRefreshSecret = crypto.randomBytes(64).toString('hex');
546
+ const jwtSecret = crypto.randomBytes(64).toString("hex");
547
+ const jwtRefreshSecret = crypto.randomBytes(64).toString("hex");
483
548
  jwtConfig = `JWT_SECRET=${jwtSecret}
484
549
  JWT_EXPIRES_IN=24h
485
550
  JWT_REFRESH_SECRET=${jwtRefreshSecret}
@@ -492,6 +557,16 @@ JWT_REFRESH_SECRET=your-refresh-secret-here
492
557
  JWT_REFRESH_EXPIRES_IN=7d`;
493
558
  }
494
559
  }
560
+ let redisEnvVars = "";
561
+ if (config.useRedis && config.redisConfig) {
562
+ const { host, port, password, db } = config.redisConfig;
563
+ redisEnvVars = `
564
+ # Redis Configuration
565
+ REDIS_HOST=${host || 'localhost'}
566
+ REDIS_PORT=${port || '6379'}
567
+ REDIS_PASSWORD=${password || ''}
568
+ REDIS_DB=${db || '0'}`;
569
+ }
495
570
  const envContent = `# Server Configuration
496
571
  PORT=${config.port}
497
572
  NODE_ENV=development
@@ -499,16 +574,15 @@ LOG_LEVEL=info
499
574
 
500
575
  # CORS Configuration
501
576
  ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
502
-
577
+ ${config.database !== "none" ? `
503
578
  # Database Configuration
504
- ${databaseUrl}
505
- ${dbEnvVars ? '\n# DB connection variables for pool\n' + dbEnvVars : ''}
506
-
507
- # JWT Configuration
508
- ${jwtConfig}
579
+ ${databaseUrl}
580
+ ${dbEnvVars ? "\n# DB connection variables for pool\n" + dbEnvVars : ""}` : ""}
581
+ ${redisEnvVars}
582
+ ${config.authentication === "jwt" ? `\n# JWT Configuration\n${jwtConfig}` : ""}
509
583
  `;
510
- await writeFile(path.join(projectPath, '.env.example'), envContent);
511
- await writeFile(path.join(projectPath, '.env'), envContent);
584
+ await writeFile(path.join(projectPath, ".env.example"), envContent);
585
+ await writeFile(path.join(projectPath, ".env"), envContent);
512
586
  const gitignoreContent = `node_modules/
513
587
  dist/
514
588
  .env
@@ -517,7 +591,7 @@ dist/
517
591
  coverage/
518
592
  .vscode/
519
593
  `;
520
- await writeFile(path.join(projectPath, '.gitignore'), gitignoreContent);
594
+ await writeFile(path.join(projectPath, ".gitignore"), gitignoreContent);
521
595
  const gitattributesContent = `# Auto normalize line endings to LF on checkout (critical for Ubuntu deployment)
522
596
  * text=auto eol=lf
523
597
 
@@ -537,8 +611,66 @@ coverage/
537
611
  *.ico binary
538
612
  *.pdf binary
539
613
  `;
540
- await writeFile(path.join(projectPath, '.gitattributes'), gitattributesContent);
541
- const indexContent = `import app from './app.js';
614
+ await writeFile(path.join(projectPath, ".gitattributes"), gitattributesContent);
615
+ let indexContent;
616
+ if (config.useKataxServiceManager) {
617
+ const dbInitCode = config.database !== "none" ? `
618
+ // Initialize database
619
+ await katax.database({
620
+ name: 'main',
621
+ type: '${config.database}',
622
+ connection: {
623
+ host: katax.envRequired('DB_HOST'),
624
+ port: parseInt(katax.env('DB_PORT', '${config.database === 'postgresql' ? '5432' : config.database === 'mysql' ? '3306' : '27017'}')),
625
+ database: katax.envRequired('DB_NAME'),
626
+ user: katax.envRequired('DB_USER'),
627
+ password: katax.envRequired('DB_PASSWORD'),
628
+ }
629
+ });
630
+ ` : '';
631
+ const cacheInitCode = config.useRedis ? `
632
+ // Initialize Redis cache
633
+ await katax.cache({
634
+ name: 'main',
635
+ host: katax.env('REDIS_HOST', 'localhost'),
636
+ port: parseInt(katax.env('REDIS_PORT', '6379')),
637
+ password: katax.env('REDIS_PASSWORD'),
638
+ db: parseInt(katax.env('REDIS_DB', '0')),
639
+ });
640
+ ` : '';
641
+ indexContent = `import { katax } from 'katax-service-manager';
642
+ import app from './app.js';
643
+ import dotenv from 'dotenv';
644
+
645
+ dotenv.config();
646
+
647
+ // Initialize katax and start server
648
+ katax.init({
649
+ logger: {
650
+ level: katax.env('LOG_LEVEL', 'info') as 'info' | 'debug' | 'warn' | 'error',
651
+ prettyPrint: katax.isDev,
652
+ }
653
+ }).then(async () => {
654
+ ${dbInitCode}${cacheInitCode}
655
+ const PORT = katax.env('PORT', '${config.port}');
656
+
657
+ app.listen(PORT, () => {
658
+ katax.logger.info({ message: \`Server running on http://localhost:\${PORT}\` });
659
+ katax.logger.info({ message: \`API endpoints available at http://localhost:\${PORT}/api\` });
660
+ katax.logger.info({ message: \`Health check: http://localhost:\${PORT}/api/health\` });
661
+ });
662
+
663
+ // Graceful shutdown
664
+ process.on('SIGTERM', async () => {
665
+ katax.logger.info({ message: 'SIGTERM received, shutting down...' });
666
+ await katax.shutdown();
667
+ process.exit(0);
668
+ });
669
+ });
670
+ `;
671
+ }
672
+ else {
673
+ indexContent = `import app from './app.js';
542
674
  import dotenv from 'dotenv';
543
675
  import { logger } from './shared/logger.utils.js';
544
676
  import { validateEnvironment } from './config/env.validator.js';
@@ -556,13 +688,14 @@ app.listen(PORT, () => {
556
688
  logger.info(\`Health check: http://localhost:\${PORT}/api/health\`);
557
689
  });
558
690
  `;
559
- await writeFile(path.join(projectPath, 'src/index.ts'), indexContent);
691
+ }
692
+ await writeFile(path.join(projectPath, "src/index.ts"), indexContent);
560
693
  const appContent = `import express from 'express';
561
694
  import cors from 'cors';
562
695
  import router from './api/routes.js';
563
696
  import { errorMiddleware } from './middleware/error.middleware.js';
564
697
  import { requestLogger } from './middleware/logger.middleware.js';
565
- import { corsOptions } from './config/cors.config.js';
698
+ import { corsOptions } from './config/cors.config.js';${config.swagger ? "\nimport { setupSwagger } from './config/swagger.config.js';" : ""}
566
699
 
567
700
  const app = express();
568
701
 
@@ -572,13 +705,13 @@ app.use(express.json());
572
705
  app.use(express.urlencoded({ extended: true }));
573
706
  app.use(requestLogger);
574
707
 
575
- // Routes
708
+ ${config.swagger ? "// API Documentation\nsetupSwagger(app);\n\n" : ""}// Routes
576
709
  app.get('/', (req, res) => {
577
710
  res.json({
578
711
  message: 'Welcome to ${config.name} API',
579
712
  version: '1.0.0',
580
713
  endpoints: '/api',
581
- health: '/api/health'
714
+ health: '/api/health'${config.swagger ? ",\n docs: '/docs'" : ""}
582
715
  });
583
716
  });
584
717
 
@@ -589,7 +722,7 @@ app.use(errorMiddleware);
589
722
 
590
723
  export default app;
591
724
  `;
592
- await writeFile(path.join(projectPath, 'src/app.ts'), appContent);
725
+ await writeFile(path.join(projectPath, "src/app.ts"), appContent);
593
726
  const routesContent = `import { Router } from 'express';
594
727
  import helloRouter from './hello/hello.routes.js';
595
728
  import { healthCheckHandler } from './health/health.handler.js';
@@ -604,7 +737,7 @@ router.use('/hello', helloRouter);
604
737
 
605
738
  export default router;
606
739
  `;
607
- await writeFile(path.join(projectPath, 'src/api/routes.ts'), routesContent);
740
+ await writeFile(path.join(projectPath, "src/api/routes.ts"), routesContent);
608
741
  const errorMiddlewareContent = `import { Request, Response, NextFunction } from 'express';
609
742
  import { logger } from '../shared/logger.utils.js';
610
743
 
@@ -638,11 +771,11 @@ export function errorMiddleware(
638
771
  });
639
772
  }
640
773
  `;
641
- await writeFile(path.join(projectPath, 'src/middleware/error.middleware.ts'), errorMiddlewareContent);
642
- if (config.database !== 'none') {
774
+ await writeFile(path.join(projectPath, "src/middleware/error.middleware.ts"), errorMiddlewareContent);
775
+ if (config.database !== "none" && !config.useKataxServiceManager) {
643
776
  await createDatabaseConnection(projectPath, config);
644
777
  }
645
- if (config.validation === 'katax-core') {
778
+ if (config.validation === "katax-core") {
646
779
  const apiUtilsContent = `import { Request, Response } from 'express';
647
780
  import { logger } from './logger.utils.js';
648
781
 
@@ -741,9 +874,9 @@ export async function sendResponse<TValidation = any, TResponse = any>(
741
874
  }
742
875
  }
743
876
  `;
744
- await writeFile(path.join(projectPath, 'src/shared/api.utils.ts'), apiUtilsContent);
877
+ await writeFile(path.join(projectPath, "src/shared/api.utils.ts"), apiUtilsContent);
745
878
  }
746
- if (config.authentication === 'jwt') {
879
+ if (config.authentication === "jwt") {
747
880
  const jwtUtilsContent = `import jwt from 'jsonwebtoken';
748
881
  import { Request, Response, NextFunction } from 'express';
749
882
 
@@ -897,9 +1030,66 @@ export function requireRole(...roles: string[]) {
897
1030
  };
898
1031
  }
899
1032
  `;
900
- await writeFile(path.join(projectPath, 'src/shared/jwt.utils.ts'), jwtUtilsContent);
1033
+ await writeFile(path.join(projectPath, "src/shared/jwt.utils.ts"), jwtUtilsContent);
901
1034
  }
902
- const loggerUtilsContent = `import pino from 'pino';
1035
+ let loggerUtilsContent;
1036
+ if (config.useKataxServiceManager) {
1037
+ loggerUtilsContent = `import { katax } from 'katax-service-manager';
1038
+
1039
+ /**
1040
+ * Re-export katax logger for convenience
1041
+ * Uses katax-service-manager's built-in pino logger
1042
+ */
1043
+ export const logger = katax.logger;
1044
+
1045
+ /**
1046
+ * Log HTTP request
1047
+ */
1048
+ export function logRequest(method: string, url: string, statusCode: number, duration: number): void {
1049
+ katax.logger.info({
1050
+ message: \`\${method} \${url} - \${statusCode} (\${duration}ms)\`,
1051
+ method,
1052
+ url,
1053
+ statusCode,
1054
+ duration: \`\${duration}ms\`
1055
+ });
1056
+ }
1057
+
1058
+ /**
1059
+ * Log error with context
1060
+ */
1061
+ export function logError(error: Error, context?: Record<string, any>): void {
1062
+ katax.logger.error({
1063
+ message: error.message,
1064
+ err: error,
1065
+ ...context
1066
+ });
1067
+ }
1068
+
1069
+ /**
1070
+ * Log info message
1071
+ */
1072
+ export function logInfo(message: string, data?: Record<string, any>): void {
1073
+ katax.logger.info({ message, ...data });
1074
+ }
1075
+
1076
+ /**
1077
+ * Log warning message
1078
+ */
1079
+ export function logWarning(message: string, data?: Record<string, any>): void {
1080
+ katax.logger.warn({ message, ...data });
1081
+ }
1082
+
1083
+ /**
1084
+ * Log debug message
1085
+ */
1086
+ export function logDebug(message: string, data?: Record<string, any>): void {
1087
+ katax.logger.debug({ message, ...data });
1088
+ }
1089
+ `;
1090
+ }
1091
+ else {
1092
+ loggerUtilsContent = `import pino from 'pino';
903
1093
 
904
1094
  const isDevelopment = process.env.NODE_ENV !== 'production';
905
1095
 
@@ -970,7 +1160,8 @@ export function logDebug(message: string, data?: Record<string, any>): void {
970
1160
  logger.debug(data, message);
971
1161
  }
972
1162
  `;
973
- await writeFile(path.join(projectPath, 'src/shared/logger.utils.ts'), loggerUtilsContent);
1163
+ }
1164
+ await writeFile(path.join(projectPath, "src/shared/logger.utils.ts"), loggerUtilsContent);
974
1165
  const loggerMiddlewareContent = `import { Request, Response, NextFunction } from 'express';
975
1166
  import { logRequest } from '../shared/logger.utils.js';
976
1167
 
@@ -989,7 +1180,7 @@ export function requestLogger(req: Request, res: Response, next: NextFunction):
989
1180
  next();
990
1181
  }
991
1182
  `;
992
- await writeFile(path.join(projectPath, 'src/middleware/logger.middleware.ts'), loggerMiddlewareContent);
1183
+ await writeFile(path.join(projectPath, "src/middleware/logger.middleware.ts"), loggerMiddlewareContent);
993
1184
  const corsConfigContent = `import { CorsOptions } from 'cors';
994
1185
 
995
1186
  const allowedOrigins = process.env.ALLOWED_ORIGINS
@@ -1013,7 +1204,7 @@ export const corsOptions: CorsOptions = {
1013
1204
  allowedHeaders: ['Content-Type', 'Authorization']
1014
1205
  };
1015
1206
  `;
1016
- await writeFile(path.join(projectPath, 'src/config/cors.config.ts'), corsConfigContent);
1207
+ await writeFile(path.join(projectPath, "src/config/cors.config.ts"), corsConfigContent);
1017
1208
  const envValidatorContent = `import { logger } from '../shared/logger.utils.js';
1018
1209
 
1019
1210
  interface RequiredEnvVars {
@@ -1029,7 +1220,7 @@ export function validateEnvironment(): void {
1029
1220
  NODE_ENV: process.env.NODE_ENV || ''
1030
1221
  };
1031
1222
 
1032
- ${config.database !== 'none' ? ` // Database variables\n required.DATABASE_URL = process.env.DATABASE_URL || '';\n` : ''}${config.authentication === 'jwt' ? ` // JWT variables\n required.JWT_SECRET = process.env.JWT_SECRET || '';\n required.JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET || '';\n` : ''}
1223
+ ${config.database !== "none" ? ` // Database variables\n required.DATABASE_URL = process.env.DATABASE_URL || '';\n` : ""}${config.authentication === "jwt" ? ` // JWT variables\n required.JWT_SECRET = process.env.JWT_SECRET || '';\n required.JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET || '';\n` : ""}
1033
1224
  const missing: string[] = [];
1034
1225
 
1035
1226
  for (const [key, value] of Object.entries(required)) {
@@ -1047,7 +1238,78 @@ ${config.database !== 'none' ? ` // Database variables\n required.DATABASE_URL
1047
1238
  logger.info('Environment variables validated successfully');
1048
1239
  }
1049
1240
  `;
1050
- await writeFile(path.join(projectPath, 'src/config/env.validator.ts'), envValidatorContent);
1241
+ await writeFile(path.join(projectPath, "src/config/env.validator.ts"), envValidatorContent);
1242
+ if (config.swagger) {
1243
+ await writeFile(path.join(projectPath, "src/config/swagger.config.ts"), generateSwaggerSetup());
1244
+ const initialOpenAPISpec = {
1245
+ openapi: "3.0.0",
1246
+ info: {
1247
+ title: config.name,
1248
+ version: "1.0.0",
1249
+ description: config.description || "API Documentation",
1250
+ },
1251
+ servers: [
1252
+ {
1253
+ url: `http://localhost:${config.port}`,
1254
+ description: "Development server",
1255
+ },
1256
+ ],
1257
+ paths: {
1258
+ "/": {
1259
+ get: {
1260
+ tags: ["General"],
1261
+ summary: "Welcome endpoint",
1262
+ responses: {
1263
+ "200": {
1264
+ description: "Welcome message",
1265
+ content: {
1266
+ "application/json": {
1267
+ schema: {
1268
+ type: "object",
1269
+ properties: {
1270
+ message: { type: "string" },
1271
+ version: { type: "string" },
1272
+ endpoints: { type: "string" },
1273
+ health: { type: "string" },
1274
+ docs: { type: "string" },
1275
+ },
1276
+ },
1277
+ },
1278
+ },
1279
+ },
1280
+ },
1281
+ },
1282
+ },
1283
+ "/api/health": {
1284
+ get: {
1285
+ tags: ["Health"],
1286
+ summary: "Health check endpoint",
1287
+ responses: {
1288
+ "200": {
1289
+ description: "Health status",
1290
+ content: {
1291
+ "application/json": {
1292
+ schema: {
1293
+ type: "object",
1294
+ properties: {
1295
+ status: { type: "string" },
1296
+ timestamp: { type: "string" },
1297
+ uptime: { type: "number" },
1298
+ },
1299
+ },
1300
+ },
1301
+ },
1302
+ },
1303
+ },
1304
+ },
1305
+ },
1306
+ },
1307
+ components: {
1308
+ schemas: {},
1309
+ },
1310
+ };
1311
+ await writeFile(path.join(projectPath, "src/openapi.json"), JSON.stringify(initialOpenAPISpec, null, 2));
1312
+ }
1051
1313
  const healthHandlerContent = `import { Request, Response } from 'express';
1052
1314
  import os from 'os';
1053
1315
 
@@ -1120,8 +1382,8 @@ function formatBytes(bytes: number): string {
1120
1382
  return \`\${size.toFixed(2)} \${units[unitIndex]}\`;
1121
1383
  }
1122
1384
  `;
1123
- await ensureDir(path.join(projectPath, 'src/api/health'));
1124
- await writeFile(path.join(projectPath, 'src/api/health/health.handler.ts'), healthHandlerContent);
1385
+ await ensureDir(path.join(projectPath, "src/api/health"));
1386
+ await writeFile(path.join(projectPath, "src/api/health/health.handler.ts"), healthHandlerContent);
1125
1387
  const readmeContent = `# ${config.name}
1126
1388
 
1127
1389
  ${config.description}
@@ -1157,15 +1419,15 @@ src/
1157
1419
 
1158
1420
  - **Express** - Web framework
1159
1421
  - **TypeScript** - Type safety
1160
- ${config.validation === 'katax-core' ? '- **katax-core** - Schema validation\n' : ''}${config.authentication === 'jwt' ? '- **JWT** - Authentication\n' : ''}${config.database !== 'none' ? `- **${config.database}** - Database\n` : ''}
1422
+ ${config.validation === "katax-core" ? "- **katax-core** - Schema validation\n" : ""}${config.authentication === "jwt" ? "- **JWT** - Authentication\n" : ""}${config.swagger ? "- **Swagger** - API Documentation\n" : ""}${config.database !== "none" ? `- **${config.database}** - Database\n` : ""}
1161
1423
  ## 📚 API Documentation
1162
1424
 
1163
1425
  Server runs on \`http://localhost:${config.port}\`
1164
-
1426
+ ${config.swagger ? `\n### Interactive Documentation\n\nSwagger UI is available at: **http://localhost:${config.port}/docs**\n\n- View all endpoints\n- Test API calls directly\n- See request/response schemas\n- Auto-updated when you add endpoints\n\n` : ""}
1165
1427
  ### Endpoints
1166
1428
 
1167
1429
  - \`GET /\` - Welcome message
1168
- - \`GET /api/health\` - Health check
1430
+ - \`GET /api/health\` - Health check${config.swagger ? "\n- `GET /docs` - Swagger UI\n- `GET /openapi.json` - OpenAPI Specification" : ""}
1169
1431
 
1170
1432
  ## 🔧 Development
1171
1433
 
@@ -1183,11 +1445,11 @@ katax generate crud products
1183
1445
 
1184
1446
  MIT
1185
1447
  `;
1186
- await writeFile(path.join(projectPath, 'README.md'), readmeContent);
1448
+ await writeFile(path.join(projectPath, "README.md"), readmeContent);
1187
1449
  await createHelloEndpoint(projectPath, config);
1188
1450
  }
1189
1451
  async function createHelloEndpoint(projectPath, config) {
1190
- const helloPath = path.join(projectPath, 'src/api/hello');
1452
+ const helloPath = path.join(projectPath, "src/api/hello");
1191
1453
  const controllerContent = [
1192
1454
  "import { ControllerResult, createSuccessResult, createErrorResult } from '../../shared/api.utils.js';",
1193
1455
  "import { HelloQuery } from './hello.validator.js';",
@@ -1216,9 +1478,9 @@ async function createHelloEndpoint(projectPath, config) {
1216
1478
  " 500",
1217
1479
  " );",
1218
1480
  " }",
1219
- "}"
1220
- ].join('\n');
1221
- await writeFile(path.join(helloPath, 'hello.controller.ts'), controllerContent);
1481
+ "}",
1482
+ ].join("\n");
1483
+ await writeFile(path.join(helloPath, "hello.controller.ts"), controllerContent);
1222
1484
  const handlerContent = [
1223
1485
  "import { Request, Response } from 'express';",
1224
1486
  "import { getHello } from './hello.controller.js';",
@@ -1240,9 +1502,9 @@ async function createHelloEndpoint(projectPath, config) {
1240
1502
  " // validData is automatically: HelloQuery (not any)",
1241
1503
  " (validData) => getHello(validData)",
1242
1504
  " );",
1243
- "}"
1244
- ].join('\n');
1245
- await writeFile(path.join(helloPath, 'hello.handler.ts'), handlerContent);
1505
+ "}",
1506
+ ].join("\n");
1507
+ await writeFile(path.join(helloPath, "hello.handler.ts"), handlerContent);
1246
1508
  const routesContent = [
1247
1509
  "import { Router } from 'express';",
1248
1510
  "import { getHelloHandler } from './hello.handler.js';",
@@ -1257,10 +1519,10 @@ async function createHelloEndpoint(projectPath, config) {
1257
1519
  " */",
1258
1520
  "router.get('/', getHelloHandler);",
1259
1521
  "",
1260
- "export default router;"
1261
- ].join('\n');
1262
- await writeFile(path.join(helloPath, 'hello.routes.ts'), routesContent);
1263
- if (config.validation === 'katax-core') {
1522
+ "export default router;",
1523
+ ].join("\n");
1524
+ await writeFile(path.join(helloPath, "hello.routes.ts"), routesContent);
1525
+ if (config.validation === "katax-core") {
1264
1526
  const validatorContent = [
1265
1527
  "import { k, kataxInfer } from 'katax-core';",
1266
1528
  "import type { ValidationResult } from '../../shared/api.utils.js';",
@@ -1301,9 +1563,9 @@ async function createHelloEndpoint(projectPath, config) {
1301
1563
  " isValid: true,",
1302
1564
  " data: result.data",
1303
1565
  " };",
1304
- "}"
1305
- ].join('\n');
1306
- await writeFile(path.join(helloPath, 'hello.validator.ts'), validatorContent);
1566
+ "}",
1567
+ ].join("\n");
1568
+ await writeFile(path.join(helloPath, "hello.validator.ts"), validatorContent);
1307
1569
  }
1308
1570
  }
1309
1571
  //# sourceMappingURL=init.js.map