nodejs-quickstart-structure 1.19.0 → 1.19.1
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/CHANGELOG.md +309 -301
- package/LICENSE +15 -15
- package/lib/generator.js +139 -139
- package/lib/modules/app-setup.js +401 -401
- package/lib/modules/config-files.js +151 -151
- package/lib/modules/database-setup.js +116 -116
- package/lib/modules/project-setup.js +32 -32
- package/lib/prompts.js +100 -100
- package/package.json +78 -78
- package/templates/clean-architecture/js/src/domain/models/User.js +9 -9
- package/templates/clean-architecture/js/src/errors/ApiError.js +14 -14
- package/templates/clean-architecture/js/src/index.js.ejs +55 -55
- package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +47 -47
- package/templates/clean-architecture/js/src/infrastructure/log/logger.js +36 -36
- package/templates/clean-architecture/js/src/infrastructure/log/logger.spec.js.ejs +63 -63
- package/templates/clean-architecture/js/src/infrastructure/webserver/middleware/errorMiddleware.js +30 -30
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +89 -89
- package/templates/clean-architecture/js/src/infrastructure/webserver/swagger.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/graphql/context.js.ejs +13 -13
- package/templates/clean-architecture/js/src/interfaces/graphql/context.spec.js.ejs +31 -31
- package/templates/clean-architecture/js/src/interfaces/graphql/index.js.ejs +5 -5
- package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/index.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/index.js.ejs +6 -6
- package/templates/clean-architecture/js/src/interfaces/routes/api.spec.js.ejs +38 -38
- package/templates/clean-architecture/js/src/usecases/CreateUser.js +14 -14
- package/templates/clean-architecture/js/src/usecases/CreateUser.spec.js.ejs +51 -51
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.js +12 -12
- package/templates/clean-architecture/js/src/usecases/GetAllUsers.spec.js.ejs +61 -61
- package/templates/clean-architecture/js/src/utils/httpCodes.js +9 -9
- package/templates/clean-architecture/ts/src/config/env.ts.ejs +46 -46
- package/templates/clean-architecture/ts/src/config/swagger.ts.ejs +6 -6
- package/templates/clean-architecture/ts/src/domain/user.ts +7 -7
- package/templates/clean-architecture/ts/src/errors/ApiError.ts +15 -15
- package/templates/clean-architecture/ts/src/index.ts.ejs +139 -139
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.spec.ts.ejs +63 -63
- package/templates/clean-architecture/ts/src/infrastructure/log/logger.ts +36 -36
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.spec.ts.ejs +32 -32
- package/templates/clean-architecture/ts/src/interfaces/graphql/context.ts.ejs +17 -17
- package/templates/clean-architecture/ts/src/interfaces/graphql/index.ts.ejs +3 -3
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/index.ts.ejs +4 -4
- package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/index.ts.ejs +4 -4
- package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.spec.ts.ejs +40 -40
- package/templates/clean-architecture/ts/src/usecases/createUser.spec.ts.ejs +51 -51
- package/templates/clean-architecture/ts/src/usecases/createUser.ts +13 -13
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.spec.ts.ejs +63 -63
- package/templates/clean-architecture/ts/src/usecases/getAllUsers.ts +10 -10
- package/templates/clean-architecture/ts/src/utils/errorMiddleware.ts.ejs +27 -27
- package/templates/clean-architecture/ts/src/utils/httpCodes.ts +7 -7
- package/templates/common/.cursorrules.ejs +60 -60
- package/templates/common/.dockerignore +12 -12
- package/templates/common/.env.example.ejs +41 -41
- package/templates/common/.gitlab-ci.yml.ejs +86 -86
- package/templates/common/.lintstagedrc +6 -6
- package/templates/common/.prettierrc +7 -7
- package/templates/common/Dockerfile +73 -73
- package/templates/common/Jenkinsfile.ejs +87 -87
- package/templates/common/SECURITY.md +20 -20
- package/templates/common/_github/workflows/ci.yml.ejs +46 -46
- package/templates/common/_github/workflows/security.yml.ejs +36 -36
- package/templates/common/_gitignore +5 -5
- package/templates/common/_husky/pre-commit +4 -4
- package/templates/common/caching/clean/js/CreateUser.js.ejs +29 -29
- package/templates/common/caching/clean/js/GetAllUsers.js.ejs +37 -37
- package/templates/common/caching/clean/ts/createUser.ts.ejs +27 -27
- package/templates/common/caching/clean/ts/getAllUsers.ts.ejs +34 -34
- package/templates/common/caching/js/memoryCache.js.ejs +60 -60
- package/templates/common/caching/js/memoryCache.spec.js.ejs +101 -101
- package/templates/common/caching/js/redisClient.js.ejs +75 -75
- package/templates/common/caching/js/redisClient.spec.js.ejs +147 -147
- package/templates/common/caching/ts/memoryCache.spec.ts.ejs +102 -102
- package/templates/common/caching/ts/redisClient.spec.ts.ejs +157 -157
- package/templates/common/database/js/database.js.ejs +19 -19
- package/templates/common/database/js/database.spec.js.ejs +56 -56
- package/templates/common/database/js/mongoose.js.ejs +33 -33
- package/templates/common/database/js/mongoose.spec.js.ejs +43 -43
- package/templates/common/database/ts/database.spec.ts.ejs +56 -56
- package/templates/common/database/ts/database.ts.ejs +21 -21
- package/templates/common/database/ts/mongoose.spec.ts.ejs +42 -42
- package/templates/common/database/ts/mongoose.ts.ejs +28 -28
- package/templates/common/docker-compose.yml.ejs +159 -159
- package/templates/common/ecosystem.config.js.ejs +40 -40
- package/templates/common/eslint.config.mjs.ejs +77 -77
- package/templates/common/health/js/healthRoute.spec.js.ejs +70 -70
- package/templates/common/health/ts/healthRoute.spec.ts.ejs +76 -76
- package/templates/common/jest.config.js.ejs +32 -32
- package/templates/common/kafka/js/config/kafka.js +9 -9
- package/templates/common/kafka/js/config/kafka.spec.js.ejs +27 -27
- package/templates/common/kafka/js/messaging/baseConsumer.spec.js.ejs +58 -58
- package/templates/common/kafka/js/messaging/userEventSchema.spec.js.ejs +27 -27
- package/templates/common/kafka/js/services/kafkaService.spec.js.ejs +106 -106
- package/templates/common/kafka/ts/config/kafka.spec.ts.ejs +27 -27
- package/templates/common/kafka/ts/config/kafka.ts +7 -7
- package/templates/common/kafka/ts/messaging/baseConsumer.spec.ts.ejs +50 -50
- package/templates/common/kafka/ts/messaging/baseConsumer.ts.ejs +27 -27
- package/templates/common/kafka/ts/services/kafkaService.spec.ts.ejs +81 -81
- package/templates/common/migrate-mongo-config.js.ejs +31 -31
- package/templates/common/migrations/init.js.ejs +23 -23
- package/templates/common/package.json.ejs +119 -118
- package/templates/common/prompts/add-feature.md.ejs +26 -26
- package/templates/common/prompts/project-context.md.ejs +43 -43
- package/templates/common/prompts/troubleshoot.md.ejs +28 -28
- package/templates/common/public/css/style.css +147 -147
- package/templates/common/scripts/run-e2e.js.ejs +63 -63
- package/templates/common/sonar-project.properties.ejs +27 -27
- package/templates/common/src/utils/errorMiddleware.spec.js.ejs +79 -79
- package/templates/common/src/utils/errorMiddleware.spec.ts.ejs +94 -94
- package/templates/common/tsconfig.json +22 -22
- package/templates/common/views/ejs/index.ejs +55 -55
- package/templates/common/views/pug/index.pug +40 -40
- package/templates/mvc/js/src/config/env.js.ejs +46 -46
- package/templates/mvc/js/src/config/swagger.js.ejs +6 -6
- package/templates/mvc/js/src/errors/ApiError.js +14 -14
- package/templates/mvc/js/src/graphql/context.js.ejs +7 -7
- package/templates/mvc/js/src/graphql/context.spec.js.ejs +29 -29
- package/templates/mvc/js/src/graphql/index.js.ejs +5 -5
- package/templates/mvc/js/src/graphql/resolvers/index.js.ejs +6 -6
- package/templates/mvc/js/src/graphql/typeDefs/index.js.ejs +6 -6
- package/templates/mvc/js/src/index.js.ejs +136 -136
- package/templates/mvc/js/src/utils/errorMiddleware.js +29 -29
- package/templates/mvc/js/src/utils/httpCodes.js +9 -9
- package/templates/mvc/js/src/utils/logger.js +40 -40
- package/templates/mvc/js/src/utils/logger.spec.js.ejs +63 -63
- package/templates/mvc/ts/src/config/env.ts.ejs +45 -45
- package/templates/mvc/ts/src/config/swagger.ts.ejs +6 -6
- package/templates/mvc/ts/src/errors/ApiError.ts +15 -15
- package/templates/mvc/ts/src/graphql/context.spec.ts.ejs +30 -30
- package/templates/mvc/ts/src/graphql/context.ts.ejs +12 -12
- package/templates/mvc/ts/src/graphql/index.ts.ejs +3 -3
- package/templates/mvc/ts/src/graphql/resolvers/index.ts.ejs +4 -4
- package/templates/mvc/ts/src/graphql/typeDefs/index.ts.ejs +4 -4
- package/templates/mvc/ts/src/utils/errorMiddleware.ts.ejs +27 -27
- package/templates/mvc/ts/src/utils/httpCodes.ts +7 -7
- package/templates/mvc/ts/src/utils/logger.spec.ts.ejs +63 -63
- package/templates/mvc/ts/src/utils/logger.ts +36 -36
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
import { errorMiddleware } from '<% if (architecture === "MVC" || language === "TypeScript") { %>@/utils/errorMiddleware<% } else { %>@/infrastructure/webserver/middleware/errorMiddleware<% } %>';
|
|
2
|
-
import { Request, Response } from 'express';
|
|
3
|
-
import { ApiError } from '@/errors/ApiError';
|
|
4
|
-
import { HTTP_STATUS } from '@/utils/httpCodes';
|
|
5
|
-
import logger from '<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>';
|
|
6
|
-
|
|
7
|
-
jest.mock('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
|
|
8
|
-
|
|
9
|
-
describe('Error Middleware', () => {
|
|
10
|
-
let mockRequest: Partial<Request>;
|
|
11
|
-
let mockResponse: Partial<Response>;
|
|
12
|
-
let nextFunction: jest.Mock;
|
|
13
|
-
const originalEnv = process.env.NODE_ENV;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
mockRequest = {
|
|
17
|
-
originalUrl: '/test',
|
|
18
|
-
method: 'GET',
|
|
19
|
-
ip: '127.0.0.1'
|
|
20
|
-
};
|
|
21
|
-
mockResponse = {
|
|
22
|
-
status: jest.fn().mockReturnThis(),
|
|
23
|
-
json: jest.fn()
|
|
24
|
-
};
|
|
25
|
-
nextFunction = jest.fn();
|
|
26
|
-
jest.clearAllMocks();
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
afterEach(() => {
|
|
30
|
-
process.env.NODE_ENV = originalEnv;
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should handle standard Error by wrapping it in a 500 ApiError', () => {
|
|
34
|
-
const error = new Error('Standard Error');
|
|
35
|
-
errorMiddleware(error, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
36
|
-
|
|
37
|
-
expect(logger.error).toHaveBeenCalled();
|
|
38
|
-
expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.INTERNAL_SERVER_ERROR);
|
|
39
|
-
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
40
|
-
statusCode: HTTP_STATUS.INTERNAL_SERVER_ERROR,
|
|
41
|
-
message: 'Standard Error'
|
|
42
|
-
}));
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should default to Internal Server Error message if none provided on Error', () => {
|
|
46
|
-
const error = new Error();
|
|
47
|
-
errorMiddleware(error, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
48
|
-
|
|
49
|
-
expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.INTERNAL_SERVER_ERROR);
|
|
50
|
-
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
51
|
-
message: 'Internal Server Error'
|
|
52
|
-
}));
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should handle custom ApiError directly', () => {
|
|
56
|
-
const customError = new ApiError(HTTP_STATUS.BAD_REQUEST, 'Bad Request Data', true);
|
|
57
|
-
errorMiddleware(customError, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
58
|
-
|
|
59
|
-
expect(logger.error).not.toHaveBeenCalled();
|
|
60
|
-
expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.BAD_REQUEST);
|
|
61
|
-
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
62
|
-
statusCode: HTTP_STATUS.BAD_REQUEST,
|
|
63
|
-
message: 'Bad Request Data'
|
|
64
|
-
}));
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should include stack trace in development environment', () => {
|
|
68
|
-
process.env.NODE_ENV = 'development';
|
|
69
|
-
const error = new Error('Test Error');
|
|
70
|
-
errorMiddleware(error, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
71
|
-
|
|
72
|
-
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
73
|
-
stack: expect.any(String)
|
|
74
|
-
}));
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should omit stack trace in production environment', () => {
|
|
78
|
-
process.env.NODE_ENV = 'production';
|
|
79
|
-
const error = new Error('Test Error');
|
|
80
|
-
errorMiddleware(error, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
81
|
-
|
|
82
|
-
const jsonArg = (mockResponse.json as jest.Mock).mock.calls[0][0];
|
|
83
|
-
expect(jsonArg.stack).toBeUndefined();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should handle error without stack trace', () => {
|
|
87
|
-
const customError = new ApiError(HTTP_STATUS.INTERNAL_SERVER_ERROR, 'No Stack', false);
|
|
88
|
-
delete customError.stack;
|
|
89
|
-
errorMiddleware(customError, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
90
|
-
|
|
91
|
-
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('No Stack'));
|
|
92
|
-
expect(logger.error).toHaveBeenCalledWith('No stack trace');
|
|
93
|
-
});
|
|
94
|
-
});
|
|
1
|
+
import { errorMiddleware } from '<% if (architecture === "MVC" || language === "TypeScript") { %>@/utils/errorMiddleware<% } else { %>@/infrastructure/webserver/middleware/errorMiddleware<% } %>';
|
|
2
|
+
import { Request, Response } from 'express';
|
|
3
|
+
import { ApiError } from '@/errors/ApiError';
|
|
4
|
+
import { HTTP_STATUS } from '@/utils/httpCodes';
|
|
5
|
+
import logger from '<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>';
|
|
6
|
+
|
|
7
|
+
jest.mock('<% if (architecture === "MVC") { %>@/utils/logger<% } else { %>@/infrastructure/log/logger<% } %>');
|
|
8
|
+
|
|
9
|
+
describe('Error Middleware', () => {
|
|
10
|
+
let mockRequest: Partial<Request>;
|
|
11
|
+
let mockResponse: Partial<Response>;
|
|
12
|
+
let nextFunction: jest.Mock;
|
|
13
|
+
const originalEnv = process.env.NODE_ENV;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
mockRequest = {
|
|
17
|
+
originalUrl: '/test',
|
|
18
|
+
method: 'GET',
|
|
19
|
+
ip: '127.0.0.1'
|
|
20
|
+
};
|
|
21
|
+
mockResponse = {
|
|
22
|
+
status: jest.fn().mockReturnThis(),
|
|
23
|
+
json: jest.fn()
|
|
24
|
+
};
|
|
25
|
+
nextFunction = jest.fn();
|
|
26
|
+
jest.clearAllMocks();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
process.env.NODE_ENV = originalEnv;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should handle standard Error by wrapping it in a 500 ApiError', () => {
|
|
34
|
+
const error = new Error('Standard Error');
|
|
35
|
+
errorMiddleware(error, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
36
|
+
|
|
37
|
+
expect(logger.error).toHaveBeenCalled();
|
|
38
|
+
expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.INTERNAL_SERVER_ERROR);
|
|
39
|
+
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
40
|
+
statusCode: HTTP_STATUS.INTERNAL_SERVER_ERROR,
|
|
41
|
+
message: 'Standard Error'
|
|
42
|
+
}));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should default to Internal Server Error message if none provided on Error', () => {
|
|
46
|
+
const error = new Error();
|
|
47
|
+
errorMiddleware(error, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
48
|
+
|
|
49
|
+
expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.INTERNAL_SERVER_ERROR);
|
|
50
|
+
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
51
|
+
message: 'Internal Server Error'
|
|
52
|
+
}));
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should handle custom ApiError directly', () => {
|
|
56
|
+
const customError = new ApiError(HTTP_STATUS.BAD_REQUEST, 'Bad Request Data', true);
|
|
57
|
+
errorMiddleware(customError, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
58
|
+
|
|
59
|
+
expect(logger.error).not.toHaveBeenCalled();
|
|
60
|
+
expect(mockResponse.status).toHaveBeenCalledWith(HTTP_STATUS.BAD_REQUEST);
|
|
61
|
+
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
62
|
+
statusCode: HTTP_STATUS.BAD_REQUEST,
|
|
63
|
+
message: 'Bad Request Data'
|
|
64
|
+
}));
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should include stack trace in development environment', () => {
|
|
68
|
+
process.env.NODE_ENV = 'development';
|
|
69
|
+
const error = new Error('Test Error');
|
|
70
|
+
errorMiddleware(error, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
71
|
+
|
|
72
|
+
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
|
73
|
+
stack: expect.any(String)
|
|
74
|
+
}));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should omit stack trace in production environment', () => {
|
|
78
|
+
process.env.NODE_ENV = 'production';
|
|
79
|
+
const error = new Error('Test Error');
|
|
80
|
+
errorMiddleware(error, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
81
|
+
|
|
82
|
+
const jsonArg = (mockResponse.json as jest.Mock).mock.calls[0][0];
|
|
83
|
+
expect(jsonArg.stack).toBeUndefined();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should handle error without stack trace', () => {
|
|
87
|
+
const customError = new ApiError(HTTP_STATUS.INTERNAL_SERVER_ERROR, 'No Stack', false);
|
|
88
|
+
delete customError.stack;
|
|
89
|
+
errorMiddleware(customError, mockRequest as Request, mockResponse as Response, nextFunction);
|
|
90
|
+
|
|
91
|
+
expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('No Stack'));
|
|
92
|
+
expect(logger.error).toHaveBeenCalledWith('No stack trace');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es2020",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"outDir": "./dist",
|
|
6
|
-
"rootDir": "./src",
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"baseUrl": ".",
|
|
12
|
-
"paths": {
|
|
13
|
-
"@/*": ["src/*"]
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"include": [
|
|
17
|
-
"src/**/*"
|
|
18
|
-
],
|
|
19
|
-
"exclude": [
|
|
20
|
-
"node_modules",
|
|
21
|
-
"dist"
|
|
22
|
-
]
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"outDir": "./dist",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"baseUrl": ".",
|
|
12
|
+
"paths": {
|
|
13
|
+
"@/*": ["src/*"]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"include": [
|
|
17
|
+
"src/**/*"
|
|
18
|
+
],
|
|
19
|
+
"exclude": [
|
|
20
|
+
"node_modules",
|
|
21
|
+
"dist"
|
|
22
|
+
]
|
|
23
23
|
}
|
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title><%= projectName %></title>
|
|
7
|
-
<link rel="stylesheet" href="/css/style.css">
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<div class="container">
|
|
11
|
-
<header class="header">
|
|
12
|
-
<div class="logo">🚀</div>
|
|
13
|
-
<h1>Welcome to <%= projectName %></h1>
|
|
14
|
-
<p class="subtitle">A production-ready Node.js microservice starter.</p>
|
|
15
|
-
</header>
|
|
16
|
-
|
|
17
|
-
<div class="card-grid">
|
|
18
|
-
<div class="card">
|
|
19
|
-
<h3>Architecture</h3>
|
|
20
|
-
<p><%= architecture %></p>
|
|
21
|
-
</div>
|
|
22
|
-
<div class="card">
|
|
23
|
-
<h3>Database</h3>
|
|
24
|
-
<p><%= database %></p>
|
|
25
|
-
</div>
|
|
26
|
-
<div class="card">
|
|
27
|
-
<h3>Communication</h3>
|
|
28
|
-
<p><%= communication %></p>
|
|
29
|
-
</div>
|
|
30
|
-
</div>
|
|
31
|
-
|
|
32
|
-
<% if (communication === 'Kafka') { %>
|
|
33
|
-
<div class="status-card">
|
|
34
|
-
<div class="status-icon">🔄</div>
|
|
35
|
-
<div class="status-content">
|
|
36
|
-
<h3>Kafka Connected</h3>
|
|
37
|
-
<p>Connection to broker established successfully.</p>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
<% } else { %>
|
|
41
|
-
<div class="status-card">
|
|
42
|
-
<div class="status-icon">✅</div>
|
|
43
|
-
<div class="status-content">
|
|
44
|
-
<h3>API Active</h3>
|
|
45
|
-
<p>REST API is running and ready to accept requests.</p>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
<% } %>
|
|
49
|
-
|
|
50
|
-
<footer>
|
|
51
|
-
<p>Generated with ❤️ by Node.js Quickstart Generator</p>
|
|
52
|
-
</footer>
|
|
53
|
-
</div>
|
|
54
|
-
</body>
|
|
55
|
-
</html>
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title><%= projectName %></title>
|
|
7
|
+
<link rel="stylesheet" href="/css/style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="container">
|
|
11
|
+
<header class="header">
|
|
12
|
+
<div class="logo">🚀</div>
|
|
13
|
+
<h1>Welcome to <%= projectName %></h1>
|
|
14
|
+
<p class="subtitle">A production-ready Node.js microservice starter.</p>
|
|
15
|
+
</header>
|
|
16
|
+
|
|
17
|
+
<div class="card-grid">
|
|
18
|
+
<div class="card">
|
|
19
|
+
<h3>Architecture</h3>
|
|
20
|
+
<p><%= architecture %></p>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="card">
|
|
23
|
+
<h3>Database</h3>
|
|
24
|
+
<p><%= database %></p>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="card">
|
|
27
|
+
<h3>Communication</h3>
|
|
28
|
+
<p><%= communication %></p>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<% if (communication === 'Kafka') { %>
|
|
33
|
+
<div class="status-card">
|
|
34
|
+
<div class="status-icon">🔄</div>
|
|
35
|
+
<div class="status-content">
|
|
36
|
+
<h3>Kafka Connected</h3>
|
|
37
|
+
<p>Connection to broker established successfully.</p>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
<% } else { %>
|
|
41
|
+
<div class="status-card">
|
|
42
|
+
<div class="status-icon">✅</div>
|
|
43
|
+
<div class="status-content">
|
|
44
|
+
<h3>API Active</h3>
|
|
45
|
+
<p>REST API is running and ready to accept requests.</p>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<% } %>
|
|
49
|
+
|
|
50
|
+
<footer>
|
|
51
|
+
<p>Generated with ❤️ by Node.js Quickstart Generator</p>
|
|
52
|
+
</footer>
|
|
53
|
+
</div>
|
|
54
|
+
</body>
|
|
55
|
+
</html>
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
doctype html
|
|
2
|
-
html(lang="en")
|
|
3
|
-
head
|
|
4
|
-
meta(charset="UTF-8")
|
|
5
|
-
meta(name="viewport", content="width=device-width, initial-scale=1.0")
|
|
6
|
-
title= projectName
|
|
7
|
-
link(rel="stylesheet", href="/css/style.css")
|
|
8
|
-
body
|
|
9
|
-
.container
|
|
10
|
-
header.header
|
|
11
|
-
.logo 🚀
|
|
12
|
-
h1 Welcome to #{projectName}
|
|
13
|
-
p.subtitle A production-ready Node.js microservice starter.
|
|
14
|
-
|
|
15
|
-
.card-grid
|
|
16
|
-
.card
|
|
17
|
-
h3 Architecture
|
|
18
|
-
p #{architecture}
|
|
19
|
-
.card
|
|
20
|
-
h3 Database
|
|
21
|
-
p #{database}
|
|
22
|
-
.card
|
|
23
|
-
h3 Communication
|
|
24
|
-
p #{communication}
|
|
25
|
-
|
|
26
|
-
if communication === 'Kafka'
|
|
27
|
-
.status-card
|
|
28
|
-
.status-icon 🔄
|
|
29
|
-
.status-content
|
|
30
|
-
h3 Kafka Connected
|
|
31
|
-
p Connection to broker established successfully.
|
|
32
|
-
else
|
|
33
|
-
.status-card
|
|
34
|
-
.status-icon ✅
|
|
35
|
-
.status-content
|
|
36
|
-
h3 API Active
|
|
37
|
-
p REST API is running and ready to accept requests.
|
|
38
|
-
|
|
39
|
-
footer
|
|
40
|
-
p Generated with ❤️ by Node.js Quickstart Generator
|
|
1
|
+
doctype html
|
|
2
|
+
html(lang="en")
|
|
3
|
+
head
|
|
4
|
+
meta(charset="UTF-8")
|
|
5
|
+
meta(name="viewport", content="width=device-width, initial-scale=1.0")
|
|
6
|
+
title= projectName
|
|
7
|
+
link(rel="stylesheet", href="/css/style.css")
|
|
8
|
+
body
|
|
9
|
+
.container
|
|
10
|
+
header.header
|
|
11
|
+
.logo 🚀
|
|
12
|
+
h1 Welcome to #{projectName}
|
|
13
|
+
p.subtitle A production-ready Node.js microservice starter.
|
|
14
|
+
|
|
15
|
+
.card-grid
|
|
16
|
+
.card
|
|
17
|
+
h3 Architecture
|
|
18
|
+
p #{architecture}
|
|
19
|
+
.card
|
|
20
|
+
h3 Database
|
|
21
|
+
p #{database}
|
|
22
|
+
.card
|
|
23
|
+
h3 Communication
|
|
24
|
+
p #{communication}
|
|
25
|
+
|
|
26
|
+
if communication === 'Kafka'
|
|
27
|
+
.status-card
|
|
28
|
+
.status-icon 🔄
|
|
29
|
+
.status-content
|
|
30
|
+
h3 Kafka Connected
|
|
31
|
+
p Connection to broker established successfully.
|
|
32
|
+
else
|
|
33
|
+
.status-card
|
|
34
|
+
.status-icon ✅
|
|
35
|
+
.status-content
|
|
36
|
+
h3 API Active
|
|
37
|
+
p REST API is running and ready to accept requests.
|
|
38
|
+
|
|
39
|
+
footer
|
|
40
|
+
p Generated with ❤️ by Node.js Quickstart Generator
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
const { z } = require('zod');
|
|
2
|
-
const logger = require('../utils/logger');
|
|
3
|
-
|
|
4
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
5
|
-
require('dotenv').config();
|
|
6
|
-
}
|
|
7
|
-
const envSchema = z.object({
|
|
8
|
-
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
9
|
-
PORT: z.string().transform(Number).default('3000'),
|
|
10
|
-
<%_ if (database !== 'None') { -%>
|
|
11
|
-
DB_HOST: z.string(),
|
|
12
|
-
<%_ if (database === 'MySQL') { -%>
|
|
13
|
-
DB_USER: z.string(),
|
|
14
|
-
DB_PASSWORD: z.string(),
|
|
15
|
-
DB_NAME: z.string(),
|
|
16
|
-
DB_PORT: z.string().transform(Number),
|
|
17
|
-
<%_ } else if (database === 'PostgreSQL') { -%>
|
|
18
|
-
DB_USER: z.string(),
|
|
19
|
-
DB_PASSWORD: z.string(),
|
|
20
|
-
DB_NAME: z.string(),
|
|
21
|
-
DB_PORT: z.string().transform(Number),
|
|
22
|
-
<%_ } else if (database === 'MongoDB') { -%>
|
|
23
|
-
DB_NAME: z.string(),
|
|
24
|
-
DB_PORT: z.string().transform(Number),
|
|
25
|
-
<%_ } -%>
|
|
26
|
-
<%_ } -%>
|
|
27
|
-
<%_ if (caching === 'Redis') { -%>
|
|
28
|
-
REDIS_HOST: z.string(),
|
|
29
|
-
REDIS_PORT: z.string().transform(Number),
|
|
30
|
-
REDIS_PASSWORD: z.string().optional(),
|
|
31
|
-
<%_ } -%>
|
|
32
|
-
<%_ if (communication === 'Kafka') { -%>
|
|
33
|
-
KAFKA_BROKER: z.string(),
|
|
34
|
-
<%_ } -%>
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const _env = envSchema.safeParse(process.env);
|
|
38
|
-
|
|
39
|
-
if (!_env.success) {
|
|
40
|
-
logger.error('❌ Invalid environment variables:', _env.error.format());
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const env = _env.data;
|
|
45
|
-
|
|
46
|
-
module.exports = { env };
|
|
1
|
+
const { z } = require('zod');
|
|
2
|
+
const logger = require('../utils/logger');
|
|
3
|
+
|
|
4
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
5
|
+
require('dotenv').config();
|
|
6
|
+
}
|
|
7
|
+
const envSchema = z.object({
|
|
8
|
+
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
9
|
+
PORT: z.string().transform(Number).default('3000'),
|
|
10
|
+
<%_ if (database !== 'None') { -%>
|
|
11
|
+
DB_HOST: z.string(),
|
|
12
|
+
<%_ if (database === 'MySQL') { -%>
|
|
13
|
+
DB_USER: z.string(),
|
|
14
|
+
DB_PASSWORD: z.string(),
|
|
15
|
+
DB_NAME: z.string(),
|
|
16
|
+
DB_PORT: z.string().transform(Number),
|
|
17
|
+
<%_ } else if (database === 'PostgreSQL') { -%>
|
|
18
|
+
DB_USER: z.string(),
|
|
19
|
+
DB_PASSWORD: z.string(),
|
|
20
|
+
DB_NAME: z.string(),
|
|
21
|
+
DB_PORT: z.string().transform(Number),
|
|
22
|
+
<%_ } else if (database === 'MongoDB') { -%>
|
|
23
|
+
DB_NAME: z.string(),
|
|
24
|
+
DB_PORT: z.string().transform(Number),
|
|
25
|
+
<%_ } -%>
|
|
26
|
+
<%_ } -%>
|
|
27
|
+
<%_ if (caching === 'Redis') { -%>
|
|
28
|
+
REDIS_HOST: z.string(),
|
|
29
|
+
REDIS_PORT: z.string().transform(Number),
|
|
30
|
+
REDIS_PASSWORD: z.string().optional(),
|
|
31
|
+
<%_ } -%>
|
|
32
|
+
<%_ if (communication === 'Kafka') { -%>
|
|
33
|
+
KAFKA_BROKER: z.string(),
|
|
34
|
+
<%_ } -%>
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const _env = envSchema.safeParse(process.env);
|
|
38
|
+
|
|
39
|
+
if (!_env.success) {
|
|
40
|
+
logger.error('❌ Invalid environment variables:', _env.error.format());
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const env = _env.data;
|
|
45
|
+
|
|
46
|
+
module.exports = { env };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const YAML = require('yamljs');
|
|
3
|
-
|
|
4
|
-
const swaggerDocument = YAML.load(path.join(__dirname, 'swagger.yml'));
|
|
5
|
-
|
|
6
|
-
module.exports = swaggerDocument;
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const YAML = require('yamljs');
|
|
3
|
+
|
|
4
|
+
const swaggerDocument = YAML.load(path.join(__dirname, 'swagger.yml'));
|
|
5
|
+
|
|
6
|
+
module.exports = swaggerDocument;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
class ApiError extends Error {
|
|
2
|
-
constructor(statusCode, message, isOperational = true, stack = '') {
|
|
3
|
-
super(message);
|
|
4
|
-
this.statusCode = statusCode;
|
|
5
|
-
this.isOperational = isOperational;
|
|
6
|
-
if (stack) {
|
|
7
|
-
this.stack = stack;
|
|
8
|
-
} else {
|
|
9
|
-
Error.captureStackTrace(this, this.constructor);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
module.exports = { ApiError };
|
|
1
|
+
class ApiError extends Error {
|
|
2
|
+
constructor(statusCode, message, isOperational = true, stack = '') {
|
|
3
|
+
super(message);
|
|
4
|
+
this.statusCode = statusCode;
|
|
5
|
+
this.isOperational = isOperational;
|
|
6
|
+
if (stack) {
|
|
7
|
+
this.stack = stack;
|
|
8
|
+
} else {
|
|
9
|
+
Error.captureStackTrace(this, this.constructor);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = { ApiError };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const gqlContext = async ({ req }) => {
|
|
2
|
-
// Setup authorization or context here
|
|
3
|
-
const token = req.headers.authorization || '';
|
|
4
|
-
return { token };
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
module.exports = { gqlContext };
|
|
1
|
+
const gqlContext = async ({ req }) => {
|
|
2
|
+
// Setup authorization or context here
|
|
3
|
+
const token = req.headers.authorization || '';
|
|
4
|
+
return { token };
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
module.exports = { gqlContext };
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
const { gqlContext } = require('@/graphql/context');
|
|
2
|
-
const { resolvers } = require('@/graphql/resolvers');
|
|
3
|
-
const { typeDefs } = require('@/graphql/typeDefs');
|
|
4
|
-
|
|
5
|
-
describe('GraphQL Context', () => {
|
|
6
|
-
it('should exercise GraphQL index entry points', () => {
|
|
7
|
-
expect(resolvers).toBeDefined();
|
|
8
|
-
expect(typeDefs).toBeDefined();
|
|
9
|
-
});
|
|
10
|
-
it('should return context with token when authorization header is present', async () => {
|
|
11
|
-
const mockRequest = {
|
|
12
|
-
headers: {
|
|
13
|
-
authorization: 'Bearer token123',
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const context = await gqlContext({ req: mockRequest });
|
|
18
|
-
expect(context).toEqual({ token: 'Bearer token123' });
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should return context with empty token when authorization header is missing', async () => {
|
|
22
|
-
const mockRequest = {
|
|
23
|
-
headers: {},
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const context = await gqlContext({ req: mockRequest });
|
|
27
|
-
expect(context).toEqual({ token: '' });
|
|
28
|
-
});
|
|
29
|
-
});
|
|
1
|
+
const { gqlContext } = require('@/graphql/context');
|
|
2
|
+
const { resolvers } = require('@/graphql/resolvers');
|
|
3
|
+
const { typeDefs } = require('@/graphql/typeDefs');
|
|
4
|
+
|
|
5
|
+
describe('GraphQL Context', () => {
|
|
6
|
+
it('should exercise GraphQL index entry points', () => {
|
|
7
|
+
expect(resolvers).toBeDefined();
|
|
8
|
+
expect(typeDefs).toBeDefined();
|
|
9
|
+
});
|
|
10
|
+
it('should return context with token when authorization header is present', async () => {
|
|
11
|
+
const mockRequest = {
|
|
12
|
+
headers: {
|
|
13
|
+
authorization: 'Bearer token123',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const context = await gqlContext({ req: mockRequest });
|
|
18
|
+
expect(context).toEqual({ token: 'Bearer token123' });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should return context with empty token when authorization header is missing', async () => {
|
|
22
|
+
const mockRequest = {
|
|
23
|
+
headers: {},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const context = await gqlContext({ req: mockRequest });
|
|
27
|
+
expect(context).toEqual({ token: '' });
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const { typeDefs } = require('./typeDefs');
|
|
2
|
-
const { resolvers } = require('./resolvers');
|
|
3
|
-
const { gqlContext } = require('./context');
|
|
4
|
-
|
|
5
|
-
module.exports = { typeDefs, resolvers, gqlContext };
|
|
1
|
+
const { typeDefs } = require('./typeDefs');
|
|
2
|
+
const { resolvers } = require('./resolvers');
|
|
3
|
+
const { gqlContext } = require('./context');
|
|
4
|
+
|
|
5
|
+
module.exports = { typeDefs, resolvers, gqlContext };
|