nodejs-quickstart-structure 1.19.0 → 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 (136) hide show
  1. package/CHANGELOG.md +320 -301
  2. package/LICENSE +15 -15
  3. package/README.md +45 -10
  4. package/bin/index.js +7 -1
  5. package/lib/generator.js +139 -139
  6. package/lib/modules/app-setup.js +401 -401
  7. package/lib/modules/config-files.js +151 -151
  8. package/lib/modules/database-setup.js +116 -116
  9. package/lib/modules/project-setup.js +32 -32
  10. package/lib/prompts.js +100 -100
  11. package/package.json +79 -78
  12. package/templates/clean-architecture/js/src/domain/models/User.js +9 -9
  13. package/templates/clean-architecture/js/src/errors/ApiError.js +14 -14
  14. package/templates/clean-architecture/js/src/index.js.ejs +55 -55
  15. package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -47
  16. package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -36
  17. package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -63
  18. package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -30
  19. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +89 -89
  20. package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -6
  21. package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -13
  22. package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -31
  23. package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -5
  24. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -6
  25. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -6
  26. package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -38
  27. package/templates/clean-architecture/js/src/usecases/CreateUser.js +14 -14
  28. package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -51
  29. package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -12
  30. package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -61
  31. package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -9
  32. package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -46
  33. package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -6
  34. package/templates/clean-architecture/ts/src/domain/user.ts +7 -7
  35. package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -15
  36. package/templates/clean-architecture/ts/src/index.ts.ejs +139 -139
  37. package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -63
  38. package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -36
  39. package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -32
  40. package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -17
  41. package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -3
  42. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -4
  43. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -4
  44. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -40
  45. package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -51
  46. package/templates/clean-architecture/ts/src/usecases/createUser.ts +13 -13
  47. package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -63
  48. package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -10
  49. package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -27
  50. package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -7
  51. package/templates/common/.cursorrules.ejs +60 -60
  52. package/templates/common/.dockerignore +12 -12
  53. package/templates/common/.env.example.ejs +41 -41
  54. package/templates/common/.gitlab-ci.yml.ejs +86 -86
  55. package/templates/common/.lintstagedrc +6 -6
  56. package/templates/common/.prettierrc +7 -7
  57. package/templates/common/Dockerfile +73 -73
  58. package/templates/common/Jenkinsfile.ejs +87 -87
  59. package/templates/common/SECURITY.md +20 -20
  60. package/templates/common/_github/workflows/ci.yml.ejs +46 -46
  61. package/templates/common/_github/workflows/security.yml.ejs +36 -36
  62. package/templates/common/_gitignore +5 -5
  63. package/templates/common/_husky/pre-commit +4 -4
  64. package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -29
  65. package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -37
  66. package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -27
  67. package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -34
  68. package/templates/common/caching/js/memoryCache.js.ejs +60 -60
  69. package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -101
  70. package/templates/common/caching/js/redisClient.js.ejs +75 -75
  71. package/templates/common/caching/js/redisClient.spec.js.ejs +147 -147
  72. package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -102
  73. package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -157
  74. package/templates/common/database/js/database.js.ejs +19 -19
  75. package/templates/common/database/js/database.spec.js.ejs +56 -56
  76. package/templates/common/database/js/mongoose.js.ejs +33 -33
  77. package/templates/common/database/js/mongoose.spec.js.ejs +43 -43
  78. package/templates/common/database/ts/database.spec.ts.ejs +56 -56
  79. package/templates/common/database/ts/database.ts.ejs +21 -21
  80. package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -42
  81. package/templates/common/database/ts/mongoose.ts.ejs +28 -28
  82. package/templates/common/docker-compose.yml.ejs +159 -159
  83. package/templates/common/ecosystem.config.js.ejs +40 -40
  84. package/templates/common/eslint.config.mjs.ejs +77 -77
  85. package/templates/common/health/js/healthRoute.spec.js.ejs +70 -70
  86. package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -76
  87. package/templates/common/jest.config.js.ejs +32 -32
  88. package/templates/common/kafka/js/config/kafka.js +9 -9
  89. package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -27
  90. package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -58
  91. package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -27
  92. package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -106
  93. package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -27
  94. package/templates/common/kafka/ts/config/kafka.ts +7 -7
  95. package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -50
  96. package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -27
  97. package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -81
  98. package/templates/common/migrate-mongo-config.js.ejs +31 -31
  99. package/templates/common/migrations/init.js.ejs +23 -23
  100. package/templates/common/package.json.ejs +119 -118
  101. package/templates/common/prompts/add-feature.md.ejs +26 -26
  102. package/templates/common/prompts/project-context.md.ejs +43 -43
  103. package/templates/common/prompts/troubleshoot.md.ejs +28 -28
  104. package/templates/common/public/css/style.css +147 -147
  105. package/templates/common/scripts/run-e2e.js.ejs +63 -63
  106. package/templates/common/sonar-project.properties.ejs +27 -27
  107. package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -79
  108. package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -94
  109. package/templates/common/tsconfig.json +22 -22
  110. package/templates/common/views/ejs/index.ejs +55 -55
  111. package/templates/common/views/pug/index.pug +40 -40
  112. package/templates/mvc/js/src/config/env.js.ejs +46 -46
  113. package/templates/mvc/js/src/config/swagger.js.ejs +6 -6
  114. package/templates/mvc/js/src/errors/ApiError.js +14 -14
  115. package/templates/mvc/js/src/graphql/context.js.ejs +7 -7
  116. package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -29
  117. package/templates/mvc/js/src/graphql/index.js.ejs +5 -5
  118. package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -6
  119. package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -6
  120. package/templates/mvc/js/src/index.js.ejs +136 -136
  121. package/templates/mvc/js/src/utils/errorMiddleware.js +29 -29
  122. package/templates/mvc/js/src/utils/httpCodes.js +9 -9
  123. package/templates/mvc/js/src/utils/logger.js +40 -40
  124. package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -63
  125. package/templates/mvc/ts/src/config/env.ts.ejs +45 -45
  126. package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -6
  127. package/templates/mvc/ts/src/errors/ApiError.ts +15 -15
  128. package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -30
  129. package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -12
  130. package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -3
  131. package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -4
  132. package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -4
  133. package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -27
  134. package/templates/mvc/ts/src/utils/httpCodes.ts +7 -7
  135. package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -63
  136. package/templates/mvc/ts/src/utils/logger.ts +36 -36
@@ -1,140 +1,140 @@
1
- import { env } from '@/config/env';
2
- import express from 'express';
3
- import cors from 'cors';
4
- import helmet from 'helmet';
5
- import hpp from 'hpp';
6
- import rateLimit from 'express-rate-limit';
7
- import logger from '@/infrastructure/log/logger';
8
- import morgan from 'morgan';
9
- import { errorMiddleware } from '@/utils/errorMiddleware';
10
- import { setupGracefulShutdown } from '@/utils/gracefulShutdown';
11
- import healthRoutes from '@/interfaces/routes/healthRoute';
12
- <% if (communication === 'REST APIs' || communication === 'Kafka') { -%>
13
- import userRoutes from '@/interfaces/routes/userRoutes';
14
- import swaggerUi from 'swagger-ui-express';
15
- import swaggerSpecs from '@/config/swagger';<% } %>
16
- <%_ if (communication === 'Kafka') { -%>import { kafkaService } from '@/infrastructure/messaging/kafkaClient';<%_ } -%>
17
- <%_ if (communication === 'GraphQL') { -%>
18
- import { ApolloServer } from '@apollo/server';
19
- import { expressMiddleware } from '@as-integrations/express4';
20
- import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default';
21
- import { unwrapResolverError } from '@apollo/server/errors';
22
- import { ApiError } from '@/errors/ApiError';
23
- import { typeDefs, resolvers } from '@/interfaces/graphql';
24
- import { gqlContext, MyContext } from '@/interfaces/graphql/context';
25
- <%_ } -%>
26
-
27
- const app = express();
28
- const port = env.PORT;
29
-
30
- // Security Middleware
31
- <%_ if (communication === 'GraphQL') { -%>
32
- app.use(helmet({
33
- crossOriginEmbedderPolicy: false,
34
- contentSecurityPolicy: {
35
- directives: {
36
- imgSrc: [`'self'`, 'data:', 'apollo-server-landing-page.cdn.apollographql.com'],
37
- scriptSrc: [`'self'`, `https: 'unsafe-inline'`],
38
- manifestSrc: [`'self'`, 'apollo-server-landing-page.cdn.apollographql.com'],
39
- frameSrc: [`'self'`, 'sandbox.embed.apollographql.com'],
40
- },
41
- },
42
- }));
43
- <%_ } else { -%>
44
- app.use(helmet());
45
- <%_ } -%>
46
- app.use(hpp());
47
- app.use(cors({ origin: '*', methods: ['GET', 'POST', 'PUT', 'DELETE'] }));
48
- const limiter = rateLimit({ windowMs: 10 * 60 * 1000, max: 100 });
49
- app.use(limiter);
50
-
51
- app.use(express.json());
52
- app.use(morgan('combined', { stream: { write: (message) => logger.info(message.trim()) } }));
53
-
54
- <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
55
- app.use('/api/users', userRoutes);
56
- <%_ } -%>
57
- <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
58
- app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
59
- <%_ } -%>
60
- app.use('/health', healthRoutes);
61
-
62
- // Start Server Logic
63
- const startServer = async () => {
64
- <%_ if (communication === 'GraphQL') { -%>
65
- // GraphQL Setup
66
- const apolloServer = new ApolloServer<MyContext>({
67
- typeDefs,
68
- resolvers,
69
- plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
70
- formatError: (formattedError, error) => {
71
- const originalError = unwrapResolverError(error);
72
- if (originalError instanceof ApiError) {
73
- return {
74
- ...formattedError,
75
- message: originalError.message,
76
- extensions: {
77
- ...formattedError.extensions,
78
- code: originalError.statusCode.toString(),
79
- }
80
- };
81
- }
82
-
83
- logger.error(`GraphQL Error: ${formattedError.message}`);
84
- if (originalError instanceof Error && originalError.stack && process.env.NODE_ENV === 'development') {
85
- logger.error(originalError.stack);
86
- }
87
- return formattedError;
88
- },
89
- });
90
- await apolloServer.start();
91
- app.use('/graphql', expressMiddleware(apolloServer, { context: gqlContext }));
92
- <%_ } -%>
93
- app.use(errorMiddleware);
94
- const server = app.listen(port, () => {
95
- logger.info(`Server running on port ${port}`);
96
- <%_ if (communication === 'Kafka') { -%>
97
- kafkaService.connect()
98
- .then(async () => {
99
- logger.info('Kafka connected');
100
- })
101
- .catch(err => {
102
- logger.error('Failed to connect to Kafka after retries:', (err as Error).message);
103
- });
104
- <%_ } -%>
105
- });
106
-
107
- setupGracefulShutdown(server<% if(communication === 'Kafka') { %>, kafkaService<% } %>);
108
- };
109
-
110
- <%_ if (database !== 'None') { -%>
111
- // Database Sync
112
- <%_ if (database !== 'None') { -%>
113
- import <% if (database === 'MongoDB') { %>connectDB<% } else { %>sequelize<% } %> from '@/infrastructure/database/database';
114
- <%_ } -%>
115
-
116
- const syncDatabase = async () => {
117
- let retries = 30;
118
- while (retries) {
119
- try {
120
- <%_ if (database === 'MongoDB') { -%>
121
- await connectDB();
122
- <%_ } else { -%>
123
- await sequelize.sync();
124
- <%_ } -%>
125
- logger.info('Database synced');
126
- await startServer();
127
- break;
128
- } catch (error) {
129
- logger.error('Error syncing database:', error);
130
- retries -= 1;
131
- logger.info(`Retries left: ${retries}`);
132
- await new Promise(res => setTimeout(res, 5000));
133
- }
134
- }
135
- };
136
-
137
- syncDatabase();
138
- <%_ } else { -%>
139
- startServer();
1
+ import { env } from '@/config/env';
2
+ import express from 'express';
3
+ import cors from 'cors';
4
+ import helmet from 'helmet';
5
+ import hpp from 'hpp';
6
+ import rateLimit from 'express-rate-limit';
7
+ import logger from '@/infrastructure/log/logger';
8
+ import morgan from 'morgan';
9
+ import { errorMiddleware } from '@/utils/errorMiddleware';
10
+ import { setupGracefulShutdown } from '@/utils/gracefulShutdown';
11
+ import healthRoutes from '@/interfaces/routes/healthRoute';
12
+ <% if (communication === 'REST APIs' || communication === 'Kafka') { -%>
13
+ import userRoutes from '@/interfaces/routes/userRoutes';
14
+ import swaggerUi from 'swagger-ui-express';
15
+ import swaggerSpecs from '@/config/swagger';<% } %>
16
+ <%_ if (communication === 'Kafka') { -%>import { kafkaService } from '@/infrastructure/messaging/kafkaClient';<%_ } -%>
17
+ <%_ if (communication === 'GraphQL') { -%>
18
+ import { ApolloServer } from '@apollo/server';
19
+ import { expressMiddleware } from '@as-integrations/express4';
20
+ import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default';
21
+ import { unwrapResolverError } from '@apollo/server/errors';
22
+ import { ApiError } from '@/errors/ApiError';
23
+ import { typeDefs, resolvers } from '@/interfaces/graphql';
24
+ import { gqlContext, MyContext } from '@/interfaces/graphql/context';
25
+ <%_ } -%>
26
+
27
+ const app = express();
28
+ const port = env.PORT;
29
+
30
+ // Security Middleware
31
+ <%_ if (communication === 'GraphQL') { -%>
32
+ app.use(helmet({
33
+ crossOriginEmbedderPolicy: false,
34
+ contentSecurityPolicy: {
35
+ directives: {
36
+ imgSrc: [`'self'`, 'data:', 'apollo-server-landing-page.cdn.apollographql.com'],
37
+ scriptSrc: [`'self'`, `https: 'unsafe-inline'`],
38
+ manifestSrc: [`'self'`, 'apollo-server-landing-page.cdn.apollographql.com'],
39
+ frameSrc: [`'self'`, 'sandbox.embed.apollographql.com'],
40
+ },
41
+ },
42
+ }));
43
+ <%_ } else { -%>
44
+ app.use(helmet());
45
+ <%_ } -%>
46
+ app.use(hpp());
47
+ app.use(cors({ origin: '*', methods: ['GET', 'POST', 'PUT', 'DELETE'] }));
48
+ const limiter = rateLimit({ windowMs: 10 * 60 * 1000, max: 100 });
49
+ app.use(limiter);
50
+
51
+ app.use(express.json());
52
+ app.use(morgan('combined', { stream: { write: (message) => logger.info(message.trim()) } }));
53
+
54
+ <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
55
+ app.use('/api/users', userRoutes);
56
+ <%_ } -%>
57
+ <%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
58
+ app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpecs));
59
+ <%_ } -%>
60
+ app.use('/health', healthRoutes);
61
+
62
+ // Start Server Logic
63
+ const startServer = async () => {
64
+ <%_ if (communication === 'GraphQL') { -%>
65
+ // GraphQL Setup
66
+ const apolloServer = new ApolloServer<MyContext>({
67
+ typeDefs,
68
+ resolvers,
69
+ plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
70
+ formatError: (formattedError, error) => {
71
+ const originalError = unwrapResolverError(error);
72
+ if (originalError instanceof ApiError) {
73
+ return {
74
+ ...formattedError,
75
+ message: originalError.message,
76
+ extensions: {
77
+ ...formattedError.extensions,
78
+ code: originalError.statusCode.toString(),
79
+ }
80
+ };
81
+ }
82
+
83
+ logger.error(`GraphQL Error: ${formattedError.message}`);
84
+ if (originalError instanceof Error && originalError.stack && process.env.NODE_ENV === 'development') {
85
+ logger.error(originalError.stack);
86
+ }
87
+ return formattedError;
88
+ },
89
+ });
90
+ await apolloServer.start();
91
+ app.use('/graphql', expressMiddleware(apolloServer, { context: gqlContext }));
92
+ <%_ } -%>
93
+ app.use(errorMiddleware);
94
+ const server = app.listen(port, () => {
95
+ logger.info(`Server running on port ${port}`);
96
+ <%_ if (communication === 'Kafka') { -%>
97
+ kafkaService.connect()
98
+ .then(async () => {
99
+ logger.info('Kafka connected');
100
+ })
101
+ .catch(err => {
102
+ logger.error('Failed to connect to Kafka after retries:', (err as Error).message);
103
+ });
104
+ <%_ } -%>
105
+ });
106
+
107
+ setupGracefulShutdown(server<% if(communication === 'Kafka') { %>, kafkaService<% } %>);
108
+ };
109
+
110
+ <%_ if (database !== 'None') { -%>
111
+ // Database Sync
112
+ <%_ if (database !== 'None') { -%>
113
+ import <% if (database === 'MongoDB') { %>connectDB<% } else { %>sequelize<% } %> from '@/infrastructure/database/database';
114
+ <%_ } -%>
115
+
116
+ const syncDatabase = async () => {
117
+ let retries = 30;
118
+ while (retries) {
119
+ try {
120
+ <%_ if (database === 'MongoDB') { -%>
121
+ await connectDB();
122
+ <%_ } else { -%>
123
+ await sequelize.sync();
124
+ <%_ } -%>
125
+ logger.info('Database synced');
126
+ await startServer();
127
+ break;
128
+ } catch (error) {
129
+ logger.error('Error syncing database:', error);
130
+ retries -= 1;
131
+ logger.info(`Retries left: ${retries}`);
132
+ await new Promise(res => setTimeout(res, 5000));
133
+ }
134
+ }
135
+ };
136
+
137
+ syncDatabase();
138
+ <%_ } else { -%>
139
+ startServer();
140
140
  <%_ } -%>
@@ -1,63 +1,63 @@
1
- jest.mock('winston-daily-rotate-file');
2
- jest.mock('winston', () => {
3
- const mockLogger = {
4
- add: jest.fn(),
5
- info: jest.fn(),
6
- error: jest.fn(),
7
- warn: jest.fn()
8
- };
9
- const format = {
10
- combine: jest.fn(),
11
- timestamp: jest.fn(),
12
- json: jest.fn(),
13
- simple: jest.fn()
14
- };
15
- const transports = {
16
- Console: jest.fn(),
17
- DailyRotateFile: jest.fn()
18
- };
19
- return {
20
- format,
21
- transports,
22
- createLogger: jest.fn().mockReturnValue(mockLogger)
23
- };
24
- });
25
-
26
- <% if (architecture === 'MVC') { -%>
27
- import logger from '@/utils/logger';
28
- <% } else { -%>
29
- import logger from '@/infrastructure/log/logger';
30
- <% } -%>
31
-
32
- describe('Logger', () => {
33
- it('should export a logger instance', () => {
34
- expect(logger).toBeDefined();
35
- });
36
-
37
- it('should have info method', () => {
38
- expect(typeof logger.info).toBe('function');
39
- });
40
-
41
- it('should have error method', () => {
42
- expect(typeof logger.error).toBe('function');
43
- });
44
-
45
- it('should call info', () => {
46
- logger.info('test message');
47
- expect(logger.info).toHaveBeenCalledWith('test message');
48
- });
49
-
50
- it('should call error', () => {
51
- logger.error('test error');
52
- expect(logger.error).toHaveBeenCalledWith('test error');
53
- });
54
-
55
- it('should use JSON format in production environment', () => {
56
- const winston = require('winston');
57
- jest.resetModules();
58
- process.env.NODE_ENV = 'production';
59
- require('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
60
- expect(winston.format.json).toHaveBeenCalled();
61
- process.env.NODE_ENV = 'test';
62
- });
63
- });
1
+ jest.mock('winston-daily-rotate-file');
2
+ jest.mock('winston', () => {
3
+ const mockLogger = {
4
+ add: jest.fn(),
5
+ info: jest.fn(),
6
+ error: jest.fn(),
7
+ warn: jest.fn()
8
+ };
9
+ const format = {
10
+ combine: jest.fn(),
11
+ timestamp: jest.fn(),
12
+ json: jest.fn(),
13
+ simple: jest.fn()
14
+ };
15
+ const transports = {
16
+ Console: jest.fn(),
17
+ DailyRotateFile: jest.fn()
18
+ };
19
+ return {
20
+ format,
21
+ transports,
22
+ createLogger: jest.fn().mockReturnValue(mockLogger)
23
+ };
24
+ });
25
+
26
+ <% if (architecture === 'MVC') { -%>
27
+ import logger from '@/utils/logger';
28
+ <% } else { -%>
29
+ import logger from '@/infrastructure/log/logger';
30
+ <% } -%>
31
+
32
+ describe('Logger', () => {
33
+ it('should export a logger instance', () => {
34
+ expect(logger).toBeDefined();
35
+ });
36
+
37
+ it('should have info method', () => {
38
+ expect(typeof logger.info).toBe('function');
39
+ });
40
+
41
+ it('should have error method', () => {
42
+ expect(typeof logger.error).toBe('function');
43
+ });
44
+
45
+ it('should call info', () => {
46
+ logger.info('test message');
47
+ expect(logger.info).toHaveBeenCalledWith('test message');
48
+ });
49
+
50
+ it('should call error', () => {
51
+ logger.error('test error');
52
+ expect(logger.error).toHaveBeenCalledWith('test error');
53
+ });
54
+
55
+ it('should use JSON format in production environment', () => {
56
+ const winston = require('winston');
57
+ jest.resetModules();
58
+ process.env.NODE_ENV = 'production';
59
+ require('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
60
+ expect(winston.format.json).toHaveBeenCalled();
61
+ process.env.NODE_ENV = 'test';
62
+ });
63
+ });
@@ -1,36 +1,36 @@
1
- import winston from 'winston';
2
- import 'winston-daily-rotate-file';
3
-
4
- const logger = winston.createLogger({
5
- level: 'info',
6
- format: winston.format.combine(
7
- winston.format.timestamp(),
8
- winston.format.json()
9
- ),
10
- defaultMeta: { service: 'user-service' },
11
- transports: [
12
- new winston.transports.DailyRotateFile({
13
- filename: 'logs/error-%DATE%.log',
14
- datePattern: 'YYYY-MM-DD',
15
- zippedArchive: true,
16
- maxSize: '20m',
17
- maxFiles: '14d',
18
- level: 'error',
19
- }),
20
- new winston.transports.DailyRotateFile({
21
- filename: 'logs/combined-%DATE%.log',
22
- datePattern: 'YYYY-MM-DD',
23
- zippedArchive: true,
24
- maxSize: '20m',
25
- maxFiles: '14d',
26
- }),
27
- ],
28
- });
29
-
30
- logger.add(new winston.transports.Console({
31
- format: process.env.NODE_ENV !== 'production'
32
- ? winston.format.simple()
33
- : winston.format.json(),
34
- }));
35
-
36
- export default logger;
1
+ import winston from 'winston';
2
+ import 'winston-daily-rotate-file';
3
+
4
+ const logger = winston.createLogger({
5
+ level: 'info',
6
+ format: winston.format.combine(
7
+ winston.format.timestamp(),
8
+ winston.format.json()
9
+ ),
10
+ defaultMeta: { service: 'user-service' },
11
+ transports: [
12
+ new winston.transports.DailyRotateFile({
13
+ filename: 'logs/error-%DATE%.log',
14
+ datePattern: 'YYYY-MM-DD',
15
+ zippedArchive: true,
16
+ maxSize: '20m',
17
+ maxFiles: '14d',
18
+ level: 'error',
19
+ }),
20
+ new winston.transports.DailyRotateFile({
21
+ filename: 'logs/combined-%DATE%.log',
22
+ datePattern: 'YYYY-MM-DD',
23
+ zippedArchive: true,
24
+ maxSize: '20m',
25
+ maxFiles: '14d',
26
+ }),
27
+ ],
28
+ });
29
+
30
+ logger.add(new winston.transports.Console({
31
+ format: process.env.NODE_ENV !== 'production'
32
+ ? winston.format.simple()
33
+ : winston.format.json(),
34
+ }));
35
+
36
+ export default logger;
@@ -1,32 +1,32 @@
1
- import { gqlContext } from '@/interfaces/graphql/context';
2
- import { Request } from 'express';
3
- import { resolvers } from '@/interfaces/graphql/resolvers';
4
- import { typeDefs } from '@/interfaces/graphql/typeDefs';
5
-
6
- jest.mock('@/infrastructure/repositories/UserRepository');
7
-
8
- describe('GraphQL Context', () => {
9
- it('should exercise GraphQL index entry points', () => {
10
- expect(resolvers).toBeDefined();
11
- expect(typeDefs).toBeDefined();
12
- });
13
- it('should return context with token when authorization header is present', async () => {
14
- const mockRequest = {
15
- headers: {
16
- authorization: 'Bearer token123',
17
- },
18
- } as Request;
19
-
20
- const context = await gqlContext({ req: mockRequest });
21
- expect(context.token).toBe('Bearer token123');
22
- });
23
-
24
- it('should return context with empty token when authorization header is missing', async () => {
25
- const mockRequest = {
26
- headers: {},
27
- } as Request;
28
-
29
- const context = await gqlContext({ req: mockRequest });
30
- expect(context.token).toBe('');
31
- });
32
- });
1
+ import { gqlContext } from '@/interfaces/graphql/context';
2
+ import { Request } from 'express';
3
+ import { resolvers } from '@/interfaces/graphql/resolvers';
4
+ import { typeDefs } from '@/interfaces/graphql/typeDefs';
5
+
6
+ jest.mock('@/infrastructure/repositories/UserRepository');
7
+
8
+ describe('GraphQL Context', () => {
9
+ it('should exercise GraphQL index entry points', () => {
10
+ expect(resolvers).toBeDefined();
11
+ expect(typeDefs).toBeDefined();
12
+ });
13
+ it('should return context with token when authorization header is present', async () => {
14
+ const mockRequest = {
15
+ headers: {
16
+ authorization: 'Bearer token123',
17
+ },
18
+ } as Request;
19
+
20
+ const context = await gqlContext({ req: mockRequest });
21
+ expect(context.token).toBe('Bearer token123');
22
+ });
23
+
24
+ it('should return context with empty token when authorization header is missing', async () => {
25
+ const mockRequest = {
26
+ headers: {},
27
+ } as Request;
28
+
29
+ const context = await gqlContext({ req: mockRequest });
30
+ expect(context.token).toBe('');
31
+ });
32
+ });
@@ -1,17 +1,17 @@
1
- import { Request } from 'express';
2
- import { UserRepository } from '@/infrastructure/repositories/UserRepository';
3
-
4
- export interface MyContext {
5
- token?: string;
6
- userRepository: UserRepository;
7
- }
8
-
9
- export const gqlContext = async ({ req }: { req: Request }): Promise<MyContext> => {
10
- const token = req.headers.authorization || '';
11
- const userRepository = new UserRepository();
12
-
13
- return {
14
- token,
15
- userRepository
16
- };
17
- };
1
+ import { Request } from 'express';
2
+ import { UserRepository } from '@/infrastructure/repositories/UserRepository';
3
+
4
+ export interface MyContext {
5
+ token?: string;
6
+ userRepository: UserRepository;
7
+ }
8
+
9
+ export const gqlContext = async ({ req }: { req: Request }): Promise<MyContext> => {
10
+ const token = req.headers.authorization || '';
11
+ const userRepository = new UserRepository();
12
+
13
+ return {
14
+ token,
15
+ userRepository
16
+ };
17
+ };
@@ -1,3 +1,3 @@
1
- export { typeDefs } from '@/interfaces/graphql/typeDefs';
2
- export { resolvers } from '@/interfaces/graphql/resolvers';
3
- export { gqlContext, MyContext } from '@/interfaces/graphql/context';
1
+ export { typeDefs } from '@/interfaces/graphql/typeDefs';
2
+ export { resolvers } from '@/interfaces/graphql/resolvers';
3
+ export { gqlContext, MyContext } from '@/interfaces/graphql/context';
@@ -1,4 +1,4 @@
1
- import { mergeResolvers } from '@graphql-tools/merge';
2
- import { userResolvers } from '@/interfaces/graphql/resolvers/user.resolvers';
3
-
4
- export const resolvers = mergeResolvers([userResolvers]);
1
+ import { mergeResolvers } from '@graphql-tools/merge';
2
+ import { userResolvers } from '@/interfaces/graphql/resolvers/user.resolvers';
3
+
4
+ export const resolvers = mergeResolvers([userResolvers]);
@@ -1,4 +1,4 @@
1
- import { mergeTypeDefs } from '@graphql-tools/merge';
2
- import { userTypes } from './user.types';
3
-
4
- export const typeDefs = mergeTypeDefs([userTypes]);
1
+ import { mergeTypeDefs } from '@graphql-tools/merge';
2
+ import { userTypes } from './user.types';
3
+
4
+ export const typeDefs = mergeTypeDefs([userTypes]);