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,120 +19,263 @@
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 Bluebird = require("bluebird");
23
- const _ = require("lodash");
24
- const { Koncorde } = require("koncorde");
25
- const debug = require("../../util/debug")("core:validation");
26
- const kerror = require("../../kerror");
27
- const { KuzzleError } = require("../../kerror/errors");
28
- const { has, isPlainObject, get } = require("../../util/safeObject");
29
- const { koncordeTest, toKoncordeIndex } = 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 bluebird_1 = __importDefault(require("bluebird"));
50
+ const koncorde_1 = require("koncorde");
51
+ const lodash_1 = require("lodash");
52
+ const kerror = __importStar(require("../../kerror"));
53
+ const errors_1 = require("../../kerror/errors");
54
+ const debug_1 = __importDefault(require("../../util/debug"));
55
+ const koncordeCompat_1 = require("../../util/koncordeCompat");
56
+ const safeObject_1 = require("../../util/safeObject");
57
+ const validationUtils_1 = require("./validationUtils");
58
+ const anything_1 = __importDefault(require("./types/anything"));
59
+ const boolean_1 = __importDefault(require("./types/boolean"));
60
+ const date_1 = __importDefault(require("./types/date"));
61
+ const email_1 = __importDefault(require("./types/email"));
62
+ const enum_1 = __importDefault(require("./types/enum"));
63
+ const geoPoint_1 = __importDefault(require("./types/geoPoint"));
64
+ const geoShape_1 = __importDefault(require("./types/geoShape"));
65
+ const integer_1 = __importDefault(require("./types/integer"));
66
+ const ipAddress_1 = __importDefault(require("./types/ipAddress"));
67
+ const numeric_1 = __importDefault(require("./types/numeric"));
68
+ const object_1 = __importDefault(require("./types/object"));
69
+ const string_1 = __importDefault(require("./types/string"));
70
+ const url_1 = __importDefault(require("./types/url"));
71
+ const debug = (0, debug_1.default)("core:validation");
30
72
  const assertionError = kerror.wrap("validation", "assert");
31
73
  /**
32
- * @class Validation
74
+ * The 13 built-in types, in the order `init` registers them.
75
+ *
76
+ * They were loaded by `require(`./types/${typeFile}`)` over a list of names.
77
+ * That is a runtime `require` in a function body, which is the third spelling
78
+ * of the defect TD-49 catalogued: a bundler cannot see it, so the module is
79
+ * unloadable from a runner that resolves the import graph itself. Naming the
80
+ * constructors statically also lets `addType`'s contract be checked at compile
81
+ * time for the built-ins, where before only the runtime assertions in `addType`
82
+ * stood between a typo and a broken boot.
83
+ */
84
+ const BUILT_IN_TYPES = [
85
+ anything_1.default,
86
+ boolean_1.default,
87
+ date_1.default,
88
+ email_1.default,
89
+ enum_1.default,
90
+ geoPoint_1.default,
91
+ geoShape_1.default,
92
+ integer_1.default,
93
+ ipAddress_1.default,
94
+ numeric_1.default,
95
+ object_1.default,
96
+ string_1.default,
97
+ url_1.default,
98
+ ];
99
+ /**
100
+ * The message of whatever was thrown.
101
+ *
102
+ * `catch` answers `unknown`, and the values that reach these handlers are not
103
+ * all Errors: a plugin's validation type may throw anything, and the code has
104
+ * always simply read `.message` off it. Narrowing to `Error` here would change
105
+ * what those messages say, which the specs pin.
106
+ */
107
+ function messageOf(error) {
108
+ if (error instanceof Error) {
109
+ return error.message;
110
+ }
111
+ if (typeof error === "object" && error !== null) {
112
+ const message = "message" in error ? error.message : undefined;
113
+ // `inspect`, not `String`: an object stringifies to "[object Object]".
114
+ return typeof message === "string" ? message : (0, node_util_1.inspect)(error);
115
+ }
116
+ // A primitive. The strictness marker used to be a thrown string, and
117
+ // reading it back verbatim is what recognises it.
118
+ return typeof error === "string" ? error : (0, node_util_1.inspect)(error);
119
+ }
120
+ /**
121
+ * The marker `recurseFieldValidation` throws when a document holds a field its
122
+ * specification does not declare and the specification is strict.
123
+ *
124
+ * It is caught by message — `error.message !== "strictness"` — at two levels,
125
+ * and carries the offending field name for the message the catcher builds. It
126
+ * was a plain `Error` with an untyped `details` property bolted on.
127
+ */
128
+ /**
129
+ * The field name a strictness marker carries, read off whatever was thrown for
130
+ * the same reason `messageOf` exists.
33
131
  */
132
+ function detailedField(error) {
133
+ if (error instanceof StrictnessError) {
134
+ return error.details.field;
135
+ }
136
+ if (typeof error === "object" && error !== null && "details" in error) {
137
+ const details = error.details;
138
+ if (typeof details === "object" && details !== null && "field" in details) {
139
+ // A field name is a string; anything else is not one to report.
140
+ return typeof details.field === "string" ? details.field : undefined;
141
+ }
142
+ }
143
+ return undefined;
144
+ }
145
+ class StrictnessError extends Error {
146
+ constructor(field) {
147
+ super("strictness");
148
+ this.details = { field };
149
+ }
150
+ }
151
+ /**
152
+ * Narrows the "a curated value, or a report of why it could not be curated"
153
+ * pair that four of the curation methods answer with.
154
+ *
155
+ * The pair is not a discriminated union — the success branch is the curated
156
+ * value itself and carries no tag — so the discriminator has to be the failure
157
+ * shape. `"isValid" in result` is what makes this a guard rather than a cast,
158
+ * and TD-43's `casts` ratchet is the reason it matters.
159
+ */
160
+ function isCurationFailure(result) {
161
+ return "isValid" in result && result.isValid === false;
162
+ }
34
163
  class Validation {
35
164
  constructor() {
36
- /** @type {...ValidationType} */
37
165
  this.types = {};
38
- /** @type {string[]} */
39
166
  this.typeAllowsChildren = [];
40
- /** @type {DocumentSpecification} */
41
167
  this.specification = {};
42
- /** @type {Koncorde} */
43
- this.koncorde = new Koncorde();
168
+ this.koncorde = new koncorde_1.Koncorde();
44
169
  this.rawConfiguration = {};
45
170
  this.logger = global.kuzzle.log.child("core:validation");
46
171
  }
47
172
  /**
48
- * Walks through all types in "defaultTypesFiles" initializes all types
173
+ * Registers every built-in validation type.
49
174
  */
50
175
  init() {
51
- for (const typeFile of [
52
- "anything",
53
- "boolean",
54
- "date",
55
- "email",
56
- "enum",
57
- "geoPoint",
58
- "geoShape",
59
- "integer",
60
- "ipAddress",
61
- "numeric",
62
- "object",
63
- "string",
64
- "url",
65
- ]) {
66
- const TypeConstructor = require(`./types/${typeFile}`);
176
+ for (const TypeConstructor of BUILT_IN_TYPES) {
67
177
  this.addType(new TypeConstructor());
68
178
  }
69
179
  }
70
- /**
71
- * Validates a document against its collection specifications
72
- *
73
- * @param {Request} request
74
- * @param {boolean} [verbose]
75
- * @returns {Promise.<{documentBody: *, errorMessages:string[], valid: boolean}|KuzzleRequest>}
76
- */
77
180
  async validate(request, verbose = false) {
78
- const { _id, index, collection } = request.input.resource, collectionSpec = (isPlainObject(this.specification) &&
79
- has(this.specification, index) &&
80
- get(this.specification[index], collection)) ||
181
+ // Read from `input.args`, which is what the deprecated `input.resource`
182
+ // getters return: same values, typed as those getters declare them.
183
+ const { args } = request.input;
184
+ const _id = args._id;
185
+ const index = args.index;
186
+ const collection = args.collection;
187
+ // `has` rather than a plain lookup: `index` and `collection` come from the
188
+ // request, so an inherited property must not answer for a specification.
189
+ const indexSpec = index !== null && (0, safeObject_1.has)(this.specification, index)
190
+ ? this.specification[index]
191
+ : undefined;
192
+ const collectionSpec = ((0, safeObject_1.isPlainObject)(this.specification) &&
193
+ indexSpec !== undefined &&
194
+ collection !== null &&
195
+ (0, safeObject_1.has)(indexSpec, collection) &&
196
+ indexSpec[collection]) ||
81
197
  {};
82
- let isUpdate = false, body = request.input.body;
83
- if (request.input.controller === "document" &&
84
- request.input.action === "update") {
85
- isUpdate = true;
86
- const document = await global.kuzzle.ask("core:storage:public:document:get", index, collection, _id);
87
- // Avoid side effects on the request during the update validation
88
- body = _.cloneDeep(request.input.body);
89
- _.defaultsDeep(body, document._source);
90
- }
198
+ const { body, isUpdate } = await this.resolveValidationBody(request, index, collection, _id);
91
199
  const errorMessages = verbose ? {} : [];
92
200
  let isValid = true;
93
- if (collectionSpec) {
94
- if (collectionSpec.fields && collectionSpec.fields.children) {
95
- try {
96
- isValid = this.recurseFieldValidation(body, collectionSpec.fields.children, collectionSpec.strict, errorMessages, verbose);
97
- }
98
- catch (error) {
99
- // The strictness message can be received here only if it happens at
100
- // the validation of the document's root
101
- if (error.message !== "strictness") {
102
- throw error;
103
- }
104
- isValid = false;
105
- manageErrorMessage("document", errorMessages, `The document validation is strict. Cannot add unspecified sub-field "${error.details.field}"`, verbose);
106
- }
107
- }
108
- if (collectionSpec.validators) {
109
- const filters = koncordeTest(this.koncorde, index, collection, body, _id);
110
- if (filters.length === 0 || filters[0] !== collectionSpec.validators) {
111
- isValid = false;
112
- manageErrorMessage("document", errorMessages, "The document does not match validation filters.", verbose);
113
- }
114
- }
201
+ // `collectionSpec` is always truthy — it falls back to `{}` above — so the
202
+ // enclosing `if (collectionSpec)` the JavaScript had was dead.
203
+ const children = collectionSpec.fields?.children;
204
+ if (children) {
205
+ isValid = this.checkDocumentFields(body, children,
206
+ // Truthiness, as in v2.56.0: curation stores `spec.strict || false`
207
+ // unchecked, so a stored `"true"` or `1` has always meant strict.
208
+ Boolean(collectionSpec.strict), errorMessages, verbose);
209
+ }
210
+ if (collectionSpec.validators && index !== null && collection !== null) {
211
+ isValid =
212
+ this.checkValidators(index, collection, _id, body, collectionSpec.validators, errorMessages, verbose) && isValid;
115
213
  }
116
214
  if (!verbose) {
117
215
  // We only modify the request if the validation succeeds
118
- if (collectionSpec.fields && collectionSpec.fields.children) {
119
- request.input.body = this.recurseApplyDefault(isUpdate, request.input.body, collectionSpec.fields.children);
216
+ if (children) {
217
+ request.input.body = this.recurseApplyDefault(isUpdate, request.input.body ?? {}, children);
120
218
  }
121
219
  return request;
122
220
  }
123
221
  return { errorMessages, valid: isValid };
124
222
  }
125
223
  /**
126
- * @param {boolean} isUpdate
127
- * @param {*} documentSubset
128
- * @param {...StructuredFieldSpecification} collectionSpecSubset
224
+ * The body validation runs against: the request's own, or — on an update —
225
+ * a copy merged over the stored document, so that a partial update is
226
+ * validated as the document it will produce.
227
+ */
228
+ async resolveValidationBody(request, index, collection, _id) {
229
+ if (request.input.controller !== "document" ||
230
+ request.input.action !== "update") {
231
+ return { body: request.input.body, isUpdate: false };
232
+ }
233
+ const document = await global.kuzzle.ask("core:storage:public:document:get", index, collection, _id);
234
+ // Avoid side effects on the request during the update validation
235
+ const body = (0, lodash_1.cloneDeep)(request.input.body ?? {}); // NOSONAR structuredClone is not equivalent here: specifications and documents are user data, and a conversion does not get to change clone semantics
236
+ (0, lodash_1.defaultsDeep)(body, document._source);
237
+ return { body, isUpdate: true };
238
+ }
239
+ /**
240
+ * Walks the document against the collection's field tree, turning a
241
+ * root-level strictness breach into a message rather than an exception.
242
+ */
243
+ checkDocumentFields(body, children, strict, errorMessages, verbose) {
244
+ try {
245
+ return this.recurseFieldValidation(body, children, strict, errorMessages, verbose);
246
+ }
247
+ catch (error) {
248
+ // The strictness message can be received here only if it happens at
249
+ // the validation of the document's root. Matched on the message, not on
250
+ // `instanceof StrictnessError`: a validation type is plugin code and may
251
+ // throw its own object, which is what the specs feed this.
252
+ if (messageOf(error) !== "strictness") {
253
+ throw error;
254
+ }
255
+ (0, validationUtils_1.manageErrorMessage)("document", errorMessages, `The document validation is strict. Cannot add unspecified sub-field "${detailedField(error)}"`, verbose);
256
+ return false;
257
+ }
258
+ }
259
+ /**
260
+ * Checks the document against the collection's Koncorde validator filter.
261
+ */
262
+ checkValidators(index, collection, _id, body, validators, errorMessages, verbose) {
263
+ const filters = (0, koncordeCompat_1.koncordeTest)(this.koncorde, index, collection, body ?? {}, _id ?? undefined);
264
+ if (filters.length === 0 || filters[0] !== validators) {
265
+ (0, validationUtils_1.manageErrorMessage)("document", errorMessages, "The document does not match validation filters.", verbose);
266
+ return false;
267
+ }
268
+ return true;
269
+ }
270
+ /**
271
+ * Fills a document subset in with the default values its specification
272
+ * declares, recursing through the fields that allow children.
129
273
  */
130
274
  recurseApplyDefault(isUpdate, documentSubset, collectionSpecSubset) {
131
- Object.keys(collectionSpecSubset).forEach((fieldName) => {
132
- const specSubset = collectionSpecSubset[fieldName], field = documentSubset[fieldName];
133
- if (has(documentSubset, fieldName) &&
134
- this.types[specSubset.type].allowChildren &&
275
+ Object.entries(collectionSpecSubset).forEach(([fieldName, specSubset]) => {
276
+ const field = documentSubset[fieldName];
277
+ if ((0, safeObject_1.has)(documentSubset, fieldName) &&
278
+ this.typeOf(specSubset.type).allowChildren &&
135
279
  specSubset.children) {
136
280
  if (Array.isArray(field)) {
137
281
  for (let i = 0; i < field.length; i++) {
@@ -143,134 +287,156 @@ class Validation {
143
287
  }
144
288
  }
145
289
  else if (specSubset.defaultValue &&
146
- (field === null || (!isUpdate && !has(documentSubset, fieldName)))) {
290
+ (field === null || (!isUpdate && !(0, safeObject_1.has)(documentSubset, fieldName)))) {
147
291
  documentSubset[fieldName] = specSubset.defaultValue;
148
292
  }
149
293
  });
150
294
  return documentSubset;
151
295
  }
152
296
  /**
153
- * @param {*} documentSubset
154
- * @param {StructuredFieldSpecification} collectionSpecSubset
155
- * @param {boolean} strictness
156
- * @param {string[]} errorMessages
157
- * @param {boolean} verbose
297
+ * Validates every field of a document subset against its specification.
298
+ *
299
+ * @throws {StrictnessError} when `strictness` holds and the subset declares a
300
+ * field the specification does not — caught by the two callers, which turn it
301
+ * into a message naming the field.
158
302
  */
159
303
  recurseFieldValidation(documentSubset, collectionSpecSubset, strictness, errorMessages, verbose) {
160
304
  if (strictness) {
161
- for (const field of Object.keys(documentSubset)) {
305
+ for (const field of Object.keys(documentSubset ?? {})) {
162
306
  if (!collectionSpecSubset[field]) {
163
- const error = new Error("strictness");
164
- error.details = { field };
165
- throw error;
307
+ throw new StrictnessError(field);
166
308
  }
167
309
  }
168
310
  }
169
311
  if (!verbose) {
170
312
  // We stop as soon as one field is not valid
171
- return Object.keys(collectionSpecSubset).every((fieldName) => this.isValidField(fieldName, documentSubset, collectionSpecSubset, strictness, errorMessages, verbose));
313
+ return Object.keys(collectionSpecSubset).every((fieldName) => this.isValidField(fieldName, documentSubset ?? {}, collectionSpecSubset, strictness, errorMessages, verbose));
172
314
  }
173
315
  // We try to validate every field in order to get all error messages if any
174
- return Object.keys(collectionSpecSubset).reduce((reductionResult, fieldName) => this.isValidField(fieldName, documentSubset, collectionSpecSubset, strictness, errorMessages, verbose) && reductionResult, true);
316
+ return Object.keys(collectionSpecSubset).reduce((reductionResult, fieldName) => this.isValidField(fieldName, documentSubset ?? {}, collectionSpecSubset, strictness, errorMessages, verbose) && reductionResult, true);
175
317
  }
176
318
  /**
177
- * @param {string} fieldName
178
- * @param {*} documentSubset
179
- * @param {StructuredFieldSpecification} collectionSpecSubset
180
- * @param {boolean} strictness
181
- * @param {string[]} errorMessages
182
- * @param {boolean} verbose
183
- * @returns {boolean}
319
+ * Validates one field of a document subset against its specification.
184
320
  */
185
321
  isValidField(fieldName, documentSubset, collectionSpecSubset, strictness, errorMessages, verbose) {
186
- /** @type StructuredFieldSpecification */
187
322
  const field = collectionSpecSubset[fieldName];
188
- let result = true;
323
+ // Both callers drive this from the map's own keys; a name that is not in
324
+ // it has no specification to check the document against.
325
+ if (field === undefined) {
326
+ return true;
327
+ }
189
328
  if (field.mandatory &&
190
- !has(field, "defaultValue") &&
191
- _.isNil(documentSubset[fieldName])) {
192
- manageErrorMessage(field.path, errorMessages, "The field is mandatory.", verbose);
329
+ !(0, safeObject_1.has)(field, "defaultValue") &&
330
+ (0, lodash_1.isNil)(documentSubset[fieldName])) {
331
+ (0, validationUtils_1.manageErrorMessage)(field.path, errorMessages, "The field is mandatory.", verbose);
193
332
  return false;
194
333
  }
195
- if (!_.isNil(documentSubset[fieldName])) {
196
- let nestedStrictness = false, fieldValues;
197
- if (field.multivalued.value) {
198
- if (!Array.isArray(documentSubset[fieldName])) {
199
- manageErrorMessage(field.path, errorMessages, "The field must be multivalued, unary value provided.", verbose);
200
- return false;
201
- }
202
- if (has(field.multivalued, "minCount") &&
203
- documentSubset[fieldName].length < field.multivalued.minCount) {
204
- manageErrorMessage(field.path, errorMessages, `Not enough elements. Minimum count is set to ${field.multivalued.minCount}.`, verbose);
205
- return false;
206
- }
207
- if (has(field.multivalued, "maxCount") &&
208
- documentSubset[fieldName].length > field.multivalued.maxCount) {
209
- manageErrorMessage(field.path, errorMessages, `Too many elements. Maximum count is set to ${field.multivalued.maxCount}.`, verbose);
210
- return false;
211
- }
212
- fieldValues = documentSubset[fieldName];
334
+ if ((0, lodash_1.isNil)(documentSubset[fieldName])) {
335
+ return true;
336
+ }
337
+ const fieldValues = this.resolveFieldValues(field, documentSubset[fieldName], errorMessages, verbose);
338
+ if (fieldValues === null) {
339
+ return false;
340
+ }
341
+ const type = this.typeOf(field.type);
342
+ const nestedStrictness = type.allowChildren
343
+ ? type.getStrictness(field.typeOptions, strictness)
344
+ : false;
345
+ let result = true;
346
+ for (const val of fieldValues) {
347
+ if (!this.validateFieldValue(field, val, errorMessages, verbose)) {
348
+ return false;
213
349
  }
214
- else {
215
- if (Array.isArray(documentSubset[fieldName])) {
216
- manageErrorMessage(field.path, errorMessages, "The field is not a multivalued field; Multiple values provided.", verbose);
217
- return false;
218
- }
219
- fieldValues = [documentSubset[fieldName]];
350
+ if (type.allowChildren && field.children) {
351
+ result =
352
+ this.validateFieldChildren(field, val, nestedStrictness, errorMessages, verbose) && result;
220
353
  }
221
- if (this.types[field.type].allowChildren) {
222
- nestedStrictness = this.types[field.type].getStrictness(field.typeOptions, strictness);
354
+ }
355
+ return result;
356
+ }
357
+ /**
358
+ * Answers the values to validate — the array itself for a multivalued field,
359
+ * a single-element list otherwise — or `null` once it has filed the reason
360
+ * the field's arity is wrong.
361
+ */
362
+ resolveFieldValues(field, value, errorMessages, verbose) {
363
+ if (!field.multivalued.value) {
364
+ if (Array.isArray(value)) {
365
+ (0, validationUtils_1.manageErrorMessage)(field.path, errorMessages, "The field is not a multivalued field; Multiple values provided.", verbose);
366
+ return null;
223
367
  }
224
- for (const val of fieldValues) {
225
- const fieldErrors = [];
226
- if (!this.types[field.type].validate(field.typeOptions, val, fieldErrors)) {
227
- if (fieldErrors.length === 0) {
228
- // We still want to trigger an error, even if no message is provided
229
- manageErrorMessage(field.path, errorMessages, "An error has occurred during validation.", verbose);
230
- }
231
- else {
232
- fieldErrors.forEach((message) => manageErrorMessage(field.path, errorMessages, message, verbose));
233
- }
234
- return false;
235
- }
236
- if (this.types[field.type].allowChildren && field.children) {
237
- try {
238
- if (!this.recurseFieldValidation(val, field.children, nestedStrictness, errorMessages, verbose)) {
239
- result = false;
240
- }
241
- }
242
- catch (error) {
243
- if (error.message === "strictness") {
244
- manageErrorMessage(field.path, errorMessages, `The field is set to "strict"; cannot add unspecified sub-field "${error.details.field}".`, verbose);
245
- }
246
- else if (verbose) {
247
- manageErrorMessage(field.path, errorMessages, error.message, verbose);
248
- }
249
- else {
250
- throw error;
251
- }
252
- result = false;
253
- }
254
- }
368
+ return [value];
369
+ }
370
+ if (!Array.isArray(value)) {
371
+ (0, validationUtils_1.manageErrorMessage)(field.path, errorMessages, "The field must be multivalued, unary value provided.", verbose);
372
+ return null;
373
+ }
374
+ const { minCount, maxCount } = field.multivalued;
375
+ if (minCount !== undefined && value.length < minCount) {
376
+ (0, validationUtils_1.manageErrorMessage)(field.path, errorMessages, `Not enough elements. Minimum count is set to ${minCount}.`, verbose);
377
+ return null;
378
+ }
379
+ if (maxCount !== undefined && value.length > maxCount) {
380
+ (0, validationUtils_1.manageErrorMessage)(field.path, errorMessages, `Too many elements. Maximum count is set to ${maxCount}.`, verbose);
381
+ return null;
382
+ }
383
+ return value;
384
+ }
385
+ /**
386
+ * Hands one value to the field's registered type.
387
+ */
388
+ validateFieldValue(field, val, errorMessages, verbose) {
389
+ const fieldErrors = [];
390
+ if (this.typeOf(field.type).validate(field.typeOptions, val, fieldErrors)) {
391
+ return true;
392
+ }
393
+ if (fieldErrors.length === 0) {
394
+ // We still want to trigger an error, even if no message is provided
395
+ (0, validationUtils_1.manageErrorMessage)(field.path, errorMessages, "An error has occurred during validation.", verbose);
396
+ }
397
+ else {
398
+ fieldErrors.forEach((message) => (0, validationUtils_1.manageErrorMessage)(field.path, errorMessages, message, verbose));
399
+ }
400
+ return false;
401
+ }
402
+ /**
403
+ * Recurses into a value's children, turning this field's strictness breach
404
+ * into a message rather than an exception.
405
+ */
406
+ validateFieldChildren(field, val, nestedStrictness, errorMessages, verbose) {
407
+ try {
408
+ return this.recurseFieldValidation(val, field.children ?? {}, nestedStrictness, errorMessages, verbose);
409
+ }
410
+ catch (error) {
411
+ if (messageOf(error) === "strictness") {
412
+ (0, validationUtils_1.manageErrorMessage)(field.path, errorMessages, `The field is set to "strict"; cannot add unspecified sub-field "${detailedField(error)}".`, verbose);
413
+ }
414
+ else if (verbose) {
415
+ (0, validationUtils_1.manageErrorMessage)(field.path, errorMessages, messageOf(error), verbose);
255
416
  }
417
+ else {
418
+ throw error;
419
+ }
420
+ return false;
256
421
  }
257
- return result;
258
422
  }
259
423
  /**
260
- * @returns {Promise.<T>}
424
+ * Loads every stored specification, curates it, and swaps the result in.
425
+ *
426
+ * A collection whose specification does not curate is logged and skipped, so
427
+ * one bad specification cannot keep the others from being applied.
261
428
  */
262
429
  curateSpecification() {
263
- const promises = [], specification = {};
264
- return getValidationConfiguration().then((validation) => {
430
+ const promises = [];
431
+ const specification = {};
432
+ return (0, validationUtils_1.getValidationConfiguration)().then((validation) => {
265
433
  this.rawConfiguration = validation;
266
- for (const indexName of Object.keys(this.rawConfiguration)) {
267
- for (const collectionName of Object.keys(this.rawConfiguration[indexName])) {
268
- const promise = this.curateCollectionSpecification(indexName, collectionName, this.rawConfiguration[indexName][collectionName])
434
+ for (const [indexName, collections] of Object.entries(this.rawConfiguration)) {
435
+ for (const [collectionName, collectionSpec] of Object.entries(collections)) {
436
+ const promise = this.curateCollectionSpecification(indexName, collectionName, collectionSpec)
269
437
  .then((curatedSpec) => {
270
- if (!has(specification, indexName)) {
271
- specification[indexName] = {};
272
- }
273
- specification[indexName][collectionName] = curatedSpec;
438
+ const indexSpec = (specification[indexName] ?? (specification[indexName] = {}));
439
+ indexSpec[collectionName] = curatedSpec;
274
440
  return null;
275
441
  })
276
442
  .catch((error) => {
@@ -281,24 +447,20 @@ class Validation {
281
447
  promises.push(promise);
282
448
  }
283
449
  }
284
- return Bluebird.all(promises).then(() => {
450
+ return bluebird_1.default.all(promises).then(() => {
285
451
  this.specification = specification;
286
452
  });
287
453
  });
288
454
  }
289
455
  /**
290
- * @param {string} indexName
291
- * @param {string} collectionName
292
- * @param {CollectionSpecification} collectionSpec
293
- * @param {boolean} [verboseErrors]
294
- * @returns {Promise<object>}
456
+ * Reports whether a specification would curate, without registering it.
295
457
  */
296
458
  validateFormat(indexName, collectionName, collectionSpec, verboseErrors = false) {
297
459
  // We make a deep clone to avoid side effects
298
- const specification = _.cloneDeep(collectionSpec);
460
+ const specification = (0, lodash_1.cloneDeep)(collectionSpec); // NOSONAR structuredClone is not equivalent here: specifications and documents are user data, and a conversion does not get to change clone semantics
299
461
  return (this.curateCollectionSpecification(indexName, collectionName, specification, true, verboseErrors)
300
462
  .then((result) => {
301
- if (verboseErrors && result.isValid === false) {
463
+ if (verboseErrors && isCurationFailure(result)) {
302
464
  return result;
303
465
  }
304
466
  return { isValid: true };
@@ -307,24 +469,15 @@ class Validation {
307
469
  // to know what is going wrong with the given spec
308
470
  .catch((error) => ({ errors: [error], isValid: false })));
309
471
  }
310
- /**
311
- * @param {string} index
312
- * @param {string} collection
313
- * @param {CollectionSpecification} spec
314
- * @param {boolean} [dryRun]
315
- * @param {boolean} [verbose]
316
- * @returns {Promise<CollectionSpecification>}
317
- * @rejects PreconditionError
318
- */
319
472
  async curateCollectionSpecification(index, collection, spec, dryRun = false, verbose = false) {
320
- let error = "";
473
+ let error;
321
474
  const processed = {
322
475
  fields: {},
323
476
  strict: spec.strict || false,
324
477
  validators: null,
325
478
  };
326
479
  const allowed = ["strict", "fields", "validators"];
327
- if (!checkAllowedProperties(spec, allowed)) {
480
+ if (!(0, validationUtils_1.checkAllowedProperties)(spec, allowed)) {
328
481
  error = assertionError.get("unexpected_properties", `${index}.${collection}`, allowed.join(", "));
329
482
  if (verbose) {
330
483
  return { errors: [error.message], isValid: false };
@@ -333,50 +486,68 @@ class Validation {
333
486
  }
334
487
  if (spec.fields) {
335
488
  const result = this.structureCollectionValidation(spec, index, collection, verbose);
336
- if (result.isValid === false) {
489
+ if (isCurationFailure(result)) {
337
490
  if (verbose) {
338
491
  // do not fail fast if we need verbose errors
339
492
  return result;
340
493
  }
341
- throw assertionError.get("invalid_specifications", result.errors.join("\n\t- "));
494
+ throw assertionError.get("invalid_specifications", (result.errors ?? []).join("\n\t- "));
342
495
  }
343
496
  processed.fields = result;
344
497
  }
345
498
  if (spec.validators && Array.isArray(spec.validators)) {
346
- try {
347
- const filterId = this.curateValidatorFilter(index, collection, spec.validators, dryRun);
348
- processed.validators = filterId;
349
- }
350
- catch (e) {
351
- this.logger.error(e);
352
- throw assertionError.getFrom(e, "invalid_filters", e.message);
353
- }
499
+ processed.validators = this.curateValidators(index, collection, spec.validators, dryRun);
354
500
  }
355
501
  return processed;
356
502
  }
503
+ /**
504
+ * Registers a specification's validator filter and answers its id.
505
+ *
506
+ * The wrapping is what `curateCollectionSpecification` did inline: a filter
507
+ * Koncorde refuses is an `invalid_filters` assertion, logged on the way
508
+ * past.
509
+ */
510
+ curateValidators(index, collection, validators, dryRun) {
511
+ try {
512
+ return this.curateValidatorFilter(index, collection, validators, dryRun);
513
+ }
514
+ catch (e) {
515
+ this.logger.error(e);
516
+ throw assertionError.getFrom(e instanceof Error ? e : new Error(messageOf(e)), "invalid_filters", messageOf(e));
517
+ }
518
+ }
519
+ /**
520
+ * Curates every field of a specification, then assembles them into a tree.
521
+ */
357
522
  structureCollectionValidation(collectionSpec, indexName, collectionName, verboseErrors = false) {
523
+ var _a;
358
524
  const fields = {};
359
- let errors = [], maxDepth = 0;
360
- for (const fieldName of Object.keys(collectionSpec.fields)) {
525
+ let errors = [];
526
+ let maxDepth = 0;
527
+ for (const [fieldName, fieldSpec] of Object.entries(collectionSpec.fields ?? {})) {
361
528
  const // We deep clone the field because we will modify it
362
- fieldSpecClone = _.cloneDeep(collectionSpec.fields[fieldName]);
529
+ fieldSpecClone = (0, lodash_1.cloneDeep)(fieldSpec); // NOSONAR structuredClone is not equivalent here: specifications and documents are user data, and a conversion does not get to change clone semantics
363
530
  try {
364
531
  const result = this.curateFieldSpecification(fieldSpecClone, indexName, collectionName, fieldName, verboseErrors);
365
- if (result.isValid === false) {
366
- errors = _.concat(errors, result.errors);
367
- this.logger.error(result.errors.join("\n"));
532
+ if (result.isValid === false || result.fieldSpec === undefined) {
533
+ const resultErrors = result.errors ?? [];
534
+ errors = errors.concat(resultErrors);
535
+ this.logger.error(resultErrors.join("\n"));
368
536
  }
369
537
  else {
370
- const field = result.fieldSpec;
371
- field.path = fieldName.split("/");
372
- field.depth = field.path.length;
538
+ // `curateFieldSpecification` answers everything but the field's
539
+ // place in the tree; the key it was filed under is what gives it one.
540
+ const path = fieldName.split("/");
541
+ const field = {
542
+ ...result.fieldSpec,
543
+ depth: path.length,
544
+ path,
545
+ };
373
546
  if (field.depth > maxDepth) {
374
547
  maxDepth = field.depth;
375
548
  }
376
- if (!fields[field.depth]) {
377
- fields[field.depth] = [];
378
- }
379
- fields[field.depth].push(field);
549
+ const sameDepth = (fields[_a = field.depth] ?? (fields[_a] = []));
550
+ sameDepth.push(field);
380
551
  }
381
552
  }
382
553
  catch (error) {
@@ -388,18 +559,15 @@ class Validation {
388
559
  return { errors, isValid: false };
389
560
  }
390
561
  if (Object.keys(fields).length > 0) {
391
- return curateStructuredFields(this.typeAllowsChildren, fields, maxDepth);
562
+ return (0, validationUtils_1.curateStructuredFields)(this.typeAllowsChildren, fields, maxDepth);
392
563
  }
393
564
  return {};
394
565
  }
395
566
  /**
396
- * @param {FieldSpecification} fieldSpec
397
- * @param {string} indexName
398
- * @param {string} collectionName
399
- * @param {string} fieldName
400
- * @param {boolean} [verboseErrors]
401
- * @returns {object}
402
- * @throws PreconditionError
567
+ * Fills a field specification's defaults in and hands its `typeOptions` to
568
+ * the type that owns them.
569
+ *
570
+ * @throws {PreconditionError}
403
571
  */
404
572
  curateFieldSpecification(fieldSpec, indexName, collectionName, fieldName, verboseErrors = false) {
405
573
  const errors = [];
@@ -407,45 +575,42 @@ class Validation {
407
575
  if (result.isValid === false) {
408
576
  return result;
409
577
  }
410
- _.defaultsDeep(fieldSpec, {
411
- mandatory: false,
412
- multivalued: {
413
- value: false,
414
- },
415
- });
416
- if (!has(fieldSpec, "typeOptions")) {
417
- fieldSpec.typeOptions = {};
418
- }
419
- const allowed = this.types[fieldSpec.type].allowedTypeOptions || [];
420
- if (!checkAllowedProperties(fieldSpec.typeOptions, allowed)) {
578
+ // Built rather than `defaultsDeep`-ed in place: the defaults are what turn
579
+ // a submitted field into a curated one, and saying so is what lets the
580
+ // return type be `UnplacedCuratedField` instead of the submitted shape.
581
+ const curated = {
582
+ ...fieldSpec,
583
+ mandatory: fieldSpec.mandatory ?? false,
584
+ multivalued: { value: false, ...fieldSpec.multivalued },
585
+ typeOptions: fieldSpec.typeOptions ?? {},
586
+ };
587
+ const allowed = this.typeOf(curated.type).allowedTypeOptions || [];
588
+ if (!(0, validationUtils_1.checkAllowedProperties)(curated.typeOptions, allowed)) {
421
589
  throwOrStoreError(assertionError.get("unexpected_properties", `${indexName}.${collectionName}.${fieldName}`, allowed.join(", ")), verboseErrors, errors);
422
590
  }
423
591
  try {
424
- fieldSpec.typeOptions = this.types[fieldSpec.type].validateFieldSpecification(fieldSpec.typeOptions);
592
+ curated.typeOptions = this.typeOf(curated.type).validateFieldSpecification(curated.typeOptions);
425
593
  }
426
594
  catch (e) {
595
+ const cause = e instanceof Error ? e : new Error(messageOf(e));
427
596
  if (!verboseErrors) {
428
- if (e instanceof KuzzleError) {
597
+ if (e instanceof errors_1.KuzzleError) {
429
598
  throw e;
430
599
  }
431
- throw kerror.getFrom(e, "plugin", "runtime", "unexpected_error", e.message);
600
+ throw kerror.getFrom(cause, "plugin", "runtime", "unexpected_error", cause.message);
432
601
  }
433
- errors.push(e.message);
602
+ errors.push(cause.message);
434
603
  }
435
604
  if (errors.length > 0) {
436
605
  return { errors, isValid: false };
437
606
  }
438
- debug("Loaded field validator: %s/%s/%s: %o", indexName, collectionName, fieldName, fieldSpec);
439
- return { fieldSpec, isValid: true };
607
+ debug("Loaded field validator: %s/%s/%s: %o", indexName, collectionName, fieldName, curated);
608
+ return { fieldSpec: curated, isValid: true };
440
609
  }
441
610
  /**
442
- * @param {FieldSpecification} fieldSpec
443
- * @param {string} indexName
444
- * @param {string} collectionName
445
- * @param {string} fieldName
446
- * @param {boolean} [verboseErrors]
447
- * @returns {object}
448
- * @throws PreconditionError
611
+ * Checks a field specification's shape, before any type is consulted.
612
+ *
613
+ * @throws {PreconditionError}
449
614
  */
450
615
  curateFieldSpecificationFormat(fieldSpec, indexName, collectionName, fieldName, verboseErrors = false) {
451
616
  const errors = [];
@@ -457,49 +622,24 @@ class Validation {
457
622
  "multivalued",
458
623
  "typeOptions",
459
624
  ];
460
- if (!checkAllowedProperties(fieldSpec, props)) {
625
+ if (!(0, validationUtils_1.checkAllowedProperties)(fieldSpec, props)) {
461
626
  throwOrStoreError(assertionError.get("unexpected_properties", `${indexName}.${collectionName}.${fieldName}`, props.join(", ")), verboseErrors, errors);
462
627
  }
463
- if (!has(fieldSpec, "type")) {
628
+ if (!(0, safeObject_1.has)(fieldSpec, "type")) {
464
629
  throwOrStoreError(assertionError.get("missing_type", `${indexName}.${collectionName}.${fieldName}`), verboseErrors, errors);
465
630
  }
466
- if (!has(this.types, fieldSpec.type)) {
631
+ if (!(0, safeObject_1.has)(this.types, fieldSpec.type)) {
467
632
  throwOrStoreError(assertionError.get("unknown_type", `${indexName}.${collectionName}.${fieldName}`, fieldSpec.type), verboseErrors, errors);
468
633
  }
469
- if (has(fieldSpec, "multivalued")) {
470
- const multivaluedProps = ["value", "minCount", "maxCount"];
471
- if (!checkAllowedProperties(fieldSpec.multivalued, multivaluedProps)) {
472
- throwOrStoreError(assertionError.get("unexpected_properties", `${indexName}.${collectionName}.${fieldName}.multivalued`, multivaluedProps.join(", ")), verboseErrors, errors);
473
- }
474
- if (!has(fieldSpec.multivalued, "value")) {
475
- throwOrStoreError(assertionError.get("missing_value", `${indexName}.${collectionName}.${fieldName}.multivalued`), verboseErrors, errors);
476
- }
477
- if (typeof fieldSpec.multivalued.value !== "boolean") {
478
- throwOrStoreError(assertionError.get("invalid_type", `${indexName}.${collectionName}.${fieldName}.multivalued.value`, "boolean"), verboseErrors, errors);
479
- }
480
- for (const unexpected of ["minCount", "maxCount"]) {
481
- if (!fieldSpec.multivalued.value &&
482
- has(fieldSpec.multivalued, unexpected)) {
483
- throwOrStoreError(assertionError.get("not_multivalued", `${indexName}.${collectionName}.${fieldName}`, unexpected), verboseErrors, errors);
484
- }
485
- }
486
- if (has(fieldSpec.multivalued, "minCount") &&
487
- has(fieldSpec.multivalued, "maxCount") &&
488
- fieldSpec.multivalued.minCount > fieldSpec.multivalued.maxCount) {
489
- throwOrStoreError(assertionError.get("invalid_range", `${indexName}.${collectionName}.${fieldName}`, "minCount", "maxCount"), verboseErrors, errors);
490
- }
491
- }
634
+ checkMultivaluedSpecification(fieldSpec, indexName, collectionName, fieldName, verboseErrors, errors);
492
635
  if (errors.length > 0) {
493
636
  return { errors, isValid: false };
494
637
  }
495
638
  return { isValid: true };
496
639
  }
497
640
  /**
498
- * @param {string} indexName
499
- * @param {string} collectionName
500
- * @param {*} validatorFilter
501
- * @param {boolean} dryRun
502
- * @returns {string}
641
+ * Registers a collection's validators as a Koncorde filter and answers its
642
+ * id — or validates it and answers `null`, on a dry run.
503
643
  */
504
644
  curateValidatorFilter(indexName, collectionName, validatorFilter, dryRun) {
505
645
  const query = {
@@ -510,12 +650,17 @@ class Validation {
510
650
  this.koncorde.validate(query);
511
651
  if (!dryRun) {
512
652
  debug("Registering filter validator %s/%s: %O", indexName, collectionName, query);
513
- return this.koncorde.register(query, toKoncordeIndex(indexName, collectionName));
653
+ return this.koncorde.register(query, (0, koncordeCompat_1.toKoncordeIndex)(indexName, collectionName));
514
654
  }
515
655
  return null;
516
656
  }
517
657
  /**
518
- * @param {ValidationType} validationType
658
+ * Registers a validation type, built-in or plugin-provided.
659
+ *
660
+ * This is public API: `pluginContext` hands it to every plugin, so the
661
+ * runtime assertions below are the contract and stay exactly as they were —
662
+ * a plugin's type is not checked by the compiler.
663
+ *
519
664
  * @throws {PluginImplementationError}
520
665
  */
521
666
  addType(validationType) {
@@ -530,7 +675,7 @@ class Validation {
530
675
  typeof validationType.validateFieldSpecification !== "function") {
531
676
  throw kerror.get("validation", "types", "missing_function", validationType.typeName, "validateFieldSpecification");
532
677
  }
533
- if (has(validationType, "allowChildren") && validationType.allowChildren) {
678
+ if ((0, safeObject_1.has)(validationType, "allowChildren") && validationType.allowChildren) {
534
679
  if (!validationType.getStrictness ||
535
680
  typeof validationType.getStrictness !== "function") {
536
681
  throw kerror.get("validation", "types", "missing_function", validationType.typeName, "getStrictness");
@@ -542,151 +687,64 @@ class Validation {
542
687
  }
543
688
  this.types[validationType.typeName] = validationType;
544
689
  }
545
- }
546
- /**
547
- * @param {*} object
548
- * @param {string[]} allowedProperties
549
- * @returns {boolean}
550
- */
551
- function checkAllowedProperties(object, allowedProperties) {
552
- if (!isPlainObject(object)) {
553
- return false;
690
+ /**
691
+ * The validation type a curated field declares.
692
+ *
693
+ * Every caller reaches this through a field that `curateFieldSpecification`
694
+ * has been through, and that method refuses a `type` the map does not hold —
695
+ * so the throw here is the invariant restated where the compiler can see it,
696
+ * not a new failure mode.
697
+ *
698
+ * @throws {PreconditionError} when the type is not registered
699
+ */
700
+ typeOf(typeName) {
701
+ const type = this.types[typeName];
702
+ if (type === undefined) {
703
+ throw kerror.get("validation", "types", "missing_type_name", typeName);
704
+ }
705
+ return type;
554
706
  }
555
- return !Object.keys(object).some((propertyName) => !allowedProperties.includes(propertyName));
556
707
  }
557
708
  /**
558
- * @param {string[]} typeAllowsChildren
559
- * @param {StructuredFieldSpecification[][]} fields
560
- * @param {number} maxDepth : depth of the fields; counting starts at 1
561
- * @throws PreconditionError
709
+ * Checks a field's `multivalued` block. Lifted verbatim out of
710
+ * `curateFieldSpecificationFormat`, whose cognitive complexity the `.js` → `.ts`
711
+ * rename re-scored as new code.
562
712
  */
563
- function curateStructuredFields(typeAllowsChildren, fields, maxDepth) {
564
- const /** @type StructuredFieldSpecification */ structuredFields = {
565
- children: {},
566
- root: true,
567
- };
568
- for (let i = 1; i <= maxDepth; i++) {
569
- if (!has(fields, i)) {
570
- throw assertionError.get("missing_nested_spec");
571
- }
572
- fields[i].forEach((field) => {
573
- const parent = getParent(structuredFields, field.path), childKey = field.path[field.path.length - 1];
574
- if (!parent.root && typeAllowsChildren.indexOf(parent.type) === -1) {
575
- throw assertionError.get("unexpected_children", parent.type);
576
- }
577
- if (!has(parent, "children")) {
578
- parent.children = {};
579
- }
580
- parent.children[childKey] = field;
581
- });
713
+ function checkMultivaluedSpecification(fieldSpec, indexName, collectionName, fieldName, verboseErrors, errors) {
714
+ const multivalued = fieldSpec.multivalued;
715
+ if (multivalued === undefined) {
716
+ return;
582
717
  }
583
- return structuredFields;
584
- }
585
- /**
586
- * @param {StructuredFieldSpecification} structuredFields
587
- * @param {string[]}fieldPath
588
- * @returns {StructuredFieldSpecification}
589
- */
590
- function getParent(structuredFields, fieldPath) {
591
- if (fieldPath.length === 1) {
592
- return structuredFields;
718
+ const multivaluedProps = ["value", "minCount", "maxCount"];
719
+ if (!(0, validationUtils_1.checkAllowedProperties)(multivalued, multivaluedProps)) {
720
+ throwOrStoreError(assertionError.get("unexpected_properties", `${indexName}.${collectionName}.${fieldName}.multivalued`, multivaluedProps.join(", ")), verboseErrors, errors);
593
721
  }
594
- let pointer = structuredFields;
595
- for (let i = 0; i < fieldPath.length - 1; i++) {
596
- if (!has(pointer.children, fieldPath[i])) {
597
- throw assertionError.get("missing_parent", fieldPath.join("."));
722
+ if (!(0, safeObject_1.has)(multivalued, "value")) {
723
+ throwOrStoreError(assertionError.get("missing_value", `${indexName}.${collectionName}.${fieldName}.multivalued`), verboseErrors, errors);
724
+ }
725
+ if (typeof multivalued.value !== "boolean") {
726
+ throwOrStoreError(assertionError.get("invalid_type", `${indexName}.${collectionName}.${fieldName}.multivalued.value`, "boolean"), verboseErrors, errors);
727
+ }
728
+ for (const unexpected of ["minCount", "maxCount"]) {
729
+ if (!multivalued.value && (0, safeObject_1.has)(multivalued, unexpected)) {
730
+ throwOrStoreError(assertionError.get("not_multivalued", `${indexName}.${collectionName}.${fieldName}`, unexpected), verboseErrors, errors);
598
731
  }
599
- pointer = pointer.children[fieldPath[i]];
600
732
  }
601
- return pointer;
733
+ if (multivalued.minCount !== undefined &&
734
+ multivalued.maxCount !== undefined &&
735
+ multivalued.minCount > multivalued.maxCount) {
736
+ throwOrStoreError(assertionError.get("invalid_range", `${indexName}.${collectionName}.${fieldName}`, "minCount", "maxCount"), verboseErrors, errors);
737
+ }
602
738
  }
603
739
  /**
604
- * @param {KuzzleError} error
605
- * @param {boolean} doNotThrow
606
- * @param {string[]} errors
740
+ * Rethrows, or collects the message — the single place the verbose/fail-fast
741
+ * choice is made during curation.
607
742
  */
608
743
  function throwOrStoreError(error, doNotThrow, errorMessages) {
609
744
  if (!doNotThrow) {
610
745
  throw error;
611
746
  }
612
- errorMessages.push(error.message);
613
- }
614
- /**
615
- * @param {string|string[]} errorContext
616
- * @param {string[]|{documentScope:string[], fieldScope: {children: ...*}}} errorHolder
617
- * @param {string} message
618
- * @param {boolean} structured
619
- */
620
- function manageErrorMessage(errorContext, errorHolder, message, structured) {
621
- if (structured) {
622
- if (errorContext === "document") {
623
- if (!errorHolder.documentScope) {
624
- errorHolder.documentScope = [];
625
- }
626
- errorHolder.documentScope.push(message);
627
- }
628
- else {
629
- if (!errorHolder.fieldScope) {
630
- errorHolder.fieldScope = {};
631
- }
632
- let pointer = errorHolder.fieldScope;
633
- for (let i = 0; i < errorContext.length; i++) {
634
- if (!pointer.children) {
635
- pointer.children = {};
636
- }
637
- if (!has(pointer.children, errorContext[i])) {
638
- pointer.children[errorContext[i]] = {};
639
- }
640
- pointer = pointer.children[errorContext[i]];
641
- }
642
- if (!has(pointer, "messages")) {
643
- pointer.messages = [];
644
- }
645
- pointer.messages.push(message);
646
- }
647
- }
648
- else if (errorContext === "document") {
649
- throw kerror.get("validation", "check", "failed_document", message);
650
- }
651
- else {
652
- throw kerror.get("validation", "check", "failed_field", errorContext.join("."), message);
653
- }
654
- }
655
- /**
656
- * Retrieve the plugins list from the database and returns it,
657
- * along with their configuration
658
- *
659
- * @returns {Promise}
660
- */
661
- function getValidationConfiguration() {
662
- return global.kuzzle.internalIndex
663
- .search("validations", {}, { from: 0, size: 1000 })
664
- .then((result) => {
665
- let validation = {};
666
- if (result && Array.isArray(result.hits) && result.hits.length > 0) {
667
- for (const { _source, _id } of result.hits) {
668
- const collectionName = `${_id.split("#")[0]}/${_id.split("#")[1]}`;
669
- if (!get(_source, "index")) {
670
- throw assertionError.get("incorrect_validation_format", collectionName, "index");
671
- }
672
- if (!get(_source, "collection")) {
673
- throw assertionError.get("incorrect_validation_format", collectionName, "collection");
674
- }
675
- if (!get(_source, "validation")) {
676
- throw assertionError.get("incorrect_validation_format", collectionName, "validation");
677
- }
678
- if (!has(validation, _source.index)) {
679
- validation[_source.index] = {};
680
- }
681
- validation[_source.index][_source.collection] = _source.validation;
682
- }
683
- }
684
- else if (global.kuzzle.config.validation) {
685
- // We can't wait prepareDb as it runs outside of the rest of the start
686
- validation = global.kuzzle.config.validation;
687
- }
688
- return validation;
689
- });
747
+ errorMessages.push(messageOf(error));
690
748
  }
691
749
  module.exports = Validation;
692
750
  //# sourceMappingURL=validation.js.map