nodejs-quickstart-structure 1.3.2 → 1.3.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.
package/bin/index.js CHANGED
@@ -50,7 +50,7 @@ program
50
50
  await generateProject(answers);
51
51
 
52
52
  console.log(chalk.green('\n✔ Project generated successfully!'));
53
- console.log(chalk.cyan(`\nNext steps:\n cd ${answers.projectName}\n npm install\n docker-compose up\n-----------------------\nStart the app manually:\n npm install\n npm run dev`));
53
+ console.log(chalk.cyan(`\nNext steps:\n cd ${answers.projectName}\n npm install\n docker-compose up\n-----------------------\nStart the app manually:\n cd ${answers.projectName}\n npm install\n npm run dev`));
54
54
 
55
55
  } catch (error) {
56
56
  console.error(chalk.red('Error generating project:'), error);
package/lib/generator.js CHANGED
@@ -126,6 +126,24 @@ export const generateProject = async (config) => {
126
126
  const kafkaSource = path.join(templatesDir, 'common', 'kafka', langExt);
127
127
  await fs.copy(kafkaSource, path.join(targetDir, 'src'));
128
128
 
129
+ // Render Kafka Service with dynamic logger path
130
+ const kafkaServiceFileName = `kafkaService.${langExt}`;
131
+ const kafkaServiceTemplate = path.join(targetDir, 'src', 'services', `${kafkaServiceFileName}.ejs`);
132
+
133
+ if (await fs.pathExists(kafkaServiceTemplate)) {
134
+ const loggerPath = architecture === 'Clean Architecture' ? '../log/logger' : '../utils/logger';
135
+ // Note: For MVC, it's relative to src/services (../utils/logger). Wait, ../utils/logger means src/utils/logger.
136
+ // src/services/kafka.ts -> ../utils/logger -> src/utils/logger. Correct.
137
+ // But wait, generated code for MVC usually puts it in src/services.
138
+ // Let's re-verify MVC structure for logger.
139
+ // In MVC, logger is usually in src/utils/logger.ts?
140
+ // Let's check where logger is copied for MVC.
141
+
142
+ const content = ejs.render(await fs.readFile(kafkaServiceTemplate, 'utf-8'), { loggerPath });
143
+ await fs.writeFile(path.join(targetDir, 'src', 'services', kafkaServiceFileName), content);
144
+ await fs.remove(kafkaServiceTemplate);
145
+ }
146
+
129
147
  if (architecture === 'Clean Architecture') {
130
148
  // Clean Architecture Restructuring
131
149
  await fs.ensureDir(path.join(targetDir, 'src/infrastructure/messaging'));
@@ -240,8 +258,10 @@ export const generateProject = async (config) => {
240
258
  // MVC TS
241
259
  const swaggerMvcTs = path.join(targetDir, 'src', 'config', 'swagger.ts.ejs');
242
260
  if (await fs.pathExists(swaggerMvcTs)) {
243
- const content = ejs.render(await fs.readFile(swaggerMvcTs, 'utf-8'), { communication });
244
- await fs.writeFile(path.join(targetDir, 'src', 'config', 'swagger.ts'), content);
261
+ if (communication === 'REST APIs') {
262
+ const content = ejs.render(await fs.readFile(swaggerMvcTs, 'utf-8'), { communication });
263
+ await fs.writeFile(path.join(targetDir, 'src', 'config', 'swagger.ts'), content);
264
+ }
245
265
  await fs.remove(swaggerMvcTs);
246
266
  }
247
267
  // Clean Architecture TS
@@ -249,8 +269,10 @@ export const generateProject = async (config) => {
249
269
  // Note: In Clean Arch, it might be in src/infrastructure/webserver or src/config depending on refactor.
250
270
  // Based on previous moves, we saw it in src/config for TS.
251
271
  if (await fs.pathExists(swaggerCleanTs)) {
252
- const content = ejs.render(await fs.readFile(swaggerCleanTs, 'utf-8'), { communication });
253
- await fs.writeFile(path.join(targetDir, 'src', 'config', 'swagger.ts'), content);
272
+ if (communication === 'REST APIs') {
273
+ const content = ejs.render(await fs.readFile(swaggerCleanTs, 'utf-8'), { communication });
274
+ await fs.writeFile(path.join(targetDir, 'src', 'config', 'swagger.ts'), content);
275
+ }
254
276
  await fs.remove(swaggerCleanTs);
255
277
  }
256
278
 
package/package.json CHANGED
@@ -1,40 +1,40 @@
1
- {
2
- "name": "nodejs-quickstart-structure",
3
- "version": "1.3.2",
4
- "type": "module",
5
- "description": "A CLI to scaffold Node.js microservices with MVC or Clean Architecture",
6
- "main": "bin/index.js",
7
- "bin": {
8
- "nodejs-quickstart": "./bin/index.js"
9
- },
10
- "scripts": {
11
- "test": "echo \"Error: no test specified\" && exit 1",
12
- "test:e2e": "npm run test:e2e:windows",
13
- "test:e2e:windows": "node scripts/validate-windows.js",
14
- "test:e2e:linux": "node scripts/validate-linux.js"
15
- },
16
- "keywords": [
17
- "nodejs",
18
- "cli",
19
- "scaffold",
20
- "mvc",
21
- "clean-architecture"
22
- ],
23
- "author": "Pau Dang <phucdangb1400718@gmail.com>",
24
- "repository": {
25
- "type": "git",
26
- "url": "git+https://github.com/paudang/nodejs-quickstart-structure.git"
27
- },
28
- "bugs": {
29
- "url": "https://github.com/paudang/nodejs-quickstart-structure/issues"
30
- },
31
- "homepage": "https://github.com/paudang/nodejs-quickstart-structure#readme",
32
- "license": "ISC",
33
- "dependencies": {
34
- "chalk": "^5.4.1",
35
- "commander": "^13.1.0",
36
- "ejs": "^3.1.10",
37
- "fs-extra": "^11.3.0",
38
- "inquirer": "^12.4.1"
39
- }
1
+ {
2
+ "name": "nodejs-quickstart-structure",
3
+ "version": "1.3.5",
4
+ "type": "module",
5
+ "description": "A CLI to scaffold Node.js microservices with MVC or Clean Architecture",
6
+ "main": "bin/index.js",
7
+ "bin": {
8
+ "nodejs-quickstart": "./bin/index.js"
9
+ },
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1",
12
+ "test:e2e": "npm run test:e2e:windows",
13
+ "test:e2e:windows": "node scripts/validate-windows.js",
14
+ "test:e2e:linux": "node scripts/validate-linux.js"
15
+ },
16
+ "keywords": [
17
+ "nodejs",
18
+ "cli",
19
+ "scaffold",
20
+ "mvc",
21
+ "clean-architecture"
22
+ ],
23
+ "author": "Pau Dang <phucdangb1400718@gmail.com>",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/paudang/nodejs-quickstart-structure.git"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/paudang/nodejs-quickstart-structure/issues"
30
+ },
31
+ "homepage": "https://github.com/paudang/nodejs-quickstart-structure#readme",
32
+ "license": "ISC",
33
+ "dependencies": {
34
+ "chalk": "^5.4.1",
35
+ "commander": "^13.1.0",
36
+ "ejs": "^3.1.10",
37
+ "fs-extra": "^11.3.0",
38
+ "inquirer": "^12.4.1"
39
+ }
40
40
  }
@@ -26,10 +26,10 @@ const syncDatabase = async () => {
26
26
  });
27
27
  <% } -%>
28
28
  break;
29
- } catch (err) {
30
- logger.error('Database sync failed:', err);
29
+ } catch (error) {
30
+ logger.error('Error syncing database:', error);
31
31
  retries -= 1;
32
- logger.info(`Retries left: ${retries}. Waiting 5s...`);
32
+ logger.info(`Retries left: ${retries}`);
33
33
  await new Promise(res => setTimeout(res, 5000));
34
34
  }
35
35
  }
@@ -13,10 +13,10 @@ const logger = winston.createLogger({
13
13
  ],
14
14
  });
15
15
 
16
- if (process.env.NODE_ENV !== 'production') {
17
- logger.add(new winston.transports.Console({
18
- format: winston.format.simple(),
19
- }));
20
- }
16
+ logger.add(new winston.transports.Console({
17
+ format: process.env.NODE_ENV !== 'production'
18
+ ? winston.format.simple()
19
+ : winston.format.json(),
20
+ }));
21
21
 
22
22
  module.exports = logger;
@@ -1,6 +1,7 @@
1
1
  const express = require('express');
2
2
  const cors = require('cors');
3
3
  require('dotenv').config();
4
+ const logger = require('../log/logger');
4
5
  <% if (communication === 'REST APIs') { %>const apiRoutes = require('../../interfaces/routes/api');<% } -%>
5
6
  <% if (communication === 'REST APIs') { -%>
6
7
  const swaggerUi = require('swagger-ui-express');
@@ -26,7 +27,7 @@ const startServer = (port) => {
26
27
  });
27
28
 
28
29
  app.listen(port, () => {
29
- console.log(`Server running on port ${port}`);
30
+ logger.info(`Server running on port ${port}`);
30
31
  });
31
32
  };
32
33
 
@@ -2,6 +2,7 @@ const CreateUser = require('../../usecases/CreateUser');
2
2
  const GetAllUsers = require('../../usecases/GetAllUsers');
3
3
  const UserRepository = require('../../infrastructure/repositories/UserRepository');
4
4
  const HTTP_STATUS = require('../../utils/httpCodes');
5
+ const logger = require('../../infrastructure/log/logger');
5
6
 
6
7
  class UserController {
7
8
  constructor() {
@@ -13,7 +14,10 @@ class UserController {
13
14
  getUsers(req, res) {
14
15
  this.getAllUsersUseCase.execute()
15
16
  .then(users => res.json(users))
16
- .catch(err => res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ error: err.message }));
17
+ .catch(err => {
18
+ logger.error('Error getting users:', err);
19
+ res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ error: err.message });
20
+ });
17
21
  }
18
22
 
19
23
  async createUser(req, res) {
@@ -22,6 +26,7 @@ class UserController {
22
26
  const user = await this.createUserUseCase.execute(name, email);
23
27
  res.status(HTTP_STATUS.CREATED).json(user);
24
28
  } catch (error) {
29
+ logger.error('Error creating user:', error);
25
30
  res.status(HTTP_STATUS.BAD_REQUEST).json({ error: error.message });
26
31
  }
27
32
  }
@@ -61,10 +61,10 @@ const syncDatabase = async () => {
61
61
  <%_ } -%>
62
62
  });
63
63
  break;
64
- } catch (err) {
65
- logger.error('Database sync failed:', err);
64
+ } catch (error) {
65
+ logger.error('Error syncing database:', error);
66
66
  retries -= 1;
67
- logger.info(`Retries left: ${retries}. Waiting 5s...`);
67
+ logger.info(`Retries left: ${retries}`);
68
68
  await new Promise(res => setTimeout(res, 5000));
69
69
  }
70
70
  }
@@ -13,10 +13,10 @@ const logger = winston.createLogger({
13
13
  ],
14
14
  });
15
15
 
16
- if (process.env.NODE_ENV !== 'production') {
17
- logger.add(new winston.transports.Console({
18
- format: winston.format.simple(),
19
- }));
20
- }
16
+ logger.add(new winston.transports.Console({
17
+ format: process.env.NODE_ENV !== 'production'
18
+ ? winston.format.simple()
19
+ : winston.format.json(),
20
+ }));
21
21
 
22
22
  export default logger;
@@ -3,6 +3,7 @@ import { UserRepository } from '../../infrastructure/repositories/UserRepository
3
3
  import CreateUser from '../../usecases/createUser';
4
4
  import GetAllUsers from '../../usecases/getAllUsers';
5
5
  import { HTTP_STATUS } from '../../utils/httpCodes';
6
+ import logger from '../../infrastructure/log/logger';
6
7
 
7
8
  export class UserController {
8
9
  private createUserUseCase: CreateUser;
@@ -20,7 +21,7 @@ export class UserController {
20
21
  const user = await this.createUserUseCase.execute(name, email);
21
22
  res.status(HTTP_STATUS.CREATED).json(user);
22
23
  } catch (error) {
23
- console.error('UserController Error:', error);
24
+ logger.error('UserController Error:', error);
24
25
  if (error instanceof Error) {
25
26
  res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ error: error.message });
26
27
  } else {
@@ -34,7 +35,7 @@ export class UserController {
34
35
  const users = await this.getAllUsersUseCase.execute();
35
36
  res.json(users);
36
37
  } catch (error) {
37
- console.error('UserController Error:', error);
38
+ logger.error('UserController Error:', error);
38
39
  if (error instanceof Error) {
39
40
  res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ error: error.message });
40
41
  } else {
@@ -1,4 +1,5 @@
1
1
  const { kafka } = require('../config/kafka');
2
+ const logger = require('<%= loggerPath %>');
2
3
 
3
4
  const producer = kafka.producer();
4
5
  const consumer = kafka.consumer({ groupId: 'test-group' });
@@ -10,7 +11,7 @@ const connectKafka = async () => {
10
11
 
11
12
  await consumer.run({
12
13
  eachMessage: async ({ topic, partition, message }) => {
13
- console.log({
14
+ logger.info({
14
15
  value: message.value.toString(),
15
16
  });
16
17
  },
@@ -1,5 +1,6 @@
1
1
  import { kafka } from '../config/kafka';
2
2
  import { EachMessagePayload, Producer, Consumer } from 'kafkajs';
3
+ import logger from '<%= loggerPath %>';
3
4
 
4
5
  export class KafkaService {
5
6
  private producer: Producer;
@@ -17,7 +18,7 @@ export class KafkaService {
17
18
 
18
19
  await this.consumer.run({
19
20
  eachMessage: async ({ topic, partition, message }: EachMessagePayload) => {
20
- console.log({
21
+ logger.info({
21
22
  value: message.value?.toString(),
22
23
  });
23
24
  },
@@ -1,12 +1,14 @@
1
1
  const User = require('../models/User');
2
2
  const HTTP_STATUS = require('../utils/httpCodes');
3
+ const logger = require('../utils/logger');
3
4
 
4
5
  const getUsers = async (req, res) => {
5
6
  try {
6
7
  const users = await User.findAll();
7
8
  res.json(users);
8
9
  } catch (error) {
9
- res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ error: error.message });
10
+ logger.error('Error fetching users:', error);
11
+ res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ error: 'Internal Server Error' });
10
12
  }
11
13
  };
12
14
 
@@ -21,10 +21,10 @@ const logger = winston.createLogger({
21
21
  // If we're not in production then log to the `console` with the format:
22
22
  // `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
23
23
  //
24
- if (process.env.NODE_ENV !== 'production') {
25
- logger.add(new winston.transports.Console({
26
- format: winston.format.simple(),
27
- }));
28
- }
24
+ logger.add(new winston.transports.Console({
25
+ format: process.env.NODE_ENV !== 'production'
26
+ ? winston.format.simple()
27
+ : winston.format.json(),
28
+ }));
29
29
 
30
30
  module.exports = logger;
@@ -1,6 +1,7 @@
1
1
  import { Request, Response } from 'express';
2
2
  import User from '../models/User';
3
3
  import { HTTP_STATUS } from '../utils/httpCodes';
4
+ import logger from '../utils/logger';
4
5
 
5
6
  export class UserController {
6
7
  async getUsers(req: Request, res: Response) {
@@ -8,6 +9,7 @@ export class UserController {
8
9
  const users = await User.findAll();
9
10
  res.json(users);
10
11
  } catch (error) {
12
+ logger.error('Error fetching users:', error);
11
13
  if (error instanceof Error) {
12
14
  res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ error: error.message });
13
15
  } else {
@@ -22,6 +24,7 @@ export class UserController {
22
24
  const user = await User.create({ name, email });
23
25
  res.status(HTTP_STATUS.CREATED).json(user);
24
26
  } catch (error) {
27
+ logger.error('Error creating user:', error);
25
28
  if (error instanceof Error) {
26
29
  res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ error: error.message });
27
30
  } else {
@@ -80,10 +80,10 @@ const syncDatabase = async () => {
80
80
  <%_ } -%>
81
81
  });
82
82
  break;
83
- } catch (err) {
84
- logger.error('Database sync failed:', err);
83
+ } catch (error) {
84
+ logger.error('Error syncing database:', error);
85
85
  retries -= 1;
86
- logger.info(`Retries left: ${retries}. Waiting 5s...`);
86
+ logger.info(`Retries left: ${retries}`);
87
87
  await new Promise(res => setTimeout(res, 5000));
88
88
  }
89
89
  }
@@ -13,10 +13,10 @@ const logger = winston.createLogger({
13
13
  ],
14
14
  });
15
15
 
16
- if (process.env.NODE_ENV !== 'production') {
17
- logger.add(new winston.transports.Console({
18
- format: winston.format.simple(),
19
- }));
20
- }
16
+ logger.add(new winston.transports.Console({
17
+ format: process.env.NODE_ENV !== 'production'
18
+ ? winston.format.simple()
19
+ : winston.format.json(),
20
+ }));
21
21
 
22
22
  export default logger;
@@ -1,14 +0,0 @@
1
- exports.getUsers = (req, res) => {
2
- res.json([
3
- { id: 1, name: 'John Doe' },
4
- { id: 2, name: 'Jane Doe' }
5
- ]);
6
- };
7
-
8
- exports.createUser = (req, res) => {
9
- const { name, email } = req.body;
10
- res.status(201).json({
11
- message: 'User created successfully',
12
- user: { name, email }
13
- });
14
- };