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
package/README.md CHANGED
@@ -1,1025 +1,991 @@
1
- # Node Server Engine
2
-
3
- Framework used to develop Node backend services. This package ships with a lot of features to standardize the creation of services, letting you focus on the business logic.
4
-
5
- - [Node Server Engine](#Node-server-engine)
6
- - [Install](#install)
7
- - [Entities](#entities)
8
- - [Server](#server)
9
- - [Server Configuration](#server-configuration)
10
- - [Endpoint](#endpoint)
11
- - [Endpoint Configuration](#endpoint-configuration)
12
- - [Methods](#methods)
13
- - [Authentication](#authentication)
14
- - [File Upload](#file-upload)
15
- - [Socket Client](#socket-client)
16
- - [Socket Client Options](#socket-client-options)
17
- - [Properties](#properties)
18
- - [Message Handler](#message-handler)
19
- - [Redis](#redis)
20
- - [Sequelize](#sequelize)
21
- - [Pub/Sub](#pubsub)
22
- - [MediaProcessor](#mediaprocessor)
23
- - [PushNotification](#pushnotification)
24
- - [Localizator](#localizator)
25
- - [ElasticSearch](#elasticsearch)
26
- - [Translation Manager](#translation-manager)
27
- - [Error Reporting](#error-reporting)
28
- - [Common options](#common-options)
29
- - [Severity](#severity)
30
- - [Log Levels](#log-levels)
31
- - [EngineError](#engineerror)
32
- - [WebError](#weberror)
33
- - [Middlewares](#middlewares)
34
- - [Swagger Docs](#swagger-docs)
35
- - [Structuring Documentation](#structuring-documentation)
36
- - [Schemas and Responses](#schemas-and-responses)
37
- - [User Resolver](#user-resolver)
38
- - [Gemini File Upload](#gemini-file-upload)
39
- - [checkPermission](#check-permission-middleware)
40
- - [Utilities](#utilities)
41
- - [Request](#request)
42
- - [TLS Request](#tls-request)
43
- - [TLS Config](#tls-config)
44
- - [Send Push Notification](#send-push-notification)
45
- - [Send Email](#send-email)
46
- - [Filter](#filter)
47
- - [Database Migration](#database-migration)
48
- - [Environment Variables Verification](#environment-variables-verification)
49
- - [Assertions Available](#assertions-available)
50
- - [Wait](#wait)
51
-
52
- ## Install
53
-
54
- To start a new service, it is **highly recomended** that you clone it from [our template](https://github.com/prakashmahendran/node-server-template). It will already include all the necessary tools and boilerplate.
55
-
56
- If you need to install it manually:
57
-
58
- ```bash
59
- npm i node-server-engine
60
- ```
61
-
62
- ## Entities
63
-
64
- ### Server
65
-
66
- The server class encapsulates all of the express boilerplate. Instantiate one per service and initialize it to get started.
67
-
68
- ```javascript
69
- import { Server } from 'node-server-engine';
70
- const server = new Server(config);
71
- server.init();
72
- ```
73
-
74
- #### Server Configuration
75
-
76
- <!-- markdownlint-disable MD033 -->
77
-
78
- | Property | Type | Behavior | Default |
79
- | ----------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
80
- | port | Number | Port to listen to | `process.env.PORT` |
81
- | endpoints | Array\<[Endpoint](#endpoint)> | List of endpoints that should be served. | [] |
82
- | globalMiddleware | Array\<Function> <br> Array\<{middleware: Function, path: String}> | List of middlewares that should be executed for each endpoint's logic. If it is given as an object with a path, it will only be applied to requests with this base path. | [] |
83
- | errorMiddleware | Array\<Function> <br> Array\<{middleware: Function, path: String}> | List of middlewares that should be executed after each endpoint's logic. If it is given as an object with a path, it will only be applied to requests with this base path. | [] |
84
- | initCallbacks | Array\<Function> | List of functions that are called on server start |
85
- | [] |
86
- | syncCallbacks | boolean | Forces the init callbacks to run one after the other and not in parallel |
87
- | false |
88
- | cron | Array\<Object> | List of cronjob that are called on server start | [] |
89
- | shutdownCallbacks | Array\<Function> | List of functions that are called on server shutdown | [] |
90
- | checkEnvironment | Object | [Schema against which verify the environment variables](#environment-variables-verification), will cause server termination if the environment variables are not properly set. | {} |
91
- | webSocket.server | Object | Settings to create a WebSocket server. See the [ws package documentation](https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback) for details. | |
92
- | webSocket.client | Object | Settings passed down to [SocketClient](#socket-client) when a new socket connection is established. | |
93
-
94
- <!-- markdownlint-enable MD033 -->
95
-
96
- ---
97
-
98
- ### Endpoint
99
-
100
- Endpoint encapsulates the logic of a single endpoint in a standard way.
101
-
102
- The main function of the endpoint is called the **handler**. This function should only handle pure business logic for a given endpoint.
103
-
104
- An endpoint usually has a **validator**. A validator is a schema that will be compared to the incoming request. The request will be denied if it contains illegal or malformed arguments. For more detail see the documentation of the underlying package [express-validator](https://express-validator.github.io/docs/schema-validation.html).
105
-
106
- ```javascript
107
- import { Endpoint, EndpointMethod } from 'node-server-engine';
108
-
109
- // A basic handler that returns an HTTP status code of 200 to the client
110
- function handler(req, res) {
111
- res.sendStatus(200);
112
- }
113
-
114
- // The request must contain `id` as a query string and it must be a UUID V4
115
- const validator = {
116
- id: {
117
- in: 'query',
118
- isUUID: {
119
- options: 4
120
- }
121
- }
122
- };
123
-
124
- // This endpoint can be passed to the Server
125
- new Endpoint({
126
- path: '/demo',
127
- method: EndpointMethod.GET,
128
- handler,
129
- validator
130
- });
131
- ```
132
-
133
- #### Endpoint Configuration
134
-
135
- `new Endpoint(config)`
136
-
137
- | Property | Type | Behavior | Default |
138
- | --------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
139
- | path | String | Path to which the endpoint should be served | **required** |
140
- | method | [Method](#methods) | Method to which the endpoint should be served | **required** |
141
- | handler | Function | Endpoint handler | **required** |
142
- | validator | Object | Schema to validate against the request. [See documentation](https://express-validator.github.io/docs/schema-validation.html) for more details. | |
143
- | authType | [AuthType](#authentication) | Authentication to use for this endpoint | AuthType.NONE |
144
- | authParams | Object | Options specific to the [authentication methods](#authentication) | {} |
145
- | files | Array\<Object> | Configuration to upload files. See the [specific documentation](#file-upload). | {} |
146
- | middleware | Array\<Function> | List of middlewares to run before the handler. | [] |
147
- | errorMiddleware | Array\<Function> | List of middlewares to run after the handler | [] |
148
-
149
- ```javascript
150
- const addNodeEndpoint = new Endpoint({
151
- path: '/note',
152
- method: EndpointMethod.POST,
153
- handler: (req, res, next) => res.json(addNote(req.body)),
154
- authType: EndpointAuthType.AUTH_JWT,
155
- middleware: [checkPermission(['DeleteUser', 'AdminAccess'])],
156
- errorMiddleware: [addNoteErrorMiddleware],
157
- validator: {
158
- id: {
159
- in: 'body',
160
- isUUID: true
161
- },
162
- content: {
163
- in: 'body',
164
- isLength: {
165
- errorMessage: 'content to long',
166
- options: {
167
- max: 150
168
- }
169
- }
170
- }
171
- }
172
- });
173
- ```
174
-
175
- #### Methods
176
-
177
- The following HTTP methods are supported
178
-
179
- - Method.GET
180
- - Method.POST
181
- - Method.PUT
182
- - Method.PATCH
183
- - Method.DELETE
184
- - Method.ALL - _respond to all requests on a path_
185
-
186
- #### Authentication
187
-
188
- Endpoints can take an authType and authParam in their configuration to determine their authentication behavior. The following table summarizes their usage.
189
-
190
- The server engine exposes an enumeration for auth types.
191
- `import {AuthType} from 'node-server-engine';`
192
-
193
- <!-- markdownlint-disable MD033 -->
194
-
195
- | AuthType | Description | AuthParams |
196
- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
197
- | AuthType.NONE | No authentication. All requests are handled | |
198
- | AuthType.JWT | A valid JSON Web Token is required as Bearer token. To be valid it must be properly signed by auth0, and its payload must match with what is set as environment variables.<br>The user's ID is added to `req.user`. | |
199
- | AuthType.TLS | Authenticate through mutual TLS. CA and an optional list of white listed host names should be set in the environment variables. | **whitelist** [Array<String>]: List of certificate Common Name or Alt Name that are permitted to make requests to this endpoint. |
200
- | AuthType.HMAC | Authenticate with a signature in the payload.<br>**This authentication is deprecated and should be avoided** | **secret** [String]: Overrides the secret used for signatures set in environment variables<br>**isGithub** [Boolean]: The request is a Github webhook and therefore uses their signature system and not the default one. |
201
- | AuthType.STATIC | A valid shared Bearer token is required. Shared token is stored in env variable (STATIC_TOKEN) | |
202
- | AuthType.ADMIN | A valid JSON Web Token is required as Bearer token. To be valid it must be properly signed by admin api, and its payload must match with what is set as environment variables.<br>The user's email and permission is added to `req.user`. | **permission** [String]: Endpoint permission required for admin user |
203
-
204
- <!-- markdownlint-enable MD033 -->
205
-
206
- #### File Upload
207
-
208
- An endpoint can upload a file to a cloud storage and pass down its url to the handler.
209
-
210
- The request must be made as `multipart/form-data`.
211
-
212
- The file's data will be available at `req.files`.
213
-
214
- The following settings can be used on each object the Endpoint's `options.files`.
215
-
216
- | Property | Type | Description | Default |
217
- | ------------------- | -------------- | ------------------------------------------------------------------------ | ------------ |
218
- | key | string | Form key as which the file should be fetched | **required** |
219
- | path | string | Base path of the directory where the file should be stored in the bucket | `/` |
220
- | bucket | string | Name of the bucket in which the file should be stored | **required** |
221
- | maxSize | string | Maximum file size in a human readable format (ex: 5MB) | **required** |
222
- | mimeTypes | Array\<string> | A list of accepted MIME Types | [] |
223
- | required | boolean | Will fail the request and not store the files if this one is missing | false |
224
- | noExtension | boolean | Store the file with no extension | false |
225
- | image | Object | Image manipulation to perform on the uploaded file | |
226
- | image.resize.height | number | Resize the image to fit a specific height | |
227
- | image.resize.width | number | Resize the image to fit a specific width | |
228
- | image.quality | number | JPEG quality factor to use for export | |
229
-
230
- ---
231
-
232
- ### Socket Client
233
-
234
- The socket server start if the [Server](#server)'s webSocket option is not undefined.
235
-
236
- Each time a new socket connection is established, a new instance of `SocketClient` is created.
237
-
238
- #### Socket Client Options
239
-
240
- Options can be set for SocketClient when setting up a Server instance.
241
-
242
- | Parameter | Type | Description | Default |
243
- | ----------------- | ------------------------------------------ | ----------------------------------------------------------------------- | ------------ |
244
- | handlers | Array\<[MessageHandler](#message-handler)> | A list of message handlers to use | **required** |
245
- | authCallbacks | Array\<function> | Callbacks called when a client successfully authenticates on the socket | [] |
246
- | initCallbacks | Array\<function> | Callbacks called when the socket client is created | [] |
247
- | shutdownCallbacks | Array\<function> | Callbacks called when the socket client is destroyed | [] |
248
-
249
- #### Properties
250
-
251
- | Property | Type | Description |
252
- | ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------- |
253
- | id | String | A unique identifier for the connection |
254
- | ws | Object | The socket being used. Instance of [WebSocket](https://github.com/websockets/ws/blob/master/doc/ws.md#class-websocket) |
255
- | authenticated | Boolean | Flag indicating that the current user is authenticated |
256
- | userId | String | Id of the current user **(available when authenticated)** |
257
-
258
- ---
259
-
260
- ### Message Handler
261
-
262
- Message handler are similar to [Endpoint](#endpoint), but in a WebSocket context. They define how incoming messages should be handled.
263
-
264
- ```javascript
265
- import { MessageHandler, Server } from 'node-server-engine';
266
-
267
- function handler(payload, client) {
268
- // payload is the message payload in a standard message.
269
- // client is an instance of SocketClient
270
- }
271
-
272
- const messageHandler = new MessageHandler(type, handler, options);
273
-
274
- new Server({
275
- webSocket: { client: { handlers: [messageHandler] } }
276
- });
277
- ```
278
-
279
- | Argument | Type | Description | Default |
280
- | --------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------- | ------------ |
281
- | type | String | The message type that should be handled | **required** |
282
- | handler | Function | A function that will run for every message of this type | **required** |
283
- | options.authenticated | A flag indicating that this kind of message handling require an authenticated client | `true` |
284
-
285
- ---
286
-
287
- ### Redis
288
-
289
- The server engine exposes a Redis client that is configured to work with the standard environment variables that are used in our services.
290
-
291
- It is a pre-configured instance of [ioredis](https://github.com/luin/ioredis). See the package documentation for more details.
292
-
293
- ```javascript
294
- import { Redis } from 'node-server-engine';
295
-
296
- await Redis.set(key, value);
297
- ```
298
-
299
- It can be configured through environment variables
300
-
301
- | env | description | default |
302
- | -------------- | ---------------------------------------------------------------------------------- | ------- |
303
- | REDIS_HOST | Host to which to connecto to | |
304
- | REDIS_PORT | Port on which redis is served | |
305
- | REDIS_PASSWORD | Password used to authenticate with the server | |
306
- | REDIS_CLUSTER | Flag indicating that redis is configured as a cluster and not as a single instance | false |
307
-
308
- ---
309
-
310
- ### Sequelize
311
-
312
- The server engine exposes an SQL ORM that is configured to work with the standard environment variables that are used in our services.
313
-
314
- It is a pre-configured instance of [sequelize](https://github.com/sequelize/sequelize). See the package documentation for more details.
315
-
316
- ```javascript
317
- import { Sequelize } from 'node-server-engine';
318
-
319
- Sequelize.sequelize;
320
- Sequelize.closeSequelize();
321
- ```
322
-
323
- It can be configured through environment variables
324
-
325
- | env | description | default |
326
- | ------------ | ------------------------------------------------- | -------- |
327
- | SQL_HOST | Host to which connect to | |
328
- | SQL_PORT | Port on which SQL is served | 5432 |
329
- | SQL_PASSWORD | Password used to authenticate with the SQL server | |
330
- | SQL_USER | User used to authenticate with the SQL server | |
331
- | SQL_DB | Database to which connect to | |
332
- | SQL_TYPE | SQL type which connect to | postgres |
333
-
334
- ---
335
-
336
- ### Pub/Sub
337
-
338
- The engine exposes a `PubSub` entity that can be used to communicate with Google Cloud Pub/Sub.
339
-
340
- ```javascript
341
- import { PubSub } from 'node-server-engine';
342
-
343
- /**
344
- * Declare that the service will be publishing to a topic
345
- * This must be done before init() is called
346
- * Any attempt to publish a message without declaring a topic first will fail
347
- * @property {string|Array.<string>} topic - The topic(s) to which we will be publishing
348
- */
349
- PubSub.addPublisher(topic);
350
-
351
- /**
352
- * Binds a message handle to a subscription
353
- * If called multiple times, handlers will be chained
354
- * This must be done before init() is called
355
- * The subscription will not be consumed until init() is called
356
- * @property {string} subscription - The subscription to consume
357
- * @property {function|Array.<function>} handler - The message handling function(s)
358
- * @property {boolean} [first] - Puts the handler(s) at the beginning of the handling chain (default: false)
359
- */
360
- PubSub.addSubscriber(subscription, handler, first);
361
-
362
- /**
363
- * Establish connection with all the declared publishers/subscribers
364
- */
365
- await PubSub.init();
366
-
367
- /**
368
- * Send a message through a previously declared publisher
369
- * @property {string} topic - The name of the topic to which the message should be pushed
370
- * @property {Object} message - The actual message (will be JSON stringified)
371
- * @property {Object} [attributes] - Message attributes
372
- * @property {string} [orderingKey] - Ordering key
373
- */
374
- await PubSub.publish(topic, message, attributes, orderingKey);
375
-
376
- /**
377
- * Flush all pending messages and close connections with Pub/Sub
378
- */
379
- await PubSub.shutdown();
380
- ```
381
-
382
- ---
383
-
384
- ### MediaProcessor
385
-
386
- Communication interface with the media processing service.
387
-
388
- ```javascript
389
- import { MediaProcessor } from 'node-server-engine';
390
-
391
- /**
392
- * Listener that will be called when the media processor has finished processing a given job group
393
- * @param {string} id - The same id as the one given in the "process" function
394
- * @param {boolean} success - Indicates success or failure of the jobs
395
- */
396
- function listener(id, success) {}
397
-
398
- MediaProcessor.addListener(listener);
399
-
400
- // The entity needs to initialize it's pub/sub connections
401
- // Handlers must be declared before this function is called
402
- await MediaProcessor.init();
403
-
404
- /**
405
- * Start a task with some processing jobs@
406
- * @param {string} id - Identifier used to recognize the job when it returns
407
- * @param {Job|Array.<Job>} - The job(s) to run
408
- */
409
- await MediaProcessor.process(id, jobs);
410
-
411
- // This should be call when the program shuts down.
412
- await MediaProcessor.shutdown();
413
- ```
414
-
415
- ---
416
-
417
- ### PushNotification
418
-
419
- Communication interface with the push service.
420
-
421
- ```javascript
422
- import { PushNotification } from 'node-server-engine';
423
-
424
- // The entity needs to initialize it's pub/sub connections
425
- // Handlers must be declared before this function is called
426
- await PushNotification.init();
427
-
428
- /**
429
- * Send a push notification through the push service
430
- * @param {String} userId - ID of the user that should receive the notification
431
- * @param {Object} notification - Notification that should be sent
432
- * @return {void}
433
- */
434
- await PushNotification.sendPush(userId, notification);
435
- ```
436
-
437
- ---
438
-
439
- ### Localizator
440
-
441
- The localizator exposes localization related utilities.
442
-
443
- ```javascript
444
- import { Localizator } from 'node-server-engine';
445
-
446
- // The synchronize init should be called first to initialize the data
447
- // The localizator will regularly synchronize new data after that without any calls having to be made
448
- await Localizator.init();
449
-
450
- // Get the different ways of displaying a user's name
451
- const { regular, formal, casual } = await Localizator.getDisplayNames(
452
- firstName,
453
- lastName,
454
- locale
455
- );
456
-
457
- // This should be call when the program shuts down.
458
- await Localizator.shutdown();
459
- ```
460
-
461
- | env | description | default |
462
- | ----------- | ----------------------------------------- | ------------ |
463
- | LOCALES_URL | Base URL where the locales data is stored | **required** |
464
-
465
- ---
466
-
467
- ### ElasticSearch
468
-
469
- The ElasticSearch exposes a service related to data searching.
470
-
471
- ```javascript
472
- import { ElasticSearch } from 'node-server-engine';
473
-
474
- // The synchronize init should be called first to initialize the data
475
- await ElasticSearch.init();
476
-
477
- // This should be call when the program shuts down.
478
- await ElasticSearch.shutdown();
479
- ```
480
-
481
- | env | description | default |
482
- | ----------------------------- | ---------------------------------------------- | ------------ |
483
- | ELASTIC_SEARCH_MIGRATION_PATH | The path link to Elastic Search migration data | **required** |
484
- | ELASTIC_SEARCH_HOST | The elastic search host url | **required** |
485
- | ELASTIC_SEARCH_USERNAME | The elastic search user name | **required** |
486
- | ELASTIC_SEARCH_PASSWORD | The elastic search password | **required** |
487
- | TLS_CA | CA for ssl config when available | |
488
-
489
- ---
490
-
491
- ### Translation Manager
492
-
493
- The translation manager exposes translation related utilities.
494
-
495
- ```javascript
496
- import { TranslationManager } from 'node-server-engine';
497
-
498
- // The synchronize init should be called first to initialize the data
499
- // The tranlsation manager will regularly synchronize new data after that without any calls having to be made
500
- await TranslationManager.init();
501
-
502
- // Get the different ways of displaying a user's name
503
- const translatedString = await TranslationManager.translate(
504
- lang,
505
- key,
506
- variables,
507
- tags
508
- );
509
-
510
- // Example
511
- const translatedString = await TranslationManager.translate(
512
- 'zh-TW',
513
- 'email.invitation.body',
514
- { name: 'John' },
515
- { link: ['a', 'href="https://www.test.com"'] }
516
- );
517
-
518
- // This should be call when the program shuts down.
519
- await TranslationManager.shutdown();
520
- ```
521
-
522
- - **lang** [String]: Locale for which the translation should be fetched (if no data is found, translation will be returned in `en-US`).
523
- - **key** [String]: Translation key
524
- - **variables** [Object]: A key=>value mapping for variable interpolation in strings. **(Optional)**
525
- - **tags** [Object]: A key=>value mapping for variable interpolation in strings. **(Optional)**
526
-
527
- | env | description | default |
528
- | ----------- | ----------------------------------------- | ------------ |
529
- | LOCALES_URL | Base URL where the locales data is stored | **required** |
530
-
531
- ---
532
-
533
- ### Error Reporting
534
-
535
- The server engine standardizes the way errors are handled and reported. The error classes provided by the Server Engine should always be used when throwing an exception.
536
-
537
- Errors are a crucial part of the application, they are what helps us to properly debug the program and offer support when need, as well as what exposes issues to the client.
538
-
539
- By standard, the client receives the following body when an error happens.
540
-
541
- ```javascript
542
- // HTTP Status code (400 | 500)
543
- {
544
- errorCode: "some-error", // Machine readable error code
545
- hint: "The selected user does not exist" // (optional) Hint for developers
546
- }
547
- ```
548
-
549
- Status codes should be limited to 400 for client errors and 500 for server errors. Other 4XX status codes should be avoided unless very specific cases (ex: authentication error).
550
-
551
- All our custom error classes take a `data` parameter. This will be logged on the backend and should contain any data that can help to understand the runtime context or the error (ex: user's ID).
552
-
553
- #### Common options
554
-
555
- These options are common to each of the error classes described below.
556
-
557
- | option | definition | example | default |
558
- | -------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------ |
559
- | message | A message logged on the backend only | "Could not find user in the DB" | **required** |
560
- | severity | The level at which this error should be logged | [Severity](#severity).WARNING | [Severity](#severity).CRITICAL |
561
- | data | Some data related to the error that will be logged on the backend. This should help to undetrstand the runtime context. | {userId: 'xf563ugh0', isAdmin: false} | |
562
- | error | An error object, when this is a wrapper around an existing error object | |
563
-
564
- #### Severity
565
-
566
- Severity allows us to order errors by their impact on the program. It is important to set severity correctly as backend logs can include hundreds of entries per seconds, severity allows us to filter out the most important errors. An enumeration is exposed that includes all the severity levels, as described in the following table.
567
-
568
- ##### Log Levels
569
-
570
- | severity | definition |
571
- | --------- | ------------------------------------------------------------------------------------------------------------------------ |
572
- | DEBUG | Detailed information of the runtime execution. Used for debugging. |
573
- | INFO | Base information level of runtime information. |
574
- | WARNING | Errors that are expected to happen and do not cause any particular issue. (ex: a client made an unauthenticated request) |
575
- | CRITICAL | Errors that are unexpected and cause an improper behavior. (ex: failed to store some data in the DB) |
576
- | EMERGENCY | Errors that prevent the program from running. (ex: some environment variables are not correctly set) |
577
-
578
- #### EngineError
579
-
580
- This error class represents errors that happen withing the Server Engine. They should be used for server configuration errors, or unexpected behaviors. They will always return `500 - {errorCode: 'server-error'}`.
581
-
582
- ```javascript
583
- import { EngineError, Severity } from 'node-server-engine';
584
-
585
- if (!process.env.IMPORTANT_VARIABLE) {
586
- throw new EngineError(options);
587
- }
588
- ```
589
-
590
- Engine Errors strictly follow the [common options](#common-options).
591
-
592
- #### WebError
593
-
594
- This error class represents errors that happen at runtime and that need specific reporting to the client. Their definition is more complex, but it includes additional data specific to the client.
595
-
596
- ```javascript
597
- import { WebError, Severity } from 'node-server-engine';
598
-
599
- const user = User.findOne({ where: { id: userId } });
600
- if (!user) {
601
- throw new WebError(options);
602
- }
603
- ```
604
-
605
- In addition to the [common options](#common-options), WebError defines some other options specific for error reporting to clients.
606
-
607
- | option | definition | example | default |
608
- | ---------- | ---------------------------------------------------------------- | ------------ | ------------ |
609
- | errorCode | A machine readable error code that will be parsed by the client. | unknown-user | **required** |
610
- | statusCode | HTTP status code of the response. | 400 | 500 |
611
- | hint | A human readable error message that is intended for developers | |
612
-
613
- ## Middlewares
614
-
615
- Server engine exposes a bunch of middlewares. These can be imported to your project and used globally or per endpoint.
616
-
617
- ### Swagger Docs
618
-
619
- This middleware allows the service to connect with the [API Documentation Service](https://github.com/prakashmahendran/api-documentation-service). It exposes the necessary endpoint for the documentation of this API to be visible by the Documentation Service.
620
-
621
- ```javascript
622
- import { Server, middleware } from 'node-server-engine';
623
-
624
- new Server({
625
- globalMiddleware: [middleware.swaggerDocs()]
626
- });
627
- ```
628
-
629
- #### Structuring Documentation
630
-
631
- The underlying system used is the [Open API](https://swagger.io/specification/) spec.
632
- Most of the data is already generate by the documentation service. The only real need is to document endpoints.
633
-
634
- Endpoints should be documented in YAML files that respect the `**/*.docs.yaml` convention. It is recommended to place them in the same directory as the endpoint definition. Endpoint documentation has to follow the [path object spec](https://swagger.io/specification/#paths-object) from Open API.
635
-
636
- ```yaml
637
- /hello:
638
- get:
639
- description: Request the API to say Hello
640
- responses:
641
- '200':
642
- description: Replies hello
643
- content:
644
- application/json:
645
- schema:
646
- type: Object
647
- properties:
648
- says:
649
- type: string
650
- example: Hello
651
- ```
652
-
653
- #### Schemas and Responses
654
-
655
- To avoid repeating the same structure across the documentation manually, one can use [schemas and responses components](https://swagger.io/docs/specification/components/).
656
-
657
- Some common components are already defined directly in the API Documentation Service, please check its documentation to avoid repeats.
658
-
659
- If you ever need to declare custom components, they simply must follow the architecture bellow.
660
-
661
- ```bash
662
- # Repository root
663
- /src
664
- /docs
665
- /responses
666
- - coolResponse.yaml
667
- / schemas
668
- - bestSchema.yaml
669
- ```
670
-
671
- Here is an example definition:
672
-
673
- ```yaml
674
- Dog:
675
- type: object
676
- properties:
677
- name:
678
- type: string
679
- example: Rex
680
- owner:
681
- type: string
682
- example: f1982af0-1579-4c56-a138-de1ab4ff39b3
683
- isAGoodBoy:
684
- type: boolean
685
- example: true
686
- required:
687
- - name
688
- - owner
689
- ```
690
-
691
- ---
692
-
693
- ### User Resolver
694
-
695
- `/!\` **Must be used in combination with AuthType.JWT**
696
-
697
- Resolves the user making the request with the user resolver. The user's complete data is added to `req.user`.
698
-
699
- ```javascript
700
- import { Endpoint, middleware, AuthType, Method } from 'node-server-engine';
701
-
702
- new Endpoint({
703
- path: '/hello',
704
- method: Method.GET,
705
- authType: AuthType.JWT,
706
- middleware: [middleware.userResolver],
707
- handler: (req, res) => {
708
- res.json({ say: `Hello ${req.user.firstName}` });
709
- }
710
- });
711
- ```
712
- ---
713
-
714
- #### Gemini File Upload
715
-
716
- An endpoint can upload a file to a google gemini AI
717
-
718
- The request must be made as `multipart/form-data`.
719
-
720
- File should be uploaded under the key file.
721
-
722
- The file's data will be available at `req.body.fileUri req.body.mimeType req.body.originalname`
723
-
724
-
725
- #### Check Permission Middleware
726
-
727
- /!\ **Must be used in combination with AuthType.JWT**
728
-
729
- Checks if the user has at least one of the required permissions. The permissions are case-insensitive.
730
-
731
- ```javascript
732
- import { Endpoint, middleware, AuthType, Method } from 'node-server-engine';
733
-
734
- new Endpoint({
735
- path: '/admin',
736
- method: Method.GET,
737
- authType: AuthType.JWT,
738
- middleware: [middleware.checkPermission(['admin', 'superuser'])],
739
- handler: (req, res) => {
740
- res.json({ message: 'Access granted' });
741
- }
742
- });
743
- ```
744
-
745
- ```typescript
746
- import { Request, Response, NextFunction } from 'express';
747
-
748
- // Middleware to check if the user has at least one of the required permissions (case-insensitive)
749
- export const checkPermission = (requiredActions: string | string[]) => {
750
- return (req: Request, res: Response, next: NextFunction) => {
751
- const user = req.user;
752
-
753
- if (!user || !user.permissions) {
754
- return res.status(403).json({ message: 'User does not have permissions' });
755
- }
756
-
757
- const requiredActionsArray = Array.isArray(requiredActions)
758
- ? requiredActions
759
- : [requiredActions];
760
-
761
- const requiredActionsLower = requiredActionsArray.map(action => action.toLowerCase());
762
-
763
- const hasPermission = user.permissions.some((permission: string) =>
764
- requiredActionsLower.includes(permission.toLowerCase())
765
- );
766
-
767
- if (!hasPermission) {
768
- return res.status(403).json({ message: 'Permission denied' });
769
- }
770
-
771
- next();
772
- };
773
- };
774
- ```
775
-
776
- ## Utilities
777
-
778
- The server engine ships with a handful of utility functions that are commonly used by servers
779
-
780
- ### Request
781
-
782
- This function is a wrapper around [axios](https://github.com/axios/axios). It adds proper error handling for reporting in the logs when a network call fails. It should be used for any requests made by a service.
783
- Refer to the [axios documentation](https://github.com/axios/axios) for the request configuration.
784
-
785
- ```javascript
786
- import { request } from 'node-server-engine';
787
- const { data } = await request({
788
- method: 'get',
789
- url: 'https://www.google.com'
790
- });
791
- ```
792
-
793
- ---
794
-
795
- ### TLS Request
796
-
797
- This function is a wrapper around [request](#request). It adds the necessary configuration to easily make requests with TLS. The settings used are based on the environment variables. It will use request specific certificate/key if defined, or will fallback to use the same ones as the ones used for the server.
798
-
799
- It is necessary to use this function when calling other services in the cluster. Requests could fail otherwise as the common CA is not set and the client certificate not exposed.
800
-
801
- ```javascript
802
- import { tlsRequest } from 'node-server-engine';
803
- const { data } = await tlsRequest({
804
- method: 'get',
805
- url: 'https://www.google.com'
806
- });
807
- ```
808
-
809
- ---
810
-
811
- ### TLS Config
812
-
813
- The server's TLS configuration can be fetched as an object. Alternatively, the server engine also exposes an [HTTPS Agent](https://nodejs.org/api/https.html#https_class_https_agent). They will not be available at startup, so it is important that the function calling them loads them first if they are not present.
814
-
815
- ```javascript
816
- import {tlsConfig, httpsAgent, loadTlsConfig} from 'node-server-engine';
817
- import https from 'https';
818
-
819
- // TLS Config
820
- if(!tlsConfig) loadTlsConfig();
821
- const customAgent = new https.Agent({
822
- key: tlsConfig.key,
823
- cert: tlsConfig.cert,
824
- ca: tlsConfig.ca,
825
- passphrase: tlsConfig.passphrase,
826
- });
827
-
828
- // HTTPS Agent
829
- if(!httpsAgent) loadTlsConfig();
830
- https.request('https://www.google.com'. {agent: httpsAgent});
831
- ```
832
-
833
- ---
834
-
835
- ### Send Push Notification
836
-
837
- Send a push notification through the push service.
838
-
839
- ```javascript
840
- import { sendPush } from 'node-server-engine';
841
- await sendPush(userId, notification);
842
- ```
843
-
844
- | parameter | description |
845
- | ------------ | ------------------------------------------------------------------------ |
846
- | userId | ID of the user that should receive the notification |
847
- | notification | Content of the notification as defined by the push service documentation |
848
-
849
- ---
850
-
851
- ---
852
-
853
- ### Send Email
854
-
855
- Send an email through the email service.
856
-
857
- ```javascript
858
- import { sendEmail } from 'node-server-engine';
859
- await sendEmail(userId, template, translationKey, parameters, tags, to);
860
- ```
861
-
862
- | parameter | description |
863
- | -------------- | -------------------------------------------------------------------------- |
864
- | userId | ID of the user that should receive the notification |
865
- | template | Email template to use |
866
- | translationKey | Key used to get localized strings |
867
- | parameters | Variables that can be inserted in the email template and localized strings |
868
- | tags | Data injected in the localized strings as HTML tags |
869
- | to | Array of email recipients |
870
- | to.\*.email | Email of an email recipient |
871
- | to.\*.name | Name of an email recipient |
872
-
873
- ---
874
-
875
- ### Filter
876
-
877
- Apply a filter on an object. It returns a copy of the object that only holds the whitelisted keys.
878
-
879
- This is particularly useful to sanitize objects before returning them to clients.
880
-
881
- ```javascript
882
- import { filter } from 'node-server-engine';
883
-
884
- const object = { a: 'kept', b: 'not kept' };
885
- const whitelist = ['a'];
886
-
887
- const result = filter(object.whitelist);
888
- // result = {a: 'kept'}
889
- ```
890
-
891
- ---
892
-
893
- ### Database Migration
894
-
895
- Some utilities are exposed to handle database migrations.
896
-
897
- `runPendingMigrations` will execute all the migration scripts that have not yet been executed.
898
-
899
- `rollbackMigrations` will rollback all the migrations that have been executed with the current version of the app and after.
900
-
901
- ```javascript
902
- import { runPendingMigrations } from 'node-server-engine';
903
- import { rollbackMigrations } from 'node-server-engine';
904
-
905
- await runPendingMigrations();
906
-
907
- await rollbackMigrations();
908
- ```
909
-
910
- ---
911
-
912
- ### Environment Variables Verification
913
-
914
- Environment variables verification can be done through the [Server](#server)'s checkEnvironment setting. It is an object defining how environment variables should be verified.
915
-
916
- ```javascript
917
- import { envAssert } from 'node-server-engine';
918
-
919
- export const checkEnvironment = {
920
- ENV_VAR: envAssert.isString()
921
- };
922
- ```
923
-
924
- #### Assertions Available
925
-
926
- The sever engine makes available a utility for environment variables assertions calls `envAssert`. The following example shows the different assertions that are possible.
927
-
928
- <!-- markdownlint-disable MD033 -->
929
-
930
- | Validator | Description |
931
- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
932
- | **isAfter(date])** | check if the string is a date that's after the specified date (defaults to now). |
933
- | **isAlpha(locale, options])** | check if the string contains only letters (a-zA-Z).<br/><br/>Locale is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-FR', 'fa-IR', 'he', 'hu-HU', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`) and defaults to `en-US`. Locale list is `validator.isAlphaLocales`. options is an optional object that can be supplied with the following key(s): ignore which can either be a String or RegExp of characters to be ignored e.g. " -" will ignore spaces and -'s. |
934
- | **isAlphanumeric(locale])** | check if the string contains only letters and numbers.<br/><br/>Locale is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-FR', 'fa-IR', 'he', 'hu-HU', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`) and defaults to `en-US`. Locale list is `validator.isAlphanumericLocales`. |
935
- | **isAscii()** | check if the string contains ASCII chars only. |
936
- | **isBase32()** | check if a string is base32 encoded. |
937
- | **isBase58()** | check if a string is base58 encoded. |
938
- | **isBase64(options])** | check if a string is base64 encoded. options is optional and defaults to `{urlSafe: false}`<br/> when `urlSafe` is true it tests the given base64 encoded string is [url safe](https://base64.guru/standards/base64url) |
939
- | **isBefore(date])** | check if the string is a date that's before the specified date. |
940
- | **isBIC()** | check if a string is a BIC (Bank Identification Code) or SWIFT code. |
941
- | **isBoolean()** | check if a string is a boolean. |
942
- | **isBtcAddress()** | check if the string is a valid BTC address. |
943
- | **isByteLength(options])** | check if the string's length (in UTF-8 bytes) falls in a range.<br/><br/>`options` is an object which defaults to `{min:0, max: undefined}`. |
944
- | **isCreditCard()** | check if the string is a credit card. |
945
- | **isCurrency(options])** | check if the string is a valid currency amount.<br/><br/>`options` is an object which defaults to `{symbol: '$', require_symbol: false, allow_space_after_symbol: false, symbol_after_digits: false, allow_negatives: true, parens_for_negatives: false, negative_sign_before_digits: false, negative_sign_after_digits: false, allow_negative_sign_placeholder: false, thousands_separator: ',', decimal_separator: '.', allow_decimal: true, require_decimal: false, digits_after_decimal: [2], allow_space_after_digits: false}`.<br/>**Note:** The array `digits_after_decimal` is filled with the exact number of digits allowed not a range, for example a range 1 to 3 will be given as [1, 2, 3]. |
946
- | **isDataURI()** | check if the string is a [data uri format](https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs). |
947
- | **isDate(input [, options])** | Check if the input is a valid date. e.g. [`2002-07-15`, new Date()].<br/><br/> `options` is an object which can contain the keys `format`, `strictMode` and/or `delimiters`<br/><br/>`format` is a string and defaults to `YYYY/MM/DD`.<br/><br/>`strictMode` is a boolean and defaults to `false`. If `strictMode` is set to true, the validator will reject inputs different from `format`.<br/><br/> `delimiters` is an array of allowed date delimiters and defaults to `['/', '-']`. |
948
- | **isDecimal(options])** | check if the string represents a decimal number, such as 0.1, .3, 1.1, 1.00003, 4.0, etc.<br/><br/>`options` is an object which defaults to `{force_decimal: false, decimal_digits: '1,', locale: 'en-US'}`<br/><br/>`locale` determine the decimal separator and is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fa', 'fa-AF', 'fa-IR', 'fr-FR', 'hu-HU', 'id-ID', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pl-Pl', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA', 'vi-VN']`.<br/>**Note:** `decimal_digits` is given as a range like '1,3', a specific value like '3' or min like '1,'. |
949
- | **isDivisibleBy(number)** | check if the string is a number that's divisible by another. |
950
- | **isEAN()** | check if the string is an EAN (European Article Number). |
951
- | **isEmail(options])** | check if the string is an email.<br/><br/>`options` is an object which defaults to `{ allow_display_name: false, require_display_name: false, allow_utf8_local_part: true, require_tld: true, allow_ip_domain: false, domain_specific_validation: false, blacklisted_chars: '' }`. If `allow_display_name` is set to true, the validator will also match `Display Name <email-address>`. If `require_display_name` is set to true, the validator will reject strings without the format `Display Name <email-address>`. If `allow_utf8_local_part` is set to false, the validator will not allow any non-English UTF8 character in email address' local part. If `require_tld` is set to false, e-mail addresses without having TLD in their domain will also be matched. If `ignore_max_length` is set to true, the validator will not check for the standard max length of an email. If `allow_ip_domain` is set to true, the validator will allow IP addresses in the host part. If `domain_specific_validation` is true, some additional validation will be enabled, e.g. disallowing certain syntactically valid email addresses that are rejected by GMail. If `blacklisted_chars` recieves a string,then the validator will reject emails that include any of the characters in the string, in the name part. |
952
- | **isEmpty(options])** | check if the string has a length of zero.<br/><br/>`options` is an object which defaults to `{ ignore_whitespace:false }`. |
953
- | **isEthereumAddress()** | check if the string is an [Ethereum](https://ethereum.org/) address using basic regex. Does not validate address checksums. |
954
- | **isFloat(options])** | check if the string is a float.<br/><br/>`options` is an object which can contain the keys `min`, `max`, `gt`, and/or `lt` to validate the float is within boundaries (e.g. `{ min: 7.22, max: 9.55 }`) it also has `locale` as an option.<br/><br/>`min` and `max` are equivalent to 'greater or equal' and 'less or equal', respectively while `gt` and `lt` are their strict counterparts.<br/><br/>`locale` determine the decimal separator and is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-FR', 'hu-HU', 'it-IT', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`. Locale list is `validator.isFloatLocales`. |
955
- | **isFQDN(options])** | check if the string is a fully qualified domain name (e.g. domain.com).<br/><br/>`options` is an object which defaults to `{ require_tld: true, allow_underscores: false, allow_trailing_dot: false , allow_numeric_tld: false }`. |
956
- | **isFullWidth()** | check if the string contains any full-width chars. |
957
- | **isHalfWidth()** | check if the string contains any half-width chars. |
958
- | **isHash(algorithm)** | check if the string is a hash of type algorithm.<br/><br/>Algorithm is one of `['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']` |
959
- | **isHexadecimal()** | check if the string is a hexadecimal number. |
960
- | **isHexColor()** | check if the string is a hexadecimal color. |
961
- | **isHost()** | check if the string is a server host name. |
962
- | **isHostList()** | check if the string is a comma separated list of server host name. |
963
- | **isHSL()** | check if the string is an HSL (hue, saturation, lightness, optional alpha) color based on [CSS Colors Level 4 specification](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).<br/><br/>Comma-separated format supported. Space-separated format supported with the exception of a few edge cases (ex: `hsl(200grad+.1%62%/1)`). |
964
- | **isIBAN()** | check if a string is a IBAN (International Bank Account Number). |
965
- | **isIdentityCard(locale])** | check if the string is a valid identity card code.<br/><br/>`locale` is one of `['ES', 'IN', 'IT', 'NO', 'zh-TW', 'he-IL', 'ar-TN', 'zh-CN']` OR `'any'`. If 'any' is used, function will check if any of the locals match.<br/><br/>Defaults to 'any'. |
966
- | **isIMEI(options]))** | check if the string is a valid IMEI number. Imei should be of format `###############` or `##-######-######-#`.<br/><br/>`options` is an object which can contain the keys `allow_hyphens`. Defaults to first format . If allow_hyphens is set to true, the validator will validate the second format. |
967
- | **isIn(values)** | check if the string is in a array of allowed values. |
968
- | **isInt(options])** | check if the string is an integer.<br/><br/>`options` is an object which can contain the keys `min` and/or `max` to check the integer is within boundaries (e.g. `{ min: 10, max: 99 }`). `options` can also contain the key `allow_leading_zeroes`, which when set to false will disallow integer values with leading zeroes (e.g. `{ allow_leading_zeroes: false }`). Finally, `options` can contain the keys `gt` and/or `lt` which will enforce integers being greater than or less than, respectively, the value provided (e.g. `{gt: 1, lt: 4}` for a number between 1 and 4). |
969
- | **isIP(version])** | check if the string is an IP (version 4 or 6). |
970
- | **isIPList()** | check if the string is a comma separated list of IP addresses (version 4 or 6). |
971
- | **isIPRange()** | check if the string is an IP Range(version 4 only). |
972
- | **isISBN(version])** | check if the string is an ISBN (version 10 or 13). |
973
- | **isISIN()** | check if the string is an [ISIN][isin] (stock/security identifier). |
974
- | **isISO8601()** | check if the string is a valid [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date; for additional checks for valid dates, e.g. invalidates dates like `2009-02-29`, pass `options` object as a second parameter with `options.strict = true`. |
975
- | **isISO31661Alpha2()** | check if the string is a valid [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) officially assigned country code. |
976
- | **isISO31661Alpha3()** | check if the string is a valid [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) officially assigned country code. |
977
- | **isISRC()** | check if the string is a [ISRC](https://en.wikipedia.org/wiki/International_Standard_Recording_Code). |
978
- | **isISSN(options])** | check if the string is an [ISSN](https://en.wikipedia.org/wiki/International_Standard_Serial_Number).<br/><br/>`options` is an object which defaults to `{ case_sensitive: false, require_hyphen: false }`. If `case_sensitive` is true, ISSNs with a lowercase `'x'` as the check digit are rejected. |
979
- | **isJSON(options])** | check if the string is valid JSON (note: uses JSON.parse).<br/><br/>`options` is an object which defaults to `{ allow_primitives: false }`. If `allow_primitives` is true, the primitives 'true', 'false' and 'null' are accepted as valid JSON values. |
980
- | **isJWT()** | check if the string is valid JWT token. |
981
- | **isLatLong(options])** | check if the string is a valid latitude-longitude coordinate in the format `lat,long` or `lat, long`.<br/><br/>`options` is an object that defaults to `{ checkDMS: false }`. Pass `checkDMS` as `true` to validate DMS(degrees, minutes, and seconds) latitude-longitude format. |
982
- | **isLength(options])** | check if the string's length falls in a range.<br/><br/>`options` is an object which defaults to `{min:0, max: undefined}`. Note: this function takes into account surrogate pairs. |
983
- | **isLocale()** | check if the string is a locale |
984
- | **isLowercase()** | check if the string is lowercase. |
985
- | **isMACAddress()** | check if the string is a MAC address.<br/><br/>`options` is an object which defaults to `{no_colons: false}`. If `no_colons` is true, the validator will allow MAC addresses without the colons. Also, it allows the use of hyphens, spaces or dots e.g '01 02 03 04 05 ab', '01-02-03-04-05-ab' or '0102.0304.05ab'. |
986
- | **isMagnetURI()** | check if the string is a [magnet uri format](https://en.wikipedia.org/wiki/Magnet_URI_scheme). |
987
- | **isMD5()** | check if the string is a MD5 hash.<br/><br/>Please note that you can also use the `isHash('md5')` function. Keep in mind that MD5 has some collision weaknesses compared to other algorithms (e.g., SHA). |
988
- | **isMimeType()** | check if the string matches to a valid [MIME type](https://en.wikipedia.org/wiki/Media_type) format |
989
- | **isMobilePhone(locale [, options]])** | check if the string is a mobile phone number,<br/><br/>(locale is either an array of locales (e.g `['sk-SK', 'sr-RS']`) OR one of `['am-Am', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', ar-JO', 'ar-KW', 'ar-MA', 'ar-SA', 'ar-SY', 'ar-TN', 'az-AZ', 'az-LY', 'az-LB', 'bs-BA', 'be-BY', 'bg-BG', 'bn-BD', 'ca-AD', 'cs-CZ', 'da-DK', 'de-DE', 'de-AT', 'de-CH', 'de-LU', 'el-GR', 'en-AU', 'en-CA', 'en-GB', 'en-GG', 'en-GH', 'en-HK', 'en-MO', 'en-IE', 'en-IN', 'en-KE', 'en-MT', 'en-MU', 'en-NG', 'en-NZ', 'en-PK', 'en-PH', 'en-RW', 'en-SG', 'en-SL', 'en-UG', 'en-US', 'en-TZ', 'en-ZA', 'en-ZM', 'en-ZW', 'es-AR', 'es-BO', 'es-CL', 'es-CO', 'es-CR', 'es-DO', 'es-HN', 'es-PE', 'es-EC', 'es-ES', 'es-MX', 'es-PA', 'es-PY', 'es-UY', 'et-EE', 'fa-IR', 'fi-FI', 'fj-FJ', 'fo-FO', 'fr-BE', 'fr-FR', 'fr-GF', 'fr-GP', 'fr-MQ', 'fr-RE', 'ga-IE', 'he-IL', 'hu-HU', 'id-ID', 'it-IT', 'it-SM', 'ja-JP', 'ka-GE', 'kk-KZ', 'kl-GL', 'ko-KR', 'lt-LT', 'ms-MY', 'nb-NO', 'ne-NP', 'nl-BE', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ro-RO', 'ru-RU', 'sl-SI', 'sk-SK', 'sq-AL', 'sr-RS', 'sv-SE', 'th-TH', 'tr-TR', 'uk-UA', 'uz-UZ', 'vi-VN', 'zh-CN', 'zh-HK', 'zh-MO', 'zh-TW']` OR defaults to 'any'. If 'any' or a falsey value is used, function will check if any of the locales match).<br/><br/>`options` is an optional object that can be supplied with the following keys: `strictMode`, if this is set to `true`, the mobile phone number must be supplied with the country code and therefore must start with `+`. Locale list is `validator.isMobilePhoneLocales`. |
990
- | **isMongoId()** | check if the string is a valid hex-encoded representation of a [MongoDB ObjectId][mongoid]. |
991
- | **isMultibyte()** | check if the string contains one or more multi-byte chars. |
992
- | **isNumber** | check if the string contains only numbers. |
993
- | **isNumeric(options])** | check if the string contains only numbers.<br/><br/>`options` is an object which defaults to `{no_symbols: false}` it also has locale as an option. If `no_symbols` is true, the validator will reject numeric strings that feature a symbol (e.g. `+`, `-`, or `.`).<br/><br/>`locale` determine the decimal separator and is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-FR', 'hu-HU', 'it-IT', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`. |
994
- | **isOctal()** | check if the string is a valid octal number. |
995
- | **isPath()** | check if the string is a valid path. |
996
- | **isPassportNumber(countryCode)** | check if the string is a valid passport number.<br/><br/>(countryCode is one of `[ 'AM', 'AR', 'AT', 'AU', 'BE', 'BG', 'BY', 'CA', 'CH', 'CN', 'CY', 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE' 'IN', 'IS', 'IT', 'JP', 'KR', 'LT', 'LU', 'LV', 'MT', 'NL', 'PO', 'PT', 'RO', 'RU', 'SE', 'SL', 'SK', 'TR', 'UA', 'US' ]`. |
997
- | **isPort()** | check if the string is a valid port number. |
998
- | **isPostalCode(locale)** | check if the string is a postal code,<br/><br/>(locale is one of `[ 'AD', 'AT', 'AU', 'AZ', 'BE', 'BG', 'BR', 'BY', 'CA', 'CH', 'CZ', 'DE', 'DK', 'DO', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HT', 'HU', 'ID', 'IE' 'IL', 'IN', 'IR', 'IS', 'IT', 'JP', 'KE', 'LI', 'LT', 'LU', 'LV', 'MT', 'MX', 'MY', 'NL', 'NO', 'NP', 'NZ', 'PL', 'PR', 'PT', 'RO', 'RU', 'SA', 'SE', 'SG', 'SI', 'TH', 'TN', 'TW', 'UA', 'US', 'ZA', 'ZM' ]` OR 'any'. If 'any' is used, function will check if any of the locals match. Locale list is `validator.isPostalCodeLocales`.). |
999
- | **isRFC3339()** | check if the string is a valid [RFC 3339](https://tools.ietf.org/html/rfc3339) date. |
1000
- | **isRgbColor(includePercentValues])** | check if the string is a rgb or rgba color.<br/><br/>`includePercentValues` defaults to `true`. If you don't want to allow to set `rgb` or `rgba` values with percents, like `rgb(5%,5%,5%)`, or `rgba(90%,90%,90%,.3)`, then set it to false. |
1001
- | **isSemVer()** | check if the string is a Semantic Versioning Specification (SemVer). |
1002
- | **isString()** | check if the string is a string. |
1003
- | **isStringList()** | check if the string is a comma separated list of string. |
1004
- | **isSurrogatePair()** | check if the string contains any surrogate pairs chars. |
1005
- | **isUppercase()** | check if the string is uppercase. |
1006
- | **isSlug** | Check if the string is of type slug. `Options` allow a single hyphen between string. e.g. [`cn-cn`, `cn-c-c`] |
1007
- | **isStrongPassword(options])** | Check if a password is strong or not. Allows for custom requirements or scoring rules. If `returnScore` is true, then the function returns an integer score for the password rather than a boolean.<br/>Default options: <br/>`{ minLength: 8, minLowercase: 1, minUppercase: 1, minNumbers: 1, minSymbols: 1, returnScore: false, pointsPerUnique: 1, pointsPerRepeat: 0.5, pointsForContainingLower: 10, pointsForContainingUpper: 10, pointsForContainingNumber: 10, pointsForContainingSymbol: 10 }` |
1008
- | **isTaxID(locale)** | Check if the given value is a valid Tax Identification Number. Default locale is `en-US` |
1009
- | **isURL(options])** | check if the string is an URL.<br/><br/>`options` is an object which defaults to `{ protocols: ['http','https','ftp'], require_tld: true, require_protocol: false, require_host: true, require_valid_protocol: true, allow_underscores: false, host_whitelist: false, host_blacklist: false, allow_trailing_dot: false, allow_protocol_relative_urls: false, disallow_auth: false }`.<br/><br/>require_protocol - if set as true isURL will return false if protocol is not present in the URL.<br/>require_valid_protocol - isURL will check if the URL's protocol is present in the protocols option.<br/>protocols - valid protocols can be modified with this option.<br/>require_host - if set as false isURL will not check if host is present in the URL.<br/>require_port - if set as true isURL will check if port is present in the URL.<br/>allow_protocol_relative_urls - if set as true protocol relative URLs will be allowed.<br/>validate_length - if set as false isURL will skip string length validation (2083 characters is IE max URL length). |
1010
- | **isUUID(version])** | check if the string is a UUID (version 3, 4 or 5). |
1011
- | **isVariableWidth()** | check if the string contains a mixture of full and half-width chars. |
1012
- | **isWhitelisted(chars)** | checks characters if they appear in the whitelist. |
1013
-
1014
- #### Wait
1015
-
1016
- Wait is used to make the process wait for the given seconds.
1017
-
1018
- ```javascript
1019
- import { wait } from 'node-server-engine';
1020
-
1021
- // This will make the process wait for 10 mins
1022
- await wait(600);
1023
- ```
1024
-
1025
- <!-- markdownlint-enable MD033 -->
1
+ # Node Server Engine
2
+
3
+ Framework used to develop Node backend services. This package ships with a lot of features to standardize the creation of services, letting you focus on the business logic.
4
+
5
+ - [Node Server Engine](#Node-server-engine)
6
+ - [Install](#install)
7
+ - [Entities](#entities)
8
+ - [Server](#server)
9
+ - [Server Configuration](#server-configuration)
10
+ - [Endpoint](#endpoint)
11
+ - [Endpoint Configuration](#endpoint-configuration)
12
+ - [Methods](#methods)
13
+ - [Authentication](#authentication)
14
+ - [File Upload](#file-upload)
15
+ - [Socket Client](#socket-client)
16
+ - [Socket Client Options](#socket-client-options)
17
+ - [Properties](#properties)
18
+ - [Message Handler](#message-handler)
19
+ - [Redis](#redis)
20
+ - [Sequelize](#sequelize)
21
+ - [Pub/Sub](#pubsub)
22
+ - [PushNotification](#pushnotification)
23
+ - [Localizator](#localizator)
24
+ - [ElasticSearch](#elasticsearch)
25
+ - [Translation Manager](#translation-manager)
26
+ - [Error Reporting](#error-reporting)
27
+ - [Common options](#common-options)
28
+ - [Severity](#severity)
29
+ - [Log Levels](#log-levels)
30
+ - [EngineError](#engineerror)
31
+ - [WebError](#weberror)
32
+ - [Middlewares](#middlewares)
33
+ - [Swagger Docs](#swagger-docs)
34
+ - [Structuring Documentation](#structuring-documentation)
35
+ - [Schemas and Responses](#schemas-and-responses)
36
+ - [User Resolver](#user-resolver)
37
+ - [Gemini File Upload](#gemini-file-upload)
38
+ - [checkPermission](#check-permission-middleware)
39
+ - [Utilities](#utilities)
40
+ - [Request](#request)
41
+ - [TLS Request](#tls-request)
42
+ - [TLS Config](#tls-config)
43
+ - [Send Push Notification](#send-push-notification)
44
+ - [Send Email](#send-email)
45
+ - [Filter](#filter)
46
+ - [Database Migration](#database-migration)
47
+ - [Environment Variables Verification](#environment-variables-verification)
48
+ - [Assertions Available](#assertions-available)
49
+ - [Wait](#wait)
50
+
51
+ ## Install
52
+
53
+ To start a new service, it is **highly recomended** that you clone it from [our template](https://github.com/prakashmahendran/node-server-template). It will already include all the necessary tools and boilerplate.
54
+
55
+ If you need to install it manually:
56
+
57
+ ```bash
58
+ npm i node-server-engine
59
+ ```
60
+
61
+ ## Entities
62
+
63
+ ### Server
64
+
65
+ The server class encapsulates all of the express boilerplate. Instantiate one per service and initialize it to get started.
66
+
67
+ ```javascript
68
+ import { Server } from 'node-server-engine';
69
+ const server = new Server(config);
70
+ server.init();
71
+ ```
72
+
73
+ #### Server Configuration
74
+
75
+ <!-- markdownlint-disable MD033 -->
76
+
77
+ | Property | Type | Behavior | Default |
78
+ | ----------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
79
+ | port | Number | Port to listen to | `process.env.PORT` |
80
+ | endpoints | Array\<[Endpoint](#endpoint)> | List of endpoints that should be served. | [] |
81
+ | globalMiddleware | Array\<Function> <br> Array\<{middleware: Function, path: String}> | List of middlewares that should be executed for each endpoint's logic. If it is given as an object with a path, it will only be applied to requests with this base path. | [] |
82
+ | errorMiddleware | Array\<Function> <br> Array\<{middleware: Function, path: String}> | List of middlewares that should be executed after each endpoint's logic. If it is given as an object with a path, it will only be applied to requests with this base path. | [] |
83
+ | initCallbacks | Array\<Function> | List of functions that are called on server start |
84
+ | [] |
85
+ | syncCallbacks | boolean | Forces the init callbacks to run one after the other and not in parallel |
86
+ | false |
87
+ | cron | Array\<Object> | List of cronjob that are called on server start | [] |
88
+ | shutdownCallbacks | Array\<Function> | List of functions that are called on server shutdown | [] |
89
+ | checkEnvironment | Object | [Schema against which verify the environment variables](#environment-variables-verification), will cause server termination if the environment variables are not properly set. | {} |
90
+ | webSocket.server | Object | Settings to create a WebSocket server. See the [ws package documentation](https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback) for details. | |
91
+ | webSocket.client | Object | Settings passed down to [SocketClient](#socket-client) when a new socket connection is established. | |
92
+
93
+ <!-- markdownlint-enable MD033 -->
94
+
95
+ ---
96
+
97
+ ### Endpoint
98
+
99
+ Endpoint encapsulates the logic of a single endpoint in a standard way.
100
+
101
+ The main function of the endpoint is called the **handler**. This function should only handle pure business logic for a given endpoint.
102
+
103
+ An endpoint usually has a **validator**. A validator is a schema that will be compared to the incoming request. The request will be denied if it contains illegal or malformed arguments. For more detail see the documentation of the underlying package [express-validator](https://express-validator.github.io/docs/schema-validation.html).
104
+
105
+ ```javascript
106
+ import { Endpoint, EndpointMethod } from 'node-server-engine';
107
+
108
+ // A basic handler that returns an HTTP status code of 200 to the client
109
+ function handler(req, res) {
110
+ res.sendStatus(200);
111
+ }
112
+
113
+ // The request must contain `id` as a query string and it must be a UUID V4
114
+ const validator = {
115
+ id: {
116
+ in: 'query',
117
+ isUUID: {
118
+ options: 4
119
+ }
120
+ }
121
+ };
122
+
123
+ // This endpoint can be passed to the Server
124
+ new Endpoint({
125
+ path: '/demo',
126
+ method: EndpointMethod.GET,
127
+ handler,
128
+ validator
129
+ });
130
+ ```
131
+
132
+ #### Endpoint Configuration
133
+
134
+ `new Endpoint(config)`
135
+
136
+ | Property | Type | Behavior | Default |
137
+ | --------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
138
+ | path | String | Path to which the endpoint should be served | **required** |
139
+ | method | [Method](#methods) | Method to which the endpoint should be served | **required** |
140
+ | handler | Function | Endpoint handler | **required** |
141
+ | validator | Object | Schema to validate against the request. [See documentation](https://express-validator.github.io/docs/schema-validation.html) for more details. | |
142
+ | authType | [AuthType](#authentication) | Authentication to use for this endpoint | AuthType.NONE |
143
+ | authParams | Object | Options specific to the [authentication methods](#authentication) | {} |
144
+ | files | Array\<Object> | Configuration to upload files. See the [specific documentation](#file-upload). | {} |
145
+ | middleware | Array\<Function> | List of middlewares to run before the handler. | [] |
146
+ | errorMiddleware | Array\<Function> | List of middlewares to run after the handler | [] |
147
+
148
+ ```javascript
149
+ const addNodeEndpoint = new Endpoint({
150
+ path: '/note',
151
+ method: EndpointMethod.POST,
152
+ handler: (req, res, next) => res.json(addNote(req.body)),
153
+ authType: EndpointAuthType.AUTH_JWT,
154
+ middleware: [checkPermission(['DeleteUser', 'AdminAccess'])],
155
+ errorMiddleware: [addNoteErrorMiddleware],
156
+ validator: {
157
+ id: {
158
+ in: 'body',
159
+ isUUID: true
160
+ },
161
+ content: {
162
+ in: 'body',
163
+ isLength: {
164
+ errorMessage: 'content to long',
165
+ options: {
166
+ max: 150
167
+ }
168
+ }
169
+ }
170
+ }
171
+ });
172
+ ```
173
+
174
+ #### Methods
175
+
176
+ The following HTTP methods are supported
177
+
178
+ - Method.GET
179
+ - Method.POST
180
+ - Method.PUT
181
+ - Method.PATCH
182
+ - Method.DELETE
183
+ - Method.ALL - _respond to all requests on a path_
184
+
185
+ #### Authentication
186
+
187
+ Endpoints can take an authType and authParam in their configuration to determine their authentication behavior. The following table summarizes their usage.
188
+
189
+ The server engine exposes an enumeration for auth types.
190
+ `import {AuthType} from 'node-server-engine';`
191
+
192
+ <!-- markdownlint-disable MD033 -->
193
+
194
+ | AuthType | Description | AuthParams |
195
+ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
196
+ | AuthType.NONE | No authentication. All requests are handled | |
197
+ | AuthType.JWT | A valid JSON Web Token is required as Bearer token. To be valid it must be properly signed by auth0, and its payload must match with what is set as environment variables.<br>The user's ID is added to `req.user`. | |
198
+ | AuthType.TLS | Authenticate through mutual TLS. CA and an optional list of white listed host names should be set in the environment variables. | **whitelist** [Array<String>]: List of certificate Common Name or Alt Name that are permitted to make requests to this endpoint. |
199
+ | AuthType.HMAC | Authenticate with a signature in the payload.<br>**This authentication is deprecated and should be avoided** | **secret** [String]: Overrides the secret used for signatures set in environment variables<br>**isGithub** [Boolean]: The request is a Github webhook and therefore uses their signature system and not the default one. |
200
+ | AuthType.STATIC | A valid shared Bearer token is required. Shared token is stored in env variable (STATIC_TOKEN) | |
201
+ | AuthType.ADMIN | A valid JSON Web Token is required as Bearer token. To be valid it must be properly signed by admin api, and its payload must match with what is set as environment variables.<br>The user's email and permission is added to `req.user`. | **permission** [String]: Endpoint permission required for admin user |
202
+
203
+ <!-- markdownlint-enable MD033 -->
204
+
205
+ #### File Upload
206
+
207
+ An endpoint can upload a file to a cloud storage and pass down its url to the handler.
208
+
209
+ The request must be made as `multipart/form-data`.
210
+
211
+ The file's data will be available at `req.files`.
212
+
213
+ The following settings can be used on each object the Endpoint's `options.files`.
214
+
215
+ | Property | Type | Description | Default |
216
+ | ------------------- | -------------- | ------------------------------------------------------------------------ | ------------ |
217
+ | key | string | Form key as which the file should be fetched | **required** |
218
+ | path | string | Base path of the directory where the file should be stored in the bucket | `/` |
219
+ | bucket | string | Name of the bucket in which the file should be stored | **required** |
220
+ | maxSize | string | Maximum file size in a human readable format (ex: 5MB) | **required** |
221
+ | mimeTypes | Array\<string> | A list of accepted MIME Types | [] |
222
+ | required | boolean | Will fail the request and not store the files if this one is missing | false |
223
+ | noExtension | boolean | Store the file with no extension | false |
224
+ | image | Object | Image manipulation to perform on the uploaded file | |
225
+ | image.resize.height | number | Resize the image to fit a specific height | |
226
+ | image.resize.width | number | Resize the image to fit a specific width | |
227
+ | image.quality | number | JPEG quality factor to use for export | |
228
+
229
+ ---
230
+
231
+ ### Socket Client
232
+
233
+ The socket server start if the [Server](#server)'s webSocket option is not undefined.
234
+
235
+ Each time a new socket connection is established, a new instance of `SocketClient` is created.
236
+
237
+ #### Socket Client Options
238
+
239
+ Options can be set for SocketClient when setting up a Server instance.
240
+
241
+ | Parameter | Type | Description | Default |
242
+ | ----------------- | ------------------------------------------ | ----------------------------------------------------------------------- | ------------ |
243
+ | handlers | Array\<[MessageHandler](#message-handler)> | A list of message handlers to use | **required** |
244
+ | authCallbacks | Array\<function> | Callbacks called when a client successfully authenticates on the socket | [] |
245
+ | initCallbacks | Array\<function> | Callbacks called when the socket client is created | [] |
246
+ | shutdownCallbacks | Array\<function> | Callbacks called when the socket client is destroyed | [] |
247
+
248
+ #### Properties
249
+
250
+ | Property | Type | Description |
251
+ | ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------- |
252
+ | id | String | A unique identifier for the connection |
253
+ | ws | Object | The socket being used. Instance of [WebSocket](https://github.com/websockets/ws/blob/master/doc/ws.md#class-websocket) |
254
+ | authenticated | Boolean | Flag indicating that the current user is authenticated |
255
+ | userId | String | Id of the current user **(available when authenticated)** |
256
+
257
+ ---
258
+
259
+ ### Message Handler
260
+
261
+ Message handler are similar to [Endpoint](#endpoint), but in a WebSocket context. They define how incoming messages should be handled.
262
+
263
+ ```javascript
264
+ import { MessageHandler, Server } from 'node-server-engine';
265
+
266
+ function handler(payload, client) {
267
+ // payload is the message payload in a standard message.
268
+ // client is an instance of SocketClient
269
+ }
270
+
271
+ const messageHandler = new MessageHandler(type, handler, options);
272
+
273
+ new Server({
274
+ webSocket: { client: { handlers: [messageHandler] } }
275
+ });
276
+ ```
277
+
278
+ | Argument | Type | Description | Default |
279
+ | --------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------- | ------------ |
280
+ | type | String | The message type that should be handled | **required** |
281
+ | handler | Function | A function that will run for every message of this type | **required** |
282
+ | options.authenticated | A flag indicating that this kind of message handling require an authenticated client | `true` |
283
+
284
+ ---
285
+
286
+ ### Redis
287
+
288
+ The server engine exposes a Redis client that is configured to work with the standard environment variables that are used in our services.
289
+
290
+ It is a pre-configured instance of [ioredis](https://github.com/luin/ioredis). See the package documentation for more details.
291
+
292
+ ```javascript
293
+ import { Redis } from 'node-server-engine';
294
+
295
+ await Redis.set(key, value);
296
+ ```
297
+
298
+ It can be configured through environment variables
299
+
300
+ | env | description | default |
301
+ | -------------- | ---------------------------------------------------------------------------------- | ------- |
302
+ | REDIS_HOST | Host to which to connecto to | |
303
+ | REDIS_PORT | Port on which redis is served | |
304
+ | REDIS_PASSWORD | Password used to authenticate with the server | |
305
+ | REDIS_CLUSTER | Flag indicating that redis is configured as a cluster and not as a single instance | false |
306
+
307
+ ---
308
+
309
+ ### Sequelize
310
+
311
+ The server engine exposes an SQL ORM that is configured to work with the standard environment variables that are used in our services.
312
+
313
+ It is a pre-configured instance of [sequelize](https://github.com/sequelize/sequelize). See the package documentation for more details.
314
+
315
+ ```javascript
316
+ import { Sequelize } from 'node-server-engine';
317
+
318
+ Sequelize.sequelize;
319
+ Sequelize.closeSequelize();
320
+ ```
321
+
322
+ It can be configured through environment variables
323
+
324
+ | env | description | default |
325
+ | ------------ | ------------------------------------------------- | -------- |
326
+ | SQL_HOST | Host to which connect to | |
327
+ | SQL_PORT | Port on which SQL is served | 5432 |
328
+ | SQL_PASSWORD | Password used to authenticate with the SQL server | |
329
+ | SQL_USER | User used to authenticate with the SQL server | |
330
+ | SQL_DB | Database to which connect to | |
331
+ | SQL_TYPE | SQL type which connect to | postgres |
332
+
333
+ ---
334
+
335
+ ### Pub/Sub
336
+
337
+ The engine exposes a `PubSub` entity that can be used to communicate with Google Cloud Pub/Sub.
338
+
339
+ ```javascript
340
+ import { PubSub } from 'node-server-engine';
341
+
342
+ /**
343
+ * Declare that the service will be publishing to a topic
344
+ * This must be done before init() is called
345
+ * Any attempt to publish a message without declaring a topic first will fail
346
+ * @property {string|Array.<string>} topic - The topic(s) to which we will be publishing
347
+ */
348
+ PubSub.addPublisher(topic);
349
+
350
+ /**
351
+ * Binds a message handle to a subscription
352
+ * If called multiple times, handlers will be chained
353
+ * This must be done before init() is called
354
+ * The subscription will not be consumed until init() is called
355
+ * @property {string} subscription - The subscription to consume
356
+ * @property {function|Array.<function>} handler - The message handling function(s)
357
+ * @property {boolean} [first] - Puts the handler(s) at the beginning of the handling chain (default: false)
358
+ */
359
+ PubSub.addSubscriber(subscription, handler, first);
360
+
361
+ /**
362
+ * Establish connection with all the declared publishers/subscribers
363
+ */
364
+ await PubSub.init();
365
+
366
+ /**
367
+ * Send a message through a previously declared publisher
368
+ * @property {string} topic - The name of the topic to which the message should be pushed
369
+ * @property {Object} message - The actual message (will be JSON stringified)
370
+ * @property {Object} [attributes] - Message attributes
371
+ * @property {string} [orderingKey] - Ordering key
372
+ */
373
+ await PubSub.publish(topic, message, attributes, orderingKey);
374
+
375
+ /**
376
+ * Flush all pending messages and close connections with Pub/Sub
377
+ */
378
+ await PubSub.shutdown();
379
+ ```
380
+
381
+ ---
382
+
383
+ ### PushNotification
384
+
385
+ Communication interface with the push service.
386
+
387
+ ```javascript
388
+ import { PushNotification } from 'node-server-engine';
389
+
390
+ // The entity needs to initialize it's pub/sub connections
391
+ // Handlers must be declared before this function is called
392
+ await PushNotification.init();
393
+
394
+ /**
395
+ * Send a push notification through the push service
396
+ * @param {String} userId - ID of the user that should receive the notification
397
+ * @param {Object} notification - Notification that should be sent
398
+ * @return {void}
399
+ */
400
+ await PushNotification.sendPush(userId, notification);
401
+ ```
402
+
403
+ ---
404
+
405
+ ### Localizator
406
+
407
+ The localizator exposes localization related utilities.
408
+
409
+ ```javascript
410
+ import { Localizator } from 'node-server-engine';
411
+
412
+ // The synchronize init should be called first to initialize the data
413
+ // The localizator will regularly synchronize new data after that without any calls having to be made
414
+ await Localizator.init();
415
+
416
+ // Get the different ways of displaying a user's name
417
+ const { regular, formal, casual } = await Localizator.getDisplayNames(
418
+ firstName,
419
+ lastName,
420
+ locale
421
+ );
422
+
423
+ // This should be call when the program shuts down.
424
+ await Localizator.shutdown();
425
+ ```
426
+
427
+ | env | description | default |
428
+ | ----------- | ----------------------------------------- | ------------ |
429
+ | LOCALES_URL | Base URL where the locales data is stored | **required** |
430
+
431
+ ---
432
+
433
+ ### ElasticSearch
434
+
435
+ The ElasticSearch exposes a service related to data searching.
436
+
437
+ ```javascript
438
+ import { ElasticSearch } from 'node-server-engine';
439
+
440
+ // The synchronize init should be called first to initialize the data
441
+ await ElasticSearch.init();
442
+
443
+ // This should be call when the program shuts down.
444
+ await ElasticSearch.shutdown();
445
+ ```
446
+
447
+ | env | description | default |
448
+ | ----------------------------- | ---------------------------------------------- | ------------ |
449
+ | ELASTIC_SEARCH_MIGRATION_PATH | The path link to Elastic Search migration data | **required** |
450
+ | ELASTIC_SEARCH_HOST | The elastic search host url | **required** |
451
+ | ELASTIC_SEARCH_USERNAME | The elastic search user name | **required** |
452
+ | ELASTIC_SEARCH_PASSWORD | The elastic search password | **required** |
453
+ | TLS_CA | CA for ssl config when available | |
454
+
455
+ ---
456
+
457
+ ### Translation Manager
458
+
459
+ The translation manager exposes translation related utilities.
460
+
461
+ ```javascript
462
+ import { TranslationManager } from 'node-server-engine';
463
+
464
+ // The synchronize init should be called first to initialize the data
465
+ // The tranlsation manager will regularly synchronize new data after that without any calls having to be made
466
+ await TranslationManager.init();
467
+
468
+ // Get the different ways of displaying a user's name
469
+ const translatedString = await TranslationManager.translate(
470
+ lang,
471
+ key,
472
+ variables,
473
+ tags
474
+ );
475
+
476
+ // Example
477
+ const translatedString = await TranslationManager.translate(
478
+ 'zh-TW',
479
+ 'email.invitation.body',
480
+ { name: 'John' },
481
+ { link: ['a', 'href="https://www.test.com"'] }
482
+ );
483
+
484
+ // This should be call when the program shuts down.
485
+ await TranslationManager.shutdown();
486
+ ```
487
+
488
+ - **lang** [String]: Locale for which the translation should be fetched (if no data is found, translation will be returned in `en-US`).
489
+ - **key** [String]: Translation key
490
+ - **variables** [Object]: A key=>value mapping for variable interpolation in strings. **(Optional)**
491
+ - **tags** [Object]: A key=>value mapping for variable interpolation in strings. **(Optional)**
492
+
493
+ | env | description | default |
494
+ | ----------- | ----------------------------------------- | ------------ |
495
+ | LOCALES_URL | Base URL where the locales data is stored | **required** |
496
+
497
+ ---
498
+
499
+ ### Error Reporting
500
+
501
+ The server engine standardizes the way errors are handled and reported. The error classes provided by the Server Engine should always be used when throwing an exception.
502
+
503
+ Errors are a crucial part of the application, they are what helps us to properly debug the program and offer support when need, as well as what exposes issues to the client.
504
+
505
+ By standard, the client receives the following body when an error happens.
506
+
507
+ ```javascript
508
+ // HTTP Status code (400 | 500)
509
+ {
510
+ errorCode: "some-error", // Machine readable error code
511
+ hint: "The selected user does not exist" // (optional) Hint for developers
512
+ }
513
+ ```
514
+
515
+ Status codes should be limited to 400 for client errors and 500 for server errors. Other 4XX status codes should be avoided unless very specific cases (ex: authentication error).
516
+
517
+ All our custom error classes take a `data` parameter. This will be logged on the backend and should contain any data that can help to understand the runtime context or the error (ex: user's ID).
518
+
519
+ #### Common options
520
+
521
+ These options are common to each of the error classes described below.
522
+
523
+ | option | definition | example | default |
524
+ | -------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------ |
525
+ | message | A message logged on the backend only | "Could not find user in the DB" | **required** |
526
+ | severity | The level at which this error should be logged | [Severity](#severity).WARNING | [Severity](#severity).CRITICAL |
527
+ | data | Some data related to the error that will be logged on the backend. This should help to undetrstand the runtime context. | {userId: 'xf563ugh0', isAdmin: false} | |
528
+ | error | An error object, when this is a wrapper around an existing error object | |
529
+
530
+ #### Severity
531
+
532
+ Severity allows us to order errors by their impact on the program. It is important to set severity correctly as backend logs can include hundreds of entries per seconds, severity allows us to filter out the most important errors. An enumeration is exposed that includes all the severity levels, as described in the following table.
533
+
534
+ ##### Log Levels
535
+
536
+ | severity | definition |
537
+ | --------- | ------------------------------------------------------------------------------------------------------------------------ |
538
+ | DEBUG | Detailed information of the runtime execution. Used for debugging. |
539
+ | INFO | Base information level of runtime information. |
540
+ | WARNING | Errors that are expected to happen and do not cause any particular issue. (ex: a client made an unauthenticated request) |
541
+ | CRITICAL | Errors that are unexpected and cause an improper behavior. (ex: failed to store some data in the DB) |
542
+ | EMERGENCY | Errors that prevent the program from running. (ex: some environment variables are not correctly set) |
543
+
544
+ #### EngineError
545
+
546
+ This error class represents errors that happen withing the Server Engine. They should be used for server configuration errors, or unexpected behaviors. They will always return `500 - {errorCode: 'server-error'}`.
547
+
548
+ ```javascript
549
+ import { EngineError, Severity } from 'node-server-engine';
550
+
551
+ if (!process.env.IMPORTANT_VARIABLE) {
552
+ throw new EngineError(options);
553
+ }
554
+ ```
555
+
556
+ Engine Errors strictly follow the [common options](#common-options).
557
+
558
+ #### WebError
559
+
560
+ This error class represents errors that happen at runtime and that need specific reporting to the client. Their definition is more complex, but it includes additional data specific to the client.
561
+
562
+ ```javascript
563
+ import { WebError, Severity } from 'node-server-engine';
564
+
565
+ const user = User.findOne({ where: { id: userId } });
566
+ if (!user) {
567
+ throw new WebError(options);
568
+ }
569
+ ```
570
+
571
+ In addition to the [common options](#common-options), WebError defines some other options specific for error reporting to clients.
572
+
573
+ | option | definition | example | default |
574
+ | ---------- | ---------------------------------------------------------------- | ------------ | ------------ |
575
+ | errorCode | A machine readable error code that will be parsed by the client. | unknown-user | **required** |
576
+ | statusCode | HTTP status code of the response. | 400 | 500 |
577
+ | hint | A human readable error message that is intended for developers | |
578
+
579
+ ## Middlewares
580
+
581
+ Server engine exposes a bunch of middlewares. These can be imported to your project and used globally or per endpoint.
582
+
583
+ ### Swagger Docs
584
+
585
+ This middleware allows the service to connect with the [API Documentation Service](https://github.com/prakashmahendran/api-documentation-service). It exposes the necessary endpoint for the documentation of this API to be visible by the Documentation Service.
586
+
587
+ ```javascript
588
+ import { Server, middleware } from 'node-server-engine';
589
+
590
+ new Server({
591
+ globalMiddleware: [middleware.swaggerDocs()]
592
+ });
593
+ ```
594
+
595
+ #### Structuring Documentation
596
+
597
+ The underlying system used is the [Open API](https://swagger.io/specification/) spec.
598
+ Most of the data is already generate by the documentation service. The only real need is to document endpoints.
599
+
600
+ Endpoints should be documented in YAML files that respect the `**/*.docs.yaml` convention. It is recommended to place them in the same directory as the endpoint definition. Endpoint documentation has to follow the [path object spec](https://swagger.io/specification/#paths-object) from Open API.
601
+
602
+ ```yaml
603
+ /hello:
604
+ get:
605
+ description: Request the API to say Hello
606
+ responses:
607
+ '200':
608
+ description: Replies hello
609
+ content:
610
+ application/json:
611
+ schema:
612
+ type: Object
613
+ properties:
614
+ says:
615
+ type: string
616
+ example: Hello
617
+ ```
618
+
619
+ #### Schemas and Responses
620
+
621
+ To avoid repeating the same structure across the documentation manually, one can use [schemas and responses components](https://swagger.io/docs/specification/components/).
622
+
623
+ Some common components are already defined directly in the API Documentation Service, please check its documentation to avoid repeats.
624
+
625
+ If you ever need to declare custom components, they simply must follow the architecture bellow.
626
+
627
+ ```bash
628
+ # Repository root
629
+ /src
630
+ /docs
631
+ /responses
632
+ - coolResponse.yaml
633
+ / schemas
634
+ - bestSchema.yaml
635
+ ```
636
+
637
+ Here is an example definition:
638
+
639
+ ```yaml
640
+ Dog:
641
+ type: object
642
+ properties:
643
+ name:
644
+ type: string
645
+ example: Rex
646
+ owner:
647
+ type: string
648
+ example: f1982af0-1579-4c56-a138-de1ab4ff39b3
649
+ isAGoodBoy:
650
+ type: boolean
651
+ example: true
652
+ required:
653
+ - name
654
+ - owner
655
+ ```
656
+
657
+ ---
658
+
659
+ ### User Resolver
660
+
661
+ `/!\` **Must be used in combination with AuthType.JWT**
662
+
663
+ Resolves the user making the request with the user resolver. The user's complete data is added to `req.user`.
664
+
665
+ ```javascript
666
+ import { Endpoint, middleware, AuthType, Method } from 'node-server-engine';
667
+
668
+ new Endpoint({
669
+ path: '/hello',
670
+ method: Method.GET,
671
+ authType: AuthType.JWT,
672
+ middleware: [middleware.userResolver],
673
+ handler: (req, res) => {
674
+ res.json({ say: `Hello ${req.user.firstName}` });
675
+ }
676
+ });
677
+ ```
678
+ ---
679
+
680
+ #### Gemini File Upload
681
+
682
+ An endpoint can upload a file to a google gemini AI
683
+
684
+ The request must be made as `multipart/form-data`.
685
+
686
+ File should be uploaded under the key file.
687
+
688
+ The file's data will be available at `req.body.fileUri req.body.mimeType req.body.originalname`
689
+
690
+
691
+ #### Check Permission Middleware
692
+
693
+ /!\ **Must be used in combination with AuthType.JWT**
694
+
695
+ Checks if the user has at least one of the required permissions. The permissions are case-insensitive.
696
+
697
+ ```javascript
698
+ import { Endpoint, middleware, AuthType, Method } from 'node-server-engine';
699
+
700
+ new Endpoint({
701
+ path: '/admin',
702
+ method: Method.GET,
703
+ authType: AuthType.JWT,
704
+ middleware: [middleware.checkPermission(['admin', 'superuser'])],
705
+ handler: (req, res) => {
706
+ res.json({ message: 'Access granted' });
707
+ }
708
+ });
709
+ ```
710
+
711
+ ```typescript
712
+ import { Request, Response, NextFunction } from 'express';
713
+
714
+ // Middleware to check if the user has at least one of the required permissions (case-insensitive)
715
+ export const checkPermission = (requiredActions: string | string[]) => {
716
+ return (req: Request, res: Response, next: NextFunction) => {
717
+ const user = req.user;
718
+
719
+ if (!user || !user.permissions) {
720
+ return res.status(403).json({ message: 'User does not have permissions' });
721
+ }
722
+
723
+ const requiredActionsArray = Array.isArray(requiredActions)
724
+ ? requiredActions
725
+ : [requiredActions];
726
+
727
+ const requiredActionsLower = requiredActionsArray.map(action => action.toLowerCase());
728
+
729
+ const hasPermission = user.permissions.some((permission: string) =>
730
+ requiredActionsLower.includes(permission.toLowerCase())
731
+ );
732
+
733
+ if (!hasPermission) {
734
+ return res.status(403).json({ message: 'Permission denied' });
735
+ }
736
+
737
+ next();
738
+ };
739
+ };
740
+ ```
741
+
742
+ ## Utilities
743
+
744
+ The server engine ships with a handful of utility functions that are commonly used by servers
745
+
746
+ ### Request
747
+
748
+ This function is a wrapper around [axios](https://github.com/axios/axios). It adds proper error handling for reporting in the logs when a network call fails. It should be used for any requests made by a service.
749
+ Refer to the [axios documentation](https://github.com/axios/axios) for the request configuration.
750
+
751
+ ```javascript
752
+ import { request } from 'node-server-engine';
753
+ const { data } = await request({
754
+ method: 'get',
755
+ url: 'https://www.google.com'
756
+ });
757
+ ```
758
+
759
+ ---
760
+
761
+ ### TLS Request
762
+
763
+ This function is a wrapper around [request](#request). It adds the necessary configuration to easily make requests with TLS. The settings used are based on the environment variables. It will use request specific certificate/key if defined, or will fallback to use the same ones as the ones used for the server.
764
+
765
+ It is necessary to use this function when calling other services in the cluster. Requests could fail otherwise as the common CA is not set and the client certificate not exposed.
766
+
767
+ ```javascript
768
+ import { tlsRequest } from 'node-server-engine';
769
+ const { data } = await tlsRequest({
770
+ method: 'get',
771
+ url: 'https://www.google.com'
772
+ });
773
+ ```
774
+
775
+ ---
776
+
777
+ ### TLS Config
778
+
779
+ The server's TLS configuration can be fetched as an object. Alternatively, the server engine also exposes an [HTTPS Agent](https://nodejs.org/api/https.html#https_class_https_agent). They will not be available at startup, so it is important that the function calling them loads them first if they are not present.
780
+
781
+ ```javascript
782
+ import {tlsConfig, httpsAgent, loadTlsConfig} from 'node-server-engine';
783
+ import https from 'https';
784
+
785
+ // TLS Config
786
+ if(!tlsConfig) loadTlsConfig();
787
+ const customAgent = new https.Agent({
788
+ key: tlsConfig.key,
789
+ cert: tlsConfig.cert,
790
+ ca: tlsConfig.ca,
791
+ passphrase: tlsConfig.passphrase,
792
+ });
793
+
794
+ // HTTPS Agent
795
+ if(!httpsAgent) loadTlsConfig();
796
+ https.request('https://www.google.com'. {agent: httpsAgent});
797
+ ```
798
+
799
+ ---
800
+
801
+ ### Send Push Notification
802
+
803
+ Send a push notification through the push service.
804
+
805
+ ```javascript
806
+ import { sendPush } from 'node-server-engine';
807
+ await sendPush(userId, notification);
808
+ ```
809
+
810
+ | parameter | description |
811
+ | ------------ | ------------------------------------------------------------------------ |
812
+ | userId | ID of the user that should receive the notification |
813
+ | notification | Content of the notification as defined by the push service documentation |
814
+
815
+ ---
816
+
817
+ ---
818
+
819
+ ### Send Email
820
+
821
+ Send an email through the email service.
822
+
823
+ ```javascript
824
+ import { sendEmail } from 'node-server-engine';
825
+ await sendEmail(userId, template, translationKey, parameters, tags, to);
826
+ ```
827
+
828
+ | parameter | description |
829
+ | -------------- | -------------------------------------------------------------------------- |
830
+ | userId | ID of the user that should receive the notification |
831
+ | template | Email template to use |
832
+ | translationKey | Key used to get localized strings |
833
+ | parameters | Variables that can be inserted in the email template and localized strings |
834
+ | tags | Data injected in the localized strings as HTML tags |
835
+ | to | Array of email recipients |
836
+ | to.\*.email | Email of an email recipient |
837
+ | to.\*.name | Name of an email recipient |
838
+
839
+ ---
840
+
841
+ ### Filter
842
+
843
+ Apply a filter on an object. It returns a copy of the object that only holds the whitelisted keys.
844
+
845
+ This is particularly useful to sanitize objects before returning them to clients.
846
+
847
+ ```javascript
848
+ import { filter } from 'node-server-engine';
849
+
850
+ const object = { a: 'kept', b: 'not kept' };
851
+ const whitelist = ['a'];
852
+
853
+ const result = filter(object.whitelist);
854
+ // result = {a: 'kept'}
855
+ ```
856
+
857
+ ---
858
+
859
+ ### Database Migration
860
+
861
+ Some utilities are exposed to handle database migrations.
862
+
863
+ `runPendingMigrations` will execute all the migration scripts that have not yet been executed.
864
+
865
+ `rollbackMigrations` will rollback all the migrations that have been executed with the current version of the app and after.
866
+
867
+ ```javascript
868
+ import { runPendingMigrations } from 'node-server-engine';
869
+ import { rollbackMigrations } from 'node-server-engine';
870
+
871
+ await runPendingMigrations();
872
+
873
+ await rollbackMigrations();
874
+ ```
875
+
876
+ ---
877
+
878
+ ### Environment Variables Verification
879
+
880
+ Environment variables verification can be done through the [Server](#server)'s checkEnvironment setting. It is an object defining how environment variables should be verified.
881
+
882
+ ```javascript
883
+ import { envAssert } from 'node-server-engine';
884
+
885
+ export const checkEnvironment = {
886
+ ENV_VAR: envAssert.isString()
887
+ };
888
+ ```
889
+
890
+ #### Assertions Available
891
+
892
+ The sever engine makes available a utility for environment variables assertions calls `envAssert`. The following example shows the different assertions that are possible.
893
+
894
+ <!-- markdownlint-disable MD033 -->
895
+
896
+ | Validator | Description |
897
+ | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
898
+ | **isAfter(date])** | check if the string is a date that's after the specified date (defaults to now). |
899
+ | **isAlpha(locale, options])** | check if the string contains only letters (a-zA-Z).<br/><br/>Locale is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-FR', 'fa-IR', 'he', 'hu-HU', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`) and defaults to `en-US`. Locale list is `validator.isAlphaLocales`. options is an optional object that can be supplied with the following key(s): ignore which can either be a String or RegExp of characters to be ignored e.g. " -" will ignore spaces and -'s. |
900
+ | **isAlphanumeric(locale])** | check if the string contains only letters and numbers.<br/><br/>Locale is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-FR', 'fa-IR', 'he', 'hu-HU', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`) and defaults to `en-US`. Locale list is `validator.isAlphanumericLocales`. |
901
+ | **isAscii()** | check if the string contains ASCII chars only. |
902
+ | **isBase32()** | check if a string is base32 encoded. |
903
+ | **isBase58()** | check if a string is base58 encoded. |
904
+ | **isBase64(options])** | check if a string is base64 encoded. options is optional and defaults to `{urlSafe: false}`<br/> when `urlSafe` is true it tests the given base64 encoded string is [url safe](https://base64.guru/standards/base64url) |
905
+ | **isBefore(date])** | check if the string is a date that's before the specified date. |
906
+ | **isBIC()** | check if a string is a BIC (Bank Identification Code) or SWIFT code. |
907
+ | **isBoolean()** | check if a string is a boolean. |
908
+ | **isBtcAddress()** | check if the string is a valid BTC address. |
909
+ | **isByteLength(options])** | check if the string's length (in UTF-8 bytes) falls in a range.<br/><br/>`options` is an object which defaults to `{min:0, max: undefined}`. |
910
+ | **isCreditCard()** | check if the string is a credit card. |
911
+ | **isCurrency(options])** | check if the string is a valid currency amount.<br/><br/>`options` is an object which defaults to `{symbol: '$', require_symbol: false, allow_space_after_symbol: false, symbol_after_digits: false, allow_negatives: true, parens_for_negatives: false, negative_sign_before_digits: false, negative_sign_after_digits: false, allow_negative_sign_placeholder: false, thousands_separator: ',', decimal_separator: '.', allow_decimal: true, require_decimal: false, digits_after_decimal: [2], allow_space_after_digits: false}`.<br/>**Note:** The array `digits_after_decimal` is filled with the exact number of digits allowed not a range, for example a range 1 to 3 will be given as [1, 2, 3]. |
912
+ | **isDataURI()** | check if the string is a [data uri format](https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs). |
913
+ | **isDate(input [, options])** | Check if the input is a valid date. e.g. [`2002-07-15`, new Date()].<br/><br/> `options` is an object which can contain the keys `format`, `strictMode` and/or `delimiters`<br/><br/>`format` is a string and defaults to `YYYY/MM/DD`.<br/><br/>`strictMode` is a boolean and defaults to `false`. If `strictMode` is set to true, the validator will reject inputs different from `format`.<br/><br/> `delimiters` is an array of allowed date delimiters and defaults to `['/', '-']`. |
914
+ | **isDecimal(options])** | check if the string represents a decimal number, such as 0.1, .3, 1.1, 1.00003, 4.0, etc.<br/><br/>`options` is an object which defaults to `{force_decimal: false, decimal_digits: '1,', locale: 'en-US'}`<br/><br/>`locale` determine the decimal separator and is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fa', 'fa-AF', 'fa-IR', 'fr-FR', 'hu-HU', 'id-ID', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pl-Pl', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA', 'vi-VN']`.<br/>**Note:** `decimal_digits` is given as a range like '1,3', a specific value like '3' or min like '1,'. |
915
+ | **isDivisibleBy(number)** | check if the string is a number that's divisible by another. |
916
+ | **isEAN()** | check if the string is an EAN (European Article Number). |
917
+ | **isEmail(options])** | check if the string is an email.<br/><br/>`options` is an object which defaults to `{ allow_display_name: false, require_display_name: false, allow_utf8_local_part: true, require_tld: true, allow_ip_domain: false, domain_specific_validation: false, blacklisted_chars: '' }`. If `allow_display_name` is set to true, the validator will also match `Display Name <email-address>`. If `require_display_name` is set to true, the validator will reject strings without the format `Display Name <email-address>`. If `allow_utf8_local_part` is set to false, the validator will not allow any non-English UTF8 character in email address' local part. If `require_tld` is set to false, e-mail addresses without having TLD in their domain will also be matched. If `ignore_max_length` is set to true, the validator will not check for the standard max length of an email. If `allow_ip_domain` is set to true, the validator will allow IP addresses in the host part. If `domain_specific_validation` is true, some additional validation will be enabled, e.g. disallowing certain syntactically valid email addresses that are rejected by GMail. If `blacklisted_chars` recieves a string,then the validator will reject emails that include any of the characters in the string, in the name part. |
918
+ | **isEmpty(options])** | check if the string has a length of zero.<br/><br/>`options` is an object which defaults to `{ ignore_whitespace:false }`. |
919
+ | **isEthereumAddress()** | check if the string is an [Ethereum](https://ethereum.org/) address using basic regex. Does not validate address checksums. |
920
+ | **isFloat(options])** | check if the string is a float.<br/><br/>`options` is an object which can contain the keys `min`, `max`, `gt`, and/or `lt` to validate the float is within boundaries (e.g. `{ min: 7.22, max: 9.55 }`) it also has `locale` as an option.<br/><br/>`min` and `max` are equivalent to 'greater or equal' and 'less or equal', respectively while `gt` and `lt` are their strict counterparts.<br/><br/>`locale` determine the decimal separator and is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-FR', 'hu-HU', 'it-IT', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`. Locale list is `validator.isFloatLocales`. |
921
+ | **isFQDN(options])** | check if the string is a fully qualified domain name (e.g. domain.com).<br/><br/>`options` is an object which defaults to `{ require_tld: true, allow_underscores: false, allow_trailing_dot: false , allow_numeric_tld: false }`. |
922
+ | **isFullWidth()** | check if the string contains any full-width chars. |
923
+ | **isHalfWidth()** | check if the string contains any half-width chars. |
924
+ | **isHash(algorithm)** | check if the string is a hash of type algorithm.<br/><br/>Algorithm is one of `['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']` |
925
+ | **isHexadecimal()** | check if the string is a hexadecimal number. |
926
+ | **isHexColor()** | check if the string is a hexadecimal color. |
927
+ | **isHost()** | check if the string is a server host name. |
928
+ | **isHostList()** | check if the string is a comma separated list of server host name. |
929
+ | **isHSL()** | check if the string is an HSL (hue, saturation, lightness, optional alpha) color based on [CSS Colors Level 4 specification](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).<br/><br/>Comma-separated format supported. Space-separated format supported with the exception of a few edge cases (ex: `hsl(200grad+.1%62%/1)`). |
930
+ | **isIBAN()** | check if a string is a IBAN (International Bank Account Number). |
931
+ | **isIdentityCard(locale])** | check if the string is a valid identity card code.<br/><br/>`locale` is one of `['ES', 'IN', 'IT', 'NO', 'zh-TW', 'he-IL', 'ar-TN', 'zh-CN']` OR `'any'`. If 'any' is used, function will check if any of the locals match.<br/><br/>Defaults to 'any'. |
932
+ | **isIMEI(options]))** | check if the string is a valid IMEI number. Imei should be of format `###############` or `##-######-######-#`.<br/><br/>`options` is an object which can contain the keys `allow_hyphens`. Defaults to first format . If allow_hyphens is set to true, the validator will validate the second format. |
933
+ | **isIn(values)** | check if the string is in a array of allowed values. |
934
+ | **isInt(options])** | check if the string is an integer.<br/><br/>`options` is an object which can contain the keys `min` and/or `max` to check the integer is within boundaries (e.g. `{ min: 10, max: 99 }`). `options` can also contain the key `allow_leading_zeroes`, which when set to false will disallow integer values with leading zeroes (e.g. `{ allow_leading_zeroes: false }`). Finally, `options` can contain the keys `gt` and/or `lt` which will enforce integers being greater than or less than, respectively, the value provided (e.g. `{gt: 1, lt: 4}` for a number between 1 and 4). |
935
+ | **isIP(version])** | check if the string is an IP (version 4 or 6). |
936
+ | **isIPList()** | check if the string is a comma separated list of IP addresses (version 4 or 6). |
937
+ | **isIPRange()** | check if the string is an IP Range(version 4 only). |
938
+ | **isISBN(version])** | check if the string is an ISBN (version 10 or 13). |
939
+ | **isISIN()** | check if the string is an [ISIN][isin] (stock/security identifier). |
940
+ | **isISO8601()** | check if the string is a valid [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date; for additional checks for valid dates, e.g. invalidates dates like `2009-02-29`, pass `options` object as a second parameter with `options.strict = true`. |
941
+ | **isISO31661Alpha2()** | check if the string is a valid [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) officially assigned country code. |
942
+ | **isISO31661Alpha3()** | check if the string is a valid [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) officially assigned country code. |
943
+ | **isISRC()** | check if the string is a [ISRC](https://en.wikipedia.org/wiki/International_Standard_Recording_Code). |
944
+ | **isISSN(options])** | check if the string is an [ISSN](https://en.wikipedia.org/wiki/International_Standard_Serial_Number).<br/><br/>`options` is an object which defaults to `{ case_sensitive: false, require_hyphen: false }`. If `case_sensitive` is true, ISSNs with a lowercase `'x'` as the check digit are rejected. |
945
+ | **isJSON(options])** | check if the string is valid JSON (note: uses JSON.parse).<br/><br/>`options` is an object which defaults to `{ allow_primitives: false }`. If `allow_primitives` is true, the primitives 'true', 'false' and 'null' are accepted as valid JSON values. |
946
+ | **isJWT()** | check if the string is valid JWT token. |
947
+ | **isLatLong(options])** | check if the string is a valid latitude-longitude coordinate in the format `lat,long` or `lat, long`.<br/><br/>`options` is an object that defaults to `{ checkDMS: false }`. Pass `checkDMS` as `true` to validate DMS(degrees, minutes, and seconds) latitude-longitude format. |
948
+ | **isLength(options])** | check if the string's length falls in a range.<br/><br/>`options` is an object which defaults to `{min:0, max: undefined}`. Note: this function takes into account surrogate pairs. |
949
+ | **isLocale()** | check if the string is a locale |
950
+ | **isLowercase()** | check if the string is lowercase. |
951
+ | **isMACAddress()** | check if the string is a MAC address.<br/><br/>`options` is an object which defaults to `{no_colons: false}`. If `no_colons` is true, the validator will allow MAC addresses without the colons. Also, it allows the use of hyphens, spaces or dots e.g '01 02 03 04 05 ab', '01-02-03-04-05-ab' or '0102.0304.05ab'. |
952
+ | **isMagnetURI()** | check if the string is a [magnet uri format](https://en.wikipedia.org/wiki/Magnet_URI_scheme). |
953
+ | **isMD5()** | check if the string is a MD5 hash.<br/><br/>Please note that you can also use the `isHash('md5')` function. Keep in mind that MD5 has some collision weaknesses compared to other algorithms (e.g., SHA). |
954
+ | **isMimeType()** | check if the string matches to a valid [MIME type](https://en.wikipedia.org/wiki/Media_type) format |
955
+ | **isMobilePhone(locale [, options]])** | check if the string is a mobile phone number,<br/><br/>(locale is either an array of locales (e.g `['sk-SK', 'sr-RS']`) OR one of `['am-Am', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', ar-JO', 'ar-KW', 'ar-MA', 'ar-SA', 'ar-SY', 'ar-TN', 'az-AZ', 'az-LY', 'az-LB', 'bs-BA', 'be-BY', 'bg-BG', 'bn-BD', 'ca-AD', 'cs-CZ', 'da-DK', 'de-DE', 'de-AT', 'de-CH', 'de-LU', 'el-GR', 'en-AU', 'en-CA', 'en-GB', 'en-GG', 'en-GH', 'en-HK', 'en-MO', 'en-IE', 'en-IN', 'en-KE', 'en-MT', 'en-MU', 'en-NG', 'en-NZ', 'en-PK', 'en-PH', 'en-RW', 'en-SG', 'en-SL', 'en-UG', 'en-US', 'en-TZ', 'en-ZA', 'en-ZM', 'en-ZW', 'es-AR', 'es-BO', 'es-CL', 'es-CO', 'es-CR', 'es-DO', 'es-HN', 'es-PE', 'es-EC', 'es-ES', 'es-MX', 'es-PA', 'es-PY', 'es-UY', 'et-EE', 'fa-IR', 'fi-FI', 'fj-FJ', 'fo-FO', 'fr-BE', 'fr-FR', 'fr-GF', 'fr-GP', 'fr-MQ', 'fr-RE', 'ga-IE', 'he-IL', 'hu-HU', 'id-ID', 'it-IT', 'it-SM', 'ja-JP', 'ka-GE', 'kk-KZ', 'kl-GL', 'ko-KR', 'lt-LT', 'ms-MY', 'nb-NO', 'ne-NP', 'nl-BE', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ro-RO', 'ru-RU', 'sl-SI', 'sk-SK', 'sq-AL', 'sr-RS', 'sv-SE', 'th-TH', 'tr-TR', 'uk-UA', 'uz-UZ', 'vi-VN', 'zh-CN', 'zh-HK', 'zh-MO', 'zh-TW']` OR defaults to 'any'. If 'any' or a falsey value is used, function will check if any of the locales match).<br/><br/>`options` is an optional object that can be supplied with the following keys: `strictMode`, if this is set to `true`, the mobile phone number must be supplied with the country code and therefore must start with `+`. Locale list is `validator.isMobilePhoneLocales`. |
956
+ | **isMongoId()** | check if the string is a valid hex-encoded representation of a [MongoDB ObjectId][mongoid]. |
957
+ | **isMultibyte()** | check if the string contains one or more multi-byte chars. |
958
+ | **isNumber** | check if the string contains only numbers. |
959
+ | **isNumeric(options])** | check if the string contains only numbers.<br/><br/>`options` is an object which defaults to `{no_symbols: false}` it also has locale as an option. If `no_symbols` is true, the validator will reject numeric strings that feature a symbol (e.g. `+`, `-`, or `.`).<br/><br/>`locale` determine the decimal separator and is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-FR', 'hu-HU', 'it-IT', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`. |
960
+ | **isOctal()** | check if the string is a valid octal number. |
961
+ | **isPath()** | check if the string is a valid path. |
962
+ | **isPassportNumber(countryCode)** | check if the string is a valid passport number.<br/><br/>(countryCode is one of `[ 'AM', 'AR', 'AT', 'AU', 'BE', 'BG', 'BY', 'CA', 'CH', 'CN', 'CY', 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE' 'IN', 'IS', 'IT', 'JP', 'KR', 'LT', 'LU', 'LV', 'MT', 'NL', 'PO', 'PT', 'RO', 'RU', 'SE', 'SL', 'SK', 'TR', 'UA', 'US' ]`. |
963
+ | **isPort()** | check if the string is a valid port number. |
964
+ | **isPostalCode(locale)** | check if the string is a postal code,<br/><br/>(locale is one of `[ 'AD', 'AT', 'AU', 'AZ', 'BE', 'BG', 'BR', 'BY', 'CA', 'CH', 'CZ', 'DE', 'DK', 'DO', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HT', 'HU', 'ID', 'IE' 'IL', 'IN', 'IR', 'IS', 'IT', 'JP', 'KE', 'LI', 'LT', 'LU', 'LV', 'MT', 'MX', 'MY', 'NL', 'NO', 'NP', 'NZ', 'PL', 'PR', 'PT', 'RO', 'RU', 'SA', 'SE', 'SG', 'SI', 'TH', 'TN', 'TW', 'UA', 'US', 'ZA', 'ZM' ]` OR 'any'. If 'any' is used, function will check if any of the locals match. Locale list is `validator.isPostalCodeLocales`.). |
965
+ | **isRFC3339()** | check if the string is a valid [RFC 3339](https://tools.ietf.org/html/rfc3339) date. |
966
+ | **isRgbColor(includePercentValues])** | check if the string is a rgb or rgba color.<br/><br/>`includePercentValues` defaults to `true`. If you don't want to allow to set `rgb` or `rgba` values with percents, like `rgb(5%,5%,5%)`, or `rgba(90%,90%,90%,.3)`, then set it to false. |
967
+ | **isSemVer()** | check if the string is a Semantic Versioning Specification (SemVer). |
968
+ | **isString()** | check if the string is a string. |
969
+ | **isStringList()** | check if the string is a comma separated list of string. |
970
+ | **isSurrogatePair()** | check if the string contains any surrogate pairs chars. |
971
+ | **isUppercase()** | check if the string is uppercase. |
972
+ | **isSlug** | Check if the string is of type slug. `Options` allow a single hyphen between string. e.g. [`cn-cn`, `cn-c-c`] |
973
+ | **isStrongPassword(options])** | Check if a password is strong or not. Allows for custom requirements or scoring rules. If `returnScore` is true, then the function returns an integer score for the password rather than a boolean.<br/>Default options: <br/>`{ minLength: 8, minLowercase: 1, minUppercase: 1, minNumbers: 1, minSymbols: 1, returnScore: false, pointsPerUnique: 1, pointsPerRepeat: 0.5, pointsForContainingLower: 10, pointsForContainingUpper: 10, pointsForContainingNumber: 10, pointsForContainingSymbol: 10 }` |
974
+ | **isTaxID(locale)** | Check if the given value is a valid Tax Identification Number. Default locale is `en-US` |
975
+ | **isURL(options])** | check if the string is an URL.<br/><br/>`options` is an object which defaults to `{ protocols: ['http','https','ftp'], require_tld: true, require_protocol: false, require_host: true, require_valid_protocol: true, allow_underscores: false, host_whitelist: false, host_blacklist: false, allow_trailing_dot: false, allow_protocol_relative_urls: false, disallow_auth: false }`.<br/><br/>require_protocol - if set as true isURL will return false if protocol is not present in the URL.<br/>require_valid_protocol - isURL will check if the URL's protocol is present in the protocols option.<br/>protocols - valid protocols can be modified with this option.<br/>require_host - if set as false isURL will not check if host is present in the URL.<br/>require_port - if set as true isURL will check if port is present in the URL.<br/>allow_protocol_relative_urls - if set as true protocol relative URLs will be allowed.<br/>validate_length - if set as false isURL will skip string length validation (2083 characters is IE max URL length). |
976
+ | **isUUID(version])** | check if the string is a UUID (version 3, 4 or 5). |
977
+ | **isVariableWidth()** | check if the string contains a mixture of full and half-width chars. |
978
+ | **isWhitelisted(chars)** | checks characters if they appear in the whitelist. |
979
+
980
+ #### Wait
981
+
982
+ Wait is used to make the process wait for the given seconds.
983
+
984
+ ```javascript
985
+ import { wait } from 'node-server-engine';
986
+
987
+ // This will make the process wait for 10 mins
988
+ await wait(600);
989
+ ```
990
+
991
+ <!-- markdownlint-enable MD033 -->