node-server-engine 1.4.8 → 1.5.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 (261) hide show
  1. package/.commitlintrc.js +27 -0
  2. package/.releaserc.js +56 -0
  3. package/README.md +154 -2
  4. package/dist/const/tokenIssuer.js +1 -0
  5. package/dist/const/tokenIssuer.js.map +1 -1
  6. package/dist/db/models/SequelizeMeta.js +3 -1
  7. package/dist/db/models/SequelizeMeta.js.map +1 -1
  8. package/dist/entities/ElasticSearch/ElasticSearch.js +1 -2
  9. package/dist/entities/ElasticSearch/ElasticSearch.js.map +1 -1
  10. package/dist/entities/SocketClient/SocketClient.js +1 -0
  11. package/dist/entities/SocketClient/SocketClient.js.map +1 -1
  12. package/dist/index.js +1 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/middleware/checkPermission/checkPermission.d.ts +1 -1
  15. package/dist/middleware/checkPermission/checkPermission.js +4 -2
  16. package/dist/middleware/checkPermission/checkPermission.js.map +1 -1
  17. package/dist/utils/createHttpServer/createHttpServer.js +1 -1
  18. package/dist/utils/createHttpServer/createHttpServer.js.map +1 -1
  19. package/dist/utils/jwt/jwt.js +1 -1
  20. package/dist/utils/jwt/jwt.js.map +1 -1
  21. package/dist/utils/semverCompare/semverCompare.js +1 -5
  22. package/dist/utils/semverCompare/semverCompare.js.map +1 -1
  23. package/package.json +30 -19
  24. package/.env.example +0 -186
  25. package/.github/workflows/publish.yml +0 -41
  26. package/.prettierrc +0 -7
  27. package/Dockerfile +0 -31
  28. package/babel.config.json +0 -34
  29. package/eslint.config.mjs +0 -11
  30. package/src/const/DebeziumEvent.ts +0 -6
  31. package/src/const/LogSeverity.ts +0 -7
  32. package/src/const/index.ts +0 -5
  33. package/src/const/metrics.ts +0 -6
  34. package/src/const/mime.ts +0 -37
  35. package/src/const/tokenIssuer.ts +0 -7
  36. package/src/db/migrations/20241030121500-create-sequelize-meta-table.ts +0 -29
  37. package/src/db/models/SequelizeMeta.ts +0 -16
  38. package/src/db/models/index.ts +0 -2
  39. package/src/entities/ElasticSearch/ElasticSearch.ts +0 -103
  40. package/src/entities/ElasticSearch/ElasticSearch.types.ts +0 -7
  41. package/src/entities/ElasticSearch/index.ts +0 -2
  42. package/src/entities/Endpoint/Endpoint.test.ts +0 -248
  43. package/src/entities/Endpoint/Endpoint.ts +0 -221
  44. package/src/entities/Endpoint/Endpoint.types.ts +0 -181
  45. package/src/entities/Endpoint/index.ts +0 -2
  46. package/src/entities/EngineError/EngineError.ts +0 -28
  47. package/src/entities/EngineError/EngineError.types.ts +0 -15
  48. package/src/entities/EngineError/index.ts +0 -2
  49. package/src/entities/KeySet/KeySet.test.ts +0 -126
  50. package/src/entities/KeySet/KeySet.ts +0 -172
  51. package/src/entities/KeySet/KeySet.types.ts +0 -28
  52. package/src/entities/KeySet/index.ts +0 -2
  53. package/src/entities/LifecycleController/LifecycleController.test.ts +0 -48
  54. package/src/entities/LifecycleController/LifecycleController.ts +0 -24
  55. package/src/entities/LifecycleController/LifecycleController.types.ts +0 -5
  56. package/src/entities/LifecycleController/index.ts +0 -2
  57. package/src/entities/Localizator/Localizator.ts +0 -139
  58. package/src/entities/Localizator/Localizator.types.ts +0 -52
  59. package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.test.ts +0 -165
  60. package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.ts +0 -58
  61. package/src/entities/Localizator/guessNamingConvention/index.ts +0 -1
  62. package/src/entities/Localizator/index.ts +0 -2
  63. package/src/entities/MessageHandler/MessageHandler.test.ts +0 -130
  64. package/src/entities/MessageHandler/MessageHandler.ts +0 -72
  65. package/src/entities/MessageHandler/MessageHandler.types.ts +0 -15
  66. package/src/entities/MessageHandler/index.ts +0 -2
  67. package/src/entities/PubSub/PubSub.test.ts +0 -297
  68. package/src/entities/PubSub/PubSub.ts +0 -202
  69. package/src/entities/PubSub/PubSub.types.ts +0 -76
  70. package/src/entities/PubSub/handleMessage/handleMessage.test.ts +0 -102
  71. package/src/entities/PubSub/handleMessage/handleMessage.ts +0 -65
  72. package/src/entities/PubSub/handleMessage/index.ts +0 -1
  73. package/src/entities/PubSub/index.ts +0 -2
  74. package/src/entities/PushNotification/PushNotification.test.ts +0 -35
  75. package/src/entities/PushNotification/PushNotification.ts +0 -44
  76. package/src/entities/PushNotification/PushNotification.types.ts +0 -25
  77. package/src/entities/PushNotification/index.ts +0 -2
  78. package/src/entities/Redis/Redis.ts +0 -71
  79. package/src/entities/Redis/Redis.types.ts +0 -19
  80. package/src/entities/Redis/Redis.validate.ts +0 -17
  81. package/src/entities/Redis/index.ts +0 -2
  82. package/src/entities/Sequelize/Sequelize.config.ts +0 -59
  83. package/src/entities/Sequelize/Sequelize.test.ts +0 -21
  84. package/src/entities/Sequelize/Sequelize.ts +0 -75
  85. package/src/entities/Sequelize/Sequelize.types.ts +0 -10
  86. package/src/entities/Sequelize/Sequelize.validate.ts +0 -15
  87. package/src/entities/Sequelize/index.ts +0 -2
  88. package/src/entities/Server/Server.const.ts +0 -56
  89. package/src/entities/Server/Server.test.ts +0 -272
  90. package/src/entities/Server/Server.ts +0 -471
  91. package/src/entities/Server/Server.types.ts +0 -88
  92. package/src/entities/Server/index.ts +0 -2
  93. package/src/entities/SocketClient/SocketClient.test.ts +0 -392
  94. package/src/entities/SocketClient/SocketClient.ts +0 -401
  95. package/src/entities/SocketClient/SocketClient.types.ts +0 -62
  96. package/src/entities/SocketClient/index.ts +0 -2
  97. package/src/entities/SocketClient/parseMessage/index.ts +0 -1
  98. package/src/entities/SocketClient/parseMessage/parseMessage.test.ts +0 -20
  99. package/src/entities/SocketClient/parseMessage/parseMessage.ts +0 -26
  100. package/src/entities/Storage/Storage.test.ts +0 -58
  101. package/src/entities/Storage/Storage.ts +0 -219
  102. package/src/entities/Storage/Storage.types.ts +0 -57
  103. package/src/entities/Storage/index.ts +0 -2
  104. package/src/entities/ValidationError/ValidationError.ts +0 -34
  105. package/src/entities/ValidationError/index.ts +0 -1
  106. package/src/entities/WebError/WebError.test.ts +0 -18
  107. package/src/entities/WebError/WebError.ts +0 -23
  108. package/src/entities/WebError/WebError.types.ts +0 -9
  109. package/src/entities/WebError/index.ts +0 -2
  110. package/src/entities/index.ts +0 -16
  111. package/src/index.ts +0 -6
  112. package/src/metrics/debug.ts +0 -10
  113. package/src/metrics/index.ts +0 -2
  114. package/src/metrics/request.ts +0 -17
  115. package/src/middleware/authHmac/authHmac.test.ts +0 -86
  116. package/src/middleware/authHmac/authHmac.ts +0 -56
  117. package/src/middleware/authHmac/authHmac.types.ts +0 -7
  118. package/src/middleware/authHmac/index.ts +0 -2
  119. package/src/middleware/authJwt/authJwt.test.ts +0 -54
  120. package/src/middleware/authJwt/authJwt.ts +0 -55
  121. package/src/middleware/authJwt/authJwt.types.ts +0 -14
  122. package/src/middleware/authJwt/index.ts +0 -2
  123. package/src/middleware/authStatic/authStatic.test.ts +0 -36
  124. package/src/middleware/authStatic/authStatic.ts +0 -45
  125. package/src/middleware/authStatic/index.ts +0 -1
  126. package/src/middleware/authTls/authTls.test.ts +0 -138
  127. package/src/middleware/authTls/authTls.ts +0 -119
  128. package/src/middleware/authTls/authTls.types.ts +0 -13
  129. package/src/middleware/authTls/index.ts +0 -2
  130. package/src/middleware/checkPermission/checkPermission.ts +0 -33
  131. package/src/middleware/checkPermission/index.ts +0 -1
  132. package/src/middleware/error/error.test.ts +0 -60
  133. package/src/middleware/error/error.ts +0 -25
  134. package/src/middleware/error/index.ts +0 -1
  135. package/src/middleware/fileUploader/fileUploader.ts +0 -154
  136. package/src/middleware/fileUploader/fileUploader.types.ts +0 -35
  137. package/src/middleware/fileUploader/index.ts +0 -2
  138. package/src/middleware/fileUploader/isMultiPart/index.ts +0 -1
  139. package/src/middleware/fileUploader/isMultiPart/isMultipart.ts +0 -9
  140. package/src/middleware/fileUploader/validate/index.ts +0 -1
  141. package/src/middleware/fileUploader/validate/validate.ts +0 -27
  142. package/src/middleware/fourOhFour/fourOhFour.test.ts +0 -14
  143. package/src/middleware/fourOhFour/fourOhFour.ts +0 -13
  144. package/src/middleware/fourOhFour/index.ts +0 -1
  145. package/src/middleware/geminiFileUploader/geminiFileUploader.ts +0 -68
  146. package/src/middleware/geminiFileUploader/index.ts +0 -1
  147. package/src/middleware/healthCheck/healthCheck.test.ts +0 -12
  148. package/src/middleware/healthCheck/healthCheck.ts +0 -14
  149. package/src/middleware/healthCheck/index.ts +0 -1
  150. package/src/middleware/index.ts +0 -17
  151. package/src/middleware/metrics/index.ts +0 -1
  152. package/src/middleware/metrics/metrics.test.ts +0 -46
  153. package/src/middleware/metrics/metrics.ts +0 -24
  154. package/src/middleware/multiPartFileUploader/index.ts +0 -2
  155. package/src/middleware/multiPartFileUploader/multiPartFileUploader.ts +0 -249
  156. package/src/middleware/multiPartFileUploader/multiPartFileUploader.types.ts +0 -23
  157. package/src/middleware/multiPartFileUploader/validate/index.ts +0 -1
  158. package/src/middleware/multiPartFileUploader/validate/validate.ts +0 -27
  159. package/src/middleware/requestMetrics/index.ts +0 -1
  160. package/src/middleware/requestMetrics/requestMetrics.test.ts +0 -77
  161. package/src/middleware/requestMetrics/requestMetrics.ts +0 -20
  162. package/src/middleware/swaggerDocs/index.ts +0 -2
  163. package/src/middleware/swaggerDocs/swaggerDocs.ts +0 -114
  164. package/src/middleware/swaggerDocs/swaggerDocs.types.ts +0 -41
  165. package/src/middleware/userResolver/index.ts +0 -1
  166. package/src/middleware/userResolver/userResolver.ts +0 -53
  167. package/src/middleware/validate/index.ts +0 -1
  168. package/src/middleware/validate/validate.test.ts +0 -43
  169. package/src/middleware/validate/validate.ts +0 -25
  170. package/src/middleware/version/index.ts +0 -1
  171. package/src/middleware/version/version.test.ts +0 -23
  172. package/src/middleware/version/version.ts +0 -12
  173. package/src/utils/checkEnvironment/index.ts +0 -49
  174. package/src/utils/createHttpServer/createHttpServer.test.ts +0 -24
  175. package/src/utils/createHttpServer/createHttpServer.ts +0 -34
  176. package/src/utils/createHttpServer/createHttpServer.validate.ts +0 -17
  177. package/src/utils/createHttpServer/index.ts +0 -1
  178. package/src/utils/createSortedObject/createSortedObject.ts +0 -20
  179. package/src/utils/createSortedObject/createSortedObjet.test.ts +0 -47
  180. package/src/utils/createSortedObject/index.ts +0 -1
  181. package/src/utils/dbMigration/dbMigration.test.ts +0 -209
  182. package/src/utils/dbMigration/dbMigration.ts +0 -199
  183. package/src/utils/dbMigration/dbMigration.types.ts +0 -11
  184. package/src/utils/dbMigration/index.ts +0 -2
  185. package/src/utils/dbMigration/migrateMetadataTable/index.ts +0 -1
  186. package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.test.ts +0 -59
  187. package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.ts +0 -102
  188. package/src/utils/envAssert/envAssert.ts +0 -31
  189. package/src/utils/envAssert/index.ts +0 -1
  190. package/src/utils/envAssert/validators/hostList.ts +0 -17
  191. package/src/utils/envAssert/validators/index.ts +0 -5
  192. package/src/utils/envAssert/validators/ipList.ts +0 -13
  193. package/src/utils/envAssert/validators/path.ts +0 -13
  194. package/src/utils/envAssert/validators/string.ts +0 -9
  195. package/src/utils/envAssert/validators/stringList.ts +0 -13
  196. package/src/utils/filter/filter.ts +0 -17
  197. package/src/utils/filter/index.ts +0 -1
  198. package/src/utils/geminiFileUpload/geminiFileUpload.ts +0 -93
  199. package/src/utils/geminiFileUpload/index.ts +0 -1
  200. package/src/utils/hmac/checkEnv/checkEnv.test.ts +0 -18
  201. package/src/utils/hmac/checkEnv/checkEnv.ts +0 -9
  202. package/src/utils/hmac/checkEnv/index.ts +0 -1
  203. package/src/utils/hmac/createHmac/createHmac.ts +0 -33
  204. package/src/utils/hmac/createHmac/index.ts +0 -1
  205. package/src/utils/hmac/index.ts +0 -4
  206. package/src/utils/hmac/index.types.ts +0 -13
  207. package/src/utils/hmac/signPayload/index.ts +0 -1
  208. package/src/utils/hmac/signPayload/signPayload.ts +0 -16
  209. package/src/utils/hmac/verifySignature/index.ts +0 -1
  210. package/src/utils/hmac/verifySignature/verifySignature.ts +0 -24
  211. package/src/utils/index.ts +0 -29
  212. package/src/utils/jwt/index.ts +0 -2
  213. package/src/utils/jwt/jwt.test.ts +0 -28
  214. package/src/utils/jwt/jwt.ts +0 -182
  215. package/src/utils/jwt/jwt.types.ts +0 -21
  216. package/src/utils/report/index.ts +0 -3
  217. package/src/utils/report/output.ts +0 -45
  218. package/src/utils/report/output.types.ts +0 -70
  219. package/src/utils/report/report.test.ts +0 -133
  220. package/src/utils/report/report.ts +0 -133
  221. package/src/utils/report/report.types.ts +0 -13
  222. package/src/utils/request/index.ts +0 -1
  223. package/src/utils/request/request.test.ts +0 -26
  224. package/src/utils/request/request.ts +0 -48
  225. package/src/utils/secretManager/index.ts +0 -2
  226. package/src/utils/secretManager/secretLoader.ts +0 -62
  227. package/src/utils/secretManager/secretResolver.ts +0 -35
  228. package/src/utils/semverCompare/index.ts +0 -1
  229. package/src/utils/semverCompare/semverCompare.test.ts +0 -49
  230. package/src/utils/semverCompare/semverCompare.ts +0 -60
  231. package/src/utils/sendEmail/index.ts +0 -2
  232. package/src/utils/sendEmail/sendEmail.ts +0 -61
  233. package/src/utils/sendEmail/sendEmail.types.ts +0 -61
  234. package/src/utils/sendPush/index.ts +0 -2
  235. package/src/utils/sendPush/sendPush.ts +0 -20
  236. package/src/utils/sendPush/sendPush.types.ts +0 -25
  237. package/src/utils/tlsConfig/index.ts +0 -2
  238. package/src/utils/tlsConfig/tlsConfig.test.ts +0 -32
  239. package/src/utils/tlsConfig/tlsConfig.ts +0 -47
  240. package/src/utils/tlsConfig/tlsConfig.types.ts +0 -11
  241. package/src/utils/tlsConfig/tlsConfig.validate.ts +0 -25
  242. package/src/utils/tlsRequest/index.ts +0 -1
  243. package/src/utils/tlsRequest/tlsRequest.test.ts +0 -63
  244. package/src/utils/tlsRequest/tlsRequest.ts +0 -12
  245. package/src/utils/trimPathSlash/index.ts +0 -1
  246. package/src/utils/trimPathSlash/trimPathSlash.test.ts +0 -26
  247. package/src/utils/trimPathSlash/trimPathSlash.ts +0 -8
  248. package/test/env.ts +0 -53
  249. package/test/factory/index.ts +0 -8
  250. package/test/factory/sequelizeMeta.ts +0 -12
  251. package/test/hooks.ts +0 -35
  252. package/test/index.ts +0 -3
  253. package/test/stub/index.ts +0 -3
  254. package/test/stub/stubLocales.ts +0 -68
  255. package/test/stub/stubPubSub.ts +0 -7
  256. package/test/stub/stubStorage.ts +0 -77
  257. package/test/stub/stubStorage.types.ts +0 -11
  258. package/test/utils/app.ts +0 -31
  259. package/test/utils/index.ts +0 -1
  260. package/tsconfig.build.json +0 -5
  261. package/tsconfig.json +0 -32
@@ -1,103 +0,0 @@
1
- import { readdirSync } from 'fs';
2
- import path from 'path';
3
- import { Client } from '@elastic/elasticsearch';
4
- import { ElasticSearchMigration } from './ElasticSearch.types';
5
- import { EngineError } from 'entities/EngineError';
6
- import { LifecycleController } from 'entities/LifecycleController';
7
- import { envAssert, reportError, reportInfo } from 'utils';
8
- import { checkEnvironment } from 'utils/checkEnvironment';
9
-
10
- /** Elastic search client */
11
- let client: undefined | Client;
12
-
13
- export const ElasticSearch = {
14
- /**
15
- * Init function that should be called on server startup to establish the connection
16
- */
17
- async init(): Promise<void> {
18
- checkEnvironment({
19
- ELASTIC_SEARCH_HOST: envAssert.isString(),
20
- ELASTIC_SEARCH_USERNAME: envAssert.isString(),
21
- ELASTIC_SEARCH_PASSWORD: envAssert.isString(),
22
- ELASTIC_SEARCH_MIGRATION_PATH: envAssert.isString()
23
- });
24
-
25
- if (!process.env.ELASTIC_SEARCH_HOST)
26
- throw new EngineError({
27
- message: 'ElasticSearch Hosts not set in environment'
28
- });
29
-
30
- client = new Client({
31
- node: process.env.ELASTIC_SEARCH_HOST,
32
- auth: {
33
- username: process.env.ELASTIC_SEARCH_USERNAME as string,
34
- password: process.env.ELASTIC_SEARCH_PASSWORD as string
35
- }
36
- });
37
- // In test environment flush the database before running migrations
38
- if (process.env.NODE_ENV === 'test')
39
- await client.indices.delete({ index: '*' });
40
- await this.migrate();
41
- LifecycleController.register(this);
42
- },
43
-
44
- /**
45
- * Migration function called during the init process
46
- * Manages the database structure
47
- */
48
- async migrate(): Promise<void> {
49
- if (!client) throw new EngineError('ElasticSearch was not initialized');
50
- const migrationPath = path.resolve(
51
- process.env.ELASTIC_SEARCH_MIGRATION_PATH as string
52
- );
53
- const files = readdirSync(`${migrationPath}`);
54
- const indexExists = await client.indices.exists({
55
- index: 'migrations'
56
- });
57
- const ran = [];
58
- for (const file of files) {
59
- if (indexExists) {
60
- const {
61
- hits: { total }
62
- } = await client.search({
63
- index: 'migrations',
64
- body: { query: { match: { file } } }
65
- });
66
- let tot = 0;
67
- if (typeof total === 'number') {
68
- tot = total;
69
- } else {
70
- tot = total?.value ?? 0;
71
- }
72
- if (tot > 0) continue;
73
- }
74
- ran.push(file);
75
- const migration = (await import(
76
- `${migrationPath}/${file}`
77
- )) as ElasticSearchMigration;
78
- try {
79
- await migration.migrate(client);
80
- } catch (error) {
81
- reportError(error);
82
- process.exit(1);
83
- }
84
-
85
- await client.create({
86
- index: 'migrations',
87
- id: file,
88
- body: { file, ranAt: new Date() }
89
- });
90
- }
91
- reportInfo({
92
- message: `ElasticSearch: ran ${ran.length} migrations`,
93
- data: { files: ran }
94
- });
95
- },
96
-
97
- /**
98
- * Shutdown function that should be called on server stop to close the connection
99
- */
100
- async shutdown(): Promise<void> {
101
- if (client) await client.close();
102
- }
103
- };
@@ -1,7 +0,0 @@
1
- import { Client } from '@elastic/elasticsearch';
2
-
3
- /** Represents a migration that should be executed on ElasticSearch */
4
- export interface ElasticSearchMigration {
5
- /** Migration function */
6
- migrate: (client: Client) => Promise<void>;
7
- }
@@ -1,2 +0,0 @@
1
- export * from './ElasticSearch';
2
- export * from './ElasticSearch.types';
@@ -1,248 +0,0 @@
1
- import { randomUUID } from 'crypto';
2
- import { generateAccessToken } from 'backend-test-tools';
3
- import { expect } from 'chai';
4
- import express, { Request, Response, NextFunction } from 'express';
5
- import { faker } from '@faker-js/faker';
6
- import { fake } from 'sinon';
7
- import request from 'supertest';
8
- import { Endpoint } from './Endpoint';
9
- import {
10
- EndpointMethod,
11
- EndpointAuthType,
12
- EndpointOptions
13
- } from './Endpoint.types';
14
- import { Server } from 'entities/Server';
15
- import { request as httpRequest } from 'utils/request';
16
- import { tlsRequest } from 'utils/tlsRequest';
17
-
18
- const PATH = '/test';
19
- let app = express();
20
-
21
- const config: EndpointOptions<EndpointAuthType.NONE> = {
22
- method: EndpointMethod.GET,
23
- path: PATH,
24
- handler: (req: Request, res: Response) => {
25
- res.sendStatus(200);
26
- },
27
- validator: {},
28
- authType: EndpointAuthType.NONE
29
- };
30
-
31
- describe('Entity - Endpoint', () => {
32
- beforeEach(() => {
33
- app = express();
34
- });
35
-
36
- // Base
37
-
38
- it('should create a valid Endpoint', async () => {
39
- const endpoint = new Endpoint(config);
40
- endpoint.register(app);
41
- await request(app).get(PATH).expect(200);
42
- });
43
-
44
- // Async
45
-
46
- it('should handle asynchronous errors', async () => {
47
- const endpoint = new Endpoint({
48
- ...config,
49
- handler: async (): Promise<void> => {
50
- return new Promise((resolve, reject) => {
51
- reject(new Error());
52
- });
53
- }
54
- });
55
- endpoint.register(app);
56
- await request(app).get(PATH).expect(500);
57
- });
58
-
59
- // Middleware
60
-
61
- it('should handle specific middleware', async () => {
62
- const middleware = fake(
63
- (req: Request, res: Response, next: NextFunction) => {
64
- next();
65
- }
66
- );
67
- const endpoint = new Endpoint({
68
- ...config,
69
- middleware: [middleware]
70
- });
71
- endpoint.register(app);
72
- await request(app).get(PATH).expect(200);
73
- expect(middleware).to.have.been.called;
74
- });
75
-
76
- it('should handle specific error middleware', async () => {
77
- const middleware = fake(
78
- (err: Error, req: Request, res: Response, next: NextFunction) => {
79
- res.sendStatus(200);
80
- }
81
- );
82
- const endpoint = new Endpoint({
83
- ...config,
84
- handler: (): void => {
85
- throw new Error();
86
- },
87
- errorMiddleware: [middleware]
88
- });
89
- endpoint.register(app);
90
- await request(app).get(PATH).expect(200);
91
- expect(middleware).to.have.been.called;
92
- });
93
-
94
- // Validator
95
-
96
- it('should accept request with a valid shape', async () => {
97
- const endpoint = new Endpoint({
98
- ...config,
99
- validator: { number: { in: 'query', isInt: true } }
100
- });
101
- endpoint.register(app);
102
- await request(app)
103
- .get(PATH)
104
- .query({ number: faker.number.int() })
105
- .expect(200);
106
- });
107
-
108
- it('should reject request with an invalid shape', async () => {
109
- const endpoint = new Endpoint({
110
- ...config,
111
- validator: { number: { in: 'query', isInt: true } }
112
- });
113
- endpoint.register(app);
114
- await request(app)
115
- .get(PATH)
116
- .query({ number: faker.lorem.word() })
117
- .expect(400);
118
- });
119
-
120
- // Middleware
121
- it('should inject middlewares', async () => {
122
- const middleware = fake(
123
- (req: Request, res: Response, next: NextFunction) => {
124
- next();
125
- }
126
- );
127
- const endpoint = new Endpoint({
128
- ...config,
129
- middleware
130
- });
131
- endpoint.register(app);
132
- await request(app).get(PATH).expect(200);
133
- expect(middleware.called).to.be.true;
134
- });
135
-
136
- it('should inject multiple middlewares', async () => {
137
- const middleware = [
138
- fake((req: Request, res: Response, next: NextFunction) => {
139
- next();
140
- }),
141
- fake((req: Request, res: Response, next: NextFunction) => {
142
- next();
143
- })
144
- ];
145
- const endpoint = new Endpoint({
146
- ...config,
147
- middleware
148
- });
149
- endpoint.register(app);
150
- await request(app).get(PATH).expect(200);
151
- expect(middleware[0].called).to.be.true;
152
- expect(middleware[1].called).to.be.true;
153
- });
154
-
155
- // AUTH JWT
156
-
157
- it('it should authenticate with authJwt middleware', async () => {
158
- const id = randomUUID();
159
- const token = generateAccessToken(id);
160
- const endpoint = new Endpoint({
161
- ...config,
162
- authType: EndpointAuthType.JWT,
163
- handler: (req: Request, res: Response) => {
164
- res.sendStatus(200);
165
- }
166
- } as EndpointOptions<EndpointAuthType.JWT>);
167
- const server = new Server({ endpoints: [endpoint] });
168
-
169
- await server.init();
170
-
171
- await request(server.getApp())
172
- .get(PATH)
173
- .set('Authorization', 'Bearer ' + token)
174
- .expect(200);
175
-
176
- await server.shutdown();
177
- });
178
-
179
- it('it should reject if the user has no valid JWT', async () => {
180
- const endpoint = new Endpoint({
181
- ...config,
182
- authType: EndpointAuthType.JWT,
183
- handler: (req: Request, res: Response) => {
184
- res.sendStatus(200);
185
- }
186
- } as EndpointOptions<EndpointAuthType.JWT>);
187
- endpoint.register(app);
188
- await request(app).get(PATH).expect(401);
189
- });
190
-
191
- it('it should not trigger JWT error if acceptInvalid is set', async () => {
192
- const endpoint = new Endpoint({
193
- ...config,
194
- authType: EndpointAuthType.JWT,
195
- authParams: { acceptInvalid: true },
196
- handler: (req: Request, res: Response) => {
197
- res.sendStatus(200);
198
- }
199
- } as EndpointOptions<EndpointAuthType.JWT>);
200
- endpoint.register(app);
201
- await request(app).get(PATH).expect(200);
202
- });
203
-
204
- // TLS
205
- it('it should authenticate with authTLS middleware', async () => {
206
- const endpoint = new Endpoint({
207
- ...config,
208
- authType: EndpointAuthType.TLS,
209
- handler: (req: Request, res: Response) => {
210
- res.sendStatus(200);
211
- }
212
- } as EndpointOptions<EndpointAuthType.TLS>);
213
- const server = new Server({ endpoints: [endpoint] });
214
-
215
- await server.init();
216
-
217
- await expect(
218
- tlsRequest({
219
- method: 'get',
220
- url: `https://127.0.0.1:${process.env.PORT as string}${PATH}`
221
- })
222
- ).to.not.be.rejected;
223
-
224
- await server.shutdown();
225
- });
226
-
227
- it('it should reject if the user has no valid TLS credentials', async () => {
228
- const endpoint = new Endpoint({
229
- ...config,
230
- authType: EndpointAuthType.TLS,
231
- handler: (req: Request, res: Response) => {
232
- res.sendStatus(200);
233
- }
234
- } as EndpointOptions<EndpointAuthType.TLS>);
235
- const server = new Server({ endpoints: [endpoint] });
236
-
237
- await server.init();
238
-
239
- await expect(
240
- httpRequest({
241
- method: 'get',
242
- url: `https://127.0.0.1:${process.env.PORT as string}${PATH}`
243
- })
244
- ).to.be.rejected;
245
-
246
- await server.shutdown();
247
- });
248
- });
@@ -1,221 +0,0 @@
1
- import {
2
- RequestHandler,
3
- ErrorRequestHandler,
4
- Application,
5
- Request,
6
- Response,
7
- NextFunction
8
- } from 'express';
9
- import { Schema } from 'express-validator';
10
- import { EngineError } from '../EngineError';
11
- import {
12
- EndpointOptions,
13
- EndpointAuthType,
14
- EndpointAuthTypes,
15
- EndpointMethod,
16
- EndpointMethods,
17
- EndpointAuthParams,
18
- Middleware,
19
- MiddlewareChainElement,
20
- SafeMiddleWareChain,
21
- EndpointAuthHandlers,
22
- EndpointAuthHandler,
23
- EndpointRequestType,
24
- EndpointHandler
25
- } from './Endpoint.types';
26
- import { LogSeverity } from 'const';
27
- import {
28
- validate,
29
- fileUploader,
30
- requestMetrics,
31
- multiPartFileUploader
32
- } from 'middleware';
33
- import { FileUploaderConfig } from 'middleware/fileUploader';
34
- import { MultiPartFileUploaderConfig } from 'middleware/multiPartFileUploader';
35
- import { reportDebug, reportError, reportInfo } from 'utils/report';
36
-
37
- const namespace = 'engine:Endpoint';
38
-
39
- /**
40
- * Object representing a REST endpoint served by server
41
- */
42
- export class Endpoint<T extends EndpointAuthType> {
43
- /** Path at which the endpoint is reachable */
44
- public readonly path: string;
45
- /** HTTP method of the endpoint */
46
- public readonly method: EndpointMethod;
47
- /** Authentication system required by this endpoint */
48
- public readonly authType: T;
49
- /** Function handling the endpoint's business logic */
50
- private handler: EndpointHandler<T>;
51
- /** Validation schema that the request must pass before reaching the handler */
52
- private validator: Schema;
53
- /** Authentication related options for this endpoint */
54
- private authParams?: EndpointAuthParams<T>;
55
- /** Settings to upload files through this endpoint (this will automatically switch the expected request to be a multipart) */
56
- private files?: Array<FileUploaderConfig>;
57
- /** Settings to upload file parts (Chunks) through this endpoint (this will automatically switch the expected request to be a multipart) */
58
- private multiPartFile?: MultiPartFileUploaderConfig;
59
- /** Express request handlers that should run on this endpoint before the business logic, they will run after the global middleware */
60
- private middleware?: Array<Middleware<T>>;
61
- /** Express error handlers that should be registered for this endpoint. they will run before the global error handler */
62
- private errorMiddleware?: Array<ErrorRequestHandler>;
63
-
64
- /** Create a REST endpoint */
65
- public constructor(config: EndpointOptions<T>) {
66
- reportDebug({
67
- namespace,
68
- message: `Creating Endpoint [${config.method} - ${config.path}]`,
69
- data: {
70
- method: config.method,
71
- path: config.path,
72
- authType: config.authType,
73
- authParams: config.authParams,
74
- file: config.file,
75
- files: config.files,
76
- multiPartFile: config.multiPartFile
77
- }
78
- });
79
-
80
- if (typeof config.path !== 'string')
81
- throw new EngineError({
82
- message: 'Endpoint path was not declared as a string'
83
- });
84
- this.path = config.path;
85
-
86
- if (!EndpointMethods.includes(config.method))
87
- throw new EngineError({
88
- message: 'Endpoint method is not a valid HTTP method'
89
- });
90
- this.method = config.method;
91
-
92
- if (typeof config.handler !== 'function')
93
- throw new EngineError({ message: 'Endpoint handler is not a function' });
94
- this.handler = config.handler;
95
-
96
- if (!EndpointAuthTypes.includes(config.authType))
97
- throw new EngineError({ message: 'Endpoint auth type is not valid' });
98
- this.authType = config.authType;
99
-
100
- this.validator = config.validator;
101
- this.authParams = config.authParams;
102
- this.files = config.file ? [config.file] : config.files;
103
-
104
- // Middleware can both be function or arrays
105
- if (typeof config.middleware === 'function')
106
- this.middleware = [config.middleware];
107
- if (config.middleware instanceof Array) this.middleware = config.middleware;
108
- if (typeof config.errorMiddleware === 'function')
109
- this.errorMiddleware = [config.errorMiddleware];
110
- if (config.errorMiddleware instanceof Array)
111
- this.errorMiddleware = config.errorMiddleware;
112
- }
113
-
114
- /**
115
- * Register the endpoint to a react app
116
- */
117
- public register(app: Application): void {
118
- // First initialize the handling calculation
119
- const middlewareChain: Array<MiddlewareChainElement<T>> = [requestMetrics];
120
- // Register auth middleware
121
- middlewareChain.push(...this.getAuthMiddleware(this.authType));
122
- if (this.files) {
123
- // Register file upload
124
- // Validation is included in the file upload process as this uses multipart/form-data
125
- middlewareChain.push(fileUploader(this.files, this.validator));
126
- }
127
-
128
- if (this.multiPartFile) {
129
- middlewareChain.push(
130
- multiPartFileUploader(this.multiPartFile, this.validator)
131
- );
132
- }
133
-
134
- if (!this.files && !this.multiPartFile) {
135
- // Register validator for regular cases
136
- middlewareChain.push(validate(this.validator));
137
- }
138
-
139
- // Register additional middleware
140
- if (this.middleware) {
141
- middlewareChain.push(...this.middleware);
142
- }
143
- // Register handler
144
- middlewareChain.push(this.handler);
145
- // Wrap middleware to await any async execution and catch any errors thrown
146
- const safeMiddlewareChain: SafeMiddleWareChain =
147
- this.catchExceptionForExpress(middlewareChain);
148
- // Register error middleware
149
- if (this.errorMiddleware) {
150
- safeMiddlewareChain.push(...this.errorMiddleware);
151
- }
152
- app[this.method](
153
- this.path,
154
- ...(safeMiddlewareChain.flat() as Array<
155
- RequestHandler | ErrorRequestHandler
156
- >)
157
- );
158
- }
159
-
160
- /**
161
- * Catch exceptions thrown inside of middleware and pass them properly to express
162
- */
163
- private catchExceptionForExpress(
164
- middlewareChain: Array<MiddlewareChainElement<T>>
165
- ): SafeMiddleWareChain {
166
- return middlewareChain.map((middleware) => {
167
- if (middleware instanceof Array) {
168
- return this.catchExceptionForExpress(middleware);
169
- }
170
- if (typeof middleware === 'function') {
171
- return (req: Request, res: Response, next: NextFunction) => {
172
- (async (): Promise<void> => {
173
- try {
174
- await middleware(req as EndpointRequestType[T], res, next);
175
- } catch (err) {
176
- next(err);
177
- }
178
- })().catch((error) => {
179
- reportError(error);
180
- });
181
- };
182
- }
183
- throw new EngineError({
184
- message: 'Middleware is not a function nor an array',
185
- data: { type: typeof middleware }
186
- });
187
- });
188
- }
189
-
190
- /**
191
- * Get the authentication middleware for a given type of authentication
192
- */
193
- private getAuthMiddleware(authType: EndpointAuthType): Array<RequestHandler> {
194
- const middlewareChain: Array<RequestHandler> = [];
195
-
196
- const handler = EndpointAuthHandlers[authType] as EndpointAuthHandler<T>;
197
- if (!handler) {
198
- reportInfo({
199
- severity: LogSeverity.WARNING,
200
- message: `Endpoint "${this.method} - ${this.path}" was declared with no authentication method`
201
- });
202
- return [];
203
- }
204
-
205
- const middleware = handler(this.authParams);
206
-
207
- middlewareChain.push(
208
- async (request: Request, response: Response, next: NextFunction) => {
209
- try {
210
- await middleware(request, response, next);
211
- } catch (error) {
212
- if (!this.authParams?.acceptInvalid) throw error;
213
- reportError(error);
214
- next();
215
- }
216
- }
217
- );
218
-
219
- return middlewareChain;
220
- }
221
- }