create-coreback 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/.github/workflows/publish.yml +13 -10
  2. package/README.md +30 -1
  3. package/dist/generators/docker.d.ts.map +1 -1
  4. package/dist/generators/docker.js +61 -4
  5. package/dist/generators/docker.js.map +1 -1
  6. package/dist/generators/envExample.d.ts.map +1 -1
  7. package/dist/generators/envExample.js +26 -0
  8. package/dist/generators/envExample.js.map +1 -1
  9. package/dist/generators/eslint.d.ts.map +1 -1
  10. package/dist/generators/eslint.js +25 -27
  11. package/dist/generators/eslint.js.map +1 -1
  12. package/dist/generators/index.js +1 -1
  13. package/dist/generators/index.js.map +1 -1
  14. package/dist/generators/packageJson.d.ts.map +1 -1
  15. package/dist/generators/packageJson.js +41 -5
  16. package/dist/generators/packageJson.js.map +1 -1
  17. package/dist/generators/sourceFiles/controllers/index.d.ts +3 -0
  18. package/dist/generators/sourceFiles/controllers/index.d.ts.map +1 -0
  19. package/dist/generators/sourceFiles/controllers/index.js +147 -0
  20. package/dist/generators/sourceFiles/controllers/index.js.map +1 -0
  21. package/dist/generators/sourceFiles/core/configFiles.d.ts +3 -0
  22. package/dist/generators/sourceFiles/core/configFiles.d.ts.map +1 -0
  23. package/dist/generators/sourceFiles/core/configFiles.js +148 -0
  24. package/dist/generators/sourceFiles/core/configFiles.js.map +1 -0
  25. package/dist/generators/sourceFiles/core/index.d.ts +3 -0
  26. package/dist/generators/sourceFiles/core/index.d.ts.map +1 -0
  27. package/dist/generators/sourceFiles/core/index.js +17 -0
  28. package/dist/generators/sourceFiles/core/index.js.map +1 -0
  29. package/dist/generators/sourceFiles/core/indexFile.d.ts +3 -0
  30. package/dist/generators/sourceFiles/core/indexFile.d.ts.map +1 -0
  31. package/dist/generators/sourceFiles/core/indexFile.js +47 -0
  32. package/dist/generators/sourceFiles/core/indexFile.js.map +1 -0
  33. package/dist/generators/sourceFiles/core/middlewares.d.ts +3 -0
  34. package/dist/generators/sourceFiles/core/middlewares.d.ts.map +1 -0
  35. package/dist/generators/sourceFiles/core/middlewares.js +123 -0
  36. package/dist/generators/sourceFiles/core/middlewares.js.map +1 -0
  37. package/dist/generators/sourceFiles/core/routes.d.ts +3 -0
  38. package/dist/generators/sourceFiles/core/routes.d.ts.map +1 -0
  39. package/dist/generators/sourceFiles/core/routes.js +281 -0
  40. package/dist/generators/sourceFiles/core/routes.js.map +1 -0
  41. package/dist/generators/sourceFiles/core/tests.d.ts +3 -0
  42. package/dist/generators/sourceFiles/core/tests.d.ts.map +1 -0
  43. package/dist/generators/sourceFiles/core/tests.js +48 -0
  44. package/dist/generators/sourceFiles/core/tests.js.map +1 -0
  45. package/dist/generators/sourceFiles/core/types.d.ts +2 -0
  46. package/dist/generators/sourceFiles/core/types.d.ts.map +1 -0
  47. package/dist/generators/sourceFiles/core/types.js +13 -0
  48. package/dist/generators/sourceFiles/core/types.js.map +1 -0
  49. package/dist/generators/sourceFiles/core/utils.d.ts +2 -0
  50. package/dist/generators/sourceFiles/core/utils.d.ts.map +1 -0
  51. package/dist/generators/sourceFiles/core/utils.js +173 -0
  52. package/dist/generators/sourceFiles/core/utils.js.map +1 -0
  53. package/dist/generators/sourceFiles/core/validators.d.ts +3 -0
  54. package/dist/generators/sourceFiles/core/validators.d.ts.map +1 -0
  55. package/dist/generators/sourceFiles/core/validators.js +37 -0
  56. package/dist/generators/sourceFiles/core/validators.js.map +1 -0
  57. package/dist/generators/sourceFiles/features/fileUpload.d.ts +3 -0
  58. package/dist/generators/sourceFiles/features/fileUpload.d.ts.map +1 -0
  59. package/dist/generators/sourceFiles/features/fileUpload.js +229 -0
  60. package/dist/generators/sourceFiles/features/fileUpload.js.map +1 -0
  61. package/dist/generators/sourceFiles/features/queue.d.ts +3 -0
  62. package/dist/generators/sourceFiles/features/queue.d.ts.map +1 -0
  63. package/dist/generators/sourceFiles/features/queue.js +211 -0
  64. package/dist/generators/sourceFiles/features/queue.js.map +1 -0
  65. package/dist/generators/sourceFiles/features/redis.d.ts +3 -0
  66. package/dist/generators/sourceFiles/features/redis.d.ts.map +1 -0
  67. package/dist/generators/sourceFiles/features/redis.js +68 -0
  68. package/dist/generators/sourceFiles/features/redis.js.map +1 -0
  69. package/dist/generators/sourceFiles/index.d.ts +3 -0
  70. package/dist/generators/sourceFiles/index.d.ts.map +1 -0
  71. package/dist/generators/sourceFiles/index.js +99 -0
  72. package/dist/generators/sourceFiles/index.js.map +1 -0
  73. package/dist/generators/sourceFiles/phase1/cliGenerators.d.ts +2 -0
  74. package/dist/generators/sourceFiles/phase1/cliGenerators.d.ts.map +1 -0
  75. package/dist/generators/sourceFiles/phase1/cliGenerators.js +336 -0
  76. package/dist/generators/sourceFiles/phase1/cliGenerators.js.map +1 -0
  77. package/dist/generators/sourceFiles/phase1/seedersFactories.d.ts +3 -0
  78. package/dist/generators/sourceFiles/phase1/seedersFactories.d.ts.map +1 -0
  79. package/dist/generators/sourceFiles/phase1/seedersFactories.js +89 -0
  80. package/dist/generators/sourceFiles/phase1/seedersFactories.js.map +1 -0
  81. package/dist/generators/sourceFiles/phase2/dtos.d.ts +2 -0
  82. package/dist/generators/sourceFiles/phase2/dtos.d.ts.map +1 -0
  83. package/dist/generators/sourceFiles/phase2/dtos.js +59 -0
  84. package/dist/generators/sourceFiles/phase2/dtos.js.map +1 -0
  85. package/dist/generators/sourceFiles/phase2/events.d.ts +2 -0
  86. package/dist/generators/sourceFiles/phase2/events.d.ts.map +1 -0
  87. package/dist/generators/sourceFiles/phase2/events.js +76 -0
  88. package/dist/generators/sourceFiles/phase2/events.js.map +1 -0
  89. package/dist/generators/sourceFiles/phase2/exceptionHandling.d.ts +2 -0
  90. package/dist/generators/sourceFiles/phase2/exceptionHandling.d.ts.map +1 -0
  91. package/dist/generators/sourceFiles/phase2/exceptionHandling.js +107 -0
  92. package/dist/generators/sourceFiles/phase2/exceptionHandling.js.map +1 -0
  93. package/dist/generators/sourceFiles/phase2/guards.d.ts +2 -0
  94. package/dist/generators/sourceFiles/phase2/guards.d.ts.map +1 -0
  95. package/dist/generators/sourceFiles/phase2/guards.js +98 -0
  96. package/dist/generators/sourceFiles/phase2/guards.js.map +1 -0
  97. package/dist/generators/sourceFiles/phase2/healthChecks.d.ts +3 -0
  98. package/dist/generators/sourceFiles/phase2/healthChecks.d.ts.map +1 -0
  99. package/dist/generators/sourceFiles/phase2/healthChecks.js +73 -0
  100. package/dist/generators/sourceFiles/phase2/healthChecks.js.map +1 -0
  101. package/dist/generators/sourceFiles/phase2/scheduledTasks.d.ts +2 -0
  102. package/dist/generators/sourceFiles/phase2/scheduledTasks.d.ts.map +1 -0
  103. package/dist/generators/sourceFiles/phase2/scheduledTasks.js +56 -0
  104. package/dist/generators/sourceFiles/phase2/scheduledTasks.js.map +1 -0
  105. package/dist/generators/sourceFiles/phase3/apiVersioning.d.ts +3 -0
  106. package/dist/generators/sourceFiles/phase3/apiVersioning.d.ts.map +1 -0
  107. package/dist/generators/sourceFiles/phase3/apiVersioning.js +72 -0
  108. package/dist/generators/sourceFiles/phase3/apiVersioning.js.map +1 -0
  109. package/dist/generators/sourceFiles/phase3/cliCommands.d.ts +2 -0
  110. package/dist/generators/sourceFiles/phase3/cliCommands.d.ts.map +1 -0
  111. package/dist/generators/sourceFiles/phase3/cliCommands.js +102 -0
  112. package/dist/generators/sourceFiles/phase3/cliCommands.js.map +1 -0
  113. package/dist/generators/sourceFiles/phase3/configSystem.d.ts +2 -0
  114. package/dist/generators/sourceFiles/phase3/configSystem.d.ts.map +1 -0
  115. package/dist/generators/sourceFiles/phase3/configSystem.js +57 -0
  116. package/dist/generators/sourceFiles/phase3/configSystem.js.map +1 -0
  117. package/dist/generators/sourceFiles/phase3/dependencyInjection.d.ts +2 -0
  118. package/dist/generators/sourceFiles/phase3/dependencyInjection.d.ts.map +1 -0
  119. package/dist/generators/sourceFiles/phase3/dependencyInjection.js +153 -0
  120. package/dist/generators/sourceFiles/phase3/dependencyInjection.js.map +1 -0
  121. package/dist/generators/sourceFiles/phase3/moduleSystem.d.ts +2 -0
  122. package/dist/generators/sourceFiles/phase3/moduleSystem.d.ts.map +1 -0
  123. package/dist/generators/sourceFiles/phase3/moduleSystem.js +166 -0
  124. package/dist/generators/sourceFiles/phase3/moduleSystem.js.map +1 -0
  125. package/dist/generators/sourceFiles/phase3/structuredLogging.d.ts +3 -0
  126. package/dist/generators/sourceFiles/phase3/structuredLogging.d.ts.map +1 -0
  127. package/dist/generators/sourceFiles/phase3/structuredLogging.js +155 -0
  128. package/dist/generators/sourceFiles/phase3/structuredLogging.js.map +1 -0
  129. package/dist/generators/sourceFiles/repositories/index.d.ts +3 -0
  130. package/dist/generators/sourceFiles/repositories/index.d.ts.map +1 -0
  131. package/dist/generators/sourceFiles/repositories/index.js +109 -0
  132. package/dist/generators/sourceFiles/repositories/index.js.map +1 -0
  133. package/dist/generators/sourceFiles/services/index.d.ts +3 -0
  134. package/dist/generators/sourceFiles/services/index.d.ts.map +1 -0
  135. package/dist/generators/sourceFiles/services/index.js +353 -0
  136. package/dist/generators/sourceFiles/services/index.js.map +1 -0
  137. package/dist/generators/sourceFiles.d.ts +1 -2
  138. package/dist/generators/sourceFiles.d.ts.map +1 -1
  139. package/dist/generators/sourceFiles.js +2 -1238
  140. package/dist/generators/sourceFiles.js.map +1 -1
  141. package/dist/prompts.d.ts.map +1 -1
  142. package/dist/prompts.js +35 -0
  143. package/dist/prompts.js.map +1 -1
  144. package/dist/types.d.ts +5 -0
  145. package/dist/types.d.ts.map +1 -1
  146. package/jest.config.js +21 -0
  147. package/package.json +4 -1
  148. package/src/generators/docker.ts +61 -4
  149. package/src/generators/envExample.ts +28 -0
  150. package/src/generators/eslint.ts +21 -24
  151. package/src/generators/index.ts +1 -1
  152. package/src/generators/packageJson.ts +45 -6
  153. package/src/generators/sourceFiles/controllers/index.ts +157 -0
  154. package/src/generators/sourceFiles/core/configFiles.ts +158 -0
  155. package/src/generators/sourceFiles/core/index.ts +28 -0
  156. package/src/generators/sourceFiles/core/indexFile.ts +49 -0
  157. package/src/generators/sourceFiles/core/middlewares.ts +129 -0
  158. package/src/generators/sourceFiles/core/routes.ts +295 -0
  159. package/src/generators/sourceFiles/core/tests.ts +62 -0
  160. package/src/generators/sourceFiles/core/types.ts +14 -0
  161. package/src/generators/sourceFiles/core/utils.ts +178 -0
  162. package/src/generators/sourceFiles/core/validators.ts +39 -0
  163. package/src/generators/sourceFiles/features/fileUpload.ts +241 -0
  164. package/src/generators/sourceFiles/features/queue.ts +226 -0
  165. package/src/generators/sourceFiles/features/redis.ts +73 -0
  166. package/src/generators/sourceFiles/index.ts +125 -0
  167. package/src/generators/sourceFiles/phase1/cliGenerators.ts +338 -0
  168. package/src/generators/sourceFiles/phase1/seedersFactories.ts +97 -0
  169. package/src/generators/sourceFiles/phase2/dtos.ts +60 -0
  170. package/src/generators/sourceFiles/phase2/events.ts +80 -0
  171. package/src/generators/sourceFiles/phase2/exceptionHandling.ts +111 -0
  172. package/src/generators/sourceFiles/phase2/guards.ts +99 -0
  173. package/src/generators/sourceFiles/phase2/healthChecks.ts +81 -0
  174. package/src/generators/sourceFiles/phase2/scheduledTasks.ts +58 -0
  175. package/src/generators/sourceFiles/phase3/apiVersioning.ts +77 -0
  176. package/src/generators/sourceFiles/phase3/cliCommands.ts +110 -0
  177. package/src/generators/sourceFiles/phase3/configSystem.ts +64 -0
  178. package/src/generators/sourceFiles/phase3/dependencyInjection.ts +155 -0
  179. package/src/generators/sourceFiles/phase3/moduleSystem.ts +170 -0
  180. package/src/generators/sourceFiles/phase3/structuredLogging.ts +160 -0
  181. package/src/generators/sourceFiles/repositories/index.ts +114 -0
  182. package/src/generators/sourceFiles/services/index.ts +363 -0
  183. package/src/generators/sourceFiles.ts +2 -1317
  184. package/src/prompts.ts +36 -1
  185. package/src/types.ts +5 -0
  186. package/tests/integration.test.ts +233 -0
@@ -0,0 +1,158 @@
1
+ import { ProjectConfig } from '../../../types.js';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+
5
+ export async function generateConfigFiles(configDir: string, config: ProjectConfig): Promise<void> {
6
+ // env.ts
7
+ const envContent = `import { z } from 'zod';
8
+ import dotenv from 'dotenv';
9
+
10
+ dotenv.config();
11
+
12
+ const envSchema = z.object({
13
+ NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
14
+ PORT: z.coerce.number().default(3000),
15
+ DATABASE_URL: z.string(),
16
+ ${config.includeAuth ? ` JWT_SECRET: z.string(),
17
+ JWT_EXPIRES_IN: z.string().default('7d'),
18
+ EMAIL_HOST: z.string().optional(),
19
+ EMAIL_PORT: z.coerce.number().optional(),
20
+ EMAIL_SECURE: z.coerce.boolean().default(false),
21
+ EMAIL_USER: z.string().optional(),
22
+ EMAIL_PASSWORD: z.string().optional(),
23
+ EMAIL_FROM: z.string().default('noreply@coreback.app'),
24
+ APP_URL: z.string().default('http://localhost:3000'),` : ''}${config.includeFileUpload ? `
25
+ MAX_FILE_SIZE: z.coerce.number().default(5242880),
26
+ ALLOWED_FILE_TYPES: z.string().default('image/jpeg,image/png,image/gif,application/pdf'),
27
+ UPLOAD_DIR: z.string().default('uploads'),${config.fileStorage === 's3' ? `
28
+ AWS_REGION: z.string().default('us-east-1'),
29
+ AWS_ACCESS_KEY_ID: z.string().optional(),
30
+ AWS_SECRET_ACCESS_KEY: z.string().optional(),
31
+ AWS_S3_BUCKET: z.string().optional(),` : ''}` : ''}${config.includeRedis ? `
32
+ REDIS_HOST: z.string().default('localhost'),
33
+ REDIS_PORT: z.coerce.number().default(6379),
34
+ REDIS_PASSWORD: z.string().optional(),
35
+ REDIS_DB: z.coerce.number().default(0),` : ''}
36
+ RATE_LIMIT_WINDOW_MS: z.coerce.number().default(900000),
37
+ RATE_LIMIT_MAX: z.coerce.number().default(100),
38
+ });
39
+
40
+ export const config = envSchema.parse(process.env);
41
+ `;
42
+
43
+ await fs.writeFile(path.join(configDir, 'env.ts'), envContent);
44
+
45
+ // database.ts
46
+ const databaseContent = `import { PrismaClient } from '@prisma/client';
47
+ import { logger } from '../utils/logger.js';
48
+
49
+ const prisma = new PrismaClient({
50
+ log: [
51
+ { level: 'query', emit: 'event' },
52
+ { level: 'error', emit: 'stdout' },
53
+ { level: 'warn', emit: 'stdout' },
54
+ ],
55
+ });
56
+
57
+ prisma.$on('query', (e) => {
58
+ logger.debug('Query: ' + e.query);
59
+ logger.debug('Params: ' + e.params);
60
+ logger.debug('Duration: ' + e.duration + 'ms');
61
+ });
62
+
63
+ export { prisma };
64
+ `;
65
+
66
+ await fs.writeFile(path.join(configDir, 'database.ts'), databaseContent);
67
+
68
+ // middlewares.ts
69
+ const middlewaresContent = `import express, { Express } from 'express';
70
+ import cors from 'cors';
71
+ import helmet from 'helmet';
72
+ import compression from 'compression';
73
+ import rateLimit from 'express-rate-limit';
74
+ import { config } from './env.js';
75
+
76
+ export function setupMiddlewares(app: Express): void {
77
+ app.use(helmet());
78
+ app.use(cors());
79
+ app.use(compression());
80
+ app.use(express.json());
81
+ app.use(express.urlencoded({ extended: true }));
82
+
83
+ const limiter = rateLimit({
84
+ windowMs: config.RATE_LIMIT_WINDOW_MS,
85
+ max: config.RATE_LIMIT_MAX,
86
+ message: 'Too many requests from this IP, please try again later.',
87
+ });
88
+
89
+ app.use('/api/', limiter);
90
+ }
91
+ `;
92
+
93
+ await fs.writeFile(path.join(configDir, 'middlewares.ts'), middlewaresContent);
94
+
95
+ // swagger.ts
96
+ const swaggerContent = `import { Express } from 'express';
97
+ import swaggerJsdoc from 'swagger-jsdoc';
98
+ import swaggerUi from 'swagger-ui-express';
99
+ import { config } from './env.js';
100
+
101
+ const options: swaggerJsdoc.Options = {
102
+ definition: {
103
+ openapi: '3.0.0',
104
+ info: {
105
+ title: 'CoreBack API',
106
+ version: '1.0.0',
107
+ description: 'Production-ready backend API',
108
+ },
109
+ servers: [
110
+ {
111
+ url: \`http://localhost:\\\${config.PORT}\`,
112
+ description: 'Development server',
113
+ },
114
+ ],
115
+ },
116
+ apis: ['./src/routes/**/*.ts', './src/controllers/**/*.ts'],
117
+ };
118
+
119
+ const swaggerSpec = swaggerJsdoc(options);
120
+
121
+ export function setupSwagger(app: Express): void {
122
+ app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
123
+ }
124
+ `;
125
+
126
+ await fs.writeFile(path.join(configDir, 'swagger.ts'), swaggerContent);
127
+
128
+ if (config.includeRedis) {
129
+ // redis.ts
130
+ const redisContent = `import Redis from 'ioredis';
131
+ import { config } from './env.js';
132
+ import { logger } from '../utils/logger.js';
133
+
134
+ const redis = new Redis({
135
+ host: config.REDIS_HOST,
136
+ port: config.REDIS_PORT,
137
+ password: config.REDIS_PASSWORD || undefined,
138
+ db: config.REDIS_DB,
139
+ retryStrategy: (times) => {
140
+ const delay = Math.min(times * 50, 2000);
141
+ return delay;
142
+ },
143
+ });
144
+
145
+ redis.on('connect', () => {
146
+ logger.info('✅ Redis connected');
147
+ });
148
+
149
+ redis.on('error', (err) => {
150
+ logger.error('❌ Redis connection error:', err);
151
+ });
152
+
153
+ export { redis };
154
+ `;
155
+
156
+ await fs.writeFile(path.join(configDir, 'redis.ts'), redisContent);
157
+ }
158
+ }
@@ -0,0 +1,28 @@
1
+ import { ProjectConfig } from '../../../types.js';
2
+ import { generateIndex } from './indexFile.js';
3
+ import { generateConfigFiles } from './configFiles.js';
4
+ import { generateMiddlewares } from './middlewares.js';
5
+ import { generateUtils } from './utils.js';
6
+ import { generateRoutes } from './routes.js';
7
+ import { generateTypes } from './types.js';
8
+ import { generateValidators } from './validators.js';
9
+
10
+ export async function generateCoreFiles(
11
+ srcDir: string,
12
+ configDir: string,
13
+ middlewaresDir: string,
14
+ utilsDir: string,
15
+ routesDir: string,
16
+ typesDir: string,
17
+ validatorsDir: string,
18
+ config: ProjectConfig
19
+ ): Promise<void> {
20
+ await generateIndex(srcDir, config);
21
+ await generateConfigFiles(configDir, config);
22
+ await generateMiddlewares(middlewaresDir, config);
23
+ await generateUtils(utilsDir);
24
+ await generateRoutes(routesDir, config);
25
+ await generateTypes(typesDir);
26
+ await generateValidators(validatorsDir, config);
27
+ }
28
+
@@ -0,0 +1,49 @@
1
+ import { ProjectConfig } from '../../../types.js';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+
5
+ export async function generateIndex(srcDir: string, config: ProjectConfig): Promise<void> {
6
+ const indexContent = `import express from 'express';
7
+ import { config } from './config/env.js';
8
+ import { setupMiddlewares } from './config/middlewares.js';
9
+ import { setupRoutes } from './routes/index.js';
10
+ import { setupSwagger } from './config/swagger.js';
11
+ import { logger } from './utils/logger.js';
12
+ import { errorHandler } from './middlewares/errorHandler.js';
13
+ import { registerListeners } from './events/listeners/index.js';
14
+ import { registerScheduledTasks } from './tasks/index.js';${config.includeRedis ? `
15
+ import { redis } from './config/redis.js';` : ''}${config.includeQueue ? `
16
+ import { startQueueWorkers } from './queue/workers.js';` : ''}
17
+
18
+ const app = express();
19
+
20
+ setupMiddlewares(app);
21
+ setupSwagger(app);
22
+ setupRoutes(app);
23
+ app.use(errorHandler);
24
+
25
+ // Register event listeners
26
+ registerListeners();
27
+
28
+ // Register scheduled tasks
29
+ registerScheduledTasks();
30
+
31
+ ${config.includeQueue ? `// Start queue workers
32
+ startQueueWorkers();` : ''}
33
+
34
+ const server = app.listen(config.PORT, () => {
35
+ logger.info(\`🚀 Server: http://localhost:\${config.PORT}\`);
36
+ logger.info(\`📚 Docs: http://localhost:\${config.PORT}/api-docs\`);${config.includeQueue ? `
37
+ logger.info(\`📊 Queue Dashboard: http://localhost:\${config.PORT}/admin/queues\`);` : ''}
38
+ });
39
+
40
+ process.on('SIGTERM', async () => {
41
+ logger.info('SIGTERM received, shutting down gracefully...');
42
+ server.close();
43
+ ${config.includeRedis ? `await redis.quit();` : ''}
44
+ process.exit(0);
45
+ });
46
+ `;
47
+
48
+ await fs.writeFile(path.join(srcDir, 'index.ts'), indexContent);
49
+ }
@@ -0,0 +1,129 @@
1
+ import { ProjectConfig } from '../../../types.js';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+
5
+ export async function generateMiddlewares(middlewaresDir: string, config: ProjectConfig): Promise<void> {
6
+ // errorHandler.ts
7
+ const errorHandlerContent = `import { Request, Response, NextFunction } from 'express';
8
+ import { ZodError } from 'zod';
9
+ import { logger } from '../utils/logger.js';
10
+
11
+ export class AppError extends Error {
12
+ constructor(
13
+ public statusCode: number,
14
+ message: string,
15
+ public isOperational = true
16
+ ) {
17
+ super(message);
18
+ Object.setPrototypeOf(this, AppError.prototype);
19
+ }
20
+ }
21
+
22
+ export const errorHandler = (
23
+ err: Error,
24
+ req: Request,
25
+ res: Response,
26
+ next: NextFunction
27
+ ) => {
28
+ logger.error(err);
29
+
30
+ if (err instanceof ZodError) {
31
+ return res.status(400).json({
32
+ status: 'error',
33
+ message: 'Validation error',
34
+ errors: err.errors,
35
+ });
36
+ }
37
+
38
+ if (err instanceof AppError) {
39
+ return res.status(err.statusCode).json({
40
+ status: 'error',
41
+ message: err.message,
42
+ });
43
+ }
44
+
45
+ res.status(500).json({
46
+ status: 'error',
47
+ message: 'Internal server error',
48
+ });
49
+ };
50
+ `;
51
+
52
+ await fs.writeFile(path.join(middlewaresDir, 'errorHandler.ts'), errorHandlerContent);
53
+
54
+ // validator.ts
55
+ const validatorContent = `import { Request, Response, NextFunction } from 'express';
56
+ import { ZodSchema, ZodError } from 'zod';
57
+
58
+ export const validate = (schema: ZodSchema) => {
59
+ return (req: Request, res: Response, next: NextFunction) => {
60
+ try {
61
+ schema.parse({
62
+ body: req.body,
63
+ query: req.query,
64
+ params: req.params,
65
+ });
66
+ next();
67
+ } catch (error) {
68
+ if (error instanceof ZodError) {
69
+ return res.status(400).json({
70
+ status: 'error',
71
+ message: 'Validation error',
72
+ errors: error.errors,
73
+ });
74
+ }
75
+ next(error);
76
+ }
77
+ };
78
+ };
79
+ `;
80
+
81
+ await fs.writeFile(path.join(middlewaresDir, 'validator.ts'), validatorContent);
82
+
83
+ if (config.includeAuth) {
84
+ // auth.ts
85
+ const authContent = `import { Request, Response, NextFunction } from 'express';
86
+ import jwt from 'jsonwebtoken';
87
+ import { config } from '../config/env.js';
88
+ import { AppError } from './errorHandler.js';
89
+
90
+ export interface AuthRequest extends Request {
91
+ user?: {
92
+ id: string;
93
+ email: string;
94
+ };
95
+ }
96
+
97
+ export const authenticate = (
98
+ req: AuthRequest,
99
+ res: Response,
100
+ next: NextFunction
101
+ ) => {
102
+ try {
103
+ const authHeader = req.headers.authorization;
104
+
105
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
106
+ throw new AppError(401, 'Authentication required');
107
+ }
108
+
109
+ const token = authHeader.substring(7);
110
+ const decoded = jwt.verify(token, config.JWT_SECRET) as {
111
+ id: string;
112
+ email: string;
113
+ };
114
+
115
+ req.user = decoded;
116
+ next();
117
+ } catch (error) {
118
+ if (error instanceof jwt.JsonWebTokenError) {
119
+ next(new AppError(401, 'Invalid token'));
120
+ } else {
121
+ next(error);
122
+ }
123
+ }
124
+ };
125
+ `;
126
+
127
+ await fs.writeFile(path.join(middlewaresDir, 'auth.ts'), authContent);
128
+ }
129
+ }
@@ -0,0 +1,295 @@
1
+ import { ProjectConfig } from '../../../types.js';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+
5
+ export async function generateRoutes(routesDir: string, config: ProjectConfig): Promise<void> {
6
+ // index.ts
7
+ let indexContent = `import { Express } from 'express';
8
+ import { healthRoutes } from './health.routes.js';
9
+ `;
10
+
11
+ if (config.includeAuth) {
12
+ indexContent += `import { authRoutes } from './auth.routes.js';
13
+ `;
14
+ }
15
+
16
+ if (config.includeFileUpload) {
17
+ indexContent += `import { fileUploadRoutes } from './fileUpload.routes.js';
18
+ `;
19
+ }
20
+
21
+ if (config.includeQueue) {
22
+ indexContent += `import { queueRoutes } from './queue.routes.js';
23
+ import { queueDashboardRouter } from '../queue/dashboard.js';
24
+ `;
25
+ }
26
+
27
+ indexContent += `
28
+ export function setupRoutes(app: Express): void {
29
+ app.use('/api/health', healthRoutes);
30
+ `;
31
+
32
+ if (config.includeAuth) {
33
+ indexContent += ` app.use('/api/auth', authRoutes);
34
+ `;
35
+ }
36
+
37
+ if (config.includeFileUpload) {
38
+ indexContent += ` app.use('/api/files', fileUploadRoutes);
39
+ `;
40
+ }
41
+
42
+ if (config.includeQueue) {
43
+ indexContent += ` app.use('/api/queue', queueRoutes);
44
+ app.use('/admin/queues', queueDashboardRouter);
45
+ `;
46
+ }
47
+
48
+ indexContent += `}
49
+ `;
50
+
51
+ await fs.writeFile(path.join(routesDir, 'index.ts'), indexContent);
52
+
53
+ // health.routes.ts
54
+ const healthRoutesContent = `import { Router } from 'express';
55
+ import { healthController } from '../controllers/health.controller.js';
56
+
57
+ /**
58
+ * @swagger
59
+ * tags:
60
+ * name: Health
61
+ * description: Health check endpoints
62
+ */
63
+
64
+ const router = Router();
65
+
66
+ /**
67
+ * @swagger
68
+ * /api/health:
69
+ * get:
70
+ * summary: Health check endpoint
71
+ * tags: [Health]
72
+ * responses:
73
+ * 200:
74
+ * description: Service is healthy
75
+ * content:
76
+ * application/json:
77
+ * schema:
78
+ * type: object
79
+ * properties:
80
+ * status:
81
+ * type: string
82
+ * example: ok
83
+ * timestamp:
84
+ * type: string
85
+ * example: 2024-01-01T00:00:00.000Z
86
+ */
87
+ router.get('/', healthController.check);
88
+
89
+ export { router as healthRoutes };
90
+ `;
91
+
92
+ await fs.writeFile(path.join(routesDir, 'health.routes.ts'), healthRoutesContent);
93
+
94
+ if (config.includeAuth) {
95
+ // auth.routes.ts
96
+ const authRoutesContent = `import { Router } from 'express';
97
+ import { authController } from '../controllers/auth.controller.js';
98
+ import { validate } from '../middlewares/validator.js';
99
+ import { registerSchema, loginSchema, emailSchema, resetPasswordSchema } from '../validators/auth.validator.js';
100
+ import { authenticate } from '../middlewares/auth.js';
101
+
102
+ /**
103
+ * @swagger
104
+ * tags:
105
+ * name: Auth
106
+ * description: Authentication endpoints
107
+ */
108
+
109
+ const router = Router();
110
+
111
+ /**
112
+ * @swagger
113
+ * /api/auth/register:
114
+ * post:
115
+ * summary: Register a new user
116
+ * tags: [Auth]
117
+ * requestBody:
118
+ * required: true
119
+ * content:
120
+ * application/json:
121
+ * schema:
122
+ * type: object
123
+ * required:
124
+ * - email
125
+ * - password
126
+ * properties:
127
+ * email:
128
+ * type: string
129
+ * format: email
130
+ * password:
131
+ * type: string
132
+ * minLength: 8
133
+ * name:
134
+ * type: string
135
+ * responses:
136
+ * 201:
137
+ * description: User created successfully
138
+ * 400:
139
+ * description: Validation error
140
+ */
141
+ router.post('/register', validate(registerSchema), authController.register);
142
+
143
+ /**
144
+ * @swagger
145
+ * /api/auth/login:
146
+ * post:
147
+ * summary: Login user
148
+ * tags: [Auth]
149
+ * requestBody:
150
+ * required: true
151
+ * content:
152
+ * application/json:
153
+ * schema:
154
+ * type: object
155
+ * required:
156
+ * - email
157
+ * - password
158
+ * properties:
159
+ * email:
160
+ * type: string
161
+ * format: email
162
+ * password:
163
+ * type: string
164
+ * responses:
165
+ * 200:
166
+ * description: Login successful
167
+ * 401:
168
+ * description: Invalid credentials
169
+ */
170
+ router.post('/login', validate(loginSchema), authController.login);
171
+
172
+ /**
173
+ * @swagger
174
+ * /api/auth/me:
175
+ * get:
176
+ * summary: Get current user
177
+ * tags: [Auth]
178
+ * security:
179
+ * - bearerAuth: []
180
+ * responses:
181
+ * 200:
182
+ * description: Current user information
183
+ * 401:
184
+ * description: Unauthorized
185
+ */
186
+ router.get('/me', authenticate, authController.me);
187
+
188
+ /**
189
+ * @swagger
190
+ * /api/auth/verify-email:
191
+ * get:
192
+ * summary: Verify email address
193
+ * tags: [Auth]
194
+ * parameters:
195
+ * - in: query
196
+ * name: token
197
+ * required: true
198
+ * schema:
199
+ * type: string
200
+ * responses:
201
+ * 200:
202
+ * description: Email verified successfully
203
+ * 400:
204
+ * description: Invalid or expired token
205
+ */
206
+ router.get('/verify-email', authController.verifyEmail);
207
+
208
+ /**
209
+ * @swagger
210
+ * /api/auth/resend-verification:
211
+ * post:
212
+ * summary: Resend verification email
213
+ * tags: [Auth]
214
+ * requestBody:
215
+ * required: true
216
+ * content:
217
+ * application/json:
218
+ * schema:
219
+ * type: object
220
+ * required:
221
+ * - email
222
+ * properties:
223
+ * email:
224
+ * type: string
225
+ * format: email
226
+ * responses:
227
+ * 200:
228
+ * description: Verification email sent
229
+ * 400:
230
+ * description: Email already verified
231
+ */
232
+ router.post('/resend-verification', validate(emailSchema), authController.resendVerification);
233
+
234
+ /**
235
+ * @swagger
236
+ * /api/auth/forgot-password:
237
+ * post:
238
+ * summary: Request password reset
239
+ * tags: [Auth]
240
+ * requestBody:
241
+ * required: true
242
+ * content:
243
+ * application/json:
244
+ * schema:
245
+ * type: object
246
+ * required:
247
+ * - email
248
+ * properties:
249
+ * email:
250
+ * type: string
251
+ * format: email
252
+ * responses:
253
+ * 200:
254
+ * description: Password reset email sent
255
+ */
256
+ router.post('/forgot-password', validate(emailSchema), authController.forgotPassword);
257
+
258
+ /**
259
+ * @swagger
260
+ * /api/auth/reset-password:
261
+ * post:
262
+ * summary: Reset password
263
+ * tags: [Auth]
264
+ * parameters:
265
+ * - in: query
266
+ * name: token
267
+ * required: true
268
+ * schema:
269
+ * type: string
270
+ * requestBody:
271
+ * required: true
272
+ * content:
273
+ * application/json:
274
+ * schema:
275
+ * type: object
276
+ * required:
277
+ * - password
278
+ * properties:
279
+ * password:
280
+ * type: string
281
+ * minLength: 8
282
+ * responses:
283
+ * 200:
284
+ * description: Password reset successfully
285
+ * 400:
286
+ * description: Invalid or expired token
287
+ */
288
+ router.post('/reset-password', validate(resetPasswordSchema), authController.resetPassword);
289
+
290
+ export { router as authRoutes };
291
+ `;
292
+
293
+ await fs.writeFile(path.join(routesDir, 'auth.routes.ts'), authRoutesContent);
294
+ }
295
+ }