@apolitical/server 2.4.2-beta.0 → 2.5.0-rc.2

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 CHANGED
@@ -5,13 +5,17 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.5.0] - 2022-05-06
9
+ ### Added
10
+ - Custom `livenessCheck` to define liveness externally
11
+
8
12
  ## [2.4.2] - 2022-03-03
9
13
  ### Bumped
10
14
  - Version number for testing
11
15
 
12
16
  ## [2.4.1] - 2022-03-02
13
17
  ### Changed
14
- - Update authorisation middleware to include authentication check in cases where we would like to protect endpoints
18
+ - Update authorisation middleware to include req.user check in cases where we would like to protect endpoints
15
19
 
16
20
  ## [2.4.0] - 2022-02-22
17
21
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apolitical/server",
3
- "version": "2.4.2-beta.0",
3
+ "version": "2.5.0-rc.2",
4
4
  "description": "Node.js module to encapsulate Apolitical's express server setup",
5
5
  "author": "Apolitical Group Limited <engineering@apolitical.co>",
6
6
  "license": "MIT",
@@ -26,41 +26,41 @@
26
26
  "dependencies": {
27
27
  "@apolitical/logger": "2.0.1",
28
28
  "@cloudnative/health-connect": "2.1.0",
29
- "awilix": "6.1.0",
30
- "body-parser": "1.19.1",
29
+ "awilix": "7.0.3",
30
+ "body-parser": "1.20.0",
31
31
  "compression": "1.7.4",
32
32
  "cookie-parser": "1.4.6",
33
33
  "cors": "2.8.5",
34
- "dotenv": "15.0.0",
35
- "express": "4.17.2",
36
- "express-jwt": "6.1.0",
34
+ "dotenv": "16.0.0",
35
+ "express": "4.18.1",
36
+ "express-jwt": "7.7.0",
37
37
  "http-status-codes": "2.2.0",
38
- "http-terminator": "3.0.4",
39
- "jsrsasign": "10.5.1",
40
- "jwks-rsa": "2.0.5",
38
+ "http-terminator": "3.2.0",
39
+ "jsrsasign": "10.5.20",
40
+ "jwks-rsa": "2.1.1",
41
41
  "jwt-decode": "3.1.2",
42
42
  "morgan": "1.10.0",
43
43
  "passport": "0.5.2",
44
44
  "passport-jwt": "4.0.0",
45
- "prerender-node": "3.4.1",
45
+ "prerender-node": "3.5.0",
46
46
  "swagger-ui-express": "4.3.0"
47
47
  },
48
48
  "devDependencies": {
49
- "@apolitical/eslint-config": "1.0.2",
49
+ "@apolitical/eslint-config": "2.0.0",
50
50
  "@apolitical/testing": "1.0.2",
51
- "audit-ci": "5.1.2",
52
- "husky": "7.0.4",
53
- "jest": "27.4.7",
54
- "jest-junit": "13.0.0",
55
- "lint-staged": "12.3.2",
56
- "mock-jwks": "1.0.1",
57
- "nock": "13.2.2"
51
+ "audit-ci": "6.2.0",
52
+ "husky": "8.0.0",
53
+ "jest": "28.1.0",
54
+ "jest-junit": "13.2.0",
55
+ "lint-staged": "12.4.1",
56
+ "mock-jwks": "1.0.3",
57
+ "nock": "13.2.4"
58
58
  },
59
59
  "engines": {
60
60
  "node": ">=16.13.0"
61
61
  },
62
62
  "eslintConfig": {
63
- "extends": "@apolitical/eslint-config/base.config"
63
+ "extends": "@apolitical/eslint-config/api.config"
64
64
  },
65
65
  "prettier": "@apolitical/eslint-config/prettier.config",
66
66
  "jest": {
package/src/config.js CHANGED
@@ -3,7 +3,7 @@
3
3
  const { NODE_ENV, LOG_LEVEL } = process.env;
4
4
 
5
5
  const NAME = 'apolitical-server';
6
- const VERSION = '2.4.2';
6
+ const VERSION = '2.5.0';
7
7
  const ADMIN_ROLE = 'administrator';
8
8
 
9
9
  module.exports = {
@@ -18,6 +18,7 @@ module.exports = {
18
18
  },
19
19
  ENDPOINTS: {
20
20
  PROBES: {
21
+ HEALTH: '/health',
21
22
  LIVENESS: '/liveness',
22
23
  READINESS: '/readiness',
23
24
  },
package/src/container.js CHANGED
@@ -34,6 +34,7 @@ const jwtPassportHelper = require('./helpers/jwt/passport.helper');
34
34
  const loggerHelper = require('./helpers/logger.helper');
35
35
  // Loaders
36
36
  const documentationLoader = require('./loaders/documentation.loader');
37
+ const expressLoader = require('./loaders/express.loader');
37
38
  const loggerLoader = require('./loaders/logger.loader');
38
39
  const middlewaresLoader = require('./loaders/middlewares.loader');
39
40
  const probesLoader = require('./loaders/probes.loader');
@@ -45,6 +46,8 @@ const jwtApoliticalMiddleware = require('./middlewares/jwt/apolitical.middleware
45
46
  const jwtAuth0Middleware = require('./middlewares/jwt/auth0.middleware');
46
47
  const errorMiddleware = require('./middlewares/error.middleware');
47
48
  // Services
49
+ const expressService = require('./services/express.service');
50
+ const healthService = require('./services/health.service');
48
51
  const jwtService = require('./services/jwt.service');
49
52
  const serverService = require('./services/server.service');
50
53
 
@@ -84,6 +87,7 @@ container.register({
84
87
  loggerHelper: asFunction(loggerHelper).singleton(),
85
88
  // Loaders
86
89
  documentationLoader: asFunction(documentationLoader).singleton(),
90
+ expressLoader: asFunction(expressLoader).singleton(),
87
91
  loggerLoader: asFunction(loggerLoader).singleton(),
88
92
  middlewaresLoader: asFunction(middlewaresLoader).singleton(),
89
93
  probesLoader: asFunction(probesLoader).singleton(),
@@ -95,6 +99,8 @@ container.register({
95
99
  jwtAuth0Middleware: asFunction(jwtAuth0Middleware).singleton(),
96
100
  errorMiddleware: asFunction(errorMiddleware).singleton(),
97
101
  // Services
102
+ expressService: asFunction(expressService).singleton(),
103
+ healthService: asFunction(healthService).singleton(),
98
104
  jwtService: asFunction(jwtService).singleton(),
99
105
  serverService: asFunction(serverService).singleton(),
100
106
  });
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ module.exports = ({
4
+ logger,
5
+ documentationLoader,
6
+ loggerLoader,
7
+ errorMiddleware,
8
+ middlewaresLoader,
9
+ probesLoader,
10
+ fallbackLoader,
11
+ }) => {
12
+ // Main (express) loader
13
+ return async function load(app, opts) {
14
+ const childLogger = logger.where(__filename, 'load');
15
+ childLogger.debug('Started');
16
+ // Load probes
17
+ probesLoader(app, opts);
18
+ // Load useful middlewares
19
+ middlewaresLoader(app, opts);
20
+ // Load logger
21
+ await loggerLoader(app, opts);
22
+ // Load custom resources
23
+ if (opts.appLoader) {
24
+ await opts.appLoader(app);
25
+ }
26
+ // Load documentation
27
+ documentationLoader(app, opts);
28
+ // Load fallback routing
29
+ fallbackLoader(app, opts);
30
+ // Use error handler
31
+ if (opts.handleErrors) {
32
+ app.use(errorMiddleware(opts));
33
+ }
34
+ childLogger.debug('Finished');
35
+ };
36
+ };
@@ -1,16 +1,22 @@
1
1
  'use strict';
2
2
 
3
- module.exports = ({ health, config, logger }) => {
4
- const { LIVENESS, READINESS } = config.ENDPOINTS.PROBES;
3
+ module.exports = ({ config, logger, healthService }) => {
4
+ const { HEALTH, LIVENESS, READINESS } = config.ENDPOINTS.PROBES;
5
5
 
6
- return function load(app) {
6
+ return function load(app, { readinessCheck, livenessCheck }) {
7
7
  const childLogger = logger.where(__filename, 'load');
8
8
  childLogger.debug('Started');
9
- // Setup health checker
10
- const healthCheck = new health.HealthChecker();
9
+ // Overwrite checks when defined
10
+ if (readinessCheck) {
11
+ healthService.registerReadiness(readinessCheck);
12
+ }
13
+ if (livenessCheck) {
14
+ healthService.registerLiveness(livenessCheck);
15
+ }
11
16
  // Load probes endpoints
12
- app.get(LIVENESS, health.LivenessEndpoint(healthCheck));
13
- app.get(READINESS, health.ReadinessEndpoint(healthCheck));
17
+ app.get(HEALTH, healthService.healthEndpoint());
18
+ app.get(READINESS, healthService.readinessEndpoint());
19
+ app.get(LIVENESS, healthService.livenessEndpoint());
14
20
  childLogger.debug('Finished');
15
21
  };
16
22
  };
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- module.exports = ({ expressJwt, jwksRsa, config }) => {
3
+ module.exports = ({ expressJwt: { expressjwt: jwt }, jwksRsa, config }) => {
4
4
  const { CACHE, RATE_LIMIT, RPM, URI, ALGORITHMS } = config.JWT.AUTH0;
5
- // Express JWT authentication (Auth0)
5
+ // Define express JWT authentication (Auth0)
6
6
  return function handler({ domain, audience, issuer }) {
7
- return expressJwt({
7
+ return jwt({
8
8
  secret: jwksRsa.expressJwtSecret({
9
9
  cache: CACHE,
10
10
  rateLimit: RATE_LIMIT,
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ module.exports = ({ express, httpTerminator, logger, expressLoader }) => {
4
+ let app = null;
5
+ let terminator = null; // I need your clothes, your boots and your motorcycle
6
+
7
+ function expressRunner(app, port) {
8
+ const childLogger = logger.where(__filename, 'expressRunner');
9
+ childLogger.debug('Started');
10
+ return new Promise((resolve, reject) => {
11
+ if (!port) {
12
+ childLogger.warn('Missing port option');
13
+ return reject(new Error('Cannot start server without port option'));
14
+ }
15
+ const server = app.listen(port, () => {
16
+ childLogger.info(`Server listening on ${port}`);
17
+ return resolve();
18
+ });
19
+ terminator = httpTerminator.createHttpTerminator({ server });
20
+ childLogger.debug('Finished');
21
+ });
22
+ }
23
+
24
+ async function startup(opts) {
25
+ const childLogger = logger.where(__filename, 'startup');
26
+ childLogger.debug('Started');
27
+ // Create, load and run the express app
28
+ if (!app) {
29
+ app = express();
30
+ await expressLoader(app, opts);
31
+ await expressRunner(app, opts.port);
32
+ }
33
+ childLogger.debug('Finished');
34
+ return app;
35
+ }
36
+
37
+ async function shutdown() {
38
+ const childLogger = logger.where(__filename, 'shutdown');
39
+ childLogger.debug('Started');
40
+ // Terminate process and clean-up variables
41
+ await terminator.terminate();
42
+ app = null;
43
+ terminator = null;
44
+ childLogger.debug('Finished');
45
+ }
46
+
47
+ return { startup, shutdown };
48
+ };
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ module.exports = ({ health }) => {
4
+ // Setup health checker
5
+ const healthCheck = new health.HealthChecker();
6
+
7
+ // function registerStartup(startup) {
8
+ // healthCheck.registerStartupCheck(new health.StartupCheck("Startup Check", startup));
9
+ // }
10
+
11
+ function healthEndpoint() {
12
+ return health.HealthEndpoint(healthCheck);
13
+ }
14
+
15
+ function registerReadiness(readiness) {
16
+ healthCheck.registerReadinessCheck(new health.ReadinessCheck('Readiness Check', readiness));
17
+ }
18
+
19
+ function readinessEndpoint() {
20
+ return health.ReadinessEndpoint(healthCheck);
21
+ }
22
+
23
+ function registerLiveness(liveness) {
24
+ healthCheck.registerLivenessCheck(new health.LivenessCheck('Liveness Check', liveness));
25
+ }
26
+
27
+ function livenessEndpoint() {
28
+ return health.LivenessEndpoint(healthCheck);
29
+ }
30
+
31
+ function registerShutdown(shutdown) {
32
+ healthCheck.registerShutdownCheck(new health.ShutdownCheck('Shutdown Check', shutdown));
33
+ }
34
+
35
+ return { healthEndpoint, readinessEndpoint, registerReadiness, registerLiveness, livenessEndpoint, registerShutdown };
36
+ };
@@ -1,75 +1,19 @@
1
1
  'use strict';
2
2
 
3
3
  module.exports = ({
4
- express,
5
- httpTerminator,
6
- logger,
7
- documentationLoader,
8
- loggerLoader,
9
4
  authenticationMiddleware,
10
5
  authorisationMiddleware,
11
- errorMiddleware,
12
- middlewaresLoader,
13
- probesLoader,
14
- fallbackLoader,
6
+ expressService: { startup, shutdown },
7
+ healthService: { registerShutdown },
15
8
  jwtService,
16
9
  serverError,
17
10
  }) => {
18
- let terminator = null; // I need your clothes, your boots and your motorcycle.
19
-
20
- function run(app, port) {
21
- const childLogger = logger.where(__filename, 'run');
22
- childLogger.debug('Started');
23
- return new Promise((resolve, reject) => {
24
- if (!port) {
25
- childLogger.warn('Missing port option');
26
- return reject(new Error('Cannot start server without port option'));
27
- }
28
- const server = app.listen(port, () => {
29
- childLogger.info(`Server listening on ${port}`);
30
- return resolve();
31
- });
32
- terminator = httpTerminator.createHttpTerminator({ server });
33
- childLogger.debug('Finished');
34
- });
35
- }
11
+ // Register shutdown to clean up any resources used by the express app
12
+ registerShutdown(shutdown);
36
13
 
37
14
  return {
38
- async start(opts) {
39
- const childLogger = logger.where(__filename, 'start');
40
- childLogger.debug('Started');
41
- // Create Express server
42
- const app = express();
43
- // Load probes
44
- probesLoader(app);
45
- // Load useful middlewares
46
- middlewaresLoader(app, opts);
47
- // Load logger
48
- await loggerLoader(app, opts);
49
- // Load custom resources
50
- if (opts.appLoader) {
51
- await opts.appLoader(app);
52
- }
53
- // Load documentation
54
- documentationLoader(app, opts);
55
- // Load fallback routing
56
- fallbackLoader(app, opts);
57
- // Use error handler
58
- if (opts.handleErrors) {
59
- app.use(errorMiddleware(opts));
60
- }
61
- // Run the server
62
- await run(app, opts.port);
63
- childLogger.debug('Finished');
64
- return app;
65
- },
66
- async stop() {
67
- const childLogger = logger.where(__filename, 'stop');
68
- childLogger.debug('Started');
69
- // Terminate server process
70
- await terminator.terminate();
71
- childLogger.debug('Finished');
72
- },
15
+ start: startup,
16
+ stop: shutdown,
73
17
  jwt: jwtService,
74
18
  errors: serverError,
75
19
  middlewares: {