kuzzle 2.56.0 → 2.57.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (408) hide show
  1. package/dist/bin/copy-binaries.js +71 -4
  2. package/dist/bin/start-kuzzle-server +191 -97
  3. package/dist/index.d.ts +31 -1
  4. package/dist/index.js +45 -2
  5. package/dist/lib/api/controllers/adminController.d.ts +4 -3
  6. package/dist/lib/api/controllers/adminController.js +1 -2
  7. package/dist/lib/api/controllers/authController.d.ts +37 -16
  8. package/dist/lib/api/controllers/authController.js +88 -39
  9. package/dist/lib/api/controllers/baseController.d.ts +10 -5
  10. package/dist/lib/api/controllers/baseController.js +36 -15
  11. package/dist/lib/api/controllers/bulkController.d.ts +11 -7
  12. package/dist/lib/api/controllers/bulkController.js +28 -5
  13. package/dist/lib/api/controllers/clusterController.d.ts +2 -2
  14. package/dist/lib/api/controllers/clusterController.js +3 -3
  15. package/dist/lib/api/controllers/collectionController.d.ts +57 -21
  16. package/dist/lib/api/controllers/collectionController.js +40 -11
  17. package/dist/lib/api/controllers/debugController.d.ts +1 -1
  18. package/dist/lib/api/controllers/documentController.d.ts +137 -28
  19. package/dist/lib/api/controllers/documentController.js +156 -125
  20. package/dist/lib/api/controllers/index.d.ts +27 -12
  21. package/dist/lib/api/controllers/index.js +28 -13
  22. package/dist/lib/api/controllers/indexController.d.ts +17 -10
  23. package/dist/lib/api/controllers/indexController.js +13 -11
  24. package/dist/lib/api/controllers/memoryStorageController.d.ts +2 -5
  25. package/dist/lib/api/controllers/memoryStorageController.js +199 -127
  26. package/dist/lib/api/controllers/realtimeController.d.ts +19 -9
  27. package/dist/lib/api/controllers/realtimeController.js +8 -4
  28. package/dist/lib/api/controllers/securityController.d.ts +42 -29
  29. package/dist/lib/api/controllers/securityController.js +35 -19
  30. package/dist/lib/api/controllers/serverController.d.ts +114 -19
  31. package/dist/lib/api/controllers/serverController.js +69 -29
  32. package/dist/lib/api/documentExtractor.d.ts +9 -7
  33. package/dist/lib/api/documentExtractor.js +105 -41
  34. package/dist/lib/api/funnel.d.ts +131 -29
  35. package/dist/lib/api/funnel.js +436 -225
  36. package/dist/lib/api/httpRoutes.d.ts +16 -11
  37. package/dist/lib/api/httpRoutes.js +272 -2
  38. package/dist/lib/api/openapi/OpenApiManager.d.ts +1 -1
  39. package/dist/lib/api/openapi/openApiGenerator.d.ts +1 -1
  40. package/dist/lib/api/rateLimiter.d.ts +15 -5
  41. package/dist/lib/api/rateLimiter.js +42 -14
  42. package/dist/lib/api/request/kuzzleRequest.d.ts +83 -12
  43. package/dist/lib/api/request/kuzzleRequest.js +88 -23
  44. package/dist/lib/api/request/requestContext.d.ts +20 -5
  45. package/dist/lib/api/request/requestContext.js +14 -4
  46. package/dist/lib/api/request/requestInput.d.ts +37 -6
  47. package/dist/lib/api/request/requestInput.js +22 -9
  48. package/dist/lib/api/request/requestResponse.d.ts +45 -9
  49. package/dist/lib/api/request/requestResponse.js +34 -3
  50. package/dist/lib/cluster/command.d.ts +131 -37
  51. package/dist/lib/cluster/command.js +243 -71
  52. package/dist/lib/cluster/idCardHandler.d.ts +18 -5
  53. package/dist/lib/cluster/idCardHandler.js +52 -19
  54. package/dist/lib/cluster/index.d.ts +8 -2
  55. package/dist/lib/cluster/index.js +6 -2
  56. package/dist/lib/cluster/node.d.ts +127 -49
  57. package/dist/lib/cluster/node.js +412 -179
  58. package/dist/lib/cluster/protobuf/command.proto +18 -0
  59. package/dist/lib/cluster/protobuf/commandMessages.d.ts +104 -0
  60. package/dist/lib/cluster/protobuf/commandMessages.js +30 -0
  61. package/dist/lib/cluster/protobuf/syncMessages.d.ts +184 -0
  62. package/dist/lib/cluster/protobuf/syncMessages.js +23 -0
  63. package/dist/lib/cluster/publisher.d.ts +118 -78
  64. package/dist/lib/cluster/publisher.js +174 -72
  65. package/dist/lib/cluster/state.d.ts +15 -9
  66. package/dist/lib/cluster/state.js +12 -8
  67. package/dist/lib/cluster/subscriber.d.ts +185 -131
  68. package/dist/lib/cluster/subscriber.js +357 -95
  69. package/dist/lib/cluster/workers/IDCardRenewer.d.ts +39 -8
  70. package/dist/lib/cluster/workers/IDCardRenewer.js +88 -23
  71. package/dist/lib/config/default.config.d.ts +2 -2
  72. package/dist/lib/config/default.config.js +10 -3
  73. package/dist/lib/config/documentEventAliases.d.ts +1 -1
  74. package/dist/lib/config/index.d.ts +2 -5
  75. package/dist/lib/config/index.js +30 -17
  76. package/dist/lib/core/auth/formatProcessing.d.ts +3 -3
  77. package/dist/lib/core/auth/passportResponse.d.ts +1 -1
  78. package/dist/lib/core/auth/passportWrapper.d.ts +1 -1
  79. package/dist/lib/core/auth/passportWrapper.js +14 -13
  80. package/dist/lib/core/auth/tokenManager.d.ts +24 -3
  81. package/dist/lib/core/auth/tokenManager.js +47 -19
  82. package/dist/lib/core/backend/applicationManager.d.ts +2 -2
  83. package/dist/lib/core/backend/backend.d.ts +16 -5
  84. package/dist/lib/core/backend/backend.js +14 -6
  85. package/dist/lib/core/backend/backendCluster.d.ts +1 -1
  86. package/dist/lib/core/backend/backendConfig.d.ts +17 -5
  87. package/dist/lib/core/backend/backendConfig.js +1 -0
  88. package/dist/lib/core/backend/backendController.d.ts +1 -1
  89. package/dist/lib/core/backend/backendController.js +8 -1
  90. package/dist/lib/core/backend/backendErrors.d.ts +15 -8
  91. package/dist/lib/core/backend/backendErrors.js +5 -0
  92. package/dist/lib/core/backend/backendHook.d.ts +1 -1
  93. package/dist/lib/core/backend/backendImport.d.ts +1 -1
  94. package/dist/lib/core/backend/backendOpenApi.d.ts +3 -2
  95. package/dist/lib/core/backend/backendPipe.d.ts +1 -1
  96. package/dist/lib/core/backend/backendPipe.js +9 -1
  97. package/dist/lib/core/backend/backendPlugin.d.ts +2 -2
  98. package/dist/lib/core/backend/backendSubscription.d.ts +2 -2
  99. package/dist/lib/core/backend/backendVault.d.ts +1 -1
  100. package/dist/lib/core/backend/backendVault.js +8 -1
  101. package/dist/lib/core/cache/cacheEngine.d.ts +7 -4
  102. package/dist/lib/core/cache/cacheEngine.js +25 -8
  103. package/dist/lib/core/debug/kuzzleDebugger.d.ts +2 -1
  104. package/dist/lib/core/debug/kuzzleDebugger.js +31 -17
  105. package/dist/lib/core/network/accessLogger.d.ts +33 -18
  106. package/dist/lib/core/network/accessLogger.js +135 -73
  107. package/dist/lib/core/network/clientConnection.d.ts +13 -11
  108. package/dist/lib/core/network/clientConnection.js +33 -9
  109. package/dist/lib/core/network/context.d.ts +17 -22
  110. package/dist/lib/core/network/context.js +43 -26
  111. package/dist/lib/core/network/entryPoint.d.ts +38 -16
  112. package/dist/lib/core/network/entryPoint.js +119 -48
  113. package/dist/lib/core/network/httpRouter/index.d.ts +20 -50
  114. package/dist/lib/core/network/httpRouter/index.js +61 -75
  115. package/dist/lib/core/network/httpRouter/routeHandler.d.ts +17 -32
  116. package/dist/lib/core/network/httpRouter/routeHandler.js +26 -36
  117. package/dist/lib/core/network/httpRouter/routePart.d.ts +9 -18
  118. package/dist/lib/core/network/httpRouter/routePart.js +61 -43
  119. package/dist/lib/core/network/httpRouter/routeTypes.d.ts +3 -0
  120. package/dist/lib/core/network/httpRouter/routeTypes.js +23 -0
  121. package/dist/lib/core/network/networkEntryPoint.d.ts +20 -0
  122. package/dist/lib/core/network/networkEntryPoint.js +23 -0
  123. package/dist/lib/core/network/protocolManifest.d.ts +5 -4
  124. package/dist/lib/core/network/protocolManifest.js +6 -3
  125. package/dist/lib/core/network/protocols/httpMessage.d.ts +25 -18
  126. package/dist/lib/core/network/protocols/httpMessage.js +14 -11
  127. package/dist/lib/core/network/protocols/httpwsProtocol.d.ts +84 -93
  128. package/dist/lib/core/network/protocols/httpwsProtocol.js +284 -129
  129. package/dist/lib/core/network/protocols/internalProtocol.d.ts +26 -15
  130. package/dist/lib/core/network/protocols/internalProtocol.js +17 -16
  131. package/dist/lib/core/network/protocols/mqttProtocol.d.ts +56 -32
  132. package/dist/lib/core/network/protocols/mqttProtocol.js +91 -44
  133. package/dist/lib/core/network/protocols/protocol.d.ts +85 -21
  134. package/dist/lib/core/network/protocols/protocol.js +83 -27
  135. package/dist/lib/core/network/router.d.ts +13 -22
  136. package/dist/lib/core/network/router.js +59 -46
  137. package/dist/lib/core/plugin/plugin.d.ts +57 -51
  138. package/dist/lib/core/plugin/plugin.js +218 -103
  139. package/dist/lib/core/plugin/pluginContext.d.ts +54 -11
  140. package/dist/lib/core/plugin/pluginContext.js +99 -58
  141. package/dist/lib/core/plugin/pluginManifest.d.ts +6 -2
  142. package/dist/lib/core/plugin/pluginManifest.js +18 -11
  143. package/dist/lib/core/plugin/pluginRepository.d.ts +35 -44
  144. package/dist/lib/core/plugin/pluginRepository.js +35 -50
  145. package/dist/lib/core/plugin/pluginsManager.d.ts +128 -46
  146. package/dist/lib/core/plugin/pluginsManager.js +468 -231
  147. package/dist/lib/core/plugin/privilegedContext.d.ts +4 -9
  148. package/dist/lib/core/plugin/privilegedContext.js +5 -10
  149. package/dist/lib/core/realtime/actionEnum.d.ts +12 -21
  150. package/dist/lib/core/realtime/actionEnum.js +6 -7
  151. package/dist/lib/core/realtime/channel.d.ts +11 -5
  152. package/dist/lib/core/realtime/channel.js +17 -2
  153. package/dist/lib/core/realtime/connectionRooms.d.ts +2 -2
  154. package/dist/lib/core/realtime/hotelClerk.d.ts +12 -6
  155. package/dist/lib/core/realtime/hotelClerk.js +29 -11
  156. package/dist/lib/core/realtime/index.d.ts +8 -3
  157. package/dist/lib/core/realtime/index.js +12 -5
  158. package/dist/lib/core/realtime/notification/document.d.ts +54 -25
  159. package/dist/lib/core/realtime/notification/document.js +10 -13
  160. package/dist/lib/core/realtime/notification/index.d.ts +9 -3
  161. package/dist/lib/core/realtime/notification/index.js +10 -4
  162. package/dist/lib/core/realtime/notification/server.d.ts +7 -10
  163. package/dist/lib/core/realtime/notification/server.js +4 -7
  164. package/dist/lib/core/realtime/notification/user.d.ts +45 -21
  165. package/dist/lib/core/realtime/notification/user.js +8 -9
  166. package/dist/lib/core/realtime/notifier.d.ts +52 -40
  167. package/dist/lib/core/realtime/notifier.js +60 -25
  168. package/dist/lib/core/realtime/room.d.ts +1 -1
  169. package/dist/lib/core/realtime/subscription.d.ts +11 -6
  170. package/dist/lib/core/realtime/subscription.js +5 -1
  171. package/dist/lib/core/security/index.d.ts +14 -6
  172. package/dist/lib/core/security/index.js +27 -13
  173. package/dist/lib/core/security/profileRepository.d.ts +24 -19
  174. package/dist/lib/core/security/profileRepository.js +23 -10
  175. package/dist/lib/core/security/roleRepository.d.ts +60 -23
  176. package/dist/lib/core/security/roleRepository.js +122 -53
  177. package/dist/lib/core/security/securityLoader.d.ts +33 -18
  178. package/dist/lib/core/security/securityLoader.js +43 -16
  179. package/dist/lib/core/security/tokenRepository.d.ts +21 -7
  180. package/dist/lib/core/security/tokenRepository.js +50 -23
  181. package/dist/lib/core/security/userRepository.d.ts +44 -21
  182. package/dist/lib/core/security/userRepository.js +59 -19
  183. package/dist/lib/core/shared/KoncordeWrapper.d.ts +1 -1
  184. package/dist/lib/core/shared/ObjectRepository.d.ts +80 -18
  185. package/dist/lib/core/shared/ObjectRepository.js +57 -29
  186. package/dist/lib/core/shared/abstractManifest.d.ts +21 -8
  187. package/dist/lib/core/shared/abstractManifest.js +57 -17
  188. package/dist/lib/core/shared/sdk/embeddedSdk.d.ts +3 -1
  189. package/dist/lib/core/shared/sdk/embeddedSdk.js +8 -7
  190. package/dist/lib/core/shared/sdk/funnelProtocol.d.ts +2 -1
  191. package/dist/lib/core/shared/sdk/funnelProtocol.js +12 -3
  192. package/dist/lib/core/shared/sdk/impersonatedSdk.d.ts +11 -5
  193. package/dist/lib/core/shared/sdk/impersonatedSdk.js +22 -9
  194. package/dist/lib/core/shared/store.d.ts +45 -29
  195. package/dist/lib/core/shared/store.js +48 -27
  196. package/dist/lib/core/statistics/statistics.d.ts +1 -1
  197. package/dist/lib/core/storage/clientAdapter.d.ts +39 -21
  198. package/dist/lib/core/storage/clientAdapter.js +88 -48
  199. package/dist/lib/core/storage/indexCache.d.ts +8 -0
  200. package/dist/lib/core/storage/indexCache.js +16 -7
  201. package/dist/lib/core/storage/storageEngine.d.ts +7 -6
  202. package/dist/lib/core/storage/storageEngine.js +11 -8
  203. package/dist/lib/core/validation/baseType.d.ts +22 -22
  204. package/dist/lib/core/validation/baseType.js +11 -26
  205. package/dist/lib/core/validation/specification.d.ts +148 -0
  206. package/dist/lib/core/validation/specification.js +34 -0
  207. package/dist/lib/core/validation/typeOptions.d.ts +62 -0
  208. package/dist/lib/core/validation/typeOptions.js +23 -0
  209. package/dist/lib/core/validation/types/anything.d.ts +3 -6
  210. package/dist/lib/core/validation/types/anything.js +7 -7
  211. package/dist/lib/core/validation/types/boolean.d.ts +5 -12
  212. package/dist/lib/core/validation/types/boolean.js +7 -12
  213. package/dist/lib/core/validation/types/date.d.ts +19 -11
  214. package/dist/lib/core/validation/types/date.js +212 -161
  215. package/dist/lib/core/validation/types/email.d.ts +7 -11
  216. package/dist/lib/core/validation/types/email.js +13 -17
  217. package/dist/lib/core/validation/types/enum.d.ts +7 -11
  218. package/dist/lib/core/validation/types/enum.js +39 -20
  219. package/dist/lib/core/validation/types/geoPoint.d.ts +5 -13
  220. package/dist/lib/core/validation/types/geoPoint.js +10 -15
  221. package/dist/lib/core/validation/types/geoShape.d.ts +22 -21
  222. package/dist/lib/core/validation/types/geoShape.js +113 -129
  223. package/dist/lib/core/validation/types/geoShapeUtils.d.ts +15 -0
  224. package/dist/lib/core/validation/types/geoShapeUtils.js +75 -0
  225. package/dist/lib/core/validation/types/integer.d.ts +7 -5
  226. package/dist/lib/core/validation/types/integer.js +7 -13
  227. package/dist/lib/core/validation/types/ipAddress.d.ts +7 -11
  228. package/dist/lib/core/validation/types/ipAddress.js +13 -17
  229. package/dist/lib/core/validation/types/numeric.d.ts +7 -11
  230. package/dist/lib/core/validation/types/numeric.js +22 -29
  231. package/dist/lib/core/validation/types/object.d.ts +8 -15
  232. package/dist/lib/core/validation/types/object.js +12 -21
  233. package/dist/lib/core/validation/types/string.d.ts +7 -11
  234. package/dist/lib/core/validation/types/string.js +22 -29
  235. package/dist/lib/core/validation/types/url.d.ts +7 -11
  236. package/dist/lib/core/validation/types/url.js +14 -18
  237. package/dist/lib/core/validation/validation.d.ts +119 -80
  238. package/dist/lib/core/validation/validation.js +470 -412
  239. package/dist/lib/core/validation/validationUtils.d.ts +31 -0
  240. package/dist/lib/core/validation/validationUtils.js +190 -0
  241. package/dist/lib/kerror/codes/4-plugin.json +0 -12
  242. package/dist/lib/kerror/codes/index.d.ts +12 -2
  243. package/dist/lib/kerror/codes/index.js +5 -4
  244. package/dist/lib/kerror/errors/badRequestError.d.ts +1 -1
  245. package/dist/lib/kerror/errors/badRequestError.js +1 -1
  246. package/dist/lib/kerror/errors/externalServiceError.d.ts +1 -1
  247. package/dist/lib/kerror/errors/externalServiceError.js +1 -1
  248. package/dist/lib/kerror/errors/forbiddenError.d.ts +1 -1
  249. package/dist/lib/kerror/errors/forbiddenError.js +1 -1
  250. package/dist/lib/kerror/errors/gatewayTimeoutError.d.ts +1 -1
  251. package/dist/lib/kerror/errors/gatewayTimeoutError.js +1 -1
  252. package/dist/lib/kerror/errors/internalError.d.ts +1 -1
  253. package/dist/lib/kerror/errors/internalError.js +1 -1
  254. package/dist/lib/kerror/errors/kuzzleError.d.ts +32 -3
  255. package/dist/lib/kerror/errors/kuzzleError.js +21 -7
  256. package/dist/lib/kerror/errors/multipleErrorsError.d.ts +2 -2
  257. package/dist/lib/kerror/errors/multipleErrorsError.js +2 -2
  258. package/dist/lib/kerror/errors/notFoundError.d.ts +1 -1
  259. package/dist/lib/kerror/errors/notFoundError.js +1 -1
  260. package/dist/lib/kerror/errors/partialError.d.ts +8 -2
  261. package/dist/lib/kerror/errors/partialError.js +22 -9
  262. package/dist/lib/kerror/errors/pluginImplementationError.d.ts +9 -1
  263. package/dist/lib/kerror/errors/pluginImplementationError.js +9 -3
  264. package/dist/lib/kerror/errors/preconditionError.d.ts +1 -1
  265. package/dist/lib/kerror/errors/preconditionError.js +1 -1
  266. package/dist/lib/kerror/errors/serviceUnavailableError.d.ts +1 -1
  267. package/dist/lib/kerror/errors/serviceUnavailableError.js +1 -1
  268. package/dist/lib/kerror/errors/sizeLimitError.d.ts +1 -1
  269. package/dist/lib/kerror/errors/sizeLimitError.js +1 -1
  270. package/dist/lib/kerror/errors/tooManyRequestsError.d.ts +1 -1
  271. package/dist/lib/kerror/errors/tooManyRequestsError.js +1 -1
  272. package/dist/lib/kerror/errors/unauthorizedError.d.ts +1 -1
  273. package/dist/lib/kerror/errors/unauthorizedError.js +1 -1
  274. package/dist/lib/kerror/index.d.ts +19 -13
  275. package/dist/lib/kerror/index.js +60 -19
  276. package/dist/lib/kuzzle/Logger.d.ts +2 -2
  277. package/dist/lib/kuzzle/dumpGenerator.d.ts +12 -8
  278. package/dist/lib/kuzzle/dumpGenerator.js +130 -62
  279. package/dist/lib/kuzzle/event/KuzzleEventEmitter.d.ts +18 -9
  280. package/dist/lib/kuzzle/event/KuzzleEventEmitter.js +45 -18
  281. package/dist/lib/kuzzle/event/pipeRunner.d.ts +37 -16
  282. package/dist/lib/kuzzle/event/pipeRunner.js +73 -26
  283. package/dist/lib/kuzzle/event/waterfall.d.ts +11 -1
  284. package/dist/lib/kuzzle/event/waterfall.js +38 -13
  285. package/dist/lib/kuzzle/internalIndexHandler.d.ts +11 -174
  286. package/dist/lib/kuzzle/internalIndexHandler.js +58 -29
  287. package/dist/lib/kuzzle/kuzzle.d.ts +25 -10
  288. package/dist/lib/kuzzle/kuzzle.js +74 -17
  289. package/dist/lib/kuzzle/kuzzleStateEnum.d.ts +16 -12
  290. package/dist/lib/kuzzle/kuzzleStateEnum.js +5 -7
  291. package/dist/lib/kuzzle/vault.d.ts +5 -1
  292. package/dist/lib/kuzzle/vault.js +29 -17
  293. package/dist/lib/model/security/profile.d.ts +34 -5
  294. package/dist/lib/model/security/profile.js +6 -5
  295. package/dist/lib/model/security/rights.d.ts +12 -4
  296. package/dist/lib/model/security/rights.js +7 -6
  297. package/dist/lib/model/security/role.d.ts +8 -4
  298. package/dist/lib/model/security/role.js +12 -6
  299. package/dist/lib/model/security/token.d.ts +8 -0
  300. package/dist/lib/model/security/user.d.ts +8 -2
  301. package/dist/lib/model/security/user.js +7 -4
  302. package/dist/lib/model/storage/apiKey.d.ts +55 -26
  303. package/dist/lib/model/storage/apiKey.js +97 -24
  304. package/dist/lib/model/storage/baseModel.d.ts +77 -66
  305. package/dist/lib/model/storage/baseModel.js +21 -34
  306. package/dist/lib/service/cache/redis.d.ts +53 -36
  307. package/dist/lib/service/cache/redis.js +148 -71
  308. package/dist/lib/service/service.d.ts +14 -19
  309. package/dist/lib/service/service.js +41 -22
  310. package/dist/lib/service/storage/7/elasticsearch.d.ts +136 -93
  311. package/dist/lib/service/storage/7/elasticsearch.js +218 -165
  312. package/dist/lib/service/storage/7/esWrapper.d.ts +30 -13
  313. package/dist/lib/service/storage/7/esWrapper.js +58 -37
  314. package/dist/lib/service/storage/8/elasticsearch.d.ts +153 -119
  315. package/dist/lib/service/storage/8/elasticsearch.js +286 -213
  316. package/dist/lib/service/storage/8/esWrapper.d.ts +30 -13
  317. package/dist/lib/service/storage/8/esWrapper.js +59 -38
  318. package/dist/lib/service/storage/commons/queryTranslator.d.ts +3 -3
  319. package/dist/lib/service/storage/commons/queryTranslator.js +71 -35
  320. package/dist/lib/types/ApiRoute.d.ts +12 -0
  321. package/dist/lib/types/ApiRoute.js +23 -0
  322. package/dist/lib/types/ClientConnection.d.ts +1 -1
  323. package/dist/lib/types/EventHandler.d.ts +10 -0
  324. package/dist/lib/types/Global.d.ts +8 -3
  325. package/dist/lib/types/HttpMessage.d.ts +2 -2
  326. package/dist/lib/types/HttpStream.d.ts +1 -1
  327. package/dist/lib/types/HttpStream.js +3 -1
  328. package/dist/lib/types/JSONObject.d.ts +9 -0
  329. package/dist/lib/types/JSONObject.js +23 -0
  330. package/dist/lib/types/Kuzzle.d.ts +5 -3
  331. package/dist/lib/types/KuzzleDocument.d.ts +1 -1
  332. package/dist/lib/types/KuzzleWebSocket.d.ts +24 -0
  333. package/dist/lib/types/KuzzleWebSocket.js +23 -0
  334. package/dist/lib/types/OpenApiDefinition.d.ts +1 -1
  335. package/dist/lib/types/Plugin.d.ts +33 -8
  336. package/dist/lib/types/PluginInstance.d.ts +67 -0
  337. package/dist/lib/types/PluginInstance.js +23 -0
  338. package/dist/lib/types/Policy.d.ts +1 -1
  339. package/dist/lib/types/Target.d.ts +8 -0
  340. package/dist/lib/types/Token.d.ts +14 -2
  341. package/dist/lib/types/config/HttpConfiguration.d.ts +5 -0
  342. package/dist/lib/types/config/KuzzleConfiguration.d.ts +102 -1
  343. package/dist/lib/types/config/PluginsConfiguration.d.ts +3 -2
  344. package/dist/lib/types/config/SecurityConfiguration.d.ts +6 -2
  345. package/dist/lib/types/config/ServerConfiguration.d.ts +2 -2
  346. package/dist/lib/types/config/ServicesConfiguration.d.ts +1 -1
  347. package/dist/lib/types/config/cache/BaseCacheRedisConfiguration.d.ts +131 -0
  348. package/dist/lib/types/config/cache/BaseCacheRedisConfiguration.js +3 -0
  349. package/dist/lib/types/config/internalCache/InternalCacheRedisConfiguration.d.ts +2 -106
  350. package/dist/lib/types/config/publicCache/PublicCacheRedisConfiguration.d.ts +2 -26
  351. package/dist/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.d.ts +3 -0
  352. package/dist/lib/types/controllers/Controller.d.ts +12 -3
  353. package/dist/lib/types/controllers/ControllerDefinition.d.ts +2 -2
  354. package/dist/lib/types/controllers/{adminControlller.type.js → adminController.type.js} +1 -1
  355. package/dist/lib/types/controllers/authController.type.d.ts +2 -2
  356. package/dist/lib/types/core/auth/formatProcessing.type.d.ts +7 -1
  357. package/dist/lib/types/errors/ErrorDomains.d.ts +1 -1
  358. package/dist/lib/types/events/EventGenericDocument.d.ts +10 -9
  359. package/dist/lib/types/events/EventProtocol.d.ts +4 -4
  360. package/dist/lib/types/index.d.ts +7 -0
  361. package/dist/lib/types/index.js +7 -0
  362. package/dist/lib/types/shared/StoreCollectionsDefinition.d.ts +1 -1
  363. package/dist/lib/types/storage/7/Elasticsearch.d.ts +62 -13
  364. package/dist/lib/types/storage/8/Elasticsearch.d.ts +62 -13
  365. package/dist/lib/util/Inflector.d.ts +4 -1
  366. package/dist/lib/util/Inflector.js +0 -3
  367. package/dist/lib/util/assertType.d.ts +24 -27
  368. package/dist/lib/util/assertType.js +28 -39
  369. package/dist/lib/util/async.js +19 -6
  370. package/dist/lib/util/asyncStore.js +1 -1
  371. package/dist/lib/util/bufferedPassThrough.d.ts +9 -0
  372. package/dist/lib/util/bufferedPassThrough.js +27 -13
  373. package/dist/lib/util/bytes.d.ts +1 -1
  374. package/dist/lib/util/bytes.js +6 -2
  375. package/dist/lib/util/debug.d.ts +3 -1
  376. package/dist/lib/util/debug.js +42 -10
  377. package/dist/lib/util/deprecate.d.ts +9 -1
  378. package/dist/lib/util/deprecate.js +10 -6
  379. package/dist/lib/util/didYouMean.d.ts +2 -1
  380. package/dist/lib/util/didYouMean.js +8 -4
  381. package/dist/lib/util/distributedLock.d.ts +56 -0
  382. package/dist/lib/util/distributedLock.js +166 -0
  383. package/dist/lib/util/dump-collection.d.ts +1 -1
  384. package/dist/lib/util/dump-collection.js +4 -5
  385. package/dist/lib/util/extractFields.d.ts +15 -11
  386. package/dist/lib/util/extractFields.js +8 -9
  387. package/dist/lib/util/koncordeCompat.d.ts +2 -2
  388. package/dist/lib/util/koncordeCompat.js +33 -0
  389. package/dist/lib/util/memoize.d.ts +7 -6
  390. package/dist/lib/util/memoize.js +3 -3
  391. package/dist/lib/util/mutex.d.ts +22 -2
  392. package/dist/lib/util/mutex.js +39 -1
  393. package/dist/lib/util/name-generator.js +14 -2
  394. package/dist/lib/util/promback.d.ts +20 -11
  395. package/dist/lib/util/promback.js +14 -7
  396. package/dist/lib/util/requestAssertions.d.ts +30 -10
  397. package/dist/lib/util/requestAssertions.js +125 -121
  398. package/dist/lib/util/safeObject.d.ts +3 -3
  399. package/dist/lib/util/safeObject.js +7 -3
  400. package/dist/lib/util/stackTrace.d.ts +13 -5
  401. package/dist/lib/util/stackTrace.js +17 -12
  402. package/dist/lib/util/thrown.d.ts +13 -0
  403. package/dist/lib/util/thrown.js +46 -0
  404. package/dist/package.json +26 -19
  405. package/package.json +26 -19
  406. package/dist/lib/util/wildcard.d.ts +0 -1
  407. package/dist/lib/util/wildcard.js +0 -46
  408. /package/dist/lib/types/controllers/{adminControlller.type.d.ts → adminController.type.d.ts} +0 -0
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /*
2
3
  * Kuzzle, a backend software, self-hostable and ready to use
3
4
  * to power modern apps
@@ -18,15 +19,72 @@
18
19
  * See the License for the specific language governing permissions and
19
20
  * limitations under the License.
20
21
  */
21
- "use strict";
22
- const { Subscriber } = require("zeromq");
23
- const protobuf = require("protobufjs");
24
- const Long = require("long");
25
- const debug = require("../util/debug")("kuzzle:cluster:sync");
26
- const DocumentNotification = require("../core/realtime/notification/document");
27
- const UserNotification = require("../core/realtime/notification/user");
28
- const { has } = require("../util/safeObject");
29
- const { fromKoncordeIndex } = require("../util/koncordeCompat");
22
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ var desc = Object.getOwnPropertyDescriptor(m, k);
25
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
26
+ desc = { enumerable: true, get: function() { return m[k]; } };
27
+ }
28
+ Object.defineProperty(o, k2, desc);
29
+ }) : (function(o, m, k, k2) {
30
+ if (k2 === undefined) k2 = k;
31
+ o[k2] = m[k];
32
+ }));
33
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
34
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
35
+ }) : function(o, v) {
36
+ o["default"] = v;
37
+ });
38
+ var __importStar = (this && this.__importStar) || function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ var __importDefault = (this && this.__importDefault) || function (mod) {
46
+ return (mod && mod.__esModule) ? mod : { "default": mod };
47
+ };
48
+ const node_util_1 = require("node:util");
49
+ const long_1 = __importDefault(require("long"));
50
+ const protobuf = __importStar(require("protobufjs"));
51
+ const zeromq_1 = require("zeromq");
52
+ const document_1 = __importDefault(require("../core/realtime/notification/document"));
53
+ const user_1 = __importDefault(require("../core/realtime/notification/user"));
54
+ const debug_1 = __importDefault(require("../util/debug"));
55
+ const koncordeCompat_1 = require("../util/koncordeCompat");
56
+ const debug = (0, debug_1.default)("kuzzle:cluster:sync");
57
+ /**
58
+ * `sync.proto` types `scope` and `user` as plain strings, while the
59
+ * notifications built from them take closed unions — and nothing between the
60
+ * wire and the notification checked that the string was a member. See TD-68
61
+ * (#2779); keep these lists in step with the unions they `satisfies`.
62
+ */
63
+ const REALTIME_SCOPES = [
64
+ "all",
65
+ "in",
66
+ "out",
67
+ ];
68
+ const REALTIME_USERS = [
69
+ "all",
70
+ "in",
71
+ "none",
72
+ "out",
73
+ ];
74
+ /**
75
+ * A topic is a protobuf type name, and the handler table below covers exactly
76
+ * `sync.proto`'s message list — but `lookup()` also resolves nested types, so a
77
+ * decodable topic is not automatically one this node knows how to apply.
78
+ */
79
+ function isSyncTopic(handlers, topic) {
80
+ return Object.hasOwn(handlers, topic);
81
+ }
82
+ function isRealtimeScope(value) {
83
+ return REALTIME_SCOPES.includes(value);
84
+ }
85
+ function isRealtimeUsers(value) {
86
+ return REALTIME_USERS.includes(value);
87
+ }
30
88
  /* eslint-disable sort-keys */
31
89
  const stateEnum = Object.freeze({
32
90
  BUFFERING: 1,
@@ -34,14 +92,12 @@ const stateEnum = Object.freeze({
34
92
  MISSING_HEARTBEAT: 3,
35
93
  EVICTED: 4,
36
94
  });
37
- /* eslint-enable sort-keys */
38
95
  // Handles messages received from other nodes
39
96
  class ClusterSubscriber {
40
97
  /**
41
- * @constructor
42
- * @param {ClusterNode} localNode
43
- * @param {string} remoteNodeId - Remote node unique ID
44
- * @param {string} remoteNodeIP - address of the distant node
98
+ * @param localNode the cluster node this subscriber belongs to
99
+ * @param remoteNodeId - Remote node unique ID
100
+ * @param remoteNodeIP - address of the distant node
45
101
  */
46
102
  constructor(localNode, remoteNodeId, remoteNodeIP) {
47
103
  // not to be confused with remote nodes
@@ -54,12 +110,25 @@ class ClusterSubscriber {
54
110
  this.socket = null;
55
111
  this.protoroot = null;
56
112
  // keeps track of received message ids from the remote node
57
- this.lastMessageId = new Long(0, 0, true);
113
+ this.lastMessageId = new long_1.default(0, 0, true);
114
+ // Receiving anything at all from the remote node is the only observable
115
+ // proof that this subscription has taken effect on its PUB socket: ZeroMQ
116
+ // propagates a subscription as a message sent TO the publisher, which does
117
+ // the filtering, and until it lands the publisher silently drops what it
118
+ // sends. See waitForSubscription() and TD-65 (#2773).
119
+ this.subscriptionConfirmed = false;
120
+ // The executor runs synchronously, so the no-op is replaced before anything
121
+ // can call it — it is there to state that this field is never unassigned.
122
+ this.confirmSubscription = () => { };
123
+ this.subscriptionProof = new Promise((resolve) => {
124
+ this.confirmSubscription = resolve;
125
+ });
58
126
  // A subscriber starts in the BUFFERING state, meaning it stores incoming
59
127
  // sync messages without processing them, until it enters the SANE state
60
128
  // This delays applying sync messages while the local node initializes
61
129
  this.state = stateEnum.BUFFERING;
62
130
  this.buffer = [];
131
+ this.recovering = false;
63
132
  // keeps track of the remote node heartbeats, and evicts it if no
64
133
  // heartbeats have been received after some time
65
134
  this.heartbeatTimer = null;
@@ -101,7 +170,7 @@ class ClusterSubscriber {
101
170
  */
102
171
  async init() {
103
172
  this.protoroot = await protobuf.load(`${__dirname}/protobuf/sync.proto`);
104
- this.socket = new Subscriber();
173
+ this.socket = new zeromq_1.Subscriber();
105
174
  this.socket.connect(this.remoteNodeAddress);
106
175
  this.socket.subscribe();
107
176
  this.heartbeatTimer = setInterval(() => this.checkHeartbeat(), this.heartbeatDelay);
@@ -114,20 +183,20 @@ class ClusterSubscriber {
114
183
  */
115
184
  async listen() {
116
185
  while (this.state !== stateEnum.EVICTED) {
117
- let topic;
118
- let data;
119
- try {
120
- [topic, data] = await this.socket.receive();
121
- }
122
- catch (e) {
123
- if (this.state !== stateEnum.EVICTED) {
124
- await this.evictNode({
125
- broadcast: true,
126
- reason: e.message,
127
- });
128
- }
186
+ const frame = await this.receiveFrame();
187
+ if (frame === null) {
129
188
  return;
130
189
  }
190
+ const [topic, data] = frame;
191
+ // A sync message is a topic and a payload. One that is neither is not
192
+ // something to dispatch on, and both frames were read unchecked.
193
+ if (topic === undefined || data === undefined) {
194
+ continue;
195
+ }
196
+ if (!this.subscriptionConfirmed) {
197
+ this.subscriptionConfirmed = true;
198
+ this.confirmSubscription();
199
+ }
131
200
  // do nothing is the node was evicted even if we already check
132
201
  // for this in processData()
133
202
  if (this.state === stateEnum.EVICTED) {
@@ -141,12 +210,71 @@ class ClusterSubscriber {
141
210
  }
142
211
  }
143
212
  }
213
+ /**
214
+ * One frame off the sync socket.
215
+ *
216
+ * @returns `null` when there is nothing more to read — the socket is gone,
217
+ * or the read failed and this node has been evicted for it, which
218
+ * is what ends `listen()`'s loop.
219
+ */
220
+ async receiveFrame() {
221
+ try {
222
+ // `dispose()` drops the socket, and the loop's own condition is checked
223
+ // before the state it sets is visible here.
224
+ if (this.socket === null) {
225
+ return null;
226
+ }
227
+ return await this.socket.receive();
228
+ }
229
+ catch (e) {
230
+ if (this.state !== stateEnum.EVICTED) {
231
+ await this.evictNode({
232
+ broadcast: true,
233
+ reason: e instanceof Error ? e.message : (0, node_util_1.inspect)(e),
234
+ });
235
+ }
236
+ return null;
237
+ }
238
+ }
239
+ /**
240
+ * Resolves once a message has been received from the remote node, which is
241
+ * the only observable proof that this subscription is live on its side.
242
+ *
243
+ * The handshake reads a remote node's `lastMessageId` over the *command*
244
+ * channel and then resumes this subscription from it. Nothing orders that
245
+ * snapshot after the subscription taking effect on the *sync* channel — they
246
+ * are different sockets — so without this wait, anything the remote publishes
247
+ * in between is dropped by its PUB socket while this node is told to resume
248
+ * from just before it. That gap is read as a desync. See TD-65 (#2773).
249
+ *
250
+ * Every node publishes a heartbeat every `cluster.heartbeat` ms (2s by
251
+ * default) from before it is discoverable, so this normally costs less than
252
+ * one round.
253
+ *
254
+ * @param timeout - ms to wait before giving up
255
+ * @return whether the subscription was proven live
256
+ */
257
+ async waitForSubscription(timeout) {
258
+ if (this.subscriptionConfirmed) {
259
+ return true;
260
+ }
261
+ let timer;
262
+ const expired = new Promise((resolve) => {
263
+ timer = setTimeout(() => resolve(false), timeout);
264
+ });
265
+ const confirmed = await Promise.race([
266
+ this.subscriptionProof.then(() => true),
267
+ expired,
268
+ ]);
269
+ clearTimeout(timer);
270
+ return confirmed;
271
+ }
144
272
  /**
145
273
  * Plays all buffered sync messages, and switches this subscriber state from
146
274
  * BUFFERING to SANE.
147
275
  *
148
- * @param {Long} lastMessageId
149
- * @return {void}
276
+ * @param lastMessageId
277
+ * @return false if a gap was found while replaying, which evicts this node
150
278
  */
151
279
  async sync(lastMessageId) {
152
280
  this.lastMessageId = lastMessageId;
@@ -155,11 +283,18 @@ class ClusterSubscriber {
155
283
  while (this.buffer.length > 0) {
156
284
  const _buffer = this.buffer;
157
285
  this.buffer = [];
158
- for (let i = 0; i < _buffer.length; i++) {
159
- await this.processData(_buffer[i][0], _buffer[i][1]);
286
+ for (const [topic, data] of _buffer) {
287
+ await this.processData(topic, data);
288
+ // A gap found during the replay evicts this node. Without this check
289
+ // the loop would go on applying messages and then overwrite EVICTED
290
+ // with SANE on the way out.
291
+ if (this.state === stateEnum.EVICTED) {
292
+ return false;
293
+ }
160
294
  }
161
295
  }
162
296
  this.state = stateEnum.SANE;
297
+ return true;
163
298
  }
164
299
  /**
165
300
  * Decodes an incoming message, and dispatches it.
@@ -170,16 +305,23 @@ class ClusterSubscriber {
170
305
  * and it also cannot afford to attach a rejection handler everytime a message
171
306
  * is received to prevent clogging the event loop with unnecessary promises
172
307
  *
173
- * @param {string} topic
174
- * @param {Buffer} data
175
- * @return {void}
308
+ * @param topic
309
+ * @param data
176
310
  */
177
311
  async processData(topic, data) {
178
312
  if (this.state === stateEnum.EVICTED) {
179
313
  return;
180
314
  }
181
- const decoder = this.protoroot.lookup(topic);
182
- if (decoder === null) {
315
+ const decoder = this.protoroot?.lookup(topic) ?? null;
316
+ // `lookup` resolves any reflection object, not only message types, so a
317
+ // topic naming — say — a nested namespace used to reach `decoder.decode`
318
+ // with that method undefined: a TypeError thrown out of a method documented
319
+ // as never throwing, into `listen()`'s un-awaitable loop. The compiler asked
320
+ // for the narrowing; treating it as the unknown-topic case below is what the
321
+ // `null` branch already meant.
322
+ if (decoder === null ||
323
+ !(decoder instanceof protobuf.Type) ||
324
+ !isSyncTopic(this.handlers, topic)) {
183
325
  await this.evictNode({
184
326
  broadcast: true,
185
327
  reason: `received an invalid message from ${this.remoteNodeId} (unknown topic "${topic}")`,
@@ -194,19 +336,33 @@ class ClusterSubscriber {
194
336
  // If we are receiving messages from a node,
195
337
  // it means the node is alive so it should counts as an heartbeat
196
338
  this.handleHeartbeat();
197
- await this.handlers[topic].call(this, message);
339
+ // `Reflect.apply`, not `handlers[topic].call`: the handler table is a
340
+ // union of per-topic signatures, and `call` asks each of them to accept
341
+ // `this` plus every other member's message. `isSyncTopic` above is what
342
+ // pairs the topic with its message.
343
+ await Reflect.apply(this.handlers[topic], this, [message]);
198
344
  }
199
345
  catch (e) {
200
- this.localNode.evictSelf(`Unable to process sync message (topic: ${topic}, message: ${JSON.stringify(message)}`, e);
346
+ this.localNode.evictSelf(`Unable to process sync message (topic: ${topic}, message: ${JSON.stringify(message)}`, e instanceof Error ? e : new Error((0, node_util_1.inspect)(e)));
201
347
  }
202
348
  }
349
+ /**
350
+ * Set from two places: a `NodePreventEviction` message published by this
351
+ * peer, and `node.preventEviction()` on this node. The local caller used to
352
+ * reach the wire handler below with a hand-built `{ evictionPrevented }` —
353
+ * an object shaped like a sync message that never came off the wire and
354
+ * carries no `messageId`. The conversion could not type that, and it should
355
+ * not have to: the two callers want the same effect, not the same envelope.
356
+ */
357
+ setEvictionPrevented(evictionPrevented) {
358
+ this.remoteNodeEvictionPrevented = evictionPrevented;
359
+ }
203
360
  async handleNodePreventEviction(message) {
204
- this.remoteNodeEvictionPrevented = message.evictionPrevented;
361
+ this.setEvictionPrevented(message.evictionPrevented);
205
362
  }
206
363
  /**
207
364
  * Handles a heartbeat from the remote node
208
365
  *
209
- * @return {void}
210
366
  */
211
367
  handleHeartbeat() {
212
368
  this.lastHeartbeat = Date.now();
@@ -214,13 +370,13 @@ class ClusterSubscriber {
214
370
  /**
215
371
  * Handles a node eviction message.
216
372
  *
217
- * @param {Object} message - decoded NodeEvicted protobuf message
218
- * @return {void}
373
+ * @param message - decoded NodeEvicted protobuf message
219
374
  */
220
375
  async handleNodeEviction(message) {
221
376
  if (message.nodeId === this.localNode.nodeId) {
222
377
  this.logger.error(`[CLUSTER] Node evicted by ${message.evictor}. Reason: ${message.reason}`);
223
- global.kuzzle.shutdown();
378
+ // A failure, like `evictSelf`'s: exit non-zero (#2785).
379
+ global.kuzzle.shutdown(1);
224
380
  return;
225
381
  }
226
382
  await this.localNode.evictNode(message.nodeId, {
@@ -231,8 +387,7 @@ class ClusterSubscriber {
231
387
  /**
232
388
  * Handles a node shutdown.
233
389
  *
234
- * @param {Object} message - decoded NodeShutdown protobuf message
235
- * @return {void}
390
+ * @param message - decoded NodeShutdown protobuf message
236
391
  */
237
392
  async handleNodeShutdown(message) {
238
393
  await this.localNode.evictNode(message.nodeId, {
@@ -243,12 +398,11 @@ class ClusterSubscriber {
243
398
  /**
244
399
  * Handles messages about realtime room creations
245
400
  *
246
- * @param {Object} message - decoded NewRealtimeRoom protobuf message
247
- * @return {void}
401
+ * @param message - decoded NewRealtimeRoom protobuf message
248
402
  */
249
403
  handleNewRealtimeRoom(message) {
250
404
  const { id, index, filter, messageId } = message;
251
- const icpair = fromKoncordeIndex(index);
405
+ const icpair = (0, koncordeCompat_1.fromKoncordeIndex)(index);
252
406
  debug("New realtime room created by node %s (message: %d, room: %s, index: %s, collection: %s)", this.remoteNodeId, messageId, id, icpair.index, icpair.collection);
253
407
  this.localNode.fullState.addRealtimeRoom(id, icpair.index, icpair.collection, JSON.parse(filter), {
254
408
  messageId,
@@ -259,8 +413,7 @@ class ClusterSubscriber {
259
413
  /**
260
414
  * Handles messages about realtime subscriptions
261
415
  *
262
- * @param {Object} message - decoded Subscription protobuf message
263
- * @return {void}
416
+ * @param message - decoded Subscription protobuf message
264
417
  */
265
418
  handleSubscription(message) {
266
419
  debug("New realtime subscription received from node %s (message: %d, room: %s)", this.remoteNodeId, message.messageId, message.roomId);
@@ -269,8 +422,7 @@ class ClusterSubscriber {
269
422
  /**
270
423
  * Handles messages about realtime room removal
271
424
  *
272
- * @param {Object} message - decoded RemoveRealtimeRoom protobuf message
273
- * @return {void}
425
+ * @param message - decoded RemoveRealtimeRoom protobuf message
274
426
  */
275
427
  handleRealtimeRoomRemoval(message) {
276
428
  debug("Realtime room removal received from node %s (message: %d, room: %s)", this.remoteNodeId, message.messageId, message.roomId);
@@ -279,8 +431,7 @@ class ClusterSubscriber {
279
431
  /**
280
432
  * Handles messages about user unsubscriptions
281
433
  *
282
- * @param {Object} message - decoded Unscription protobuf message
283
- * @return {void}
434
+ * @param message - decoded Unsubscription protobuf message
284
435
  */
285
436
  handleUnsubscription(message) {
286
437
  debug("Realtime unsubscription received from node %s (message: %d, room: %s)", this.remoteNodeId, message.messageId, message.roomId);
@@ -289,8 +440,7 @@ class ClusterSubscriber {
289
440
  /**
290
441
  * Handles messages about cluster-wide events
291
442
  *
292
- * @param {Object} message - decoded ClusterWideEvent protobuf message
293
- * @return {void}
443
+ * @param message - decoded ClusterWideEvent protobuf message
294
444
  */
295
445
  handleClusterWideEvent(message) {
296
446
  const payload = JSON.parse(message.payload);
@@ -299,11 +449,21 @@ class ClusterSubscriber {
299
449
  /**
300
450
  * Handles messages about document notifications
301
451
  *
302
- * @param {Object} message - decoded DocumentNotification protobuf message
303
- * @return {void}
452
+ * @param message - decoded DocumentNotification protobuf message
304
453
  */
305
454
  async handleDocumentNotification(message) {
306
- const notification = new DocumentNotification({
455
+ // The wire says `string`, `DocumentNotification` says "in" | "out" | "all",
456
+ // and until this conversion nothing checked. Treated as the malformed
457
+ // message it is — the same answer this file already gives to an unknown
458
+ // topic or a missing `messageId`. TD-68 (#2779).
459
+ if (!isRealtimeScope(message.scope)) {
460
+ await this.evictNode({
461
+ broadcast: true,
462
+ reason: `received an invalid message from ${this.remoteNodeId} (unknown document notification scope "${message.scope}")`,
463
+ });
464
+ return;
465
+ }
466
+ const notification = new document_1.default({
307
467
  action: message.action,
308
468
  collection: message.collection,
309
469
  controller: message.controller,
@@ -322,11 +482,19 @@ class ClusterSubscriber {
322
482
  /**
323
483
  * Handles messages about user notifications
324
484
  *
325
- * @param {Object} message - decoded UserNotification protobuf message
326
- * @return {void}
485
+ * @param message - decoded UserNotification protobuf message
327
486
  */
328
487
  async handleUserNotification(message) {
329
- const notification = new UserNotification({
488
+ // Same as handleDocumentNotification above: "in" | "out" | "all" | "none"
489
+ // on this side, an unchecked string on the wire. TD-68 (#2779).
490
+ if (!isRealtimeUsers(message.user)) {
491
+ await this.evictNode({
492
+ broadcast: true,
493
+ reason: `received an invalid message from ${this.remoteNodeId} (unknown user notification scope "${message.user}")`,
494
+ });
495
+ return;
496
+ }
497
+ const notification = new user_1.default({
330
498
  action: message.action,
331
499
  collection: message.collection,
332
500
  controller: message.controller,
@@ -344,8 +512,7 @@ class ClusterSubscriber {
344
512
  /**
345
513
  * Handles messages about new authentication strategies
346
514
  *
347
- * @param {Object} message - decoded NewAuthStrategy protobuf message
348
- * @return {void}
515
+ * @param message - decoded NewAuthStrategy protobuf message
349
516
  */
350
517
  handleNewAuthStrategy(message) {
351
518
  const { pluginName, strategy, strategyName } = message;
@@ -356,8 +523,7 @@ class ClusterSubscriber {
356
523
  /**
357
524
  * Handles messages about authentication strategy removals
358
525
  *
359
- * @param {Object} message - decoded RemoveAuthStrategy protobuf message
360
- * @return {void}
526
+ * @param message - decoded RemoveAuthStrategy protobuf message
361
527
  */
362
528
  handleAuthStrategyRemoval(message) {
363
529
  const { pluginName, strategyName } = message;
@@ -368,7 +534,6 @@ class ClusterSubscriber {
368
534
  /**
369
535
  * Handles messages about security resets
370
536
  *
371
- * @return {void}
372
537
  */
373
538
  async handleResetSecurity() {
374
539
  debug("Security reset received from node %s", this.remoteNodeId);
@@ -378,8 +543,7 @@ class ClusterSubscriber {
378
543
  /**
379
544
  * Handles a cross-nodes dump request
380
545
  *
381
- * @param {Object} message - decoded DumpRequest protobuf message
382
- * @return {void}
546
+ * @param message - decoded DumpRequest protobuf message
383
547
  */
384
548
  handleDumpRequest(message) {
385
549
  debug("Dump generation request received from node %s", this.remoteNodeId);
@@ -387,7 +551,6 @@ class ClusterSubscriber {
387
551
  }
388
552
  /**
389
553
  * Handles cluster-wide shutdown
390
- * @return {void}
391
554
  */
392
555
  handleShutdown() {
393
556
  debug("Cluster-wide shutdown request received from node %s", this.remoteNodeId);
@@ -397,7 +560,6 @@ class ClusterSubscriber {
397
560
  /**
398
561
  * Handles changes on document validators
399
562
  *
400
- * @return {void}
401
563
  */
402
564
  async handleRefreshValidators() {
403
565
  debug("Validators changed notification received from node %s", this.remoteNodeId);
@@ -415,8 +577,7 @@ class ClusterSubscriber {
415
577
  /**
416
578
  * Invalidates a profile to force reloading it from the storage space
417
579
  *
418
- * @param {Object} message - decoded DumpRequest protobuf message
419
- * @return {void}
580
+ * @param message - decoded InvalidateProfile protobuf message
420
581
  */
421
582
  async handleProfileInvalidation(message) {
422
583
  debug("Profile invalidation request received from node %s (profile: %s)", this.remoteNodeId, message.profileId);
@@ -425,8 +586,7 @@ class ClusterSubscriber {
425
586
  /**
426
587
  * Invalidates a role to force reloading it from the storage space
427
588
  *
428
- * @param {Object} message - decoded DumpRequest protobuf message
429
- * @return {void}
589
+ * @param message - decoded InvalidateRole protobuf message
430
590
  */
431
591
  async handleRoleInvalidation(message) {
432
592
  debug("Role invalidation request received from node %s (role: %s)", this.remoteNodeId, message.roleId);
@@ -435,8 +595,7 @@ class ClusterSubscriber {
435
595
  /**
436
596
  * Adds a new index to the index cache
437
597
  *
438
- * @param {Object} message - decoded IndexCacheAdd protobuf message
439
- * @return {void}
598
+ * @param message - decoded AddIndex protobuf message
440
599
  */
441
600
  async handleIndexAddition(message) {
442
601
  const { index, scope } = message;
@@ -446,8 +605,7 @@ class ClusterSubscriber {
446
605
  /**
447
606
  * Removes indexes from the index cache
448
607
  *
449
- * @param {Object} message - decoded IndexCacheAdd protobuf message
450
- * @return {void}
608
+ * @param message - decoded RemoveIndexes protobuf message
451
609
  */
452
610
  async handleIndexesRemoval(message) {
453
611
  const { indexes, scope } = message;
@@ -457,8 +615,7 @@ class ClusterSubscriber {
457
615
  /**
458
616
  * Adds a new collection to the index cache
459
617
  *
460
- * @param {Object} message - decoded IndexCacheAdd protobuf message
461
- * @return {void}
618
+ * @param message - decoded AddCollection protobuf message
462
619
  */
463
620
  async handleCollectionAddition(message) {
464
621
  const { collection, index, scope } = message;
@@ -468,8 +625,7 @@ class ClusterSubscriber {
468
625
  /**
469
626
  * Removes a collection from the index cache
470
627
  *
471
- * @param {Object} message - decoded IndexCacheAdd protobuf message
472
- * @return {void}
628
+ * @param message - decoded RemoveCollection protobuf message
473
629
  */
474
630
  async handleCollectionRemoval(message) {
475
631
  const { collection, index, scope } = message;
@@ -492,6 +648,29 @@ class ClusterSubscriber {
492
648
  if (this.state === stateEnum.EVICTED) {
493
649
  return;
494
650
  }
651
+ // A recovery holds `listen()` until the remote node has retransmitted
652
+ // (up to `cluster.syncTimeout`), so its heartbeats wait unread in the
653
+ // socket and `lastHeartbeat` goes stale while the node is alive and
654
+ // answering. Evicting it for that would broadcast the eviction of a
655
+ // healthy node (step 15, F-04). The recovery settles it either way: the
656
+ // retransmitted messages count as heartbeats, and a node that does not
657
+ // answer makes this node evict itself, as it did before #2785.
658
+ if (this.recovering) {
659
+ return;
660
+ }
661
+ // BUFFERING is left by `sync()` only, once the handshake has told this
662
+ // subscriber where to resume from. Setting SANE here used to end it early
663
+ // whenever the handshake outlasted one check period — which the waits of
664
+ // TD-65 (#2777, #2781) made routine: `listen()` then applied live messages
665
+ // against a counter still at 0, and `sync()` replayed a buffer opening on
666
+ // the very message it resumes after, outside the one state that drops
667
+ // those. The joining node read it as a loss and left the cluster (step 15,
668
+ // F-12). And there is no verdict to reach meanwhile: buffered frames are
669
+ // not applied, so they do not refresh `lastHeartbeat`; the handshake that
670
+ // owns this phase has its own timeouts.
671
+ if (this.state === stateEnum.BUFFERING) {
672
+ return;
673
+ }
495
674
  const now = Date.now();
496
675
  if (now - this.lastHeartbeat > this.heartbeatDelay) {
497
676
  if (this.state === stateEnum.MISSING_HEARTBEAT) {
@@ -516,17 +695,20 @@ class ClusterSubscriber {
516
695
  return;
517
696
  }
518
697
  this.state = stateEnum.EVICTED;
519
- this.socket.close();
698
+ this.socket?.close();
520
699
  this.socket = null;
521
- clearInterval(this.heartbeatTimer);
700
+ clearInterval(this.heartbeatTimer ?? undefined);
522
701
  }
523
702
  /**
524
703
  * Checks that the received message is the one we expect.
525
- * @param {Object} message - decoded protobuf message
526
- * @return {boolean} false: the message must be discarded, true otherwise
704
+ * @param message - decoded protobuf message
705
+ * @return false: the message must be discarded, true otherwise
527
706
  */
528
707
  async validateMessage(message) {
529
- if (!has(message, "messageId")) {
708
+ const messageId = message.messageId;
709
+ // Read once and checked for what it is: `has()` answers whether the key
710
+ // is there, which is not what the three `Long` operations below need.
711
+ if (messageId === undefined) {
530
712
  this.logger.warn(`Invalid message received from node ${this.remoteNodeId}. Evicting it.`);
531
713
  await this.evictNode({
532
714
  broadcast: true,
@@ -534,18 +716,98 @@ class ClusterSubscriber {
534
716
  });
535
717
  return false;
536
718
  }
537
- if (this.state === stateEnum.BUFFERING &&
538
- this.lastMessageId.greaterThanOrEqual(message.messageId)) {
719
+ const received = long_1.default.fromValue(messageId);
720
+ // An id this subscriber has already reached is a message already applied
721
+ // — or, while buffering, one the full state it resumes from already
722
+ // includes. Nothing is missing, so there is nothing to recover and no
723
+ // reason to leave the cluster: it used to be dropped while buffering only,
724
+ // and anywhere else it was reported as a loss of "18446744073709551615"
725
+ // messages — the difference, negative, printed as an unsigned 64-bit
726
+ // number (step 15, F-12).
727
+ if (this.lastMessageId.greaterThanOrEqual(received)) {
728
+ debug("Ignoring message %s from node %s: already applied (last applied: %s)", received.toString(), this.remoteNodeId, this.lastMessageId.toString());
539
729
  return false;
540
730
  }
541
- this.lastMessageId = this.lastMessageId.add(1);
542
- if (this.lastMessageId.notEquals(message.messageId)) {
543
- await this.localNode.evictSelf(`Node out-of-sync: ${message.messageId - this.lastMessageId - 1} messages lost from node ${this.remoteNodeId}`);
731
+ const expected = this.lastMessageId.add(1);
732
+ if (expected.equals(received)) {
733
+ this.lastMessageId = expected;
734
+ return true;
735
+ }
736
+ // Messages were lost in between: ask the remote node for them, and apply
737
+ // them before this one. `recover` leaves `lastMessageId` on the last one
738
+ // it applied, which is then this message's predecessor.
739
+ if (!this.recovering && (await this.recover(expected, received))) {
740
+ this.lastMessageId = received;
741
+ return true;
742
+ }
743
+ // `recover` may have evicted this node itself, applying a replayed message.
744
+ if (this.state === stateEnum.EVICTED) {
745
+ return false;
746
+ }
747
+ // Long arithmetic rather than `-`: message ids are 64-bit and
748
+ // `message.messageId` may arrive as a Long or as a number depending on how
749
+ // the protobuf reader was configured, so subtracting with `-` leans on
750
+ // `Long.prototype.valueOf` — which works, loses precision past 2^53, and is
751
+ // what SonarCloud's S3757 objects to. `fromValue` accepts either shape and
752
+ // `subtract` is exact. The count is against the id this node EXPECTED, so
753
+ // a single-message loss reads "1" — see TD-58 (#2762). `received` is past
754
+ // `expected` here, as the checks above leave nothing else, so the
755
+ // difference cannot wrap.
756
+ const lost = received.subtract(expected);
757
+ // Stop before evicting, for two reasons. `lastMessageId` is not
758
+ // resynchronised here, so leaving this subscriber running would re-trip
759
+ // this same check on every subsequent message: one drop was reported nine
760
+ // times in five seconds in CI, and occurrence counts read off those lines
761
+ // overcount. It also ends `listen()`'s loop, which is what "this node is
762
+ // out of the cluster" should mean locally. See TD-67 (#2776).
763
+ this.state = stateEnum.EVICTED;
764
+ await this.localNode.evictSelf(`Node out-of-sync: ${lost.toString()} messages lost from node ${this.remoteNodeId}`);
765
+ return false;
766
+ }
767
+ /**
768
+ * Fetches the messages with ids `from` to `upTo - 1` from the remote node,
769
+ * which keeps its last ones for that purpose, and applies them in order
770
+ * (#2785).
771
+ *
772
+ * Awaited where the gap is found, so nothing that came after it is applied
773
+ * before it: `listen()` stops reading meanwhile (ZeroMQ queues what arrives)
774
+ * and `sync()` stops replaying.
775
+ *
776
+ * @return whether every missing message was applied; `false` leaves the
777
+ * decision — eviction — to the caller
778
+ */
779
+ async recover(from, upTo) {
780
+ const to = upTo.subtract(1);
781
+ // Set for the whole recovery, the wait included. Each frame goes through
782
+ // `validateMessage` again, which is what checks that the remote node
783
+ // answered with the ids that were asked for; a gap found *there* is not
784
+ // recovered from a second time: the remote node just answered with
785
+ // something other than what it was asked. And `checkHeartbeat` stands
786
+ // down meanwhile — see there.
787
+ this.recovering = true;
788
+ let frames;
789
+ try {
790
+ frames = await this.localNode.command.requestRetransmit(this.remoteNodeIP, from, to);
791
+ if (frames === null || this.state === stateEnum.EVICTED) {
792
+ return false;
793
+ }
794
+ for (const [topic, data] of frames) {
795
+ await this.processData(topic, data);
796
+ if (this.state === stateEnum.EVICTED) {
797
+ return false;
798
+ }
799
+ }
800
+ }
801
+ finally {
802
+ this.recovering = false;
803
+ }
804
+ if (!this.lastMessageId.equals(to)) {
544
805
  return false;
545
806
  }
807
+ this.logger.warn(`[CLUSTER] Recovered ${frames.length} message(s) lost from node ${this.remoteNodeId}`);
546
808
  return true;
547
809
  }
548
- async evictNode({ broadcast, reason }) {
810
+ async evictNode({ broadcast, reason, }) {
549
811
  this.state = stateEnum.EVICTED;
550
812
  await this.localNode.evictNode(this.remoteNodeId, { broadcast, reason });
551
813
  }