express-genix 1.1.4 → 2.0.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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +204 -259
  3. package/index.js +229 -113
  4. package/lib/cleanup.js +41 -129
  5. package/lib/features.js +239 -0
  6. package/lib/generator.js +286 -204
  7. package/lib/utils.js +43 -91
  8. package/package.json +81 -63
  9. package/templates/cicd/github-actions.yml.ejs +70 -0
  10. package/templates/config/database.mongo.js.ejs +29 -33
  11. package/templates/config/database.postgres.js.ejs +41 -40
  12. package/templates/config/database.prisma.js.ejs +26 -0
  13. package/templates/config/redis.js.ejs +28 -0
  14. package/templates/config/schema.prisma.ejs +20 -0
  15. package/templates/config/swagger.js.ejs +30 -0
  16. package/templates/config/websocket.js.ejs +62 -0
  17. package/templates/controllers/authController.js.ejs +152 -129
  18. package/templates/controllers/exampleController.js.ejs +92 -152
  19. package/templates/controllers/userController.js.ejs +52 -60
  20. package/templates/core/Dockerfile.ejs +41 -31
  21. package/templates/core/README.md.ejs +191 -179
  22. package/templates/core/app.js.ejs +114 -64
  23. package/templates/core/docker-compose.yml.ejs +59 -47
  24. package/templates/core/dockerignore.ejs +7 -0
  25. package/templates/core/env.ejs +25 -19
  26. package/templates/core/env.example.ejs +26 -0
  27. package/templates/core/eslintrc.json.ejs +50 -20
  28. package/templates/core/gitignore.ejs +51 -51
  29. package/templates/core/healthcheck.js.ejs +24 -24
  30. package/templates/core/jest.config.js.ejs +19 -22
  31. package/templates/core/package.json.ejs +70 -33
  32. package/templates/core/prettierrc.json.ejs +11 -11
  33. package/templates/core/server.js.ejs +64 -48
  34. package/templates/core/tsconfig.json.ejs +19 -0
  35. package/templates/middleware/auth.js.ejs +80 -66
  36. package/templates/middleware/cache.js.ejs +67 -0
  37. package/templates/middleware/errorHandler.js.ejs +50 -46
  38. package/templates/middleware/requestId.js.ejs +9 -0
  39. package/templates/middleware/validation.js.ejs +109 -47
  40. package/templates/migrations/create-users.js.ejs +50 -0
  41. package/templates/migrations/seed-users.js.ejs +34 -0
  42. package/templates/migrations/sequelizerc.ejs +8 -0
  43. package/templates/models/User.mongo.js.ejs +29 -29
  44. package/templates/models/User.postgres.js.ejs +40 -40
  45. package/templates/models/index.mongo.js.ejs +7 -7
  46. package/templates/models/index.postgres.js.ejs +11 -11
  47. package/templates/routes/authRoutes.js.ejs +222 -13
  48. package/templates/routes/exampleRoutes.js.ejs +100 -12
  49. package/templates/routes/index.js.ejs +34 -24
  50. package/templates/routes/userRoutes.js.ejs +78 -15
  51. package/templates/services/authService.js.ejs +111 -35
  52. package/templates/services/exampleService.js.ejs +112 -112
  53. package/templates/services/userService.mongodb.js.ejs +33 -33
  54. package/templates/services/userService.postgres.js.ejs +30 -30
  55. package/templates/services/userService.prisma.js.ejs +36 -0
  56. package/templates/tests/auth.test.js.ejs +83 -66
  57. package/templates/tests/example.test.js.ejs +109 -112
  58. package/templates/tests/setup.js.ejs +11 -11
  59. package/templates/tests/users.test.js.ejs +42 -42
  60. package/templates/utils/envValidator.js.ejs +23 -0
  61. package/templates/utils/errors.js.ejs +12 -12
  62. package/templates/utils/logger.js.ejs +37 -28
  63. package/templates/utils/response.js.ejs +28 -0
  64. package/templates/utils/validators.js.ejs +34 -34
  65. package/templates/config/swagger.json.ejs +0 -194
  66. package/templates/core/index.js.ejs +0 -24
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ async up(queryInterface, Sequelize) {
5
+ await queryInterface.createTable('users', {
6
+ id: {
7
+ type: Sequelize.UUID,
8
+ defaultValue: Sequelize.UUIDV4,
9
+ primaryKey: true,
10
+ allowNull: false,
11
+ },
12
+ username: {
13
+ type: Sequelize.STRING(50),
14
+ allowNull: false,
15
+ unique: true,
16
+ },
17
+ email: {
18
+ type: Sequelize.STRING(255),
19
+ allowNull: false,
20
+ unique: true,
21
+ },
22
+ password: {
23
+ type: Sequelize.STRING(255),
24
+ allowNull: false,
25
+ },
26
+ role: {
27
+ type: Sequelize.STRING(20),
28
+ allowNull: false,
29
+ defaultValue: 'user',
30
+ },
31
+ createdAt: {
32
+ type: Sequelize.DATE,
33
+ allowNull: false,
34
+ defaultValue: Sequelize.literal('NOW()'),
35
+ },
36
+ updatedAt: {
37
+ type: Sequelize.DATE,
38
+ allowNull: false,
39
+ defaultValue: Sequelize.literal('NOW()'),
40
+ },
41
+ });
42
+
43
+ await queryInterface.addIndex('users', ['email'], { unique: true });
44
+ await queryInterface.addIndex('users', ['username'], { unique: true });
45
+ },
46
+
47
+ async down(queryInterface) {
48
+ await queryInterface.dropTable('users');
49
+ },
50
+ };
@@ -0,0 +1,34 @@
1
+ 'use strict';
2
+
3
+ const bcrypt = require('bcryptjs');
4
+
5
+ module.exports = {
6
+ async up(queryInterface) {
7
+ const hashedPassword = await bcrypt.hash('Password1', 12);
8
+
9
+ await queryInterface.bulkInsert('users', [
10
+ {
11
+ id: '00000000-0000-4000-a000-000000000001',
12
+ username: 'admin',
13
+ email: 'admin@example.com',
14
+ password: hashedPassword,
15
+ role: 'admin',
16
+ createdAt: new Date(),
17
+ updatedAt: new Date(),
18
+ },
19
+ {
20
+ id: '00000000-0000-4000-a000-000000000002',
21
+ username: 'testuser',
22
+ email: 'user@example.com',
23
+ password: hashedPassword,
24
+ role: 'user',
25
+ createdAt: new Date(),
26
+ updatedAt: new Date(),
27
+ },
28
+ ]);
29
+ },
30
+
31
+ async down(queryInterface) {
32
+ await queryInterface.bulkDelete('users', null, {});
33
+ },
34
+ };
@@ -0,0 +1,8 @@
1
+ const path = require('path');
2
+
3
+ module.exports = {
4
+ config: path.resolve('src/config', 'database.js'),
5
+ 'models-path': path.resolve('src/models'),
6
+ 'migrations-path': path.resolve('migrations'),
7
+ 'seeders-path': path.resolve('seeders'),
8
+ };
@@ -1,30 +1,30 @@
1
- const mongoose = require('mongoose');
2
-
3
- const userSchema = new mongoose.Schema({
4
- username: {
5
- type: String,
6
- required: [true, 'Username is required'],
7
- unique: true,
8
- trim: true,
9
- minlength: [3, 'Username must be at least 3 characters long'],
10
- maxlength: [50, 'Username must not exceed 50 characters'],
11
- },
12
- email: {
13
- type: String,
14
- required: [true, 'Email is required'],
15
- unique: true,
16
- lowercase: true,
17
- trim: true,
18
- match: [/^\S+@\S+\.\S+$/, 'Please enter a valid email address'],
19
- },
20
- password: {
21
- type: String,
22
- required: [true, 'Password is required'],
23
- minlength: [6, 'Password must be at least 6 characters long'],
24
- },
25
- }, {
26
- timestamps: true,
27
- });
28
-
29
-
1
+ const mongoose = require('mongoose');
2
+
3
+ const userSchema = new mongoose.Schema({
4
+ username: {
5
+ type: String,
6
+ required: [true, 'Username is required'],
7
+ unique: true,
8
+ trim: true,
9
+ minlength: [3, 'Username must be at least 3 characters long'],
10
+ maxlength: [50, 'Username must not exceed 50 characters'],
11
+ },
12
+ email: {
13
+ type: String,
14
+ required: [true, 'Email is required'],
15
+ unique: true,
16
+ lowercase: true,
17
+ trim: true,
18
+ match: [/^\S+@\S+\.\S+$/, 'Please enter a valid email address'],
19
+ },
20
+ password: {
21
+ type: String,
22
+ required: [true, 'Password is required'],
23
+ minlength: [8, 'Password must be at least 8 characters long'],
24
+ },
25
+ }, {
26
+ timestamps: true,
27
+ });
28
+
29
+
30
30
  module.exports = mongoose.model('User', userSchema);
@@ -1,41 +1,41 @@
1
- const { DataTypes } = require('sequelize');
2
- const { sequelize } = require('../config/database');
3
-
4
- const User = sequelize.define('User', {
5
- id: {
6
- type: DataTypes.UUID,
7
- defaultValue: DataTypes.UUIDV4,
8
- primaryKey: true,
9
- },
10
- username: {
11
- type: DataTypes.STRING(50),
12
- allowNull: false,
13
- unique: true,
14
- validate: {
15
- len: [3, 50],
16
- notEmpty: true,
17
- },
18
- },
19
- email: {
20
- type: DataTypes.STRING,
21
- allowNull: false,
22
- unique: true,
23
- validate: {
24
- isEmail: true,
25
- notEmpty: true,
26
- },
27
- },
28
- password: {
29
- type: DataTypes.STRING,
30
- allowNull: false,
31
- validate: {
32
- len: [6, 255],
33
- notEmpty: true,
34
- },
35
- },
36
- }, {
37
- timestamps: true,
38
- tableName: 'users',
39
- });
40
-
1
+ const { DataTypes } = require('sequelize');
2
+ const { sequelize } = require('../config/database');
3
+
4
+ const User = sequelize.define('User', {
5
+ id: {
6
+ type: DataTypes.UUID,
7
+ defaultValue: DataTypes.UUIDV4,
8
+ primaryKey: true,
9
+ },
10
+ username: {
11
+ type: DataTypes.STRING(50),
12
+ allowNull: false,
13
+ unique: true,
14
+ validate: {
15
+ len: [3, 50],
16
+ notEmpty: true,
17
+ },
18
+ },
19
+ email: {
20
+ type: DataTypes.STRING,
21
+ allowNull: false,
22
+ unique: true,
23
+ validate: {
24
+ isEmail: true,
25
+ notEmpty: true,
26
+ },
27
+ },
28
+ password: {
29
+ type: DataTypes.STRING,
30
+ allowNull: false,
31
+ validate: {
32
+ len: [8, 255],
33
+ notEmpty: true,
34
+ },
35
+ },
36
+ }, {
37
+ timestamps: true,
38
+ tableName: 'users',
39
+ });
40
+
41
41
  module.exports = User;
@@ -1,8 +1,8 @@
1
- // For MongoDB, we typically don't need an index file as we import models directly
2
- // But you can use this file to define model relationships if needed
3
-
4
- const User = require('./User');
5
-
6
- module.exports = {
7
- User,
1
+ // For MongoDB, we typically don't need an index file as we import models directly
2
+ // But you can use this file to define model relationships if needed
3
+
4
+ const User = require('./User');
5
+
6
+ module.exports = {
7
+ User,
8
8
  };
@@ -1,12 +1,12 @@
1
- const { sequelize } = require('../config/database');
2
- const User = require('./User');
3
-
4
- // Define associations here if you have multiple models
5
- // Example:
6
- // User.hasMany(Post);
7
- // Post.belongsTo(User);
8
-
9
- module.exports = {
10
- sequelize,
11
- User,
1
+ const { sequelize } = require('../config/database');
2
+ const User = require('./User');
3
+
4
+ // Define associations here if you have multiple models
5
+ // Example:
6
+ // User.hasMany(Post);
7
+ // Post.belongsTo(User);
8
+
9
+ module.exports = {
10
+ sequelize,
11
+ User,
12
12
  };
@@ -1,14 +1,223 @@
1
- // templates/routes/authRoutes.js.ejs
2
- const express = require('express');
3
- const authController = require('../controllers/authController');
4
- const { validateLogin, validateRegister } = require('../middleware/validation');
5
-
6
- const router = express.Router();
7
-
8
- // Authentication routes
9
- router.post('/register', validateRegister, authController.register);
10
- router.post('/login', validateLogin, authController.login);
11
- router.post('/refresh', authController.refreshToken);
12
- router.post('/logout', authController.authenticateToken, authController.logout);
13
-
1
+ const express = require('express');
2
+ const authController = require('../controllers/authController');
3
+ const { validateLogin, validateRegister, validate, forgotPasswordSchema, resetPasswordSchema } = require('../middleware/validation');
4
+ const { authenticateToken } = require('../middleware/auth');
5
+
6
+ const router = express.Router();
7
+
8
+ /**
9
+ * @swagger
10
+ * /auth/register:
11
+ * post:
12
+ * summary: Register a new user
13
+ * tags: [Authentication]
14
+ * requestBody:
15
+ * required: true
16
+ * content:
17
+ * application/json:
18
+ * schema:
19
+ * type: object
20
+ * required: [username, email, password]
21
+ * properties:
22
+ * username:
23
+ * type: string
24
+ * minLength: 3
25
+ * maxLength: 50
26
+ * description: Display name (3-50 characters)
27
+ * example: johndoe
28
+ * email:
29
+ * type: string
30
+ * format: email
31
+ * description: Valid email address
32
+ * example: john@example.com
33
+ * password:
34
+ * type: string
35
+ * minLength: 8
36
+ * description: "Must contain at least one uppercase letter, one lowercase letter, and one number"
37
+ * example: Secret123
38
+ * example:
39
+ * username: johndoe
40
+ * email: john@example.com
41
+ * password: Secret123
42
+ * responses:
43
+ * 201:
44
+ * description: User registered successfully
45
+ * content:
46
+ * application/json:
47
+ * schema:
48
+ * type: object
49
+ * properties:
50
+ * success:
51
+ * type: boolean
52
+ * example: true
53
+ * data:
54
+ * type: object
55
+ * properties:
56
+ * message:
57
+ * type: string
58
+ * user:
59
+ * type: object
60
+ * properties:
61
+ * id:
62
+ * type: string
63
+ * username:
64
+ * type: string
65
+ * email:
66
+ * type: string
67
+ * accessToken:
68
+ * type: string
69
+ * refreshToken:
70
+ * type: string
71
+ * 400:
72
+ * description: Validation error (weak password, invalid email, etc.)
73
+ * 409:
74
+ * description: User already exists
75
+ */
76
+ router.post('/register', validateRegister, authController.register);
77
+
78
+ /**
79
+ * @swagger
80
+ * /auth/login:
81
+ * post:
82
+ * summary: Login user
83
+ * tags: [Authentication]
84
+ * requestBody:
85
+ * required: true
86
+ * content:
87
+ * application/json:
88
+ * schema:
89
+ * type: object
90
+ * required: [email, password]
91
+ * properties:
92
+ * email:
93
+ * type: string
94
+ * format: email
95
+ * example: john@example.com
96
+ * password:
97
+ * type: string
98
+ * example: Secret123
99
+ * example:
100
+ * email: john@example.com
101
+ * password: Secret123
102
+ * responses:
103
+ * 200:
104
+ * description: Login successful
105
+ * content:
106
+ * application/json:
107
+ * schema:
108
+ * type: object
109
+ * properties:
110
+ * success:
111
+ * type: boolean
112
+ * example: true
113
+ * data:
114
+ * type: object
115
+ * properties:
116
+ * message:
117
+ * type: string
118
+ * user:
119
+ * type: object
120
+ * accessToken:
121
+ * type: string
122
+ * refreshToken:
123
+ * type: string
124
+ * 401:
125
+ * description: Invalid credentials
126
+ */
127
+ router.post('/login', validateLogin, authController.login);
128
+
129
+ /**
130
+ * @swagger
131
+ * /auth/refresh:
132
+ * post:
133
+ * summary: Refresh access token
134
+ * tags: [Authentication]
135
+ * requestBody:
136
+ * required: true
137
+ * content:
138
+ * application/json:
139
+ * schema:
140
+ * type: object
141
+ * required: [refreshToken]
142
+ * properties:
143
+ * refreshToken:
144
+ * type: string
145
+ * description: The refresh token received from login or register
146
+ * example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
147
+ * responses:
148
+ * 200:
149
+ * description: Token refreshed
150
+ * 401:
151
+ * description: Invalid refresh token
152
+ */
153
+ router.post('/refresh', authController.refreshToken);
154
+
155
+ /**
156
+ * @swagger
157
+ * /auth/logout:
158
+ * post:
159
+ * summary: Logout user
160
+ * tags: [Authentication]
161
+ * security:
162
+ * - bearerAuth: []
163
+ * responses:
164
+ * 200:
165
+ * description: Logout successful
166
+ */
167
+ router.post('/logout', authenticateToken, authController.logout);
168
+
169
+ /**
170
+ * @swagger
171
+ * /auth/forgot-password:
172
+ * post:
173
+ * summary: Request password reset
174
+ * tags: [Authentication]
175
+ * requestBody:
176
+ * required: true
177
+ * content:
178
+ * application/json:
179
+ * schema:
180
+ * type: object
181
+ * required: [email]
182
+ * properties:
183
+ * email:
184
+ * type: string
185
+ * format: email
186
+ * example: john@example.com
187
+ * responses:
188
+ * 200:
189
+ * description: Reset link sent (if account exists)
190
+ */
191
+ router.post('/forgot-password', validate({ body: forgotPasswordSchema }), authController.forgotPassword);
192
+
193
+ /**
194
+ * @swagger
195
+ * /auth/reset-password:
196
+ * post:
197
+ * summary: Reset password with token
198
+ * tags: [Authentication]
199
+ * requestBody:
200
+ * required: true
201
+ * content:
202
+ * application/json:
203
+ * schema:
204
+ * type: object
205
+ * required: [token, password]
206
+ * properties:
207
+ * token:
208
+ * type: string
209
+ * description: The reset token from the password reset email
210
+ * password:
211
+ * type: string
212
+ * minLength: 8
213
+ * description: "Must contain at least one uppercase letter, one lowercase letter, and one number"
214
+ * example: NewSecret123
215
+ * responses:
216
+ * 200:
217
+ * description: Password reset successful
218
+ * 400:
219
+ * description: Invalid or expired reset token
220
+ */
221
+ router.post('/reset-password', validate({ body: resetPasswordSchema }), authController.resetPassword);
222
+
14
223
  module.exports = router;
@@ -1,13 +1,101 @@
1
- const express = require('express');
2
- const exampleController = require('../controllers/exampleController');
3
-
4
- const router = express.Router();
5
-
6
- // Example routes
7
- router.get('/', exampleController.getAllExamples);
8
- router.get('/:id', exampleController.getExampleById);
9
- router.post('/', exampleController.createExample);
10
- router.put('/:id', exampleController.updateExample);
11
- router.delete('/:id', exampleController.deleteExample);
12
-
1
+ const express = require('express');
2
+ const exampleController = require('../controllers/exampleController');
3
+
4
+ const router = express.Router();
5
+
6
+ /**
7
+ * @swagger
8
+ * /examples:
9
+ * get:
10
+ * summary: Get all examples
11
+ * tags: [Examples]
12
+ * parameters:
13
+ * - in: query
14
+ * name: page
15
+ * schema:
16
+ * type: integer
17
+ * default: 1
18
+ * description: Page number
19
+ * - in: query
20
+ * name: limit
21
+ * schema:
22
+ * type: integer
23
+ * default: 10
24
+ * description: Items per page (max 100)
25
+ * responses:
26
+ * 200:
27
+ * description: Examples retrieved
28
+ * post:
29
+ * summary: Create new example
30
+ * tags: [Examples]
31
+ * requestBody:
32
+ * required: true
33
+ * content:
34
+ * application/json:
35
+ * schema:
36
+ * type: object
37
+ * required: [title, description]
38
+ * properties:
39
+ * title:
40
+ * type: string
41
+ * example: My First Example
42
+ * description:
43
+ * type: string
44
+ * example: A description of the example item
45
+ * example:
46
+ * title: My First Example
47
+ * description: A description of the example item
48
+ * responses:
49
+ * 201:
50
+ * description: Example created
51
+ */
52
+ router.get('/', exampleController.getAllExamples);
53
+ router.post('/', exampleController.createExample);
54
+
55
+ /**
56
+ * @swagger
57
+ * /examples/{id}:
58
+ * get:
59
+ * summary: Get example by ID
60
+ * tags: [Examples]
61
+ * parameters:
62
+ * - in: path
63
+ * name: id
64
+ * required: true
65
+ * schema:
66
+ * type: string
67
+ * responses:
68
+ * 200:
69
+ * description: Example retrieved
70
+ * 404:
71
+ * description: Example not found
72
+ * put:
73
+ * summary: Update example
74
+ * tags: [Examples]
75
+ * parameters:
76
+ * - in: path
77
+ * name: id
78
+ * required: true
79
+ * schema:
80
+ * type: string
81
+ * responses:
82
+ * 200:
83
+ * description: Example updated
84
+ * delete:
85
+ * summary: Delete example
86
+ * tags: [Examples]
87
+ * parameters:
88
+ * - in: path
89
+ * name: id
90
+ * required: true
91
+ * schema:
92
+ * type: string
93
+ * responses:
94
+ * 200:
95
+ * description: Example deleted
96
+ */
97
+ router.get('/:id', exampleController.getExampleById);
98
+ router.put('/:id', exampleController.updateExample);
99
+ router.delete('/:id', exampleController.deleteExample);
100
+
13
101
  module.exports = router;
@@ -1,24 +1,34 @@
1
- const express = require('express');<% if (hasDatabase) { %>
2
- const authRoutes = require('./authRoutes');
3
- const userRoutes = require('./userRoutes');<% } else { %>
4
- const exampleRoutes = require('./exampleRoutes');<% } %>
5
-
6
- const router = express.Router();
7
-
8
- // Mount route modules<% if (hasDatabase) { %>
9
- router.use('/auth', authRoutes);
10
- router.use('/users', userRoutes);<% } else { %>
11
- router.use('/examples', exampleRoutes);<% } %>
12
-
13
- // API root endpoint
14
- router.get('/', (req, res) => {
15
- res.json({
16
- message: 'Welcome to the API',
17
- version: '1.0.0',
18
- documentation: '/api-docs',<% if (hasDatabase) { %>
19
- features: ['authentication', 'user-management', '<%= db %>-database']<% } else { %>
20
- features: ['rate-limiting', 'logging', 'swagger-docs']<% } %>,
21
- });
22
- });
23
-
24
- module.exports = router;
1
+ const express = require('express');
2
+ <% if (hasAuth) { %>const authRoutes = require('./authRoutes');
3
+ const userRoutes = require('./userRoutes');
4
+ <% } else { %>const exampleRoutes = require('./exampleRoutes');
5
+ <% } %>
6
+
7
+ const router = express.Router();
8
+
9
+ <% if (hasAuth) { %>router.use('/auth', authRoutes);
10
+ router.use('/users', userRoutes);
11
+ <% } else { %>router.use('/examples', exampleRoutes);
12
+ <% } %>
13
+
14
+ /**
15
+ * @swagger
16
+ * /api:
17
+ * get:
18
+ * summary: API root
19
+ * responses:
20
+ * 200:
21
+ * description: API information
22
+ */
23
+ router.get('/', (req, res) => {
24
+ res.json({
25
+ success: true,
26
+ data: {
27
+ message: 'Welcome to the API',
28
+ version: '1.0.0',<% if (hasSwagger) { %>
29
+ documentation: '/api-docs',<% } %>
30
+ },
31
+ });
32
+ });
33
+
34
+ module.exports = router;