@mimik/init 2.1.1 → 3.6.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.
package/.eslintrc CHANGED
@@ -1,17 +1,29 @@
1
- // Use this file as a starting point for your project's .eslintrc.
2
- // Copy this file, and add rule overrides as needed.
3
1
  {
2
+ "plugins": [
3
+ "@mimik/document-env",
4
+ "@mimik/dependencies"
5
+ ],
4
6
  "env": {
5
7
  "node": true
6
8
  },
9
+ "parserOptions": {
10
+ "ecmaVersion": 2020
11
+ },
7
12
  "extends": "airbnb",
8
13
  "rules": {
14
+ "import/no-extraneous-dependencies": ["error", {"devDependencies": true}],
9
15
  "brace-style": [1, "stroustrup", {"allowSingleLine": true}],
10
16
  "no-confusing-arrow": [0], // arrow isnt confusing
11
17
  "max-len": [1, 180, { "ignoreComments": true }],
12
18
  "linebreak-style": 0,
13
19
  "quotes": [1, "single"],
14
- "semi": [1, "always"]
20
+ "semi": [1, "always"],
21
+ "no-process-env": ["error"],
22
+ "@mimik/document-env/validate-document-env": 2,
23
+ "@mimik/dependencies/case-sensitive": 2,
24
+ "@mimik/dependencies/no-cycles": 2,
25
+ "@mimik/dependencies/no-unresolved": 2,
26
+ "@mimik/dependencies/require-json-ext": 2
15
27
  },
16
28
  "settings":{
17
29
  "react": {
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ . "$(dirname "$0")/_/husky.sh"
3
+
4
+ npm run commit-ready
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ . "$(dirname "$0")/_/husky.sh"
3
+
4
+ npm run test
package/Gulpfile.js CHANGED
@@ -16,14 +16,13 @@ const files = [
16
16
  const createDocs = (done) => {
17
17
  jsdoc2md.render({ files: 'index.js' })
18
18
  .then((output) => fs.writeFileSync('README.md', output))
19
- .catch((err) => log.error('docs creation failed:', err.message));
20
- return done();
19
+ .catch((err) => log.error('docs creation failed:', err.message))
20
+ .finally(() => done());
21
21
  };
22
22
 
23
23
  const lint = () => gulp.src(files)
24
24
  .pipe(eslint({}))
25
- .pipe(eslint.format())
26
- .pipe(eslint.failOnError());
25
+ .pipe(eslint.format());
27
26
 
28
27
  const add = () => gulp.src('README.md')
29
28
  .pipe(git.add({ quiet: true }));
package/README.md CHANGED
@@ -9,17 +9,18 @@ init(config, dbValidate, { postOps: [suscribe] }).then(result => config = result
9
9
  ```
10
10
  <a name="exp_module_ini--module.exports"></a>
11
11
 
12
- ### module.exports(app, rootDir, config, dbValidate, options) ⇒ <code>object</code> ⏏
12
+ ### module.exports(app, rootDir, config, validates, cluster, options) ⇒ <code>object</code> ⏏
13
13
  Init process for a micro-service.
14
14
 
15
15
  **Kind**: Exported function
16
16
  **Returns**: <code>object</code> - The updated configuration.
17
17
 
18
- The secOptions has the following strucuture:
18
+ The secOptions has the following structure:
19
19
  ``` javascript
20
20
  {
21
21
  preOps: [function], // functions to process before starting the micro-service
22
22
  postOps: [function], // functions to process after starting the micro-service
23
+ exitOps: [function], // functions to process before exiting the micro-service
23
24
  secOptions: { securityDefinition: function }, // extra security options to validate the API request
24
25
  extractName: string, // ability to extract data from the req and send it to a logging environment
25
26
  }
@@ -30,13 +31,14 @@ The `return` object has the following strucuture:
30
31
  config: The configuration object,
31
32
  }
32
33
  ```
33
- For the preOps and postOps the function are executed with 3 parameters (correlationId, config, server)
34
+ For the preOps, postOps and exitOps the function are executed with 3 parameters (correlationId, config, server)
34
35
 
35
36
  | Param | Type | Description |
36
37
  | --- | --- | --- |
37
38
  | app | <code>object</code> | The app implementing the micro-service. |
38
39
  | rootDir | <code>PATH.&lt;string&gt;</code> | The root directory of the micro-service. |
39
40
  | config | <code>object</code> | Configuration of the micro-service. |
40
- | dbValidate | <code>Promise</code> | Promise to validate the databases used. |
41
+ | validates | <code>array</code> | Array of Promises to validate dependent systems (database, topic). |
42
+ | cluster | <code>Promise</code> | Promise to be used for cluster management and registration. |
41
43
  | options | <code>object</code> | options to start the micro-service. The options can be `null`. |
42
44
 
package/index.js CHANGED
@@ -7,13 +7,15 @@ const helmet = require('helmet');
7
7
 
8
8
  const logger = require('@mimik/sumologic-winston-logger');
9
9
  const swagger = require('@mimik/swagger-helper');
10
- const eventHelper = require('@mimik/event-helper');
11
10
  const oauthHelper = require('@mimik/oauth-helper');
12
11
  const { startupHealthInfo } = require('@mimik/healthcheck');
13
12
  const { getPublic } = require('@mimik/public-helper');
14
- const cluster = require('@mimik/cluster');
15
-
13
+ const { getCorrelationId } = require('@mimik/request-helper');
16
14
  const { extractLogs } = require('./lib/logs');
15
+ const { sigProcess } = require('./lib/exit');
16
+
17
+ const SIGINT = 'SIGINT';
18
+ const SIGTERM = 'SIGTERM';
17
19
 
18
20
  /**
19
21
  * @module ini
@@ -29,15 +31,17 @@ const { extractLogs } = require('./lib/logs');
29
31
  * @param {object} app - The app implementing the micro-service.
30
32
  * @param {PATH<string>} rootDir - The root directory of the micro-service.
31
33
  * @param {object} config - Configuration of the micro-service.
32
- * @param {Promise} dbValidate - Promise to validate the databases used.
34
+ * @param {array} validates - Array of Promises to validate dependent systems (database, topic).
35
+ * @param {Promise} cluster - Promise to be used for cluster management and registration.
33
36
  * @param {object} options - options to start the micro-service. The options can be `null`.
34
37
  * @returns {object} The updated configuration.
35
38
  *
36
- * The secOptions has the following strucuture:
39
+ * The secOptions has the following structure:
37
40
  * ``` javascript
38
41
  * {
39
42
  * preOps: [function], // functions to process before starting the micro-service
40
43
  * postOps: [function], // functions to process after starting the micro-service
44
+ * exitOps: [function], // functions to process before exiting the micro-service
41
45
  * secOptions: { securityDefinition: function }, // extra security options to validate the API request
42
46
  * extractName: string, // ability to extract data from the req and send it to a logging environment
43
47
  * }
@@ -48,31 +52,44 @@ const { extractLogs } = require('./lib/logs');
48
52
  * config: The configuration object,
49
53
  * }
50
54
  * ```
51
- * For the preOps and postOps the function are executed with 3 parameters (correlationId, config, server)
55
+ * For the preOps, postOps and exitOps the function are executed with 3 parameters (correlationId, config, server)
52
56
  */
53
- module.exports = (app, rootDir, config, dbValidate, options) => {
54
- const event = eventHelper(config);
55
- const oauth = oauthHelper(config);
56
- const { register, unRegister } = cluster(config);
57
+ module.exports = (app, rootDir, config, validates, cluster, options) => {
58
+ const fatalError = (error, correlationId) => {
59
+ if (!config) logger.error('fatal error: could not start server', { error }, getCorrelationId('system-start'));
60
+ else logger.error('fatal error: could not start server', { name: config.serverSettings.name, id: config.serverSettings.id, error }, correlationId);
61
+ logger.flushAndExit(1);
62
+ };
63
+
64
+ if (!config) return fatalError(new Error('config is required'));
57
65
  const { serverSettings, dependencies } = config;
58
- const server = http.createServer(app);
59
- const correlationIdStart = `system-start-${serverSettings.id}`;
60
- const correlationIdShut = `system-shutdown-${serverSettings.id}`;
61
66
  const serverPort = serverSettings.port;
67
+ const correlationIdStart = getCorrelationId(`system-start:${serverSettings.id}`);
68
+
69
+ if (!cluster) return fatalError(new Error('cluster lib required'), correlationIdStart);
70
+ if (!app) return fatalError(new Error('app is required'), correlationIdStart);
71
+ const { register, unRegister } = cluster;
72
+ const oauth = oauthHelper(config);
73
+ const server = http.createServer(app);
62
74
 
63
75
  let swaggerFilename = serverSettings.api;
64
76
  let extractName = null;
65
77
  let registration = false;
66
78
 
67
- process.on('SIGINT', () => {
68
- if (registration) unRegister(correlationIdShut);
69
- else {
70
- logger.info('service shutdown successfully', { serverId: serverSettings.id }, correlationIdShut);
71
- logger.flushAndExit(0);
72
- }
79
+ process.on(SIGINT, () => {
80
+ sigProcess(SIGINT, registration, options, config, server, unRegister, getCorrelationId(`system-shutdown(${SIGINT}):${serverSettings.id}`));
81
+ });
82
+ process.on(SIGTERM, () => {
83
+ sigProcess(SIGTERM, registration, options, config, server, unRegister, getCorrelationId(`system-shutdown(${SIGTERM}):${serverSettings.id}`));
73
84
  });
74
85
 
75
- app.use(helmet());
86
+ app.use(helmet.contentSecurityPolicy({
87
+ directives: {
88
+ ...helmet.contentSecurityPolicy.getDefaultDirectives(),
89
+ 'script-src': ['\'self\'', '\'unsafe-inline\''],
90
+ 'connect-src': ['\'self\'', '*.swagger.io'],
91
+ },
92
+ }));
76
93
  if (options && options.extractName) {
77
94
  ({ extractName } = options);
78
95
  if (!dependencies || !dependencies.mLG) {
@@ -95,6 +112,7 @@ module.exports = (app, rootDir, config, dbValidate, options) => {
95
112
  AdminSecurity: oauth.apiTokenAdminSecurityHelper,
96
113
  SystemSecurity: oauth.apiTokenSecurityHelper,
97
114
  UserSecurity: oauth.apiTokenSecurityHelper,
115
+ APIKeySecurity: oauth.apiKeySecurityHelper,
98
116
  };
99
117
 
100
118
  if (options && options.secOptions) {
@@ -114,16 +132,15 @@ module.exports = (app, rootDir, config, dbValidate, options) => {
114
132
  }
115
133
  app.use(middleware.swaggerRouter({
116
134
  useStubs: config.nodeEnvironment === 'local',
117
- controllers: './controllers',
135
+ controllers: `${rootDir}/controllers`,
118
136
  }));
119
137
  app.use(middleware.swaggerUi());
120
138
  app.use(swagger.sendError);
121
139
  if (serverSettings.interceptError === 'on') {
122
140
  app.use(swagger.interceptError);
123
141
  }
124
- return event.validate()
125
- .then(() => dbValidate())
126
- .then(() => getPublic(config.locationProvider, config.cloudProvider).then((publicConfig) => {
142
+ return Promise.each(validates, (validate) => validate())
143
+ .then(() => getPublic(config.locationProvider, config.cloudProvider, correlationIdStart).then((publicConfig) => {
127
144
  logger.info('public environment', { status: publicConfig.status }, correlationIdStart);
128
145
  serverSettings.ip.public = publicConfig.ip || serverSettings.ip.public;
129
146
  serverSettings.instanceId = publicConfig.id;
@@ -140,12 +157,7 @@ module.exports = (app, rootDir, config, dbValidate, options) => {
140
157
  if (options && options.postOps) options.postOps.forEach((ops) => ops(correlationIdStart, config, server));
141
158
  });
142
159
  })
143
- .catch((error) => {
144
- logger.error('fatal error: could not start server', {
145
- name: serverSettings.name, id: serverSettings.id, error,
146
- }, correlationIdStart);
147
- logger.flushAndExit(1);
148
- });
160
+ .catch((error) => fatalError(error, correlationIdStart));
149
161
  }))
150
162
  .then(() => ({ config }));
151
163
  };
package/lib/exit.js ADDED
@@ -0,0 +1,44 @@
1
+ const Promise = require('bluebird');
2
+
3
+ const logger = require('@mimik/sumologic-winston-logger');
4
+
5
+ const SHUTDOWN = 'service shutdown successfully';
6
+ const SHUTDOWN_WITH_ERROR = 'service shutdown with error';
7
+
8
+ const shutdown = (res, correlationId) => {
9
+ if (res.errors) {
10
+ logger.warn(SHUTDOWN_WITH_ERROR, res, correlationId);
11
+ logger.flushAndExit(1);
12
+ }
13
+ else {
14
+ logger.info(SHUTDOWN, res, correlationId);
15
+ logger.flushAndExit(0);
16
+ }
17
+ };
18
+
19
+ const sigProcess = (signal, registration, options, config, server, unRegister, correlationId) => {
20
+ if (registration) {
21
+ return unRegister(correlationId)
22
+ .then((origResult) => {
23
+ const result = origResult;
24
+
25
+ result.signal = signal;
26
+ if (!options || !options.exitOps) {
27
+ return shutdown(result, correlationId);
28
+ }
29
+ return Promise.each(options.exitOps, (ops) => ops(correlationId, config, server)
30
+ .catch((err) => {
31
+ if (result.errors) result.errors.push(err);
32
+ else result.errors = [err];
33
+ }))
34
+ .then(() => shutdown(result, correlationId));
35
+ });
36
+ }
37
+ logger.info(SHUTDOWN, { serverId: config.serverSettings.id, signal }, correlationId);
38
+ logger.flushAndExit(0);
39
+ return null;
40
+ };
41
+
42
+ module.exports = {
43
+ sigProcess,
44
+ };
package/lib/logs.js CHANGED
@@ -4,8 +4,9 @@ const { publicIpFromRequest } = require('@mimik/address-helper');
4
4
  const oauthHelper = require('@mimik/oauth-helper');
5
5
  const logger = require('@mimik/sumologic-winston-logger');
6
6
  const { getRichError } = require('@mimik/response-helper');
7
+ const { getCorrelationId } = require('@mimik/request-helper');
7
8
 
8
- const correlationId = 'log-extraction';
9
+ const correlationId = getCorrelationId('log-extraction');
9
10
  const NOTIFICATION = '/notifications';
10
11
 
11
12
  const extractLogs = (config, extractName) => (req, res, next) => {
@@ -28,6 +29,7 @@ const extractLogs = (config, extractName) => (req, res, next) => {
28
29
  method: 'POST',
29
30
  headers: {
30
31
  'x-forwarded-for': xForwardedFor,
32
+ 'x-correlation-id': correlationId,
31
33
  },
32
34
  url,
33
35
  body: {
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@mimik/init",
3
- "version": "2.1.1",
3
+ "version": "3.6.0",
4
4
  "description": "Init process for micro-service",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "lint": "gulp lint",
8
8
  "docs": "gulp docs",
9
9
  "test": "exit 0",
10
- "commit-ready": "gulp docs; gulp lint; npm run test"
10
+ "prepublishOnly": "gulp docs; gulp lint; npm run test",
11
+ "commit-ready": "gulp docs; gulp lint; npm run test",
12
+ "prepare": "husky install"
11
13
  },
12
14
  "husky": {
13
15
  "hooks": {
@@ -19,39 +21,40 @@
19
21
  "mimik",
20
22
  "microservice"
21
23
  ],
22
- "author": "mimik",
24
+ "author": "mimik technology inc <support@mimik.com> (https://developer.mimik.com/)",
23
25
  "license": "Apache-2.0",
24
26
  "repository": {
25
27
  "type": "git",
26
28
  "url": "https://bitbucket.org/mimiktech/init"
27
29
  },
28
30
  "dependencies": {
29
- "@mimik/address-helper": "1.3.0",
30
- "@mimik/cluster": "2.1.1",
31
- "@mimik/event-helper": "1.1.1",
32
- "@mimik/healthcheck": "1.4.1",
33
- "@mimik/oauth-helper": "1.6.1",
34
- "@mimik/public-helper": "1.3.1",
35
- "@mimik/response-helper": "2.2.1",
36
- "@mimik/sumologic-winston-logger": "1.3.0",
37
- "@mimik/swagger-helper": "2.1.1",
38
- "bluebird": "3.7.1",
31
+ "@mimik/address-helper": "^1.6.2",
32
+ "@mimik/healthcheck": "^1.5.7",
33
+ "@mimik/oauth-helper": "^1.9.6",
34
+ "@mimik/public-helper": "^1.5.3",
35
+ "@mimik/request-helper": "^1.7.3",
36
+ "@mimik/response-helper": "^2.6.0",
37
+ "@mimik/sumologic-winston-logger": "^1.6.6",
38
+ "@mimik/swagger-helper": "^2.5.0",
39
+ "bluebird": "3.7.2",
39
40
  "cors": "2.8.5",
40
- "helmet": "3.21.2",
41
+ "helmet": "4.6.0",
41
42
  "swagger-tools": "0.10.4"
42
43
  },
43
44
  "devDependencies": {
44
- "eslint": "6.6.0",
45
- "eslint-config-airbnb": "18.0.1",
46
- "eslint-plugin-import": "2.18.2",
47
- "eslint-plugin-jsx-a11y": "6.2.3",
48
- "eslint-plugin-react": "7.16.0",
49
- "eslint-plugin-react-hooks": "2.2.0",
45
+ "@mimik/eslint-plugin-dependencies": "^2.4.1",
46
+ "@mimik/eslint-plugin-document-env": "^1.0.0",
47
+ "eslint": "8.4.1",
48
+ "eslint-config-airbnb": "18.2.1",
49
+ "eslint-plugin-import": "2.25.3",
50
+ "eslint-plugin-jsx-a11y": "6.5.1",
51
+ "eslint-plugin-react": "7.27.1",
52
+ "eslint-plugin-react-hooks": "4.3.0",
50
53
  "fancy-log": "1.3.3",
51
54
  "gulp": "4.0.2",
52
55
  "gulp-eslint": "6.0.0",
53
- "gulp-git": "2.9.0",
54
- "husky": "3.0.9",
55
- "jsdoc-to-markdown": "5.0.2"
56
+ "gulp-git": "2.10.1",
57
+ "husky": "7.0.4",
58
+ "jsdoc-to-markdown": "7.1.0"
56
59
  }
57
60
  }
package/package.json.bak DELETED
@@ -1,58 +0,0 @@
1
- {
2
- "name": "@mimik/init",
3
- "version": "2.1.1",
4
- "description": "Init process for micro-service",
5
- "main": "index.js",
6
- "scripts": {
7
- "lint": "gulp lint",
8
- "docs": "gulp docs",
9
- "test": "exit 0",
10
- "prepublishOnly": "gulp docs; gulp lint; npm run test",
11
- "commit-ready": "gulp docs; gulp lint; npm run test"
12
- },
13
- "husky": {
14
- "hooks": {
15
- "pre-commit": "npm run commit-ready",
16
- "pre-push": "npm run test"
17
- }
18
- },
19
- "keywords": [
20
- "mimik",
21
- "microservice"
22
- ],
23
- "author": "mimik",
24
- "license": "Apache-2.0",
25
- "repository": {
26
- "type": "git",
27
- "url": "https://bitbucket.org/mimiktech/init"
28
- },
29
- "dependencies": {
30
- "@mimik/address-helper": "1.3.0",
31
- "@mimik/cluster": "2.1.1",
32
- "@mimik/event-helper": "1.1.1",
33
- "@mimik/healthcheck": "1.4.1",
34
- "@mimik/oauth-helper": "1.6.1",
35
- "@mimik/public-helper": "1.3.1",
36
- "@mimik/response-helper": "2.2.1",
37
- "@mimik/sumologic-winston-logger": "1.3.0",
38
- "@mimik/swagger-helper": "2.1.1",
39
- "bluebird": "3.7.1",
40
- "cors": "2.8.5",
41
- "helmet": "3.21.2",
42
- "swagger-tools": "0.10.4"
43
- },
44
- "devDependencies": {
45
- "eslint": "6.6.0",
46
- "eslint-config-airbnb": "18.0.1",
47
- "eslint-plugin-import": "2.18.2",
48
- "eslint-plugin-jsx-a11y": "6.2.3",
49
- "eslint-plugin-react": "7.16.0",
50
- "eslint-plugin-react-hooks": "2.2.0",
51
- "fancy-log": "1.3.3",
52
- "gulp": "4.0.2",
53
- "gulp-eslint": "6.0.0",
54
- "gulp-git": "2.9.0",
55
- "husky": "3.0.9",
56
- "jsdoc-to-markdown": "5.0.2"
57
- }
58
- }