nodejs-quickstart-structure 1.18.0 → 1.19.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 (113) hide show
  1. package/CHANGELOG.md +17 -4
  2. package/README.md +2 -1
  3. package/bin/index.js +93 -92
  4. package/lib/generator.js +1 -1
  5. package/lib/modules/caching-setup.js +76 -73
  6. package/lib/modules/config-files.js +4 -0
  7. package/lib/modules/kafka-setup.js +249 -191
  8. package/lib/modules/project-setup.js +1 -0
  9. package/package.json +13 -2
  10. package/templates/clean-architecture/js/src/errors/BadRequestError.js +11 -10
  11. package/templates/clean-architecture/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  12. package/templates/clean-architecture/js/src/errors/NotFoundError.js +11 -10
  13. package/templates/clean-architecture/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  14. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +69 -39
  15. package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +142 -81
  16. package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +1 -1
  17. package/templates/clean-architecture/js/src/interfaces/controllers/userController.js.ejs +156 -75
  18. package/templates/clean-architecture/js/src/interfaces/controllers/userController.spec.js.ejs +234 -138
  19. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.js.ejs +27 -21
  20. package/templates/clean-architecture/js/src/interfaces/graphql/resolvers/user.resolvers.spec.js.ejs +66 -49
  21. package/templates/clean-architecture/js/src/interfaces/graphql/typeDefs/user.types.js.ejs +19 -17
  22. package/templates/clean-architecture/js/src/interfaces/routes/api.js +12 -10
  23. package/templates/clean-architecture/js/src/usecases/DeleteUser.js +11 -0
  24. package/templates/clean-architecture/js/src/usecases/DeleteUser.spec.js.ejs +47 -0
  25. package/templates/clean-architecture/js/src/usecases/UpdateUser.js +11 -0
  26. package/templates/clean-architecture/js/src/usecases/UpdateUser.spec.js.ejs +48 -0
  27. package/templates/clean-architecture/js/src/utils/errorMessages.js +14 -0
  28. package/templates/clean-architecture/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  29. package/templates/clean-architecture/ts/src/errors/BadRequestError.ts +9 -8
  30. package/templates/clean-architecture/ts/src/errors/NotFoundError.spec.ts.ejs +22 -21
  31. package/templates/clean-architecture/ts/src/errors/NotFoundError.ts +9 -8
  32. package/templates/clean-architecture/ts/src/index.ts.ejs +1 -1
  33. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +175 -85
  34. package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +74 -0
  35. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.spec.ts.ejs +331 -185
  36. package/templates/clean-architecture/ts/src/interfaces/controllers/userController.ts.ejs +173 -84
  37. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  38. package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  39. package/templates/clean-architecture/ts/src/interfaces/graphql/typeDefs/user.types.ts.ejs +17 -15
  40. package/templates/clean-architecture/ts/src/interfaces/routes/userRoutes.ts +13 -11
  41. package/templates/clean-architecture/ts/src/usecases/deleteUser.spec.ts.ejs +47 -0
  42. package/templates/clean-architecture/ts/src/usecases/deleteUser.ts +9 -0
  43. package/templates/clean-architecture/ts/src/usecases/updateUser.spec.ts.ejs +48 -0
  44. package/templates/clean-architecture/ts/src/usecases/updateUser.ts +9 -0
  45. package/templates/clean-architecture/ts/src/utils/errorMessages.ts +12 -0
  46. package/templates/common/.gitattributes +46 -0
  47. package/templates/common/.snyk.ejs +45 -0
  48. package/templates/common/Dockerfile +17 -9
  49. package/templates/common/README.md.ejs +295 -263
  50. package/templates/common/caching/clean/js/DeleteUser.js.ejs +27 -0
  51. package/templates/common/caching/clean/js/UpdateUser.js.ejs +27 -0
  52. package/templates/common/caching/clean/ts/deleteUser.ts.ejs +24 -0
  53. package/templates/common/caching/clean/ts/updateUser.ts.ejs +25 -0
  54. package/templates/common/caching/ts/memoryCache.ts.ejs +73 -64
  55. package/templates/common/caching/ts/redisClient.ts.ejs +89 -80
  56. package/templates/common/database/js/models/User.js.ejs +79 -53
  57. package/templates/common/database/js/models/User.js.mongoose.ejs +23 -19
  58. package/templates/common/database/js/models/User.spec.js.ejs +94 -84
  59. package/templates/common/database/ts/models/User.spec.ts.ejs +100 -84
  60. package/templates/common/database/ts/models/User.ts.ejs +87 -61
  61. package/templates/common/database/ts/models/User.ts.mongoose.ejs +30 -25
  62. package/templates/common/health/js/healthRoute.js.ejs +50 -47
  63. package/templates/common/health/ts/healthRoute.ts.ejs +49 -46
  64. package/templates/common/jest.e2e.config.js.ejs +8 -8
  65. package/templates/common/kafka/js/messaging/baseConsumer.js.ejs +30 -30
  66. package/templates/common/kafka/js/messaging/userEventSchema.js.ejs +12 -11
  67. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.js.ejs +44 -31
  68. package/templates/common/kafka/js/messaging/welcomeEmailConsumer.spec.js.ejs +86 -49
  69. package/templates/common/kafka/js/services/kafkaService.js.ejs +93 -93
  70. package/templates/common/kafka/js/utils/kafkaEvents.js.ejs +7 -0
  71. package/templates/common/kafka/ts/messaging/userEventSchema.spec.ts.ejs +51 -51
  72. package/templates/common/kafka/ts/messaging/userEventSchema.ts.ejs +12 -11
  73. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.spec.ts.ejs +86 -49
  74. package/templates/common/kafka/ts/messaging/welcomeEmailConsumer.ts.ejs +38 -25
  75. package/templates/common/kafka/ts/services/kafkaService.ts.ejs +95 -95
  76. package/templates/common/kafka/ts/utils/kafkaEvents.ts.ejs +5 -0
  77. package/templates/common/package.json.ejs +10 -2
  78. package/templates/common/shutdown/js/gracefulShutdown.js.ejs +65 -61
  79. package/templates/common/shutdown/js/gracefulShutdown.spec.js.ejs +149 -160
  80. package/templates/common/shutdown/ts/gracefulShutdown.spec.ts.ejs +179 -158
  81. package/templates/common/shutdown/ts/gracefulShutdown.ts.ejs +59 -55
  82. package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +120 -49
  83. package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +120 -49
  84. package/templates/common/swagger.yml.ejs +118 -66
  85. package/templates/db/mysql/V1__Initial_Setup.sql.ejs +10 -9
  86. package/templates/db/postgres/V1__Initial_Setup.sql.ejs +10 -9
  87. package/templates/mvc/js/src/controllers/userController.js.ejs +246 -105
  88. package/templates/mvc/js/src/controllers/userController.spec.js.ejs +481 -209
  89. package/templates/mvc/js/src/errors/BadRequestError.js +11 -10
  90. package/templates/mvc/js/src/errors/BadRequestError.spec.js.ejs +22 -21
  91. package/templates/mvc/js/src/errors/NotFoundError.js +11 -10
  92. package/templates/mvc/js/src/errors/NotFoundError.spec.js.ejs +22 -21
  93. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +25 -19
  94. package/templates/mvc/js/src/graphql/resolvers/user.resolvers.spec.js.ejs +64 -47
  95. package/templates/mvc/js/src/graphql/typeDefs/user.types.js.ejs +19 -17
  96. package/templates/mvc/js/src/index.js.ejs +1 -1
  97. package/templates/mvc/js/src/routes/api.js +10 -8
  98. package/templates/mvc/js/src/routes/api.spec.js.ejs +41 -36
  99. package/templates/mvc/js/src/utils/errorMessages.js +14 -0
  100. package/templates/mvc/ts/src/controllers/userController.spec.ts.ejs +481 -203
  101. package/templates/mvc/ts/src/controllers/userController.ts.ejs +248 -107
  102. package/templates/mvc/ts/src/errors/BadRequestError.spec.ts.ejs +22 -21
  103. package/templates/mvc/ts/src/errors/BadRequestError.ts +9 -8
  104. package/templates/mvc/ts/src/errors/NotFoundError.spec.ts.ejs +27 -21
  105. package/templates/mvc/ts/src/errors/NotFoundError.ts +9 -8
  106. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.spec.ts.ejs +68 -51
  107. package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +29 -21
  108. package/templates/mvc/ts/src/graphql/typeDefs/user.types.ts.ejs +17 -15
  109. package/templates/mvc/ts/src/index.ts.ejs +156 -153
  110. package/templates/mvc/ts/src/routes/api.spec.ts.ejs +59 -40
  111. package/templates/mvc/ts/src/routes/api.ts +12 -10
  112. package/templates/mvc/ts/src/utils/errorMessages.ts +12 -0
  113. package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.ts.ejs +0 -37
@@ -1,95 +1,95 @@
1
- import { kafka } from '<%= configPath %>';
2
- import { EachMessagePayload, Producer, Consumer } from 'kafkajs';
3
- import logger from '<%= loggerPath %>';
4
-
5
- export class KafkaService {
6
- private producer: Producer;
7
- private consumer: Consumer;
8
- private isConnected = false;
9
- private connectionPromise: Promise<void> | null = null;
10
-
11
- constructor() {
12
- this.producer = kafka.producer();
13
- this.consumer = kafka.consumer({ groupId: 'test-group' });
14
- }
15
-
16
- async connect(retries = 10) {
17
- if (this.connectionPromise) return this.connectionPromise;
18
-
19
- this.connectionPromise = (async () => {
20
- let attempt = 0;
21
- // Auto-register WelcomeEmailConsumer if it exists
22
- // Note: Dynamic import used here for simplicity and to avoid startup crashes.
23
- // In enterprise production, consider using Dependency Injection.
24
- const { WelcomeEmailConsumer } = await import('<% if (architecture === "Clean Architecture") { %>@/interfaces/messaging/consumers/instances/welcomeEmailConsumer<% } else { %>@/messaging/consumers/instances/welcomeEmailConsumer<% } %>');
25
- while (attempt < retries) {
26
- try {
27
- await this.producer.connect();
28
- await this.consumer.connect();
29
- logger.info('[Kafka] Producer connected successfully');
30
- logger.info('[Kafka] Consumer connected successfully');
31
- this.isConnected = true;
32
-
33
- try {
34
- const welcomeConsumer = new WelcomeEmailConsumer();
35
- await this.consumer.subscribe({ topic: welcomeConsumer.topic, fromBeginning: true });
36
- logger.info(`[Kafka] Registered consumer for topic: ${welcomeConsumer.topic}`);
37
-
38
- await this.consumer.run({
39
- eachMessage: async (payload) => welcomeConsumer.onMessage(payload),
40
- });
41
- } catch (e) {
42
- // Fallback or no consumers found
43
- logger.warn(`[Kafka] Could not load WelcomeEmailConsumer, using fallback: ${(e as Error).message}`);
44
- await this.consumer.subscribe({ topic: 'user-topic', fromBeginning: true });
45
- await this.consumer.run({
46
- eachMessage: async ({ message }: EachMessagePayload) => {
47
- logger.info(`[Kafka] Consumer: Received message on user-topic: ${message.value?.toString()}`);
48
- },
49
- });
50
- }
51
- return; // Success
52
- } catch (error) {
53
- attempt++;
54
- logger.error(`[Kafka] Connection attempt ${attempt} failed:`, (error as Error).message);
55
- if (attempt >= retries) {
56
- throw error;
57
- }
58
- await new Promise(res => setTimeout(res, 3000));
59
- }
60
- }
61
- })();
62
-
63
- return this.connectionPromise;
64
- }
65
-
66
- async sendMessage(topic: string, message: string) {
67
- if (this.connectionPromise) {
68
- await this.connectionPromise;
69
- }
70
-
71
- if (!this.isConnected) {
72
- throw new Error('[Kafka] Producer not connected. Check logs for connection errors.');
73
- }
74
-
75
- await this.producer.send({
76
- topic,
77
- messages: [
78
- { value: message },
79
- ],
80
- });
81
- try {
82
- const parsed = JSON.parse(message);
83
- logger.info(`[Kafka] Producer: Sent ${parsed.action} event for '${parsed.payload?.email || 'unknown'}'`);
84
- } catch {
85
- logger.info(`[Kafka] Producer: Sent message to ${topic}`);
86
- }
87
- }
88
-
89
- async disconnect() {
90
- await this.producer.disconnect();
91
- await this.consumer.disconnect();
92
- }
93
- }
94
-
95
- export const kafkaService = new KafkaService();
1
+ import { kafka } from '<%= configPath %>';
2
+ import { EachMessagePayload, Producer, Consumer } from 'kafkajs';
3
+ import logger from '<%= loggerPath %>';
4
+
5
+ export class KafkaService {
6
+ private producer: Producer;
7
+ private consumer: Consumer;
8
+ private isConnected = false;
9
+ private connectionPromise: Promise<void> | null = null;
10
+
11
+ constructor() {
12
+ this.producer = kafka.producer();
13
+ this.consumer = kafka.consumer({ groupId: 'test-group' });
14
+ }
15
+
16
+ async connect(retries = 10) {
17
+ if (this.connectionPromise) return this.connectionPromise;
18
+
19
+ this.connectionPromise = (async () => {
20
+ let attempt = 0;
21
+ // Auto-register WelcomeEmailConsumer if it exists
22
+ // Note: Dynamic import used here for simplicity and to avoid startup crashes.
23
+ // In enterprise production, consider using Dependency Injection.
24
+ const { WelcomeEmailConsumer } = await import('<% if (architecture === "Clean Architecture") { %>@/interfaces/messaging/consumers/instances/welcomeEmailConsumer<% } else { %>@/messaging/consumers/instances/welcomeEmailConsumer<% } %>');
25
+ while (attempt < retries) {
26
+ try {
27
+ await this.producer.connect();
28
+ await this.consumer.connect();
29
+ logger.info('[Kafka] Producer connected successfully');
30
+ logger.info('[Kafka] Consumer connected successfully');
31
+ this.isConnected = true;
32
+
33
+ try {
34
+ const welcomeConsumer = new WelcomeEmailConsumer();
35
+ await this.consumer.subscribe({ topic: welcomeConsumer.topic, fromBeginning: true });
36
+ logger.info(`[Kafka] Registered consumer for topic: ${welcomeConsumer.topic}`);
37
+
38
+ await this.consumer.run({
39
+ eachMessage: async (payload) => welcomeConsumer.onMessage(payload),
40
+ });
41
+ } catch (e) {
42
+ // Fallback or no consumers found
43
+ logger.warn(`[Kafka] Could not load WelcomeEmailConsumer, using fallback: ${(e as Error).message}`);
44
+ await this.consumer.subscribe({ topic: 'user-topic', fromBeginning: true });
45
+ await this.consumer.run({
46
+ eachMessage: async ({ message }: EachMessagePayload) => {
47
+ logger.info(`[Kafka] Consumer: Received message on user-topic: ${message.value?.toString()}`);
48
+ },
49
+ });
50
+ }
51
+ return; // Success
52
+ } catch (error) {
53
+ attempt++;
54
+ logger.error(`[Kafka] Connection attempt ${attempt} failed:`, (error as Error).message);
55
+ if (attempt >= retries) {
56
+ throw error;
57
+ }
58
+ await new Promise(res => setTimeout(res, 3000));
59
+ }
60
+ }
61
+ })();
62
+
63
+ return this.connectionPromise;
64
+ }
65
+
66
+ async sendMessage(topic: string, message: string, key?: string) {
67
+ if (this.connectionPromise) {
68
+ await this.connectionPromise;
69
+ }
70
+
71
+ if (!this.isConnected) {
72
+ throw new Error('[Kafka] Producer not connected. Check logs for connection errors.');
73
+ }
74
+
75
+ await this.producer.send({
76
+ topic,
77
+ messages: [
78
+ { key, value: message },
79
+ ],
80
+ });
81
+ try {
82
+ const parsed = JSON.parse(message);
83
+ logger.info(`[Kafka] Producer: Sent ${parsed.action} event for '${parsed.payload?.email || 'unknown'}'`);
84
+ } catch {
85
+ logger.info(`[Kafka] Producer: Sent message to ${topic}`);
86
+ }
87
+ }
88
+
89
+ async disconnect() {
90
+ await this.producer.disconnect();
91
+ await this.consumer.disconnect();
92
+ }
93
+ }
94
+
95
+ export const kafkaService = new KafkaService();
@@ -0,0 +1,5 @@
1
+ export enum KAFKA_ACTIONS {
2
+ USER_CREATED = 'USER_CREATED',
3
+ USER_UPDATED = 'USER_UPDATED',
4
+ USER_DELETED = 'USER_DELETED'
5
+ }
@@ -22,6 +22,13 @@
22
22
  "security:check": "npm audit && npm run snyk:test",
23
23
  "snyk:test": "snyk test"<% } %>
24
24
  },
25
+ "overrides": {
26
+ "brace-expansion": "^5.0.5",
27
+ "jake": "^10.9.4",
28
+ "micromatch": "^4.0.8",
29
+ "braces": "^3.0.3",
30
+ "picomatch": "^4.0.4"
31
+ },
25
32
  "dependencies": {
26
33
  "express": "^4.18.2",
27
34
  "dotenv": "^16.3.1",
@@ -54,7 +61,8 @@
54
61
  "morgan": "^1.10.0"<% if (communication === 'REST APIs' || communication === 'Kafka') { %>,
55
62
  "swagger-ui-express": "^5.0.0",
56
63
  "yamljs": "^0.3.0"<% } %><% if (communication === 'GraphQL') { %>,
57
- "@apollo/server": "^4.10.0",
64
+ "@apollo/server": "^5.5.0",
65
+ "@as-integrations/express4": "^1.1.2",
58
66
  "graphql": "^16.8.1",
59
67
  "@graphql-tools/merge": "^9.0.3"<% } %>
60
68
  },
@@ -76,7 +84,7 @@
76
84
  "@types/morgan": "^1.9.9",
77
85
  "rimraf": "^6.0.1"<% if ((viewEngine && viewEngine !== 'None') || communication === 'REST APIs' || communication === 'Kafka') { %>,
78
86
  "cpx2": "^8.0.0"<% } %><% } %>,
79
- "eslint": "^9.20.1",
87
+ "eslint": "^10.1.0",
80
88
  "@eslint/js": "^9.20.0",
81
89
  "globals": "^15.14.0",
82
90
  "prettier": "^3.5.1",
@@ -1,61 +1,65 @@
1
- <%_
2
- let loggerPath = './logger';
3
- let dbPath = '../config/database';
4
- let redisPath = '../config/redisClient';
5
- let kafkaPath = '../services/kafkaService';
6
-
7
- if (architecture === 'Clean Architecture') {
8
- loggerPath = '../infrastructure/log/logger';
9
- dbPath = '../infrastructure/database/database';
10
- redisPath = '../infrastructure/caching/redisClient';
11
- kafkaPath = '../infrastructure/messaging/kafkaClient';
12
- }
13
- _%>
14
- const logger = require('<%- loggerPath %>');
15
-
16
- const setupGracefulShutdown = (server) => {
17
- const gracefulShutdown = async (signal) => {
18
- logger.info(`Received ${signal}. Shutting down gracefully...`);
19
- server.close(async () => {
20
- logger.info('HTTP server closed.');
21
- try {
22
- <%_ if (database !== 'None') { -%>
23
- <%_ if (database === 'MongoDB') { -%>
24
- const mongoose = require('mongoose');
25
- await mongoose.connection.close(false);
26
- logger.info('MongoDB connection closed.');
27
- <%_ } else { -%>
28
- const sequelize = require('<%- dbPath %>');
29
- await sequelize.close();
30
- logger.info('Database connection closed.');
31
- <%_ } -%>
32
- <%_ } -%>
33
- <%_ if (caching === 'Redis') { -%>
34
- const redisService = require('<%- redisPath %>');
35
- await redisService.quit();
36
- logger.info('Redis connection closed.');
37
- <%_ } -%>
38
- <%_ if (communication === 'Kafka') { -%>
39
- const { disconnectKafka } = require('<%- kafkaPath %>');
40
- await disconnectKafka();
41
- logger.info('Kafka connection closed.');
42
- <%_ } -%>
43
- logger.info('Graceful shutdown fully completed.');
44
- process.exit(0);
45
- } catch (err) {
46
- logger.error('Error during shutdown:', err);
47
- process.exit(1);
48
- }
49
- });
50
-
51
- setTimeout(() => {
52
- logger.error('Could not close connections in time, forcefully shutting down');
53
- process.exit(1);
54
- }, 15000);
55
- };
56
-
57
- process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
58
- process.on('SIGINT', () => gracefulShutdown('SIGINT'));
59
- };
60
-
61
- module.exports = setupGracefulShutdown;
1
+ <%_
2
+ let loggerPath = './logger';
3
+ let dbPath = '../config/database';
4
+ let redisPath = '../config/redisClient';
5
+ let kafkaPath = '../services/kafkaService';
6
+
7
+ if (architecture === 'Clean Architecture') {
8
+ loggerPath = '../infrastructure/log/logger';
9
+ dbPath = '../infrastructure/database/database';
10
+ redisPath = '../infrastructure/caching/redisClient';
11
+ kafkaPath = '../infrastructure/messaging/kafkaClient';
12
+ }
13
+ -%>
14
+ const logger = require('<%- loggerPath %>');
15
+
16
+ const setupGracefulShutdown = (server) => {
17
+ const gracefulShutdown = async (signal) => {
18
+ logger.info(`Received ${signal}. Shutting down gracefully...`);
19
+ server.close(async (err) => {
20
+ if (err) {
21
+ logger.error('Error closing HTTP server:', err);
22
+ process.exit(1);
23
+ }
24
+ logger.info('HTTP server closed.');
25
+ try {
26
+ <%_ if (database !== 'None') { -%>
27
+ <%_ if (database === 'MongoDB') { -%>
28
+ const mongoose = require('mongoose');
29
+ await mongoose.connection.close(false);
30
+ logger.info('MongoDB connection closed.');
31
+ <%_ } else { -%>
32
+ const sequelize = require('<%- dbPath %>');
33
+ await sequelize.close();
34
+ logger.info('Database connection closed.');
35
+ <%_ } -%>
36
+ <%_ } -%>
37
+ <%_ if (caching === 'Redis') { -%>
38
+ const redisService = require('<%- redisPath %>');
39
+ await redisService.quit();
40
+ logger.info('Redis connection closed.');
41
+ <%_ } -%>
42
+ <%_ if (communication === 'Kafka') { -%>
43
+ const { disconnectKafka } = require('<%- kafkaPath %>');
44
+ await disconnectKafka();
45
+ logger.info('Kafka connection closed.');
46
+ <%_ } -%>
47
+ logger.info('Graceful shutdown fully completed.');
48
+ process.exit(0);
49
+ } catch (err) {
50
+ logger.error('Error during shutdown:', err);
51
+ process.exit(1);
52
+ }
53
+ });
54
+
55
+ setTimeout(() => {
56
+ logger.error('Could not close connections in time, forcefully shutting down');
57
+ process.exit(1);
58
+ }, 15000);
59
+ };
60
+
61
+ process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
62
+ process.on('SIGINT', () => gracefulShutdown('SIGINT'));
63
+ };
64
+
65
+ module.exports = setupGracefulShutdown;