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,401 +1,401 @@
1
- import { randomUUID } from 'crypto';
2
- import { IncomingMessage } from 'http';
3
- import WS, { RawData } from 'ws';
4
- import { parseMessage } from './parseMessage';
5
- import {
6
- SocketClientOptions,
7
- SocketClientSendMessageOptions,
8
- SocketAuthenticationMessage,
9
- SocketClientCallback,
10
- SocketClientList,
11
- SocketUser
12
- } from './SocketClient.types';
13
- import { LogSeverity } from 'const';
14
- import { EngineError } from 'entities/EngineError';
15
- import { MessageHandler } from 'entities/MessageHandler';
16
- import { ValidationError } from 'entities/ValidationError';
17
- import { WebError } from 'entities/WebError';
18
- import { jwtVerify, UserTokenPayload } from 'utils/jwt';
19
- import { reportInfo, reportError, reportDebug } from 'utils/report';
20
-
21
- const namespace = 'SocketClient';
22
-
23
- /**
24
- * Class where each instance represents a client connected through web-sockets
25
- */
26
- export class SocketClient {
27
- /** Mapping of all the connected socket clients */
28
- private static socketClients: SocketClientList = {};
29
- /** Unique identifier of the client */
30
- public readonly id: string;
31
- /** Date at which the client connection was established */
32
- public readonly establishedAt: Date;
33
- /** WS instance of the client connection */
34
- private ws: WS;
35
- /** List of message handlers that are registered with the client */
36
- private handlers: Array<MessageHandler>;
37
- /** Callback function that are called when the client is created */
38
- private initCallbacks: Array<SocketClientCallback> = [];
39
- /** Callback function that are called when the client successfully authenticates */
40
- private authCallbacks: Array<SocketClientCallback> = [];
41
- /** Callback function that are called when the client connection is terminated */
42
- private shutdownCallbacks: Array<SocketClientCallback> = [];
43
- /** Authentication status of the client */
44
- private authenticated = false;
45
- /** Timer used to track when to send authentication renewal reminder to the client */
46
- private authRenewTimer: NodeJS.Timeout | string | number | undefined;
47
- /** Timers used to track the time at which a user losses authentication */
48
- private authExpireTimer: NodeJS.Timeout | string | number | undefined;
49
- /** ID of the user that is authenticated */
50
- private userId: undefined | string;
51
- /** ID of the device with which the client authenticated */
52
- private deviceId: undefined | string;
53
- /** Id of the token with which the client authenticated */
54
- private tokenId: undefined | string;
55
- /** Audience claims that were in the latest authentication token used by the client */
56
- private audience: undefined | Array<string>;
57
- /** Status tracking variable used to check the liveness of connections */
58
- private isAlive = true;
59
- /** Timer used to track interval between client pinging */
60
- private pingInterval: NodeJS.Timeout | string | number | undefined;
61
-
62
- /**
63
- * Create a WS client
64
- */
65
- public constructor(
66
- webSocket: WS,
67
- request: IncomingMessage,
68
- options: SocketClientOptions
69
- ) {
70
- this.id = randomUUID();
71
- this.ws = webSocket;
72
- this.establishedAt = new Date();
73
-
74
- reportDebug({ namespace, message: `Creating socket client [${this.id}]` });
75
-
76
- // Make sure that callbacks are made as lists of functions
77
- // Init
78
- if (typeof options.initCallbacks === 'function')
79
- this.initCallbacks = [options.initCallbacks];
80
- else if (options.initCallbacks instanceof Array)
81
- this.initCallbacks = options.initCallbacks;
82
- // Auth
83
- if (typeof options.authCallbacks === 'function')
84
- this.authCallbacks = [options.authCallbacks];
85
- else if (options.authCallbacks instanceof Array)
86
- this.authCallbacks = options.authCallbacks;
87
- // Shutdown
88
- if (typeof options.shutdownCallbacks === 'function')
89
- this.shutdownCallbacks = [options.shutdownCallbacks];
90
- else if (options.shutdownCallbacks instanceof Array)
91
- this.shutdownCallbacks = options.shutdownCallbacks;
92
-
93
- // Check that all handlers are valid
94
- this.handlers = options.handlers;
95
- for (const handler of this.handlers) {
96
- if (!(handler instanceof MessageHandler))
97
- throw new EngineError({
98
- message: 'Handler is not an instance of MessageHandler'
99
- });
100
- }
101
- // Register in clients list
102
- SocketClient.socketClients[this.id] = this;
103
-
104
- reportInfo({ message: `Client connected [${this.id}]` });
105
- // On socket close, deregister from clients list
106
- this.ws.on('close', () => {
107
- this.handleClose
108
- .bind(this)()
109
- .catch((error) => {
110
- reportError(error);
111
- });
112
- });
113
- // On socket error, log the error
114
- this.ws.on('error', (error) => {
115
- reportError(
116
- new EngineError({
117
- severity: LogSeverity.WARNING,
118
- message: `Error [${this.id}]`
119
- })
120
- );
121
- reportError(error);
122
- });
123
- // When receiving a message, call message handler
124
- this.ws.on('message', (data) => {
125
- this.handleMessage
126
- .bind(this)(data)
127
- .catch((error) => {
128
- reportError(error);
129
- });
130
- });
131
-
132
- // Run all the init callbacks
133
- // For proper error handling of potential asynchronous callbacks, we wrap the execution in an auto-executing async function
134
- (async (): Promise<void> => {
135
- const callbackResults = await Promise.allSettled(
136
- this.initCallbacks.map((callback) => callback(this))
137
- );
138
- callbackResults.forEach((result) => {
139
- if (result.status === 'rejected') reportError(result.reason);
140
- });
141
- })().catch((error) => {
142
- reportError(error);
143
- });
144
-
145
- // Server -> client ping mechanism using WS standard ping control frames
146
- // We terminate the connection if we did not get a reply in the previous interval
147
- this.pingInterval = setInterval(
148
- () => {
149
- if (!this.isAlive) {
150
- reportError(
151
- new EngineError({
152
- severity: LogSeverity.WARNING,
153
- message: `Terminating socket connection, ping timeout [${this.id}]`
154
- })
155
- );
156
- this.ws.terminate();
157
- return;
158
- }
159
- this.isAlive = false;
160
- this.ws.ping();
161
- reportDebug({ namespace, message: `Ping sent to client [${this.id}]` });
162
- },
163
- process.env.WS_PING_INTERVAL
164
- ? parseInt(process.env.WS_PING_INTERVAL) * 1000
165
- : 30000
166
- );
167
-
168
- // Track the connection as alive as we get a pong back
169
- this.ws.on('pong', () => {
170
- reportDebug({
171
- namespace,
172
- message: `Client responded to ping [${this.id}]`
173
- });
174
- this.isAlive = true;
175
- });
176
- }
177
-
178
- /** Get the list of all connected clients indexed by ID */
179
- public static getSocketClients(): SocketClientList {
180
- return this.socketClients;
181
- }
182
-
183
- /** Get a client by his ID */
184
- public static getSocketClient(id: string): SocketClient | undefined {
185
- return this.socketClients[id];
186
- }
187
-
188
- /**
189
- * Send a message to the client
190
- */
191
- public sendMessage(
192
- type: string,
193
- payload: unknown = {},
194
- options: SocketClientSendMessageOptions = {}
195
- ): void {
196
- reportDebug({
197
- namespace,
198
- message: `Received request to send message to client of type "${type}" [${this.id}]`,
199
- data: { options }
200
- });
201
- let send = false;
202
- // If the message is sent to unauthenticated user skip auth check
203
- if (options.noAuth) send = true;
204
- // If the message is authenticated and with the correct audience, it gets sent
205
- else if (
206
- this.authenticated &&
207
- (this.audience as Array<string>).includes(
208
- options.audience ?? (process.env.DEFAULT_MESSAGE_AUDIENCE as string)
209
- )
210
- )
211
- send = true;
212
-
213
- if (send) {
214
- reportDebug({
215
- namespace,
216
- message: `Sending message to client of type "${type ?? 'unknown'}" [${this.id}]`
217
- });
218
- this.ws.send(JSON.stringify({ type, payload }));
219
- }
220
- }
221
-
222
- /** Get the client authentication status */
223
- public isAuthenticated(): boolean {
224
- return this.authenticated;
225
- }
226
-
227
- /** Fetch data on the user if he is authenticated */
228
- public getUser(): SocketUser | undefined {
229
- if (this.authenticated)
230
- return {
231
- userId: this.userId as string,
232
- deviceId: this.deviceId as string,
233
- tokenId: this.tokenId as string,
234
- audience: this.audience as Array<string>
235
- };
236
- }
237
-
238
- /** Process an incoming message */
239
- private async handleMessage(data: RawData): Promise<void> {
240
- try {
241
- const message = parseMessage(data.toString('utf-8'));
242
- reportInfo({
243
- message: `Received message of type "${message?.type ?? 'unknown'}" [${this.id}]`
244
- });
245
- switch (message.type) {
246
- case 'authenticate':
247
- await this.authenticate(message as SocketAuthenticationMessage);
248
- break;
249
- // As not all client libraries allow sending pings through WS control frames,
250
- // we add a higher level ping mechanism
251
- case 'ping':
252
- reportDebug({
253
- namespace,
254
- message: `Received ping from client [${this.id}]`
255
- });
256
- this.sendMessage('pong', {}, { noAuth: true });
257
- break;
258
- default:
259
- for (const handler of this.handlers) {
260
- await handler.handle(message, this);
261
- }
262
- }
263
- } catch (error) {
264
- this.handleError(error);
265
- }
266
- }
267
-
268
- /**
269
- * Process an authentication request
270
- * @param {String} message - Authentication message
271
- */
272
- private async authenticate(
273
- message: SocketAuthenticationMessage
274
- ): Promise<void> {
275
- const token = message.payload?.token;
276
- if (!token) {
277
- throw new WebError({
278
- errorCode: 'no-token',
279
- message: 'No token was given',
280
- data: { message }
281
- });
282
- }
283
- const payload = await jwtVerify(token);
284
- this.setUserData(payload);
285
-
286
- this.authenticated = true;
287
- // Time remaining before token expiration
288
- const authExpiration = payload.exp * 1000 - Date.now();
289
- // Clear previously created timers
290
- this.clearTimeouts();
291
- // Send a refresh request to the client 1 minute before expiration
292
- this.authRenewTimer = setTimeout(
293
- () => {
294
- this.sendMessage('renewAuthentication');
295
- },
296
- authExpiration - 60 * 1000
297
- );
298
- // Expire client authentication
299
- this.authExpireTimer = setTimeout(() => {
300
- this.authenticated = false;
301
- }, authExpiration);
302
-
303
- // Run all the post-authentication callbacks
304
- const callbackResults = await Promise.allSettled(
305
- this.authCallbacks.map((callback) => callback(this))
306
- );
307
- callbackResults.forEach((result) => {
308
- if (result.status === 'rejected') reportError(result.reason);
309
- });
310
- }
311
-
312
- // Clear all the pending timers
313
- /** */
314
- private clearTimeouts(): void {
315
- if (this.authRenewTimer) clearTimeout(this.authRenewTimer);
316
- if (this.authExpireTimer) clearTimeout(this.authExpireTimer);
317
- }
318
-
319
- /**
320
- * Fetch the user's data and attach it to the connection for new connections. For existing connections, it checks that the authentication is done on the same user.
321
- */
322
- private setUserData({ sub, dev, jti, aud }: UserTokenPayload): void {
323
- // Check if the user is already authenticated
324
- if (this.userId) {
325
- // Check that the token is for the same connection as before
326
- if (this.userId && this.userId !== sub)
327
- throw new WebError({
328
- errorCode: 'wrong-user-token',
329
- message:
330
- 'A user tried to authenticate with a token that is not for him [userId]'
331
- });
332
- } else {
333
- // Set the user's ID
334
- this.userId = sub;
335
- // Set the user's Device Id
336
- this.deviceId = dev;
337
- // Set the token ID
338
- this.tokenId = jti;
339
- // Set the aud
340
- this.audience = aud instanceof Array ? aud : [aud];
341
-
342
- reportDebug({
343
- namespace,
344
- message: `Successfully authenticated client [${this.id}]`,
345
- data: {
346
- userId: this.userId,
347
- deviceId: this.deviceId,
348
- tokenId: this.tokenId,
349
- audience: this.audience
350
- }
351
- });
352
- }
353
- }
354
-
355
- /**
356
- * Properly return errors to clients
357
- */
358
- private handleError(error: unknown): void {
359
- reportError(error);
360
- if (error instanceof WebError) {
361
- this.sendMessage(
362
- 'error',
363
- { errorCode: error.errorCode, hint: error.hint },
364
- { noAuth: true }
365
- );
366
- } else if (error instanceof ValidationError) {
367
- this.sendMessage(
368
- 'error',
369
- { errorCode: 'validation-error', hint: error.data },
370
- { noAuth: true }
371
- );
372
- } else {
373
- this.sendMessage(
374
- 'error',
375
- { errorCode: 'server-error' },
376
- { noAuth: true }
377
- );
378
- }
379
- }
380
-
381
- /**
382
- * Process a socket close event
383
- */
384
- private async handleClose(code?: string, reason?: string): Promise<void> {
385
- delete SocketClient.socketClients[this.id];
386
- this.clearTimeouts();
387
- // Stop ping process
388
- if (this.pingInterval) clearInterval(this.pingInterval);
389
- // Run all the shutdown callbacks
390
- const callbackResults = await Promise.allSettled(
391
- this.shutdownCallbacks.map((callback) => callback(this))
392
- );
393
- callbackResults.forEach((result) => {
394
- if (result.status === 'rejected') reportError(result.reason);
395
- });
396
- reportInfo({
397
- message: `Client disconnected [${this.id}]`,
398
- data: { code, reason }
399
- });
400
- }
401
- }
1
+ import { randomUUID } from 'crypto';
2
+ import { IncomingMessage } from 'http';
3
+ import WS, { RawData } from 'ws';
4
+ import { parseMessage } from './parseMessage';
5
+ import {
6
+ SocketClientOptions,
7
+ SocketClientSendMessageOptions,
8
+ SocketAuthenticationMessage,
9
+ SocketClientCallback,
10
+ SocketClientList,
11
+ SocketUser
12
+ } from './SocketClient.types';
13
+ import { LogSeverity } from 'const';
14
+ import { EngineError } from 'entities/EngineError';
15
+ import { MessageHandler } from 'entities/MessageHandler';
16
+ import { ValidationError } from 'entities/ValidationError';
17
+ import { WebError } from 'entities/WebError';
18
+ import { jwtVerify, UserTokenPayload } from 'utils/jwt';
19
+ import { reportInfo, reportError, reportDebug } from 'utils/report';
20
+
21
+ const namespace = 'SocketClient';
22
+
23
+ /**
24
+ * Class where each instance represents a client connected through web-sockets
25
+ */
26
+ export class SocketClient {
27
+ /** Mapping of all the connected socket clients */
28
+ private static socketClients: SocketClientList = {};
29
+ /** Unique identifier of the client */
30
+ public readonly id: string;
31
+ /** Date at which the client connection was established */
32
+ public readonly establishedAt: Date;
33
+ /** WS instance of the client connection */
34
+ private ws: WS;
35
+ /** List of message handlers that are registered with the client */
36
+ private handlers: Array<MessageHandler>;
37
+ /** Callback function that are called when the client is created */
38
+ private initCallbacks: Array<SocketClientCallback> = [];
39
+ /** Callback function that are called when the client successfully authenticates */
40
+ private authCallbacks: Array<SocketClientCallback> = [];
41
+ /** Callback function that are called when the client connection is terminated */
42
+ private shutdownCallbacks: Array<SocketClientCallback> = [];
43
+ /** Authentication status of the client */
44
+ private authenticated = false;
45
+ /** Timer used to track when to send authentication renewal reminder to the client */
46
+ private authRenewTimer: NodeJS.Timeout | string | number | undefined;
47
+ /** Timers used to track the time at which a user losses authentication */
48
+ private authExpireTimer: NodeJS.Timeout | string | number | undefined;
49
+ /** ID of the user that is authenticated */
50
+ private userId: undefined | string;
51
+ /** ID of the device with which the client authenticated */
52
+ private deviceId: undefined | string;
53
+ /** Id of the token with which the client authenticated */
54
+ private tokenId: undefined | string;
55
+ /** Audience claims that were in the latest authentication token used by the client */
56
+ private audience: undefined | Array<string>;
57
+ /** Status tracking variable used to check the liveness of connections */
58
+ private isAlive = true;
59
+ /** Timer used to track interval between client pinging */
60
+ private pingInterval: NodeJS.Timeout | string | number | undefined;
61
+
62
+ /**
63
+ * Create a WS client
64
+ */
65
+ public constructor(
66
+ webSocket: WS,
67
+ request: IncomingMessage,
68
+ options: SocketClientOptions
69
+ ) {
70
+ this.id = randomUUID();
71
+ this.ws = webSocket;
72
+ this.establishedAt = new Date();
73
+
74
+ reportDebug({ namespace, message: `Creating socket client [${this.id}]` });
75
+
76
+ // Make sure that callbacks are made as lists of functions
77
+ // Init
78
+ if (typeof options.initCallbacks === 'function')
79
+ this.initCallbacks = [options.initCallbacks];
80
+ else if (options.initCallbacks instanceof Array)
81
+ this.initCallbacks = options.initCallbacks;
82
+ // Auth
83
+ if (typeof options.authCallbacks === 'function')
84
+ this.authCallbacks = [options.authCallbacks];
85
+ else if (options.authCallbacks instanceof Array)
86
+ this.authCallbacks = options.authCallbacks;
87
+ // Shutdown
88
+ if (typeof options.shutdownCallbacks === 'function')
89
+ this.shutdownCallbacks = [options.shutdownCallbacks];
90
+ else if (options.shutdownCallbacks instanceof Array)
91
+ this.shutdownCallbacks = options.shutdownCallbacks;
92
+
93
+ // Check that all handlers are valid
94
+ this.handlers = options.handlers;
95
+ for (const handler of this.handlers) {
96
+ if (!(handler instanceof MessageHandler))
97
+ throw new EngineError({
98
+ message: 'Handler is not an instance of MessageHandler'
99
+ });
100
+ }
101
+ // Register in clients list
102
+ SocketClient.socketClients[this.id] = this;
103
+
104
+ reportInfo({ message: `Client connected [${this.id}]` });
105
+ // On socket close, deregister from clients list
106
+ this.ws.on('close', () => {
107
+ this.handleClose
108
+ .bind(this)()
109
+ .catch((error) => {
110
+ reportError(error);
111
+ });
112
+ });
113
+ // On socket error, log the error
114
+ this.ws.on('error', (error) => {
115
+ reportError(
116
+ new EngineError({
117
+ severity: LogSeverity.WARNING,
118
+ message: `Error [${this.id}]`
119
+ })
120
+ );
121
+ reportError(error);
122
+ });
123
+ // When receiving a message, call message handler
124
+ this.ws.on('message', (data) => {
125
+ this.handleMessage
126
+ .bind(this)(data)
127
+ .catch((error) => {
128
+ reportError(error);
129
+ });
130
+ });
131
+
132
+ // Run all the init callbacks
133
+ // For proper error handling of potential asynchronous callbacks, we wrap the execution in an auto-executing async function
134
+ (async (): Promise<void> => {
135
+ const callbackResults = await Promise.allSettled(
136
+ this.initCallbacks.map((callback) => callback(this))
137
+ );
138
+ callbackResults.forEach((result) => {
139
+ if (result.status === 'rejected') reportError(result.reason);
140
+ });
141
+ })().catch((error) => {
142
+ reportError(error);
143
+ });
144
+
145
+ // Server -> client ping mechanism using WS standard ping control frames
146
+ // We terminate the connection if we did not get a reply in the previous interval
147
+ this.pingInterval = setInterval(
148
+ () => {
149
+ if (!this.isAlive) {
150
+ reportError(
151
+ new EngineError({
152
+ severity: LogSeverity.WARNING,
153
+ message: `Terminating socket connection, ping timeout [${this.id}]`
154
+ })
155
+ );
156
+ this.ws.terminate();
157
+ return;
158
+ }
159
+ this.isAlive = false;
160
+ this.ws.ping();
161
+ reportDebug({ namespace, message: `Ping sent to client [${this.id}]` });
162
+ },
163
+ process.env.WS_PING_INTERVAL
164
+ ? parseInt(process.env.WS_PING_INTERVAL) * 1000
165
+ : 30000
166
+ );
167
+
168
+ // Track the connection as alive as we get a pong back
169
+ this.ws.on('pong', () => {
170
+ reportDebug({
171
+ namespace,
172
+ message: `Client responded to ping [${this.id}]`
173
+ });
174
+ this.isAlive = true;
175
+ });
176
+ }
177
+
178
+ /** Get the list of all connected clients indexed by ID */
179
+ public static getSocketClients(): SocketClientList {
180
+ return this.socketClients;
181
+ }
182
+
183
+ /** Get a client by his ID */
184
+ public static getSocketClient(id: string): SocketClient | undefined {
185
+ return this.socketClients[id];
186
+ }
187
+
188
+ /**
189
+ * Send a message to the client
190
+ */
191
+ public sendMessage(
192
+ type: string,
193
+ payload: unknown = {},
194
+ options: SocketClientSendMessageOptions = {}
195
+ ): void {
196
+ reportDebug({
197
+ namespace,
198
+ message: `Received request to send message to client of type "${type}" [${this.id}]`,
199
+ data: { options }
200
+ });
201
+ let send = false;
202
+ // If the message is sent to unauthenticated user skip auth check
203
+ if (options.noAuth) send = true;
204
+ // If the message is authenticated and with the correct audience, it gets sent
205
+ else if (
206
+ this.authenticated &&
207
+ (this.audience as Array<string>).includes(
208
+ options.audience ?? (process.env.DEFAULT_MESSAGE_AUDIENCE as string)
209
+ )
210
+ )
211
+ send = true;
212
+
213
+ if (send) {
214
+ reportDebug({
215
+ namespace,
216
+ message: `Sending message to client of type "${type ?? 'unknown'}" [${this.id}]`
217
+ });
218
+ this.ws.send(JSON.stringify({ type, payload }));
219
+ }
220
+ }
221
+
222
+ /** Get the client authentication status */
223
+ public isAuthenticated(): boolean {
224
+ return this.authenticated;
225
+ }
226
+
227
+ /** Fetch data on the user if he is authenticated */
228
+ public getUser(): SocketUser | undefined {
229
+ if (this.authenticated)
230
+ return {
231
+ userId: this.userId as string,
232
+ deviceId: this.deviceId as string,
233
+ tokenId: this.tokenId as string,
234
+ audience: this.audience as Array<string>
235
+ };
236
+ }
237
+
238
+ /** Process an incoming message */
239
+ private async handleMessage(data: RawData): Promise<void> {
240
+ try {
241
+ const message = parseMessage(data.toString('utf-8'));
242
+ reportInfo({
243
+ message: `Received message of type "${message?.type ?? 'unknown'}" [${this.id}]`
244
+ });
245
+ switch (message.type) {
246
+ case 'authenticate':
247
+ await this.authenticate(message as SocketAuthenticationMessage);
248
+ break;
249
+ // As not all client libraries allow sending pings through WS control frames,
250
+ // we add a higher level ping mechanism
251
+ case 'ping':
252
+ reportDebug({
253
+ namespace,
254
+ message: `Received ping from client [${this.id}]`
255
+ });
256
+ this.sendMessage('pong', {}, { noAuth: true });
257
+ break;
258
+ default:
259
+ for (const handler of this.handlers) {
260
+ await handler.handle(message, this);
261
+ }
262
+ }
263
+ } catch (error) {
264
+ this.handleError(error);
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Process an authentication request
270
+ * @param {String} message - Authentication message
271
+ */
272
+ private async authenticate(
273
+ message: SocketAuthenticationMessage
274
+ ): Promise<void> {
275
+ const token = message.payload?.token;
276
+ if (!token) {
277
+ throw new WebError({
278
+ errorCode: 'no-token',
279
+ message: 'No token was given',
280
+ data: { message }
281
+ });
282
+ }
283
+ const payload = await jwtVerify(token);
284
+ this.setUserData(payload);
285
+
286
+ this.authenticated = true;
287
+ // Time remaining before token expiration
288
+ const authExpiration = payload.exp * 1000 - Date.now();
289
+ // Clear previously created timers
290
+ this.clearTimeouts();
291
+ // Send a refresh request to the client 1 minute before expiration
292
+ this.authRenewTimer = setTimeout(
293
+ () => {
294
+ this.sendMessage('renewAuthentication');
295
+ },
296
+ authExpiration - 60 * 1000
297
+ );
298
+ // Expire client authentication
299
+ this.authExpireTimer = setTimeout(() => {
300
+ this.authenticated = false;
301
+ }, authExpiration);
302
+
303
+ // Run all the post-authentication callbacks
304
+ const callbackResults = await Promise.allSettled(
305
+ this.authCallbacks.map((callback) => callback(this))
306
+ );
307
+ callbackResults.forEach((result) => {
308
+ if (result.status === 'rejected') reportError(result.reason);
309
+ });
310
+ }
311
+
312
+ // Clear all the pending timers
313
+ /** */
314
+ private clearTimeouts(): void {
315
+ if (this.authRenewTimer) clearTimeout(this.authRenewTimer);
316
+ if (this.authExpireTimer) clearTimeout(this.authExpireTimer);
317
+ }
318
+
319
+ /**
320
+ * Fetch the user's data and attach it to the connection for new connections. For existing connections, it checks that the authentication is done on the same user.
321
+ */
322
+ private setUserData({ sub, dev, jti, aud }: UserTokenPayload): void {
323
+ // Check if the user is already authenticated
324
+ if (this.userId) {
325
+ // Check that the token is for the same connection as before
326
+ if (this.userId && this.userId !== sub)
327
+ throw new WebError({
328
+ errorCode: 'wrong-user-token',
329
+ message:
330
+ 'A user tried to authenticate with a token that is not for him [userId]'
331
+ });
332
+ } else {
333
+ // Set the user's ID
334
+ this.userId = sub;
335
+ // Set the user's Device Id
336
+ this.deviceId = dev;
337
+ // Set the token ID
338
+ this.tokenId = jti;
339
+ // Set the aud
340
+ this.audience = aud instanceof Array ? aud : [aud];
341
+
342
+ reportDebug({
343
+ namespace,
344
+ message: `Successfully authenticated client [${this.id}]`,
345
+ data: {
346
+ userId: this.userId,
347
+ deviceId: this.deviceId,
348
+ tokenId: this.tokenId,
349
+ audience: this.audience
350
+ }
351
+ });
352
+ }
353
+ }
354
+
355
+ /**
356
+ * Properly return errors to clients
357
+ */
358
+ private handleError(error: unknown): void {
359
+ reportError(error);
360
+ if (error instanceof WebError) {
361
+ this.sendMessage(
362
+ 'error',
363
+ { errorCode: error.errorCode, hint: error.hint },
364
+ { noAuth: true }
365
+ );
366
+ } else if (error instanceof ValidationError) {
367
+ this.sendMessage(
368
+ 'error',
369
+ { errorCode: 'validation-error', hint: error.data },
370
+ { noAuth: true }
371
+ );
372
+ } else {
373
+ this.sendMessage(
374
+ 'error',
375
+ { errorCode: 'server-error' },
376
+ { noAuth: true }
377
+ );
378
+ }
379
+ }
380
+
381
+ /**
382
+ * Process a socket close event
383
+ */
384
+ private async handleClose(code?: string, reason?: string): Promise<void> {
385
+ delete SocketClient.socketClients[this.id];
386
+ this.clearTimeouts();
387
+ // Stop ping process
388
+ if (this.pingInterval) clearInterval(this.pingInterval);
389
+ // Run all the shutdown callbacks
390
+ const callbackResults = await Promise.allSettled(
391
+ this.shutdownCallbacks.map((callback) => callback(this))
392
+ );
393
+ callbackResults.forEach((result) => {
394
+ if (result.status === 'rejected') reportError(result.reason);
395
+ });
396
+ reportInfo({
397
+ message: `Client disconnected [${this.id}]`,
398
+ data: { code, reason }
399
+ });
400
+ }
401
+ }