node-server-engine 1.1.2 → 1.1.3

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 (469) hide show
  1. package/.env.example +193 -193
  2. package/.mocharc.js +13 -13
  3. package/.nycrc +18 -18
  4. package/.prettierrc +7 -7
  5. package/Dockerfile +30 -30
  6. package/README.md +991 -1025
  7. package/babel.config.json +35 -35
  8. package/dist/const/DebeziumEvent.js.map +1 -1
  9. package/dist/const/LogSeverity.js.map +1 -1
  10. package/dist/const/index.js.map +1 -1
  11. package/dist/const/metrics.js.map +1 -1
  12. package/dist/const/mime.js.map +1 -1
  13. package/dist/const/tokenIssuer.js.map +1 -1
  14. package/dist/db/migrations/20241030121500-create-sequelize-meta-table.js.map +1 -1
  15. package/dist/db/models/SequelizeMeta.js.map +1 -1
  16. package/dist/db/models/index.js.map +1 -1
  17. package/dist/entities/ElasticSearch/ElasticSearch.js +7 -7
  18. package/dist/entities/ElasticSearch/ElasticSearch.js.map +1 -1
  19. package/dist/entities/ElasticSearch/ElasticSearch.types.js.map +1 -1
  20. package/dist/entities/ElasticSearch/index.js.map +1 -1
  21. package/dist/entities/Endpoint/Endpoint.js +8 -8
  22. package/dist/entities/Endpoint/Endpoint.js.map +1 -1
  23. package/dist/entities/Endpoint/Endpoint.types.js.map +1 -1
  24. package/dist/entities/Endpoint/index.js.map +1 -1
  25. package/dist/entities/EngineError/EngineError.js +2 -2
  26. package/dist/entities/EngineError/EngineError.js.map +1 -1
  27. package/dist/entities/EngineError/EngineError.types.js.map +1 -1
  28. package/dist/entities/EngineError/index.js.map +1 -1
  29. package/dist/entities/KeySet/KeySet.js +3 -3
  30. package/dist/entities/KeySet/KeySet.js.map +1 -1
  31. package/dist/entities/KeySet/KeySet.types.js.map +1 -1
  32. package/dist/entities/KeySet/index.js.map +1 -1
  33. package/dist/entities/LifecycleController/LifecycleController.js.map +1 -1
  34. package/dist/entities/LifecycleController/LifecycleController.types.js.map +1 -1
  35. package/dist/entities/LifecycleController/index.js.map +1 -1
  36. package/dist/entities/Localizator/Localizator.js +7 -7
  37. package/dist/entities/Localizator/Localizator.js.map +1 -1
  38. package/dist/entities/Localizator/Localizator.types.js.map +1 -1
  39. package/dist/entities/Localizator/guessNamingConvention/guessNamingConvention.js.map +1 -1
  40. package/dist/entities/Localizator/guessNamingConvention/index.js.map +1 -1
  41. package/dist/entities/Localizator/index.js.map +1 -1
  42. package/dist/entities/MessageHandler/MessageHandler.js +2 -2
  43. package/dist/entities/MessageHandler/MessageHandler.js.map +1 -1
  44. package/dist/entities/MessageHandler/MessageHandler.types.js.map +1 -1
  45. package/dist/entities/MessageHandler/index.js.map +1 -1
  46. package/dist/entities/PubSub/PubSub.js +25 -25
  47. package/dist/entities/PubSub/PubSub.js.map +1 -1
  48. package/dist/entities/PubSub/PubSub.types.js.map +1 -1
  49. package/dist/entities/PubSub/handleMessage/handleMessage.js +6 -6
  50. package/dist/entities/PubSub/handleMessage/handleMessage.js.map +1 -1
  51. package/dist/entities/PubSub/handleMessage/index.js.map +1 -1
  52. package/dist/entities/PubSub/index.js.map +1 -1
  53. package/dist/entities/PushNotification/PushNotification.js +4 -4
  54. package/dist/entities/PushNotification/PushNotification.js.map +1 -1
  55. package/dist/entities/PushNotification/PushNotification.types.js.map +1 -1
  56. package/dist/entities/PushNotification/index.js.map +1 -1
  57. package/dist/entities/Redis/Redis.js +8 -8
  58. package/dist/entities/Redis/Redis.js.map +1 -1
  59. package/dist/entities/Redis/Redis.types.js.map +1 -1
  60. package/dist/entities/Redis/Redis.validate.js +2 -2
  61. package/dist/entities/Redis/Redis.validate.js.map +1 -1
  62. package/dist/entities/Redis/index.js.map +1 -1
  63. package/dist/entities/Sequelize/Sequelize.config.js +42 -2
  64. package/dist/entities/Sequelize/Sequelize.config.js.map +1 -1
  65. package/dist/entities/Sequelize/Sequelize.js +3 -3
  66. package/dist/entities/Sequelize/Sequelize.js.map +1 -1
  67. package/dist/entities/Sequelize/Sequelize.types.js.map +1 -1
  68. package/dist/entities/Sequelize/Sequelize.validate.js +2 -2
  69. package/dist/entities/Sequelize/Sequelize.validate.js.map +1 -1
  70. package/dist/entities/Sequelize/index.js.map +1 -1
  71. package/dist/entities/Server/Server.const.js.map +1 -1
  72. package/dist/entities/Server/Server.js +2 -2
  73. package/dist/entities/Server/Server.js.map +1 -1
  74. package/dist/entities/Server/Server.types.js.map +1 -1
  75. package/dist/entities/Server/index.js.map +1 -1
  76. package/dist/entities/SocketClient/SocketClient.js +15 -15
  77. package/dist/entities/SocketClient/SocketClient.js.map +1 -1
  78. package/dist/entities/SocketClient/SocketClient.types.js.map +1 -1
  79. package/dist/entities/SocketClient/index.js.map +1 -1
  80. package/dist/entities/SocketClient/parseMessage/index.js.map +1 -1
  81. package/dist/entities/SocketClient/parseMessage/parseMessage.js +2 -2
  82. package/dist/entities/SocketClient/parseMessage/parseMessage.js.map +1 -1
  83. package/dist/entities/Storage/Storage.js +20 -20
  84. package/dist/entities/Storage/Storage.js.map +1 -1
  85. package/dist/entities/Storage/Storage.types.js.map +1 -1
  86. package/dist/entities/Storage/index.js.map +1 -1
  87. package/dist/entities/ValidationError/ValidationError.js.map +1 -1
  88. package/dist/entities/ValidationError/index.js.map +1 -1
  89. package/dist/entities/WebError/WebError.js +4 -4
  90. package/dist/entities/WebError/WebError.js.map +1 -1
  91. package/dist/entities/WebError/WebError.types.js.map +1 -1
  92. package/dist/entities/WebError/index.js.map +1 -1
  93. package/dist/entities/index.js.map +1 -1
  94. package/dist/index.js.map +1 -1
  95. package/dist/metrics/debug.js.map +1 -1
  96. package/dist/metrics/index.js.map +1 -1
  97. package/dist/metrics/request.js.map +1 -1
  98. package/dist/middleware/authAdmin/authAdmin.js.map +1 -1
  99. package/dist/middleware/authAdmin/authAdmin.types.js.map +1 -1
  100. package/dist/middleware/authAdmin/index.js.map +1 -1
  101. package/dist/middleware/authHmac/authHmac.js.map +1 -1
  102. package/dist/middleware/authHmac/authHmac.types.js.map +1 -1
  103. package/dist/middleware/authHmac/index.js.map +1 -1
  104. package/dist/middleware/authJwt/authJwt.js.map +1 -1
  105. package/dist/middleware/authJwt/authJwt.types.js.map +1 -1
  106. package/dist/middleware/authJwt/index.js.map +1 -1
  107. package/dist/middleware/authStatic/authStatic.js +3 -3
  108. package/dist/middleware/authStatic/authStatic.js.map +1 -1
  109. package/dist/middleware/authStatic/index.js.map +1 -1
  110. package/dist/middleware/authTls/authTls.js +8 -8
  111. package/dist/middleware/authTls/authTls.js.map +1 -1
  112. package/dist/middleware/authTls/authTls.types.js.map +1 -1
  113. package/dist/middleware/authTls/index.js.map +1 -1
  114. package/dist/middleware/checkPermission/checkPermission.js.map +1 -1
  115. package/dist/middleware/error/error.js.map +1 -1
  116. package/dist/middleware/error/index.js.map +1 -1
  117. package/dist/middleware/fileUploader/compressAvatar/compressAvatar.js +2 -2
  118. package/dist/middleware/fileUploader/compressAvatar/compressAvatar.js.map +1 -1
  119. package/dist/middleware/fileUploader/compressAvatar/compressAvatar.types.js.map +1 -1
  120. package/dist/middleware/fileUploader/compressAvatar/index.js.map +1 -1
  121. package/dist/middleware/fileUploader/fileUploader.js +12 -12
  122. package/dist/middleware/fileUploader/fileUploader.js.map +1 -1
  123. package/dist/middleware/fileUploader/fileUploader.types.js.map +1 -1
  124. package/dist/middleware/fileUploader/index.js.map +1 -1
  125. package/dist/middleware/fileUploader/isMultiPart/index.js.map +1 -1
  126. package/dist/middleware/fileUploader/isMultiPart/isMultipart.js.map +1 -1
  127. package/dist/middleware/fileUploader/validate/index.js.map +1 -1
  128. package/dist/middleware/fileUploader/validate/validate.js.map +1 -1
  129. package/dist/middleware/fourOhFour/fourOhFour.js.map +1 -1
  130. package/dist/middleware/fourOhFour/index.js.map +1 -1
  131. package/dist/middleware/geminiFileUploader/geminiFileUploader.js.map +1 -1
  132. package/dist/middleware/geminiFileUploader/index.js.map +1 -1
  133. package/dist/middleware/healthCheck/healthCheck.js +2 -2
  134. package/dist/middleware/healthCheck/healthCheck.js.map +1 -1
  135. package/dist/middleware/healthCheck/index.js.map +1 -1
  136. package/dist/middleware/index.js.map +1 -1
  137. package/dist/middleware/metrics/index.js.map +1 -1
  138. package/dist/middleware/metrics/metrics.js.map +1 -1
  139. package/dist/middleware/requestMetrics/index.js.map +1 -1
  140. package/dist/middleware/requestMetrics/requestMetrics.js.map +1 -1
  141. package/dist/middleware/swaggerDocs/index.js.map +1 -1
  142. package/dist/middleware/swaggerDocs/swaggerDocs.js +7 -7
  143. package/dist/middleware/swaggerDocs/swaggerDocs.js.map +1 -1
  144. package/dist/middleware/swaggerDocs/swaggerDocs.types.js.map +1 -1
  145. package/dist/middleware/userResolver/index.js.map +1 -1
  146. package/dist/middleware/userResolver/userResolver.js.map +1 -1
  147. package/dist/middleware/validate/index.js.map +1 -1
  148. package/dist/middleware/validate/validate.js.map +1 -1
  149. package/dist/middleware/version/index.js.map +1 -1
  150. package/dist/middleware/version/version.js +3 -3
  151. package/dist/middleware/version/version.js.map +1 -1
  152. package/dist/utils/checkEnvironment/index.js +13 -13
  153. package/dist/utils/checkEnvironment/index.js.map +1 -1
  154. package/dist/utils/createHttpServer/createHttpServer.js.map +1 -1
  155. package/dist/utils/createHttpServer/createHttpServer.validate.js +2 -2
  156. package/dist/utils/createHttpServer/createHttpServer.validate.js.map +1 -1
  157. package/dist/utils/createHttpServer/index.js.map +1 -1
  158. package/dist/utils/createSortedObject/createSortedObject.js.map +1 -1
  159. package/dist/utils/createSortedObject/index.js.map +1 -1
  160. package/dist/utils/dbMigration/dbMigration.js +8 -8
  161. package/dist/utils/dbMigration/dbMigration.js.map +1 -1
  162. package/dist/utils/dbMigration/dbMigration.types.js.map +1 -1
  163. package/dist/utils/dbMigration/index.js.map +1 -1
  164. package/dist/utils/dbMigration/migrateMetadataTable/index.js.map +1 -1
  165. package/dist/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.d.ts +2 -2
  166. package/dist/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.js +47 -15
  167. package/dist/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.js.map +1 -1
  168. package/dist/utils/envAssert/envAssert.js +6 -6
  169. package/dist/utils/envAssert/envAssert.js.map +1 -1
  170. package/dist/utils/envAssert/index.js.map +1 -1
  171. package/dist/utils/envAssert/validators/hostList.js +2 -2
  172. package/dist/utils/envAssert/validators/hostList.js.map +1 -1
  173. package/dist/utils/envAssert/validators/index.js.map +1 -1
  174. package/dist/utils/envAssert/validators/ipList.js +2 -2
  175. package/dist/utils/envAssert/validators/ipList.js.map +1 -1
  176. package/dist/utils/envAssert/validators/path.js +2 -2
  177. package/dist/utils/envAssert/validators/path.js.map +1 -1
  178. package/dist/utils/envAssert/validators/string.js +2 -2
  179. package/dist/utils/envAssert/validators/string.js.map +1 -1
  180. package/dist/utils/envAssert/validators/stringList.js +3 -3
  181. package/dist/utils/envAssert/validators/stringList.js.map +1 -1
  182. package/dist/utils/filter/filter.js +4 -4
  183. package/dist/utils/filter/filter.js.map +1 -1
  184. package/dist/utils/filter/index.js.map +1 -1
  185. package/dist/utils/getDynamicLink/getDynamicLink.js.map +1 -1
  186. package/dist/utils/getDynamicLink/getDynamicLink.types.js.map +1 -1
  187. package/dist/utils/getDynamicLink/getDynamicLink.validate.js.map +1 -1
  188. package/dist/utils/getDynamicLink/index.js.map +1 -1
  189. package/dist/utils/hmac/checkEnv/checkEnv.js +2 -2
  190. package/dist/utils/hmac/checkEnv/checkEnv.js.map +1 -1
  191. package/dist/utils/hmac/checkEnv/index.js.map +1 -1
  192. package/dist/utils/hmac/createHmac/createHmac.js.map +1 -1
  193. package/dist/utils/hmac/createHmac/index.js.map +1 -1
  194. package/dist/utils/hmac/index.js.map +1 -1
  195. package/dist/utils/hmac/index.types.js.map +1 -1
  196. package/dist/utils/hmac/signPayload/index.js.map +1 -1
  197. package/dist/utils/hmac/signPayload/signPayload.js.map +1 -1
  198. package/dist/utils/hmac/verifySignature/index.js.map +1 -1
  199. package/dist/utils/hmac/verifySignature/verifySignature.js.map +1 -1
  200. package/dist/utils/index.js.map +1 -1
  201. package/dist/utils/jwt/index.js.map +1 -1
  202. package/dist/utils/jwt/jwt.js.map +1 -1
  203. package/dist/utils/jwt/jwt.types.js.map +1 -1
  204. package/dist/utils/report/index.js.map +1 -1
  205. package/dist/utils/report/output.js.map +1 -1
  206. package/dist/utils/report/output.types.js.map +1 -1
  207. package/dist/utils/report/report.js.map +1 -1
  208. package/dist/utils/report/report.types.js.map +1 -1
  209. package/dist/utils/request/index.js.map +1 -1
  210. package/dist/utils/request/request.js.map +1 -1
  211. package/dist/utils/semverCompare/index.js.map +1 -1
  212. package/dist/utils/semverCompare/semverCompare.js +5 -5
  213. package/dist/utils/semverCompare/semverCompare.js.map +1 -1
  214. package/dist/utils/sendEmail/index.js.map +1 -1
  215. package/dist/utils/sendEmail/sendEmail.js +8 -8
  216. package/dist/utils/sendEmail/sendEmail.js.map +1 -1
  217. package/dist/utils/sendEmail/sendEmail.types.js.map +1 -1
  218. package/dist/utils/sendPush/index.js.map +1 -1
  219. package/dist/utils/sendPush/sendPush.js +5 -5
  220. package/dist/utils/sendPush/sendPush.js.map +1 -1
  221. package/dist/utils/sendPush/sendPush.types.js.map +1 -1
  222. package/dist/utils/tlsConfig/index.js.map +1 -1
  223. package/dist/utils/tlsConfig/tlsConfig.js +2 -2
  224. package/dist/utils/tlsConfig/tlsConfig.js.map +1 -1
  225. package/dist/utils/tlsConfig/tlsConfig.types.js.map +1 -1
  226. package/dist/utils/tlsConfig/tlsConfig.validate.js +2 -2
  227. package/dist/utils/tlsConfig/tlsConfig.validate.js.map +1 -1
  228. package/dist/utils/tlsRequest/index.js.map +1 -1
  229. package/dist/utils/tlsRequest/tlsRequest.js.map +1 -1
  230. package/dist/utils/trimPathSlash/index.js.map +1 -1
  231. package/dist/utils/trimPathSlash/trimPathSlash.js +4 -4
  232. package/dist/utils/trimPathSlash/trimPathSlash.js.map +1 -1
  233. package/eslint.config.mjs +11 -11
  234. package/package.json +164 -161
  235. package/src/const/DebeziumEvent.ts +6 -6
  236. package/src/const/LogSeverity.ts +7 -7
  237. package/src/const/index.ts +5 -5
  238. package/src/const/metrics.ts +6 -6
  239. package/src/const/mime.ts +37 -37
  240. package/src/const/tokenIssuer.ts +9 -9
  241. package/src/db/migrations/20241030121500-create-sequelize-meta-table.ts +29 -29
  242. package/src/db/models/SequelizeMeta.ts +16 -16
  243. package/src/db/models/index.ts +2 -2
  244. package/src/entities/ElasticSearch/ElasticSearch.ts +103 -103
  245. package/src/entities/ElasticSearch/ElasticSearch.types.ts +7 -7
  246. package/src/entities/ElasticSearch/index.ts +2 -2
  247. package/src/entities/Endpoint/Endpoint.test.ts +337 -337
  248. package/src/entities/Endpoint/Endpoint.ts +202 -202
  249. package/src/entities/Endpoint/Endpoint.types.ts +205 -205
  250. package/src/entities/Endpoint/index.ts +2 -2
  251. package/src/entities/EngineError/EngineError.ts +28 -28
  252. package/src/entities/EngineError/EngineError.types.ts +15 -15
  253. package/src/entities/EngineError/index.ts +2 -2
  254. package/src/entities/KeySet/KeySet.test.ts +126 -126
  255. package/src/entities/KeySet/KeySet.ts +172 -172
  256. package/src/entities/KeySet/KeySet.types.ts +28 -28
  257. package/src/entities/KeySet/index.ts +2 -2
  258. package/src/entities/LifecycleController/LifecycleController.test.ts +48 -48
  259. package/src/entities/LifecycleController/LifecycleController.ts +24 -24
  260. package/src/entities/LifecycleController/LifecycleController.types.ts +5 -5
  261. package/src/entities/LifecycleController/index.ts +2 -2
  262. package/src/entities/Localizator/Localizator.ts +139 -139
  263. package/src/entities/Localizator/Localizator.types.ts +52 -52
  264. package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.test.ts +165 -165
  265. package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.ts +58 -58
  266. package/src/entities/Localizator/guessNamingConvention/index.ts +1 -1
  267. package/src/entities/Localizator/index.ts +2 -2
  268. package/src/entities/MessageHandler/MessageHandler.test.ts +130 -130
  269. package/src/entities/MessageHandler/MessageHandler.ts +72 -72
  270. package/src/entities/MessageHandler/MessageHandler.types.ts +15 -15
  271. package/src/entities/MessageHandler/index.ts +2 -2
  272. package/src/entities/PubSub/PubSub.test.ts +297 -297
  273. package/src/entities/PubSub/PubSub.ts +202 -202
  274. package/src/entities/PubSub/PubSub.types.ts +76 -76
  275. package/src/entities/PubSub/handleMessage/handleMessage.test.ts +102 -102
  276. package/src/entities/PubSub/handleMessage/handleMessage.ts +65 -65
  277. package/src/entities/PubSub/handleMessage/index.ts +1 -1
  278. package/src/entities/PubSub/index.ts +2 -2
  279. package/src/entities/PushNotification/PushNotification.test.ts +35 -35
  280. package/src/entities/PushNotification/PushNotification.ts +44 -44
  281. package/src/entities/PushNotification/PushNotification.types.ts +25 -25
  282. package/src/entities/PushNotification/index.ts +2 -2
  283. package/src/entities/Redis/Redis.ts +71 -71
  284. package/src/entities/Redis/Redis.types.ts +19 -19
  285. package/src/entities/Redis/Redis.validate.ts +17 -17
  286. package/src/entities/Redis/index.ts +2 -2
  287. package/src/entities/Sequelize/Sequelize.config.ts +59 -29
  288. package/src/entities/Sequelize/Sequelize.test.ts +21 -21
  289. package/src/entities/Sequelize/Sequelize.ts +75 -75
  290. package/src/entities/Sequelize/Sequelize.types.ts +10 -10
  291. package/src/entities/Sequelize/Sequelize.validate.ts +15 -15
  292. package/src/entities/Sequelize/index.ts +2 -2
  293. package/src/entities/Server/Server.const.ts +56 -56
  294. package/src/entities/Server/Server.test.ts +272 -272
  295. package/src/entities/Server/Server.ts +445 -445
  296. package/src/entities/Server/Server.types.ts +88 -88
  297. package/src/entities/Server/index.ts +2 -2
  298. package/src/entities/SocketClient/SocketClient.test.ts +392 -392
  299. package/src/entities/SocketClient/SocketClient.ts +401 -401
  300. package/src/entities/SocketClient/SocketClient.types.ts +62 -62
  301. package/src/entities/SocketClient/index.ts +2 -2
  302. package/src/entities/SocketClient/parseMessage/index.ts +1 -1
  303. package/src/entities/SocketClient/parseMessage/parseMessage.test.ts +20 -20
  304. package/src/entities/SocketClient/parseMessage/parseMessage.ts +26 -26
  305. package/src/entities/Storage/Storage.test.ts +58 -58
  306. package/src/entities/Storage/Storage.ts +219 -219
  307. package/src/entities/Storage/Storage.types.ts +57 -57
  308. package/src/entities/Storage/index.ts +2 -2
  309. package/src/entities/ValidationError/ValidationError.ts +34 -34
  310. package/src/entities/ValidationError/index.ts +1 -1
  311. package/src/entities/WebError/WebError.test.ts +18 -18
  312. package/src/entities/WebError/WebError.ts +23 -23
  313. package/src/entities/WebError/WebError.types.ts +9 -9
  314. package/src/entities/WebError/index.ts +2 -2
  315. package/src/entities/index.ts +16 -16
  316. package/src/index.ts +4 -4
  317. package/src/metrics/debug.ts +10 -10
  318. package/src/metrics/index.ts +2 -2
  319. package/src/metrics/request.ts +17 -17
  320. package/src/middleware/authAdmin/authAdmin.test.ts +199 -199
  321. package/src/middleware/authAdmin/authAdmin.ts +114 -114
  322. package/src/middleware/authAdmin/authAdmin.types.ts +19 -19
  323. package/src/middleware/authAdmin/index.ts +2 -2
  324. package/src/middleware/authHmac/authHmac.test.ts +86 -86
  325. package/src/middleware/authHmac/authHmac.ts +56 -56
  326. package/src/middleware/authHmac/authHmac.types.ts +7 -7
  327. package/src/middleware/authHmac/index.ts +2 -2
  328. package/src/middleware/authJwt/authJwt.test.ts +54 -54
  329. package/src/middleware/authJwt/authJwt.ts +55 -55
  330. package/src/middleware/authJwt/authJwt.types.ts +14 -14
  331. package/src/middleware/authJwt/index.ts +2 -2
  332. package/src/middleware/authStatic/authStatic.test.ts +36 -36
  333. package/src/middleware/authStatic/authStatic.ts +45 -45
  334. package/src/middleware/authStatic/index.ts +1 -1
  335. package/src/middleware/authTls/authTls.test.ts +138 -138
  336. package/src/middleware/authTls/authTls.ts +106 -106
  337. package/src/middleware/authTls/authTls.types.ts +13 -13
  338. package/src/middleware/authTls/index.ts +2 -2
  339. package/src/middleware/checkPermission/checkPermission.ts +32 -32
  340. package/src/middleware/error/error.test.ts +60 -60
  341. package/src/middleware/error/error.ts +25 -25
  342. package/src/middleware/error/index.ts +1 -1
  343. package/src/middleware/fileUploader/compressAvatar/compressAvatar.ts +25 -25
  344. package/src/middleware/fileUploader/compressAvatar/compressAvatar.types.ts +12 -12
  345. package/src/middleware/fileUploader/compressAvatar/index.ts +2 -2
  346. package/src/middleware/fileUploader/fileUploader.test.ts +310 -310
  347. package/src/middleware/fileUploader/fileUploader.ts +303 -303
  348. package/src/middleware/fileUploader/fileUploader.types.ts +52 -52
  349. package/src/middleware/fileUploader/index.ts +2 -2
  350. package/src/middleware/fileUploader/isMultiPart/index.ts +1 -1
  351. package/src/middleware/fileUploader/isMultiPart/isMultipart.ts +9 -9
  352. package/src/middleware/fileUploader/validate/index.ts +1 -1
  353. package/src/middleware/fileUploader/validate/validate.ts +27 -27
  354. package/src/middleware/fourOhFour/fourOhFour.test.ts +14 -14
  355. package/src/middleware/fourOhFour/fourOhFour.ts +13 -13
  356. package/src/middleware/fourOhFour/index.ts +1 -1
  357. package/src/middleware/geminiFileUploader/geminiFileUploader.ts +117 -117
  358. package/src/middleware/geminiFileUploader/index.ts +1 -1
  359. package/src/middleware/healthCheck/healthCheck.test.ts +12 -12
  360. package/src/middleware/healthCheck/healthCheck.ts +14 -14
  361. package/src/middleware/healthCheck/index.ts +1 -1
  362. package/src/middleware/index.ts +17 -17
  363. package/src/middleware/metrics/index.ts +1 -1
  364. package/src/middleware/metrics/metrics.test.ts +46 -46
  365. package/src/middleware/metrics/metrics.ts +24 -24
  366. package/src/middleware/requestMetrics/index.ts +1 -1
  367. package/src/middleware/requestMetrics/requestMetrics.test.ts +77 -77
  368. package/src/middleware/requestMetrics/requestMetrics.ts +20 -20
  369. package/src/middleware/swaggerDocs/index.ts +2 -2
  370. package/src/middleware/swaggerDocs/swaggerDocs.ts +114 -114
  371. package/src/middleware/swaggerDocs/swaggerDocs.types.ts +41 -41
  372. package/src/middleware/userResolver/index.ts +1 -1
  373. package/src/middleware/userResolver/userResolver.test.ts +35 -35
  374. package/src/middleware/userResolver/userResolver.ts +35 -35
  375. package/src/middleware/validate/index.ts +1 -1
  376. package/src/middleware/validate/validate.test.ts +43 -43
  377. package/src/middleware/validate/validate.ts +25 -25
  378. package/src/middleware/version/index.ts +1 -1
  379. package/src/middleware/version/version.test.ts +23 -23
  380. package/src/middleware/version/version.ts +12 -12
  381. package/src/utils/checkEnvironment/index.ts +49 -49
  382. package/src/utils/createHttpServer/createHttpServer.test.ts +24 -24
  383. package/src/utils/createHttpServer/createHttpServer.ts +34 -34
  384. package/src/utils/createHttpServer/createHttpServer.validate.ts +17 -17
  385. package/src/utils/createHttpServer/index.ts +1 -1
  386. package/src/utils/createSortedObject/createSortedObject.ts +20 -20
  387. package/src/utils/createSortedObject/createSortedObjet.test.ts +47 -47
  388. package/src/utils/createSortedObject/index.ts +1 -1
  389. package/src/utils/dbMigration/dbMigration.test.ts +209 -209
  390. package/src/utils/dbMigration/dbMigration.ts +199 -199
  391. package/src/utils/dbMigration/dbMigration.types.ts +11 -11
  392. package/src/utils/dbMigration/index.ts +2 -2
  393. package/src/utils/dbMigration/migrateMetadataTable/index.ts +1 -1
  394. package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.test.ts +59 -59
  395. package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.ts +102 -70
  396. package/src/utils/envAssert/envAssert.ts +31 -31
  397. package/src/utils/envAssert/index.ts +1 -1
  398. package/src/utils/envAssert/validators/hostList.ts +17 -17
  399. package/src/utils/envAssert/validators/index.ts +5 -5
  400. package/src/utils/envAssert/validators/ipList.ts +13 -13
  401. package/src/utils/envAssert/validators/path.ts +13 -13
  402. package/src/utils/envAssert/validators/string.ts +9 -9
  403. package/src/utils/envAssert/validators/stringList.ts +13 -13
  404. package/src/utils/filter/filter.ts +17 -17
  405. package/src/utils/filter/index.ts +1 -1
  406. package/src/utils/getDynamicLink/getDynamicLink.test.ts +51 -51
  407. package/src/utils/getDynamicLink/getDynamicLink.ts +28 -28
  408. package/src/utils/getDynamicLink/getDynamicLink.types.ts +11 -11
  409. package/src/utils/getDynamicLink/getDynamicLink.validate.ts +6 -6
  410. package/src/utils/getDynamicLink/index.ts +2 -2
  411. package/src/utils/hmac/checkEnv/checkEnv.test.ts +18 -18
  412. package/src/utils/hmac/checkEnv/checkEnv.ts +9 -9
  413. package/src/utils/hmac/checkEnv/index.ts +1 -1
  414. package/src/utils/hmac/createHmac/createHmac.ts +33 -33
  415. package/src/utils/hmac/createHmac/index.ts +1 -1
  416. package/src/utils/hmac/index.ts +4 -4
  417. package/src/utils/hmac/index.types.ts +13 -13
  418. package/src/utils/hmac/signPayload/index.ts +1 -1
  419. package/src/utils/hmac/signPayload/signPayload.ts +16 -16
  420. package/src/utils/hmac/verifySignature/index.ts +1 -1
  421. package/src/utils/hmac/verifySignature/verifySignature.ts +24 -24
  422. package/src/utils/index.ts +26 -26
  423. package/src/utils/jwt/index.ts +2 -2
  424. package/src/utils/jwt/jwt.test.ts +41 -41
  425. package/src/utils/jwt/jwt.ts +204 -204
  426. package/src/utils/jwt/jwt.types.ts +21 -21
  427. package/src/utils/report/index.ts +3 -3
  428. package/src/utils/report/output.ts +45 -45
  429. package/src/utils/report/output.types.ts +70 -70
  430. package/src/utils/report/report.test.ts +133 -133
  431. package/src/utils/report/report.ts +134 -134
  432. package/src/utils/report/report.types.ts +13 -13
  433. package/src/utils/request/index.ts +1 -1
  434. package/src/utils/request/request.test.ts +26 -26
  435. package/src/utils/request/request.ts +48 -48
  436. package/src/utils/semverCompare/index.ts +1 -1
  437. package/src/utils/semverCompare/semverCompare.test.ts +49 -49
  438. package/src/utils/semverCompare/semverCompare.ts +60 -60
  439. package/src/utils/sendEmail/index.ts +1 -1
  440. package/src/utils/sendEmail/sendEmail.ts +27 -27
  441. package/src/utils/sendEmail/sendEmail.types.ts +7 -7
  442. package/src/utils/sendPush/index.ts +2 -2
  443. package/src/utils/sendPush/sendPush.ts +20 -20
  444. package/src/utils/sendPush/sendPush.types.ts +25 -25
  445. package/src/utils/tlsConfig/index.ts +2 -2
  446. package/src/utils/tlsConfig/tlsConfig.test.ts +32 -32
  447. package/src/utils/tlsConfig/tlsConfig.ts +47 -47
  448. package/src/utils/tlsConfig/tlsConfig.types.ts +11 -11
  449. package/src/utils/tlsConfig/tlsConfig.validate.ts +25 -25
  450. package/src/utils/tlsRequest/index.ts +1 -1
  451. package/src/utils/tlsRequest/tlsRequest.test.ts +63 -63
  452. package/src/utils/tlsRequest/tlsRequest.ts +12 -12
  453. package/src/utils/trimPathSlash/index.ts +1 -1
  454. package/src/utils/trimPathSlash/trimPathSlash.test.ts +26 -26
  455. package/src/utils/trimPathSlash/trimPathSlash.ts +8 -8
  456. package/test/env.ts +56 -56
  457. package/test/factory/index.ts +8 -8
  458. package/test/factory/sequelizeMeta.ts +12 -12
  459. package/test/hooks.ts +37 -37
  460. package/test/index.ts +3 -3
  461. package/test/stub/index.ts +3 -3
  462. package/test/stub/stubLocales.ts +68 -68
  463. package/test/stub/stubPubSub.ts +7 -7
  464. package/test/stub/stubStorage.ts +77 -77
  465. package/test/stub/stubStorage.types.ts +11 -11
  466. package/test/utils/app.ts +31 -31
  467. package/test/utils/index.ts +1 -1
  468. package/tsconfig.build.json +5 -5
  469. package/tsconfig.json +32 -32
@@ -1,445 +1,445 @@
1
- import fs from 'fs';
2
- import http from 'http';
3
- import https from 'https';
4
- import { AddressInfo } from 'net';
5
- import path from 'path';
6
- import { setTimeout as setTimeoutPromise } from 'timers/promises';
7
- import { ValidatorSpec } from 'envalid';
8
- import express, { Application } from 'express';
9
- import { Server as WebSocketServer } from 'ws';
10
- import { SocketClient } from '../SocketClient';
11
- import {
12
- defaultMiddleware,
13
- defaultErrorMiddleware,
14
- secondaryMiddleware,
15
- shutdownSignals
16
- } from './Server.const';
17
- import {
18
- ServerOptions,
19
- ServerCronJon,
20
- ServerAuthConfig,
21
- ServerWebSocketConfig,
22
- ServerGlobalMiddleware,
23
- ServerErrorMiddleWare,
24
- ServerCallback
25
- } from './Server.types';
26
- import { Endpoint } from 'entities/Endpoint';
27
- import { EngineError } from 'entities/EngineError';
28
- import { LifecycleController } from 'entities/LifecycleController';
29
- import { PubSub } from 'entities/PubSub';
30
- import { checkEnvironment, envAssert, createHttpServer } from 'utils';
31
- import { initKeySets, shutdownKeySets } from 'utils/jwt';
32
- import { reportInfo, reportError, reportDebug } from 'utils/report';
33
- import { tlsConfig, loadTlsConfig, TlsConfig } from 'utils/tlsConfig';
34
-
35
- const namespace = 'engine:Server';
36
-
37
- /** Main server class */
38
- export class Server {
39
- /** The express application powering the main endpoints */
40
- private app: Application;
41
- /** The node HTTP(S) server, serving the main express application */
42
- private httpServer: http.Server | https.Server;
43
- /** The express application powering the support endpoints */
44
- private secondaryApp: Application;
45
- /** The node HTTP(S) server, serving the secondary express application */
46
- private secondaryHttpServer: http.Server | https.Server;
47
- /** List of endpoint instances that the server should handle */
48
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
- private endpoints: Array<Endpoint<any>>;
50
- /** Mapping of env variable name with functions that should run to check their validity */
51
- private checkEnvironment: Record<string, ValidatorSpec<unknown>>;
52
- /** Middleware that should run on every request before the endpoint specific logic */
53
- private globalMiddleware: Array<ServerGlobalMiddleware>;
54
- /** Error middleware that should run on every request after the endpoint specific logic, but before the generic global middleware */
55
- private errorMiddleware: Array<
56
- ServerGlobalMiddleware | ServerErrorMiddleWare
57
- >;
58
- /** Functions that should be called on server startup */
59
- private initCallbacks: Array<ServerCallback>;
60
- /** Functions that should be called on server shutdown */
61
- private shutdownCallbacks: Array<ServerCallback>;
62
- /** When set to true, this indicates that init callbacks should run synchronously in the order they are declared. By default they all run in parallel */
63
- private syncCallbacks: boolean;
64
- /** Config to set regularly running jobs on the server */
65
- private cron?: Array<ServerCronJon>;
66
- /** Global auth related configuration */
67
- private auth: ServerAuthConfig;
68
- /** WebSocket server instance, if configured */
69
- private wss?: WebSocketServer;
70
- /** Abort controller that handles signals for the server */
71
- private abortController = new AbortController();
72
-
73
- /** Create a server */
74
- public constructor(config: ServerOptions) {
75
- this.validate(config);
76
-
77
- reportDebug({
78
- namespace,
79
- message: `Creating server`
80
- });
81
-
82
- this.endpoints = config.endpoints;
83
- this.globalMiddleware = config.globalMiddleware ?? [];
84
- this.errorMiddleware = config.errorMiddleware ?? [];
85
- this.initCallbacks = config.initCallbacks ?? [];
86
- this.shutdownCallbacks = config.shutdownCallbacks ?? [];
87
- this.syncCallbacks = config.syncCallbacks ?? false;
88
- this.cron = config.cron;
89
- this.auth = { noFetch: false, ...config.auth };
90
-
91
- // The minimal environment check is different between the migration modes of execution and the regular server execution mode
92
- // When running in migration mode, we only check that we have SQL related environment variables
93
- this.checkEnvironment =
94
- process.env.RUN_MIGRATION === 'true' ||
95
- process.env.UNDO_MIGRATION === 'true'
96
- ? {
97
- SQL_HOST: envAssert.isHost(),
98
- SQL_USER: envAssert.isString(),
99
- SQL_PASSWORD: envAssert.isString(),
100
- SQL_DB: envAssert.isString()
101
- }
102
- : {
103
- NODE_ENV: envAssert.isString(),
104
- PORT: envAssert.isPort(),
105
- SECONDARY_PORT: envAssert.isPort(),
106
- ...config.checkEnvironment
107
- };
108
-
109
- checkEnvironment(this.checkEnvironment);
110
-
111
- // Create the primary express core that serves the business logic
112
- this.app = express();
113
- this.registerMiddleware(this.app);
114
- this.httpServer = createHttpServer(this.app);
115
-
116
- // Create a secondary express core that servers metrics and analytics
117
- // This will be served on a different port, allowing to specify different firewall rules for these routes
118
- this.secondaryApp = express();
119
- [...secondaryMiddleware, ...defaultErrorMiddleware].forEach(
120
- (middleware) => {
121
- if (middleware) this.secondaryApp.use(middleware);
122
- }
123
- );
124
- this.secondaryHttpServer = createHttpServer(this.secondaryApp);
125
-
126
- // Remove the express headers
127
- this.app.disable('x-powered-by');
128
- this.secondaryApp.disable('x-powered-by');
129
-
130
- // We remove all node timeout on connections and requests
131
- // This responsibility is delegated to the front-facing load balancer
132
- [this.httpServer, this.secondaryHttpServer].forEach((server) => {
133
- server.headersTimeout = 0;
134
- server.keepAliveTimeout = 0;
135
- });
136
-
137
- if (config.webSocket) {
138
- this.attachWebSocket(config.webSocket);
139
- }
140
- }
141
-
142
- /** Start the server */
143
- public async init(): Promise<void> {
144
- reportDebug({ namespace, message: `Starting Server` });
145
- // Fetch the keys for JWT authentication
146
- // Ignore in test environment as we do symmetrical token signing
147
- if (process.env.NODE_ENV !== 'test' && !this.auth.noFetch)
148
- await initKeySets();
149
- // Run all the init callbacks
150
- // We can either run them all 1/1 synchronously or run them all in parallel (default)
151
- // Callback can either be direct function or an object with function and parameters attributes
152
-
153
- if (this.syncCallbacks) {
154
- for (const callback of this.initCallbacks) {
155
- await this.runCallback(callback);
156
- }
157
- } else {
158
- await Promise.all(
159
- this.initCallbacks.map((callback) => this.runCallback(callback))
160
- );
161
- }
162
-
163
- // Initialize the Pub/Sub module
164
- await PubSub.init();
165
- // Run all the cronjob
166
- if (this.cron) {
167
- this.cron.forEach((job) => {
168
- this.runCronJob(job);
169
- });
170
- }
171
-
172
- // Start listening to requests
173
- await Promise.all([
174
- new Promise<void>((resolve) =>
175
- this.httpServer.listen(process.env.PORT, () => {
176
- resolve();
177
- })
178
- ),
179
- new Promise<void>((resolve) =>
180
- this.secondaryHttpServer.listen(process.env.SECONDARY_PORT, () => {
181
- resolve();
182
- })
183
- )
184
- ]);
185
- reportInfo({
186
- message: 'SERVER_RUNNING',
187
- data: {
188
- port: process.env.PORT,
189
- secondaryPort: process.env.SECONDARY_PORT,
190
- nodeEnv: process.env.NODE_ENV
191
- }
192
- });
193
-
194
- this.handleSignal();
195
-
196
- // Watch TSL config files changing
197
- this.watchTlsCaFileChange();
198
- }
199
-
200
- /** Graceful shutdown */
201
- public async shutdown(): Promise<void> {
202
- reportDebug({ namespace, message: `Shutting down Server` });
203
-
204
- // Stop listening to HTTP requests
205
- await Promise.all(
206
- [this.httpServer, this.secondaryHttpServer].map((server) => {
207
- // Ignore if the server was already stopped
208
- // We have observed cases where SIGTERM was thrown multiple times
209
- if (!server.listening) return;
210
- const { port } = server.address() as AddressInfo;
211
- server.on('close', (error: unknown) => {
212
- if (error) {
213
- reportError(error);
214
- process.exit(1);
215
- } else {
216
- reportInfo({
217
- message: `Stopped listening to requests on port ${port}`
218
- });
219
- }
220
- });
221
- server.close();
222
- })
223
- );
224
-
225
- // Close all socket connections
226
- if (this.wss) {
227
- // First ask then to close gracefully
228
- this.wss.clients.forEach((socket) => {
229
- socket.close();
230
- });
231
- // Hard terminate all connections still open after a defined time
232
- const socketKillTimeout = process.env.WEBSOCKET_CLOSE_TIMEOUT
233
- ? parseInt(process.env.WEBSOCKET_CLOSE_TIMEOUT)
234
- : 5000;
235
- await new Promise<void>((resolve) => {
236
- setTimeout(() => {
237
- (this.wss as WebSocketServer).clients.forEach((socket) => {
238
- if (
239
- socket.readyState === socket.CLOSING ||
240
- socket.readyState === socket.OPEN
241
- ) {
242
- socket.terminate();
243
- }
244
- });
245
- resolve();
246
- }, socketKillTimeout);
247
- });
248
- }
249
-
250
- // Run all the shutdown callback
251
- if (this.syncCallbacks) {
252
- for (const callback of this.shutdownCallbacks) {
253
- await this.runCallback(callback);
254
- }
255
- } else {
256
- await Promise.all(
257
- this.shutdownCallbacks.map((callback) => this.runCallback(callback))
258
- );
259
- }
260
-
261
- // Shutdown all the running entities
262
- await LifecycleController.shutdownRunningInstances();
263
-
264
- // Abort all the cronjob
265
- if (this.abortController) this.abortController.abort();
266
-
267
- // Stop the keyset timers
268
- shutdownKeySets();
269
-
270
- shutdownSignals.forEach((signal) => process.removeAllListeners(signal));
271
- }
272
-
273
- /** Get the express app instance of the server */
274
- public getApp(): Application {
275
- return this.app;
276
- }
277
-
278
- /** Get the express app instance of the server */
279
- public getSecondaryApp(): Application {
280
- return this.secondaryApp;
281
- }
282
-
283
- /** Registers all the middleware with the express app */
284
- private registerMiddleware(app: Application): void {
285
- // Global middleware can specify a path to which they apply
286
- [...defaultMiddleware, ...this.globalMiddleware].forEach((middleware) => {
287
- if (typeof middleware === 'function') {
288
- app.use(middleware);
289
- } else {
290
- app.use(middleware.path, middleware.middleware);
291
- }
292
- });
293
- // Call the register method of each endpoint
294
- this.endpoints.forEach((endpoint) => {
295
- endpoint.register(app);
296
- });
297
- // Add error middleware
298
- [...this.errorMiddleware, ...defaultErrorMiddleware].forEach(
299
- (middleware) => {
300
- if (typeof middleware === 'function') {
301
- app.use(middleware);
302
- } else {
303
- app.use(middleware.path, middleware.middleware);
304
- }
305
- }
306
- );
307
- }
308
-
309
- /** Add a handler for WebSocket connections */
310
- private attachWebSocket(options: ServerWebSocketConfig): void {
311
- this.wss = new WebSocketServer({
312
- ...options.server,
313
- server: this.httpServer
314
- })
315
- .on('connection', (webSocket, request) => {
316
- new SocketClient(webSocket, request, options.client);
317
- })
318
- .on('error', (error) => {
319
- reportError(error);
320
- });
321
- }
322
-
323
- /** Call shutdown if signal gets sent to the process */
324
- private handleSignal(): void {
325
- shutdownSignals.forEach((signal) =>
326
- process.on(signal, () => {
327
- (async (): Promise<void> => {
328
- reportInfo(`Received shutdown signal [${signal}]`);
329
- await this.shutdown();
330
- })().catch((error) => {
331
- reportError(error);
332
- });
333
- })
334
- );
335
- }
336
-
337
- /** Watch the TLS certificate change event */
338
- private watchTlsCaFileChange(): void {
339
- [
340
- 'TLS_REQUEST_KEY',
341
- 'TLS_REQUEST_KEY_PASSPHRASE',
342
- 'TLS_REQUEST_CERT',
343
- 'TLS_REQUEST_CA',
344
- 'TLS_SERVER_KEY',
345
- 'TLS_SERVER_KEY_PASSPHRASE',
346
- 'TLS_SERVER_CERT',
347
- 'TLS_CA'
348
- ].forEach((key) => {
349
- const file = process.env[key];
350
- if (file)
351
- fs.watch(path.resolve(file), (event) => {
352
- if (event !== 'change') return;
353
- reportInfo(`Reloading TLS config [${file} changed]`);
354
- loadTlsConfig();
355
- (this.httpServer as https.Server).setSecureContext(
356
- tlsConfig as TlsConfig
357
- );
358
- });
359
- });
360
- }
361
-
362
- /** Executes a recurring job */
363
- private runCronJob(job: ServerCronJon): void {
364
- (async (): Promise<void> => {
365
- reportInfo({ message: `Starting scheduled job "${job.handler.name}"` });
366
- try {
367
- await job.handler();
368
- reportInfo({
369
- message: `Job "${job.handler.name}" finished, starting again in ${job.interval} seconds`
370
- });
371
- await setTimeoutPromise(job.interval * 1000, undefined, {
372
- signal: this.abortController.signal
373
- });
374
- this.runCronJob(job);
375
- } catch (error) {
376
- if (error instanceof Error && error.name === 'AbortError') {
377
- reportDebug({
378
- namespace,
379
- message: `Scheduled job "${job.handler?.name}" has been aborted`
380
- });
381
- } else {
382
- throw error;
383
- }
384
- }
385
- })().catch((error) => {
386
- reportError(error);
387
- });
388
- }
389
-
390
- /** Run a shutdown/init callback */
391
- private runCallback(callback: ServerCallback): unknown {
392
- return typeof callback === 'function'
393
- ? callback()
394
- : callback.function.apply(null, callback.parameters ?? []);
395
- }
396
-
397
- /**
398
- * Validate the Server constructor configuration
399
- */
400
- private validate(config: ServerOptions): void {
401
- if (
402
- !config.endpoints ||
403
- config.endpoints.some((endpoint) => !(endpoint instanceof Endpoint))
404
- )
405
- throw new EngineError(
406
- 'Server endpoints should be declared and all be Endpoint instances'
407
- );
408
-
409
- if (
410
- config.checkEnvironment &&
411
- Object.values(config.checkEnvironment).some(
412
- (validator) => typeof validator !== 'function'
413
- )
414
- )
415
- throw new EngineError(
416
- 'Some of the environment checks are not valid functions'
417
- );
418
-
419
- if (
420
- config.initCallbacks &&
421
- (!(config.initCallbacks instanceof Array) ||
422
- config.initCallbacks.some(
423
- (callback) =>
424
- !(
425
- typeof callback === 'function' ||
426
- typeof callback?.function === 'function'
427
- )
428
- ))
429
- )
430
- throw new EngineError('Init callbacks is not a list of functions');
431
-
432
- if (
433
- config.shutdownCallbacks &&
434
- (!(config.shutdownCallbacks instanceof Array) ||
435
- config.shutdownCallbacks.some(
436
- (callback) =>
437
- !(
438
- typeof callback === 'function' ||
439
- typeof callback?.function === 'function'
440
- )
441
- ))
442
- )
443
- throw new EngineError('Shutdown callbacks is not a list of functions');
444
- }
445
- }
1
+ import fs from 'fs';
2
+ import http from 'http';
3
+ import https from 'https';
4
+ import { AddressInfo } from 'net';
5
+ import path from 'path';
6
+ import { setTimeout as setTimeoutPromise } from 'timers/promises';
7
+ import { ValidatorSpec } from 'envalid';
8
+ import express, { Application } from 'express';
9
+ import { Server as WebSocketServer } from 'ws';
10
+ import { SocketClient } from '../SocketClient';
11
+ import {
12
+ defaultMiddleware,
13
+ defaultErrorMiddleware,
14
+ secondaryMiddleware,
15
+ shutdownSignals
16
+ } from './Server.const';
17
+ import {
18
+ ServerOptions,
19
+ ServerCronJon,
20
+ ServerAuthConfig,
21
+ ServerWebSocketConfig,
22
+ ServerGlobalMiddleware,
23
+ ServerErrorMiddleWare,
24
+ ServerCallback
25
+ } from './Server.types';
26
+ import { Endpoint } from 'entities/Endpoint';
27
+ import { EngineError } from 'entities/EngineError';
28
+ import { LifecycleController } from 'entities/LifecycleController';
29
+ import { PubSub } from 'entities/PubSub';
30
+ import { checkEnvironment, envAssert, createHttpServer } from 'utils';
31
+ import { initKeySets, shutdownKeySets } from 'utils/jwt';
32
+ import { reportInfo, reportError, reportDebug } from 'utils/report';
33
+ import { tlsConfig, loadTlsConfig, TlsConfig } from 'utils/tlsConfig';
34
+
35
+ const namespace = 'engine:Server';
36
+
37
+ /** Main server class */
38
+ export class Server {
39
+ /** The express application powering the main endpoints */
40
+ private app: Application;
41
+ /** The node HTTP(S) server, serving the main express application */
42
+ private httpServer: http.Server | https.Server;
43
+ /** The express application powering the support endpoints */
44
+ private secondaryApp: Application;
45
+ /** The node HTTP(S) server, serving the secondary express application */
46
+ private secondaryHttpServer: http.Server | https.Server;
47
+ /** List of endpoint instances that the server should handle */
48
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
+ private endpoints: Array<Endpoint<any>>;
50
+ /** Mapping of env variable name with functions that should run to check their validity */
51
+ private checkEnvironment: Record<string, ValidatorSpec<unknown>>;
52
+ /** Middleware that should run on every request before the endpoint specific logic */
53
+ private globalMiddleware: Array<ServerGlobalMiddleware>;
54
+ /** Error middleware that should run on every request after the endpoint specific logic, but before the generic global middleware */
55
+ private errorMiddleware: Array<
56
+ ServerGlobalMiddleware | ServerErrorMiddleWare
57
+ >;
58
+ /** Functions that should be called on server startup */
59
+ private initCallbacks: Array<ServerCallback>;
60
+ /** Functions that should be called on server shutdown */
61
+ private shutdownCallbacks: Array<ServerCallback>;
62
+ /** When set to true, this indicates that init callbacks should run synchronously in the order they are declared. By default they all run in parallel */
63
+ private syncCallbacks: boolean;
64
+ /** Config to set regularly running jobs on the server */
65
+ private cron?: Array<ServerCronJon>;
66
+ /** Global auth related configuration */
67
+ private auth: ServerAuthConfig;
68
+ /** WebSocket server instance, if configured */
69
+ private wss?: WebSocketServer;
70
+ /** Abort controller that handles signals for the server */
71
+ private abortController = new AbortController();
72
+
73
+ /** Create a server */
74
+ public constructor(config: ServerOptions) {
75
+ this.validate(config);
76
+
77
+ reportDebug({
78
+ namespace,
79
+ message: `Creating server`
80
+ });
81
+
82
+ this.endpoints = config.endpoints;
83
+ this.globalMiddleware = config.globalMiddleware ?? [];
84
+ this.errorMiddleware = config.errorMiddleware ?? [];
85
+ this.initCallbacks = config.initCallbacks ?? [];
86
+ this.shutdownCallbacks = config.shutdownCallbacks ?? [];
87
+ this.syncCallbacks = config.syncCallbacks ?? false;
88
+ this.cron = config.cron;
89
+ this.auth = { noFetch: false, ...config.auth };
90
+
91
+ // The minimal environment check is different between the migration modes of execution and the regular server execution mode
92
+ // When running in migration mode, we only check that we have SQL related environment variables
93
+ this.checkEnvironment =
94
+ process.env.RUN_MIGRATION === 'true' ||
95
+ process.env.UNDO_MIGRATION === 'true'
96
+ ? {
97
+ SQL_HOST: envAssert.isHost(),
98
+ SQL_USER: envAssert.isString(),
99
+ SQL_PASSWORD: envAssert.isString(),
100
+ SQL_DB: envAssert.isString()
101
+ }
102
+ : {
103
+ NODE_ENV: envAssert.isString(),
104
+ PORT: envAssert.isPort(),
105
+ SECONDARY_PORT: envAssert.isPort(),
106
+ ...config.checkEnvironment
107
+ };
108
+
109
+ checkEnvironment(this.checkEnvironment);
110
+
111
+ // Create the primary express core that serves the business logic
112
+ this.app = express();
113
+ this.registerMiddleware(this.app);
114
+ this.httpServer = createHttpServer(this.app);
115
+
116
+ // Create a secondary express core that servers metrics and analytics
117
+ // This will be served on a different port, allowing to specify different firewall rules for these routes
118
+ this.secondaryApp = express();
119
+ [...secondaryMiddleware, ...defaultErrorMiddleware].forEach(
120
+ (middleware) => {
121
+ if (middleware) this.secondaryApp.use(middleware);
122
+ }
123
+ );
124
+ this.secondaryHttpServer = createHttpServer(this.secondaryApp);
125
+
126
+ // Remove the express headers
127
+ this.app.disable('x-powered-by');
128
+ this.secondaryApp.disable('x-powered-by');
129
+
130
+ // We remove all node timeout on connections and requests
131
+ // This responsibility is delegated to the front-facing load balancer
132
+ [this.httpServer, this.secondaryHttpServer].forEach((server) => {
133
+ server.headersTimeout = 0;
134
+ server.keepAliveTimeout = 0;
135
+ });
136
+
137
+ if (config.webSocket) {
138
+ this.attachWebSocket(config.webSocket);
139
+ }
140
+ }
141
+
142
+ /** Start the server */
143
+ public async init(): Promise<void> {
144
+ reportDebug({ namespace, message: `Starting Server` });
145
+ // Fetch the keys for JWT authentication
146
+ // Ignore in test environment as we do symmetrical token signing
147
+ if (process.env.NODE_ENV !== 'test' && !this.auth.noFetch)
148
+ await initKeySets();
149
+ // Run all the init callbacks
150
+ // We can either run them all 1/1 synchronously or run them all in parallel (default)
151
+ // Callback can either be direct function or an object with function and parameters attributes
152
+
153
+ if (this.syncCallbacks) {
154
+ for (const callback of this.initCallbacks) {
155
+ await this.runCallback(callback);
156
+ }
157
+ } else {
158
+ await Promise.all(
159
+ this.initCallbacks.map((callback) => this.runCallback(callback))
160
+ );
161
+ }
162
+
163
+ // Initialize the Pub/Sub module
164
+ await PubSub.init();
165
+ // Run all the cronjob
166
+ if (this.cron) {
167
+ this.cron.forEach((job) => {
168
+ this.runCronJob(job);
169
+ });
170
+ }
171
+
172
+ // Start listening to requests
173
+ await Promise.all([
174
+ new Promise<void>((resolve) =>
175
+ this.httpServer.listen(process.env.PORT, () => {
176
+ resolve();
177
+ })
178
+ ),
179
+ new Promise<void>((resolve) =>
180
+ this.secondaryHttpServer.listen(process.env.SECONDARY_PORT, () => {
181
+ resolve();
182
+ })
183
+ )
184
+ ]);
185
+ reportInfo({
186
+ message: 'SERVER_RUNNING',
187
+ data: {
188
+ port: process.env.PORT,
189
+ secondaryPort: process.env.SECONDARY_PORT,
190
+ nodeEnv: process.env.NODE_ENV
191
+ }
192
+ });
193
+
194
+ this.handleSignal();
195
+
196
+ // Watch TSL config files changing
197
+ this.watchTlsCaFileChange();
198
+ }
199
+
200
+ /** Graceful shutdown */
201
+ public async shutdown(): Promise<void> {
202
+ reportDebug({ namespace, message: `Shutting down Server` });
203
+
204
+ // Stop listening to HTTP requests
205
+ await Promise.all(
206
+ [this.httpServer, this.secondaryHttpServer].map((server) => {
207
+ // Ignore if the server was already stopped
208
+ // We have observed cases where SIGTERM was thrown multiple times
209
+ if (!server.listening) return;
210
+ const { port } = server.address() as AddressInfo;
211
+ server.on('close', (error: unknown) => {
212
+ if (error) {
213
+ reportError(error);
214
+ process.exit(1);
215
+ } else {
216
+ reportInfo({
217
+ message: `Stopped listening to requests on port ${port}`
218
+ });
219
+ }
220
+ });
221
+ server.close();
222
+ })
223
+ );
224
+
225
+ // Close all socket connections
226
+ if (this.wss) {
227
+ // First ask then to close gracefully
228
+ this.wss.clients.forEach((socket) => {
229
+ socket.close();
230
+ });
231
+ // Hard terminate all connections still open after a defined time
232
+ const socketKillTimeout = process.env.WEBSOCKET_CLOSE_TIMEOUT
233
+ ? parseInt(process.env.WEBSOCKET_CLOSE_TIMEOUT)
234
+ : 5000;
235
+ await new Promise<void>((resolve) => {
236
+ setTimeout(() => {
237
+ (this.wss as WebSocketServer).clients.forEach((socket) => {
238
+ if (
239
+ socket.readyState === socket.CLOSING ||
240
+ socket.readyState === socket.OPEN
241
+ ) {
242
+ socket.terminate();
243
+ }
244
+ });
245
+ resolve();
246
+ }, socketKillTimeout);
247
+ });
248
+ }
249
+
250
+ // Run all the shutdown callback
251
+ if (this.syncCallbacks) {
252
+ for (const callback of this.shutdownCallbacks) {
253
+ await this.runCallback(callback);
254
+ }
255
+ } else {
256
+ await Promise.all(
257
+ this.shutdownCallbacks.map((callback) => this.runCallback(callback))
258
+ );
259
+ }
260
+
261
+ // Shutdown all the running entities
262
+ await LifecycleController.shutdownRunningInstances();
263
+
264
+ // Abort all the cronjob
265
+ if (this.abortController) this.abortController.abort();
266
+
267
+ // Stop the keyset timers
268
+ shutdownKeySets();
269
+
270
+ shutdownSignals.forEach((signal) => process.removeAllListeners(signal));
271
+ }
272
+
273
+ /** Get the express app instance of the server */
274
+ public getApp(): Application {
275
+ return this.app;
276
+ }
277
+
278
+ /** Get the express app instance of the server */
279
+ public getSecondaryApp(): Application {
280
+ return this.secondaryApp;
281
+ }
282
+
283
+ /** Registers all the middleware with the express app */
284
+ private registerMiddleware(app: Application): void {
285
+ // Global middleware can specify a path to which they apply
286
+ [...defaultMiddleware, ...this.globalMiddleware].forEach((middleware) => {
287
+ if (typeof middleware === 'function') {
288
+ app.use(middleware);
289
+ } else {
290
+ app.use(middleware.path, middleware.middleware);
291
+ }
292
+ });
293
+ // Call the register method of each endpoint
294
+ this.endpoints.forEach((endpoint) => {
295
+ endpoint.register(app);
296
+ });
297
+ // Add error middleware
298
+ [...this.errorMiddleware, ...defaultErrorMiddleware].forEach(
299
+ (middleware) => {
300
+ if (typeof middleware === 'function') {
301
+ app.use(middleware);
302
+ } else {
303
+ app.use(middleware.path, middleware.middleware);
304
+ }
305
+ }
306
+ );
307
+ }
308
+
309
+ /** Add a handler for WebSocket connections */
310
+ private attachWebSocket(options: ServerWebSocketConfig): void {
311
+ this.wss = new WebSocketServer({
312
+ ...options.server,
313
+ server: this.httpServer
314
+ })
315
+ .on('connection', (webSocket, request) => {
316
+ new SocketClient(webSocket, request, options.client);
317
+ })
318
+ .on('error', (error) => {
319
+ reportError(error);
320
+ });
321
+ }
322
+
323
+ /** Call shutdown if signal gets sent to the process */
324
+ private handleSignal(): void {
325
+ shutdownSignals.forEach((signal) =>
326
+ process.on(signal, () => {
327
+ (async (): Promise<void> => {
328
+ reportInfo(`Received shutdown signal [${signal}]`);
329
+ await this.shutdown();
330
+ })().catch((error) => {
331
+ reportError(error);
332
+ });
333
+ })
334
+ );
335
+ }
336
+
337
+ /** Watch the TLS certificate change event */
338
+ private watchTlsCaFileChange(): void {
339
+ [
340
+ 'TLS_REQUEST_KEY',
341
+ 'TLS_REQUEST_KEY_PASSPHRASE',
342
+ 'TLS_REQUEST_CERT',
343
+ 'TLS_REQUEST_CA',
344
+ 'TLS_SERVER_KEY',
345
+ 'TLS_SERVER_KEY_PASSPHRASE',
346
+ 'TLS_SERVER_CERT',
347
+ 'TLS_CA'
348
+ ].forEach((key) => {
349
+ const file = process.env[key];
350
+ if (file)
351
+ fs.watch(path.resolve(file), (event) => {
352
+ if (event !== 'change') return;
353
+ reportInfo(`Reloading TLS config [${file} changed]`);
354
+ loadTlsConfig();
355
+ (this.httpServer as https.Server).setSecureContext(
356
+ tlsConfig as TlsConfig
357
+ );
358
+ });
359
+ });
360
+ }
361
+
362
+ /** Executes a recurring job */
363
+ private runCronJob(job: ServerCronJon): void {
364
+ (async (): Promise<void> => {
365
+ reportInfo({ message: `Starting scheduled job "${job.handler.name}"` });
366
+ try {
367
+ await job.handler();
368
+ reportInfo({
369
+ message: `Job "${job.handler.name}" finished, starting again in ${job.interval} seconds`
370
+ });
371
+ await setTimeoutPromise(job.interval * 1000, undefined, {
372
+ signal: this.abortController.signal
373
+ });
374
+ this.runCronJob(job);
375
+ } catch (error) {
376
+ if (error instanceof Error && error.name === 'AbortError') {
377
+ reportDebug({
378
+ namespace,
379
+ message: `Scheduled job "${job.handler?.name}" has been aborted`
380
+ });
381
+ } else {
382
+ throw error;
383
+ }
384
+ }
385
+ })().catch((error) => {
386
+ reportError(error);
387
+ });
388
+ }
389
+
390
+ /** Run a shutdown/init callback */
391
+ private runCallback(callback: ServerCallback): unknown {
392
+ return typeof callback === 'function'
393
+ ? callback()
394
+ : callback.function.apply(null, callback.parameters ?? []);
395
+ }
396
+
397
+ /**
398
+ * Validate the Server constructor configuration
399
+ */
400
+ private validate(config: ServerOptions): void {
401
+ if (
402
+ !config.endpoints ||
403
+ config.endpoints.some((endpoint) => !(endpoint instanceof Endpoint))
404
+ )
405
+ throw new EngineError(
406
+ 'Server endpoints should be declared and all be Endpoint instances'
407
+ );
408
+
409
+ if (
410
+ config.checkEnvironment &&
411
+ Object.values(config.checkEnvironment).some(
412
+ (validator) => typeof validator !== 'function'
413
+ )
414
+ )
415
+ throw new EngineError(
416
+ 'Some of the environment checks are not valid functions'
417
+ );
418
+
419
+ if (
420
+ config.initCallbacks &&
421
+ (!(config.initCallbacks instanceof Array) ||
422
+ config.initCallbacks.some(
423
+ (callback) =>
424
+ !(
425
+ typeof callback === 'function' ||
426
+ typeof callback?.function === 'function'
427
+ )
428
+ ))
429
+ )
430
+ throw new EngineError('Init callbacks is not a list of functions');
431
+
432
+ if (
433
+ config.shutdownCallbacks &&
434
+ (!(config.shutdownCallbacks instanceof Array) ||
435
+ config.shutdownCallbacks.some(
436
+ (callback) =>
437
+ !(
438
+ typeof callback === 'function' ||
439
+ typeof callback?.function === 'function'
440
+ )
441
+ ))
442
+ )
443
+ throw new EngineError('Shutdown callbacks is not a list of functions');
444
+ }
445
+ }