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,31 +19,75 @@
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 Deque = require("denque");
24
- const Cookie = require("cookie");
25
- const kuzzleStateEnum = require("../kuzzle/kuzzleStateEnum");
26
- const { KuzzleError } = require("../kerror/errors");
27
- const { AdminController, AuthController, BulkController, ClusterController, CollectionController, DebugController, DocumentController, IndexController, MemoryStorageController, RealtimeController, SecurityController, ServerController, } = require("./controllers");
28
- const { documentEventAliases } = require("../config/documentEventAliases");
29
- const DocumentExtractor = require("./documentExtractor");
30
- const sdkCompatibility = require("../config/sdkCompatibility");
31
- const RateLimiter = require("./rateLimiter");
32
- const kerror = require("../kerror");
33
- const debug = require("../util/debug")("kuzzle:funnel");
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 bluebird_1 = __importDefault(require("bluebird"));
49
+ const denque_1 = __importDefault(require("denque"));
50
+ const Cookie = __importStar(require("cookie"));
51
+ const get_1 = __importDefault(require("lodash/get"));
52
+ const kuzzleStateEnum_1 = __importDefault(require("../kuzzle/kuzzleStateEnum"));
53
+ const errors_1 = require("../kerror/errors");
54
+ const controllers_1 = __importDefault(require("./controllers"));
55
+ const documentEventAliases_1 = require("../config/documentEventAliases");
56
+ const documentExtractor_1 = __importDefault(require("./documentExtractor"));
57
+ const sdkCompatibility_json_1 = __importDefault(require("../config/sdkCompatibility.json"));
58
+ const rateLimiter_1 = __importDefault(require("./rateLimiter"));
59
+ const kerror = __importStar(require("../kerror"));
60
+ const debug_1 = __importDefault(require("../util/debug"));
61
+ const thrown_1 = require("../util/thrown");
62
+ const safeObject_1 = require("../util/safeObject");
63
+ const types_1 = require("../types");
64
+ const { AdminController, AuthController, BulkController, ClusterController, CollectionController, DebugController, DocumentController, IndexController, MemoryStorageController, RealtimeController, SecurityController, ServerController, } = controllers_1.default;
65
+ const debug = (0, debug_1.default)("kuzzle:funnel");
34
66
  const processError = kerror.wrap("api", "process");
35
- const { has } = require("../util/safeObject");
36
- const { HttpStream } = require("../types");
37
- const get = require("lodash/get");
38
67
  // Actions of the auth controller that does not necessite to verify the token
39
68
  // when cookie auth is active
40
- const SKIP_TOKEN_VERIF_ACTIONS = ["login", "checkToken", "logout"];
69
+ const SKIP_TOKEN_VERIF_ACTIONS = new Set(["login", "checkToken", "logout"]);
70
+ /**
71
+ * The controller and action a request names.
72
+ *
73
+ * `RequestInput` leaves both `null` until they are set, and ten sites below
74
+ * — the event names, the document alias table, the `Reflect.get` that
75
+ * dispatches — read them as strings. A request naming neither is what
76
+ * `controller_not_found` has always been for, and it was raised at the bottom
77
+ * of `getController` and nowhere else.
78
+ */
79
+ function targetOf(request) {
80
+ const { action, controller } = request.input;
81
+ if (controller === null) {
82
+ throw processError.get("controller_not_found", controller);
83
+ }
84
+ if (action === null) {
85
+ throw processError.get("action_not_found", controller, action);
86
+ }
87
+ return { action, controller };
88
+ }
41
89
  /**
42
90
  * @class PendingRequest
43
- * @param {Request} request
44
- * @param {Function} fn
45
- * @param {Object} context
46
91
  */
47
92
  class PendingRequest {
48
93
  constructor(request, fn, context) {
@@ -59,15 +104,15 @@ class Funnel {
59
104
  this.overloaded = false;
60
105
  this.concurrentRequests = 0;
61
106
  this.controllers = new Map();
62
- this.pendingRequestsQueue = new Deque();
107
+ this.pendingRequestsQueue = new denque_1.default();
63
108
  this.pendingRequestsById = new Map();
64
109
  this.lastOverloadTime = 0;
65
110
  this.overloadWarned = false;
66
111
  this.lastWarningTime = 0;
67
- this.rateLimiter = new RateLimiter();
112
+ this.rateLimiter = new rateLimiter_1.default();
68
113
  this.lastDumpedErrors = {};
69
- this.loadDocumentEventAliases();
70
- this.sdkCompatibility = sdkCompatibility;
114
+ this.sdkCompatibility = sdkCompatibility_json_1.default;
115
+ this.documentEventAliases = this.loadDocumentEventAliases();
71
116
  this.logger = global.kuzzle.log.child("api:funnel");
72
117
  }
73
118
  init() {
@@ -85,7 +130,7 @@ class Funnel {
85
130
  */
86
131
  global.kuzzle.onAsk("kuzzle:api:funnel:metrics", () => this.metrics());
87
132
  this.rateLimiter.init();
88
- this.controllers.set("auth", new AuthController.default());
133
+ this.controllers.set("auth", new AuthController());
89
134
  this.controllers.set("bulk", new BulkController());
90
135
  this.controllers.set("cluster", new ClusterController());
91
136
  this.controllers.set("collection", new CollectionController());
@@ -93,23 +138,46 @@ class Funnel {
93
138
  this.controllers.set("document", new DocumentController());
94
139
  this.controllers.set("index", new IndexController());
95
140
  this.controllers.set("realtime", new RealtimeController());
96
- this.controllers.set("security", new SecurityController.default());
141
+ this.controllers.set("security", new SecurityController());
97
142
  this.controllers.set("server", new ServerController());
98
- this.controllers.set("admin", new AdminController.default());
143
+ this.controllers.set("admin", new AdminController());
99
144
  const msController = new MemoryStorageController();
100
145
  this.controllers.set("memoryStorage", msController);
101
146
  this.controllers.set("ms", msController);
102
- const initPromises = Array.from(this.controllers.keys()).map((ctrl) => this.controllers.get(ctrl).init());
103
- return Bluebird.all(initPromises);
147
+ const initPromises = Array.from(this.controllers.values()).map((controller) => controller.init());
148
+ return bluebird_1.default.all(initPromises);
104
149
  }
150
+ /**
151
+ * Answers the table rather than assigning it: a field set by a method the
152
+ * constructor calls is not one the compiler can see being initialised.
153
+ */
105
154
  loadDocumentEventAliases() {
106
- this.documentEventAliases = documentEventAliases;
107
- this.documentEventAliases.mirrorList = {};
108
- Object.keys(documentEventAliases.list).forEach((alias) => {
109
- documentEventAliases.list[alias].forEach((aliasOf) => {
110
- this.documentEventAliases.mirrorList[aliasOf] = alias;
111
- });
112
- });
155
+ const aliases = documentEventAliases_1.documentEventAliases;
156
+ aliases.mirrorList = {};
157
+ for (const [alias, aliasedActions] of Object.entries(documentEventAliases_1.documentEventAliases.list)) {
158
+ for (const aliasOf of aliasedActions) {
159
+ aliases.mirrorList[aliasOf] = alias;
160
+ }
161
+ }
162
+ return aliases;
163
+ }
164
+ /**
165
+ * Emits the "core:overload" event and logs a warning when the pending-request
166
+ * queue crosses its warning threshold — rate-limited to once per 500ms.
167
+ */
168
+ _warnOverload() {
169
+ const now = Date.now();
170
+ if (this.pendingRequestsQueue.length <=
171
+ global.kuzzle.config.limits.requestsBufferWarningThreshold ||
172
+ (this.lastWarningTime !== 0 && this.lastWarningTime >= now - 500)) {
173
+ return;
174
+ }
175
+ const overloadPercentage = Math.round((10000 * this.pendingRequestsQueue.length) /
176
+ global.kuzzle.config.limits.requestsBufferSize) / 100;
177
+ global.kuzzle.emit("core:overload", overloadPercentage);
178
+ this.logger.warn(`[!WARNING!] Kuzzle overloaded: ${overloadPercentage}%. Delaying requests...`);
179
+ this.overloadWarned = true;
180
+ this.lastWarningTime = now;
113
181
  }
114
182
  /**
115
183
  * Asks the overload-protection system for an execution slot.
@@ -137,25 +205,15 @@ class Funnel {
137
205
  * immediately executed or not.
138
206
  */
139
207
  throttle(fn, context, request) {
140
- if (global.kuzzle.state === kuzzleStateEnum.SHUTTING_DOWN) {
208
+ if (global.kuzzle.state === kuzzleStateEnum_1.default.SHUTTING_DOWN) {
141
209
  throw processError.get("shutting_down");
142
210
  }
143
- if (global.kuzzle.state === kuzzleStateEnum.NOT_ENOUGH_NODES) {
211
+ if (global.kuzzle.state === kuzzleStateEnum_1.default.NOT_ENOUGH_NODES) {
144
212
  throw processError.get("not_enough_nodes");
145
213
  }
146
- const isRequestFromDebugSession = get(request, "context.connection.misc.internal.debugSession", false);
214
+ const isRequestFromDebugSession = (0, get_1.default)(request, "context.connection.misc.internal.debugSession", false);
147
215
  if (this.overloaded) {
148
- const now = Date.now();
149
- if (this.pendingRequestsQueue.length >
150
- global.kuzzle.config.limits.requestsBufferWarningThreshold &&
151
- (this.lastWarningTime === 0 || this.lastWarningTime < now - 500)) {
152
- const overloadPercentage = Math.round((10000 * this.pendingRequestsQueue.length) /
153
- global.kuzzle.config.limits.requestsBufferSize) / 100;
154
- global.kuzzle.emit("core:overload", overloadPercentage);
155
- this.logger.warn(`[!WARNING!] Kuzzle overloaded: ${overloadPercentage}%. Delaying requests...`);
156
- this.overloadWarned = true;
157
- this.lastWarningTime = now;
158
- }
216
+ this._warnOverload();
159
217
  }
160
218
  if (this.concurrentRequests < global.kuzzle.config.limits.concurrentRequests) {
161
219
  if (this.pendingRequestsById.has(request.internalId)) {
@@ -223,11 +281,11 @@ class Funnel {
223
281
  * @returns {Number} -1: request delayed, 0: request processing, 1: error
224
282
  */
225
283
  execute(request, callback) {
226
- if (!request.input.controller || !request.input.controller.length) {
284
+ if (!request.input.controller?.length) {
227
285
  callback(kerror.get("api", "assert", "missing_argument", "controller"), request);
228
286
  return 1;
229
287
  }
230
- if (!request.input.action || !request.input.action.length) {
288
+ if (!request.input.action?.length) {
231
289
  callback(kerror.get("api", "assert", "missing_argument", "action"), request);
232
290
  return 1;
233
291
  }
@@ -243,88 +301,107 @@ class Funnel {
243
301
  return 1;
244
302
  }
245
303
  if (request.input.headers &&
246
- has(request.input.headers, "origin") &&
304
+ (0, safeObject_1.has)(request.input.headers, "origin") &&
247
305
  !this._isOriginAuthorized(request.input.headers.origin)) {
248
306
  debug("Reject request, unauthorized origin %s", request.input.headers.origin);
249
307
  return this._executeError(kerror.get("api", "process", "unauthorized_origin", request.input.headers.origin), request, true, callback);
250
308
  }
251
309
  try {
252
- const executing = this.throttle((req) => {
253
- // if the connection is closed there is no need to execute the request
254
- // => discarding it
255
- if (!global.kuzzle.router.isConnectionAlive(req.context)) {
256
- debug("Client connection dead: dropping request: %a", req.input);
257
- callback(processError.get("connection_dropped"), req);
258
- return;
259
- }
260
- debug("Starting request %s:%s [%s]: %j", req.input.controller, req.input.action, req.id, req.input);
261
- global.kuzzle.asyncStore.run(() => {
262
- global.kuzzle.asyncStore.set("REQUEST", req);
263
- global.kuzzle
264
- .pipe("request:beforeExecution", req)
265
- .then((modifiedRequest) => {
266
- let _request;
267
- return this.checkRights(modifiedRequest)
268
- .then((newModifiedRequest) => {
269
- _request = newModifiedRequest;
270
- return this.rateLimiter.isAllowed(_request);
271
- })
272
- .then((allowed) => {
273
- if (!allowed) {
274
- if (request.input.controller === "auth" &&
275
- request.input.action === "login") {
276
- throw processError.get("too_many_logins_requests");
277
- }
278
- throw processError.get("too_many_requests");
279
- }
280
- return this.processRequest(_request);
281
- })
282
- .then((processResult) => {
283
- debug("Request %s successfully executed. Result: %a", modifiedRequest.id, processResult);
284
- return global.kuzzle
285
- .pipe("request:afterExecution", {
286
- request: _request,
287
- result: processResult,
288
- success: true,
289
- })
290
- .then((pipeEvent) => {
291
- callback(null, pipeEvent.result);
292
- // disables a bluebird warning in dev. mode triggered when
293
- // a promise is created and not returned
294
- return null;
295
- });
296
- })
297
- .catch((err) => {
298
- debug("Error processing request %s: %a", modifiedRequest.id, err);
299
- return global.kuzzle
300
- .pipe("request:afterExecution", {
301
- error: err,
302
- request: modifiedRequest,
303
- success: false,
304
- })
305
- .then((pipeEvent) => this._executeError(pipeEvent.error, pipeEvent.request, true, callback));
306
- });
307
- })
308
- .catch((err) => {
309
- debug("Error processing request %s: %a", req.id, err);
310
- return global.kuzzle
311
- .pipe("request:afterExecution", {
312
- error: err,
313
- request: req,
314
- success: false,
315
- })
316
- .then((pipeEvent) => this._executeError(pipeEvent.error, pipeEvent.request, true, callback));
317
- });
318
- });
319
- }, this, request);
310
+ const executing = this.throttle((req) => this._executeThrottled(req, callback), this, request);
320
311
  return executing ? 0 : -1;
321
312
  }
322
313
  catch (error) {
323
- request.setError(error);
324
- callback(error, request);
314
+ const cause = (0, thrown_1.causeOf)(error);
315
+ request.setError(cause);
316
+ callback(cause, request);
325
317
  return 1;
326
318
  }
327
319
  }
320
+ /**
321
+ * Runs a request that has been granted an execution slot by the
322
+ * overload-protection system. Extracted from `execute` verbatim.
323
+ *
324
+ * @param request - the very request `execute` handed to `throttle`
325
+ */
326
+ _executeThrottled(request, callback) {
327
+ // if the connection is closed there is no need to execute the request
328
+ // => discarding it
329
+ if (!global.kuzzle.router.isConnectionAlive(request.context)) {
330
+ debug("Client connection dead: dropping request: %a", request.input);
331
+ callback(processError.get("connection_dropped"), request);
332
+ return;
333
+ }
334
+ debug("Starting request %s:%s [%s]: %j", request.input.controller, request.input.action, request.id, request.input);
335
+ global.kuzzle.asyncStore.run(() => {
336
+ global.kuzzle.asyncStore.set("REQUEST", request);
337
+ global.kuzzle
338
+ .pipe("request:beforeExecution", request)
339
+ .then((modifiedRequest) => this._dispatch(request, modifiedRequest, callback))
340
+ .catch((err) => {
341
+ debug("Error processing request %s: %a", request.id, err);
342
+ return this._reportExecutionError(err, request, callback);
343
+ });
344
+ });
345
+ }
346
+ /**
347
+ * Rights check -> rate limit -> controller action, then reports the outcome
348
+ * through `callback`. Extracted from `execute` verbatim.
349
+ *
350
+ * @param request - the original request (the rate-limit branch inspects it,
351
+ * not the pipe-modified one)
352
+ * @param modifiedRequest - the "request:beforeExecution" pipe result
353
+ */
354
+ _dispatch(request, modifiedRequest, callback) {
355
+ let _request;
356
+ return this.checkRights(modifiedRequest)
357
+ .then((newModifiedRequest) => {
358
+ _request = newModifiedRequest;
359
+ return this.rateLimiter.isAllowed(_request);
360
+ })
361
+ .then((allowed) => {
362
+ if (!allowed) {
363
+ if (request.input.controller === "auth" &&
364
+ request.input.action === "login") {
365
+ throw processError.get("too_many_logins_requests");
366
+ }
367
+ throw processError.get("too_many_requests");
368
+ }
369
+ return this.processRequest(_request);
370
+ })
371
+ .then((processResult) => {
372
+ debug("Request %s successfully executed. Result: %a", modifiedRequest.id, processResult);
373
+ return global.kuzzle
374
+ .pipe("request:afterExecution", {
375
+ request: _request,
376
+ result: processResult,
377
+ success: true,
378
+ })
379
+ .then((pipeEvent) => {
380
+ callback(null, pipeEvent.result);
381
+ // disables a bluebird warning in dev. mode triggered when
382
+ // a promise is created and not returned
383
+ return null;
384
+ });
385
+ })
386
+ .catch((err) => {
387
+ debug("Error processing request %s: %a", modifiedRequest.id, err);
388
+ return this._reportExecutionError(err, modifiedRequest, callback);
389
+ });
390
+ }
391
+ /**
392
+ * Fires "request:afterExecution" in failure mode, then reports the (possibly
393
+ * pipe-rewritten) error through `callback`. Extracted from `execute` verbatim
394
+ * — both of its catch blocks did exactly this.
395
+ */
396
+ _reportExecutionError(error, request, callback) {
397
+ return global.kuzzle
398
+ .pipe("request:afterExecution", {
399
+ error,
400
+ request,
401
+ success: false,
402
+ })
403
+ .then((pipeEvent) => this._executeError(pipeEvent.error, pipeEvent.request, true, callback));
404
+ }
328
405
  /**
329
406
  * Checks if an error is worth dumping Kuzzle. If so,
330
407
  * creates a dump.
@@ -336,27 +413,36 @@ class Funnel {
336
413
  if (global.kuzzle.config.dump.enabled && handledErrors.enabled) {
337
414
  setImmediate(() => {
338
415
  const errorType = typeof err === "object" && err.name ? err.name : typeof err;
339
- if (handledErrors.whitelist.indexOf(errorType) > -1) {
416
+ if (handledErrors.whitelist.includes(errorType)) {
340
417
  const now = Date.now();
341
418
  // JSON.stringify(new NativeError()) === '{}'
342
419
  // i.e. Error, SyntaxError, TypeError, ReferenceError, etc.
343
- this.logger.error(err instanceof Error && !(err instanceof KuzzleError)
420
+ this.logger.error(err instanceof Error && !(err instanceof errors_1.KuzzleError)
344
421
  ? `${err.message}\n${err.stack}`
345
422
  : err);
346
- if (!this.lastDumpedErrors[errorType] ||
347
- this.lastDumpedErrors[errorType] < now - handledErrors.minInterval) {
423
+ const lastDumped = this.lastDumpedErrors[errorType];
424
+ if (!lastDumped || lastDumped < now - handledErrors.minInterval) {
348
425
  // simplify error message to use it in folder dump name
349
- let errorMessage = err.message;
350
- if (errorMessage.indexOf("\n") > -1) {
351
- errorMessage = errorMessage.split("\n")[0];
352
- }
353
- errorMessage = errorMessage
426
+ //
427
+ // `split()[0]` of a string that contains a "\n" is a string; the
428
+ // `includes` guard was the only thing saying so.
429
+ const errorMessage = err.message.split("\n")[0] ?? err.message;
430
+ // The dump generator only accepts `^[A-Za-z0-9_-]{0,64}$` (#2665),
431
+ // so the error type is slugified with the message, and the whole
432
+ // suffix is capped: an error message is usually longer than that.
433
+ const suffix = `handled-${errorType}-${errorMessage}`
354
434
  .toLowerCase()
355
- .replace(/[^a-zA-Z0-9-_]/g, "-")
435
+ .replace(/[^a-z0-9-_]/g, "-")
356
436
  .split("-")
357
437
  .filter((value) => value !== "")
358
- .join("-");
359
- global.kuzzle.dump(`handled-${errorType.toLocaleLowerCase()}-${errorMessage}`);
438
+ .join("-")
439
+ .slice(0, 64);
440
+ // Nothing awaits this dump: a failure has to be handled here, or
441
+ // it surfaces as an unhandled rejection, which stops Kuzzle in
442
+ // development mode.
443
+ global.kuzzle.dump(suffix).catch((error) => {
444
+ this.logger.error(`Unable to dump after a handled error: ${(0, thrown_1.causeOf)(error).message}`);
445
+ });
360
446
  }
361
447
  this.lastDumpedErrors[errorType] = now;
362
448
  }
@@ -374,34 +460,7 @@ class Funnel {
374
460
  request.getBoolean("cookieAuth")) {
375
461
  throw kerror.get("security", "cookie", "unsupported");
376
462
  }
377
- let skipTokenVerification = false;
378
- // When the Support of Cookie as Authentication Token is enabled we check if an auth token cookie is present
379
- // When a request is made with cookieAuth set to true
380
- // We try to use the auth token cookie if present as auth token
381
- // otherwise check for auth token as input
382
- if (request.input.headers && has(request.input.headers, "cookie")) {
383
- let cookie;
384
- try {
385
- cookie = Cookie.parse(request.input.headers.cookie);
386
- }
387
- catch (error) {
388
- throw kerror.get("security", "cookie", "invalid");
389
- }
390
- // if cookie is present and not null, and a token is present we should throw because we don't know which one to use
391
- if (cookie.authToken && cookie.authToken !== "null") {
392
- if (!global.kuzzle.config.http.cookieAuthentication) {
393
- throw kerror.get("security", "cookie", "unsupported");
394
- }
395
- if (request.input.jwt) {
396
- throw kerror.get("security", "token", "verification_error", "Both token and cookie are present, could not decide which one to use");
397
- }
398
- request.input.jwt = cookie.authToken;
399
- skipTokenVerification =
400
- request.getBoolean("cookieAuth") &&
401
- request.input.controller === "auth" &&
402
- SKIP_TOKEN_VERIF_ACTIONS.includes(request.input.action);
403
- }
404
- }
463
+ const skipTokenVerification = this._applyCookieAuthToken(request);
405
464
  try {
406
465
  // If the verification should be skipped, we pass a null token,
407
466
  // this way the verification will be made as anonymous
@@ -412,29 +471,78 @@ class Funnel {
412
471
  await global.kuzzle.pipe("request:onUnauthorized", request);
413
472
  throw error;
414
473
  }
415
- const userId = request.context.token.userId;
416
- request.context.user = await global.kuzzle.ask("core:security:user:get", userId);
474
+ // `request.context` is a getter, so a check on `request.context.token`
475
+ // does not narrow the next read of it. Both are read once here instead.
476
+ const token = request.context.token;
477
+ const userId = token === null ? null : token.userId;
478
+ const user = await global.kuzzle.ask("core:security:user:get", userId);
479
+ request.context.user = user;
417
480
  // If we have a token, link the connection with the token,
418
481
  // this way the connection can be notified when the token has expired.
419
- if (global.kuzzle.config.internal.notifiableProtocols.includes(request.context.connection.protocol)) {
420
- global.kuzzle.tokenManager.link(request.context.token, request.context.connection.id);
482
+ const { id: connectionId, protocol } = request.context.connection;
483
+ if (token !== null &&
484
+ connectionId !== null &&
485
+ protocol !== null &&
486
+ global.kuzzle.config.internal.notifiableProtocols.includes(protocol)) {
487
+ global.kuzzle.tokenManager.link(token, connectionId);
421
488
  }
422
- if (!(await request.context.user.isActionAllowed(request))) {
489
+ if (!(await user.isActionAllowed(request))) {
423
490
  // anonymous user => 401 (Unauthorized) error
424
491
  // logged-in user with insufficient permissions => 403 (Forbidden) error
425
- const error = kerror.get("security", "rights", userId === "-1" ? "unauthorized" : "forbidden", request.input.controller, request.input.action, request.context.user._id);
492
+ const error = kerror.get("security", "rights", userId === "-1" ? "unauthorized" : "forbidden", request.input.controller, request.input.action, user._id);
426
493
  request.setError(error);
427
494
  await global.kuzzle.pipe("request:onUnauthorized", request);
428
495
  throw error;
429
496
  }
430
497
  if (global.kuzzle.config.plugins.common.failsafeMode &&
431
498
  !this._isLogin(request) &&
432
- !request.context.user.profileIds.includes("admin")) {
499
+ !user.profileIds.includes("admin")) {
433
500
  await global.kuzzle.pipe("request:onUnauthorized", request);
434
501
  throw kerror.get("security", "rights", "failsafe_mode_admin_only");
435
502
  }
436
503
  return global.kuzzle.pipe("request:onAuthorized", request);
437
504
  }
505
+ /**
506
+ * When cookie authentication is enabled, promotes the request's auth-token
507
+ * cookie to `request.input.jwt`. Extracted from `checkRights` verbatim.
508
+ *
509
+ * @returns whether token verification must be skipped (anonymous check)
510
+ */
511
+ _applyCookieAuthToken(request) {
512
+ // When the Support of Cookie as Authentication Token is enabled we check if an auth token cookie is present
513
+ // When a request is made with cookieAuth set to true
514
+ // We try to use the auth token cookie if present as auth token
515
+ // otherwise check for auth token as input
516
+ if (!request.input.headers || !(0, safeObject_1.has)(request.input.headers, "cookie")) {
517
+ return false;
518
+ }
519
+ let cookie;
520
+ try {
521
+ cookie = Cookie.parse(request.input.headers.cookie);
522
+ }
523
+ catch {
524
+ throw kerror.get("security", "cookie", "invalid");
525
+ }
526
+ // if cookie is present and not null, and a token is present we should throw because we don't know which one to use
527
+ //
528
+ // `"null"` is the literal string, not a missing value: `auth:logout` used
529
+ // to clear the cookie by serialising `null` into it. It sends an empty
530
+ // value now, and this stays for the cookies already in browsers.
531
+ if (!cookie.authToken || cookie.authToken === "null") {
532
+ return false;
533
+ }
534
+ if (!global.kuzzle.config.http.cookieAuthentication) {
535
+ throw kerror.get("security", "cookie", "unsupported");
536
+ }
537
+ if (request.input.jwt) {
538
+ throw kerror.get("security", "token", "verification_error", "Both token and cookie are present, could not decide which one to use");
539
+ }
540
+ request.input.jwt = cookie.authToken;
541
+ return (request.getBoolean("cookieAuth") &&
542
+ request.input.controller === "auth" &&
543
+ request.input.action !== null &&
544
+ SKIP_TOKEN_VERIF_ACTIONS.has(request.input.action));
545
+ }
438
546
  _isLogin(request) {
439
547
  return (request.input.controller === "auth" && request.input.action === "login");
440
548
  }
@@ -451,24 +559,32 @@ class Funnel {
451
559
  this.concurrentRequests++;
452
560
  let _request = request;
453
561
  try {
454
- await this._checkSdkVersion(_request);
562
+ this._checkSdkVersion(_request);
455
563
  _request = await global.kuzzle.pipe("request:onExecution", _request);
456
564
  _request = await this.performDocumentAlias(_request, "before");
457
565
  _request = await global.kuzzle.pipe(this.getEventName(_request, "before"), _request);
458
- const responseData = await doAction(controller, _request);
459
- _request.setResult(responseData, {
460
- status: _request.status === 102 ? 200 : _request.status,
461
- });
566
+ let responseData;
567
+ try {
568
+ responseData = await doAction(controller, _request);
569
+ }
570
+ catch (e) {
571
+ // Only here is the error known to come from the controller itself:
572
+ // `_wrapError` sits downstream of the pipes too and cannot tell the
573
+ // two apart (TD-27).
574
+ throw this._wrapControllerError(_request, (0, thrown_1.causeOf)(e));
575
+ }
576
+ // No status: a pending 102 becomes 200, any other is kept.
577
+ _request.response.configure({ result: responseData });
462
578
  if (!this.isNativeController(_request.input.controller) &&
463
579
  !_request.response.raw) {
464
580
  // check if the plugin response can be serialized
465
581
  try {
466
- if (!(responseData instanceof HttpStream)) {
582
+ if (!(responseData instanceof types_1.HttpStream)) {
467
583
  JSON.stringify(responseData);
468
584
  }
469
585
  }
470
- catch (e) {
471
- _request.setResult(null);
586
+ catch {
587
+ _request.response.configure({ result: null, status: 200 });
472
588
  throw kerror.get("plugin", "controller", "unserializable_response");
473
589
  }
474
590
  }
@@ -478,7 +594,7 @@ class Funnel {
478
594
  global.kuzzle.statistics.completedRequest(_request);
479
595
  }
480
596
  catch (error) {
481
- return this.handleProcessRequestError(_request, _request, error);
597
+ return this.handleProcessRequestError(_request, _request, (0, thrown_1.causeOf)(error));
482
598
  }
483
599
  finally {
484
600
  this.concurrentRequests--;
@@ -497,16 +613,20 @@ class Funnel {
497
613
  */
498
614
  async performDocumentAlias(request, prefix) {
499
615
  const { controller, action } = request.input;
500
- const mustTrigger = controller === "document" &&
501
- this.documentEventAliases.mirrorList[action] &&
502
- (prefix !== "before" ||
503
- !this.documentEventAliases.notBefore.includes(action));
504
- if (!mustTrigger) {
616
+ if (controller !== "document" || action === null) {
505
617
  return request;
506
618
  }
619
+ // One lookup: the alias is what decides whether to trigger and what to
620
+ // name the event, and it was read twice with the table indexed by a
621
+ // possibly-null action.
507
622
  const alias = this.documentEventAliases.mirrorList[action];
623
+ if (!alias ||
624
+ (prefix === "before" &&
625
+ this.documentEventAliases.notBefore.includes(action))) {
626
+ return request;
627
+ }
508
628
  const event = `${this.documentEventAliases.namespace}:${prefix}${capitalize(alias)}`;
509
- const extractor = new DocumentExtractor(request);
629
+ const extractor = new documentExtractor_1.default(request);
510
630
  const documents = await global.kuzzle.pipe(event, extractor.extract(), request);
511
631
  return extractor.insert(documents);
512
632
  }
@@ -540,7 +660,7 @@ class Funnel {
540
660
  error: error,
541
661
  request: request,
542
662
  result: res,
543
- success: error === undefined ? true : false,
663
+ success: error === undefined,
544
664
  });
545
665
  }
546
666
  }
@@ -548,7 +668,7 @@ class Funnel {
548
668
  return await doAction(this.getController(request), request);
549
669
  }
550
670
  catch (e) {
551
- this.handleErrorDump(e);
671
+ this.handleErrorDump((0, thrown_1.causeOf)(e));
552
672
  throw e;
553
673
  }
554
674
  }
@@ -566,7 +686,7 @@ class Funnel {
566
686
  return updated;
567
687
  }
568
688
  catch (err) {
569
- _error = this._wrapError(request, err);
689
+ _error = this._wrapError(request, (0, thrown_1.causeOf)(err));
570
690
  }
571
691
  // Handling the error thrown by the error pipe
572
692
  modifiedRequest.setError(_error);
@@ -579,7 +699,7 @@ class Funnel {
579
699
  return updated;
580
700
  }
581
701
  catch (err) {
582
- throw this._wrapError(request, err);
702
+ throw this._wrapError(request, (0, thrown_1.causeOf)(err));
583
703
  }
584
704
  }
585
705
  /**
@@ -591,10 +711,9 @@ class Funnel {
591
711
  * @returns {string} event name
592
712
  */
593
713
  getEventName(request, prefix) {
594
- const event = request.input.controller === "memoryStorage"
595
- ? "ms"
596
- : request.input.controller;
597
- return `${event}:${prefix}${capitalize(request.input.action)}`;
714
+ const { action, controller } = targetOf(request);
715
+ const event = controller === "memoryStorage" ? "ms" : controller;
716
+ return `${event}:${prefix}${capitalize(action)}`;
598
717
  }
599
718
  /**
600
719
  * Returns the number of remaining requests
@@ -612,13 +731,18 @@ class Funnel {
612
731
  * @throws {BadRequestError} If the asked controller or action is unknown
613
732
  */
614
733
  getController(request) {
615
- for (const controllers of [
734
+ // `BaseController`, not `NativeController`: the second map holds plugin
735
+ // controllers, which extend the base and not the native one. The narrower
736
+ // return type described half of what this returns.
737
+ const controllerMaps = [
616
738
  this.controllers,
617
739
  global.kuzzle.pluginsManager.controllers,
618
- ]) {
619
- const controller = controllers.get(request.input.controller);
740
+ ];
741
+ const { action, controller: name } = targetOf(request);
742
+ for (const controllers of controllerMaps) {
743
+ const controller = controllers.get(name);
620
744
  if (controller) {
621
- if (controller._isAction(request.input.action)) {
745
+ if (controller._isAction(action)) {
622
746
  return controller;
623
747
  }
624
748
  throw processError.get("action_not_found", request.input.controller, request.input.action);
@@ -631,8 +755,13 @@ class Funnel {
631
755
  * @param {String} controller
632
756
  * @returns {Boolean}
633
757
  */
758
+ /**
759
+ * `string | null`: the two callers ask it of `request.input.controller`,
760
+ * which is null until set. A request naming no controller is not a native
761
+ * one, which is the answer the map already gave.
762
+ */
634
763
  isNativeController(controller) {
635
- return this.controllers.has(controller);
764
+ return controller !== null && this.controllers.has(controller);
636
765
  }
637
766
  /**
638
767
  * Returns inner metrics from the Funnel
@@ -656,8 +785,8 @@ class Funnel {
656
785
  if (!global.kuzzle.config.server.strictSdkVersion) {
657
786
  return;
658
787
  }
659
- const sdkVersion = request.input.volatile && request.input.volatile.sdkVersion;
660
- const sdkName = request.input.volatile && request.input.volatile.sdkName;
788
+ const sdkVersion = request.input.volatile?.sdkVersion;
789
+ const sdkName = request.input.volatile?.sdkName;
661
790
  // sdkVersion property is only used by Kuzzle v1 SDKs
662
791
  if (sdkVersion) {
663
792
  throw processError.get("incompatible_sdk_version", sdkVersion, "Kuzzle v2");
@@ -665,7 +794,7 @@ class Funnel {
665
794
  if (!sdkName || typeof sdkName !== "string") {
666
795
  return;
667
796
  }
668
- const separatorIdx = sdkName.indexOf("@"), name = sdkName.substr(0, separatorIdx), version = sdkName.substr(separatorIdx + 1);
797
+ const separatorIdx = sdkName.indexOf("@"), name = sdkName.substring(0, separatorIdx), version = sdkName.substring(separatorIdx + 1);
669
798
  if (name.length === 0 || version.length === 0) {
670
799
  return;
671
800
  }
@@ -699,6 +828,34 @@ class Funnel {
699
828
  }
700
829
  return null;
701
830
  }
831
+ /**
832
+ * Plays the request at the front of the pending queue.
833
+ *
834
+ * @returns whether the loop should carry on — false when the queue has
835
+ * nothing playable at its head, when the throttle refuses the
836
+ * slot, or when it throws.
837
+ */
838
+ _playOnePendingRequest() {
839
+ const pendingId = this.pendingRequestsQueue.peekFront();
840
+ const pendingItem = pendingId === undefined
841
+ ? undefined
842
+ : this.pendingRequestsById.get(pendingId);
843
+ // `quantityToInject` is capped by the queue's length, so the queue has an
844
+ // id and the map has its item. Both were dereferenced on that reasoning.
845
+ if (pendingItem === undefined) {
846
+ return false;
847
+ }
848
+ try {
849
+ if (!this.throttle(pendingItem.fn, pendingItem.context, pendingItem.request)) {
850
+ return false;
851
+ }
852
+ }
853
+ catch {
854
+ return false;
855
+ }
856
+ this.pendingRequestsQueue.shift();
857
+ return true;
858
+ }
702
859
  /**
703
860
  * Background task. Checks if there are any requests in cache, and replay them
704
861
  * if Kuzzle is not overloaded anymore,
@@ -706,20 +863,9 @@ class Funnel {
706
863
  _playPendingRequests() {
707
864
  // If there is room to play bufferized requests, do it now. If not, retry later
708
865
  const quantityToInject = Math.min(this.pendingRequestsQueue.length, global.kuzzle.config.limits.concurrentRequests - this.concurrentRequests);
709
- if (quantityToInject > 0) {
710
- for (let i = 0; i < quantityToInject; i++) {
711
- const pendingItem = this.pendingRequestsById.get(this.pendingRequestsQueue.peekFront());
712
- try {
713
- if (this.throttle(pendingItem.fn, pendingItem.context, pendingItem.request)) {
714
- this.pendingRequestsQueue.shift();
715
- }
716
- else {
717
- break;
718
- }
719
- }
720
- catch (error) {
721
- break;
722
- }
866
+ for (let i = 0; i < quantityToInject; i++) {
867
+ if (!this._playOnePendingRequest()) {
868
+ break;
723
869
  }
724
870
  }
725
871
  if (this.pendingRequestsQueue.length > 0) {
@@ -738,16 +884,49 @@ class Funnel {
738
884
  }
739
885
  }
740
886
  /**
741
- * Eventually wrap an error into a PluginImplementationError
887
+ * Eventually wrap an error into a PluginImplementationError.
888
+ *
889
+ * Everything that reaches this method comes out of a pipe — the error pipes
890
+ * of `handleProcessRequestError`, or `processRequest`'s own
891
+ * `request:onExecution` / before / after pipes — i.e. out of plugin code. A
892
+ * controller's error is wrapped at its source by `_wrapControllerError` and
893
+ * arrives here already a KuzzleError, so there is nothing left to guard on:
894
+ * see TD-27 (https://github.com/kuzzleio/kuzzle/issues/2703), which is why
895
+ * the previous guard on the controller name is gone rather than fixed.
896
+ *
742
897
  * @param {Request} request
743
898
  * @param {Error} error
744
899
  * @returns {KuzzleError}
745
900
  */
746
901
  _wrapError(request, error) {
747
- if (!this.isNativeController(request) && !(error instanceof KuzzleError)) {
748
- return kerror.getFrom(error, "plugin", "runtime", "unexpected_error", error.message);
902
+ if (error instanceof errors_1.KuzzleError) {
903
+ return error;
904
+ }
905
+ return kerror.getFrom(error, "plugin", "runtime", "unexpected_error", error.message);
906
+ }
907
+ /**
908
+ * Normalizes an error thrown by a controller action into a KuzzleError.
909
+ *
910
+ * A native controller throwing something that is not a KuzzleError is a
911
+ * Kuzzle bug, and it is reported as one (`core.fatal.unexpected_error`).
912
+ * Reporting it as `plugin.runtime.unexpected_error` — which is what happened
913
+ * for as long as `_wrapError`'s guard was dead — names the wrong culprit,
914
+ * and letting it through raw is worse still: `KuzzleRequest.setError` then
915
+ * builds an InternalError with no `id` and no `code`, on a 500 sent to a
916
+ * client. See TD-27 (https://github.com/kuzzleio/kuzzle/issues/2703).
917
+ *
918
+ * @param {Request} request
919
+ * @param {Error} error
920
+ * @returns {KuzzleError}
921
+ */
922
+ _wrapControllerError(request, error) {
923
+ if (error instanceof errors_1.KuzzleError) {
924
+ return error;
749
925
  }
750
- return error;
926
+ const [domain, subdomain] = this.isNativeController(request.input.controller)
927
+ ? ["core", "fatal"]
928
+ : ["plugin", "runtime"];
929
+ return kerror.getFrom(error, domain, subdomain, "unexpected_error", error.message);
751
930
  }
752
931
  /**
753
932
  * Verifies if requests sent from a specific origin are allowed
@@ -762,17 +941,27 @@ class Funnel {
762
941
  if (global.kuzzle.config.internal.allowAllOrigins) {
763
942
  return true;
764
943
  }
944
+ const allowed = loadedOrigins(httpConfig);
765
945
  if (httpConfig.accessControlAllowOriginUseRegExp) {
766
- for (const re of httpConfig.accessControlAllowOrigin) {
946
+ for (const re of allowed) {
767
947
  if (re.test(origin)) {
768
948
  return true;
769
949
  }
770
950
  }
771
951
  return false;
772
952
  }
773
- return httpConfig.accessControlAllowOrigin.includes(origin);
953
+ return allowed.includes(origin);
774
954
  }
775
955
  }
956
+ /**
957
+ * What `http.accessControlAllowOrigin` holds once the configuration is
958
+ * loaded. It is declared `string` (see HttpConfiguration); the parameter's
959
+ * wider type is what lets the caller say so without a cast, and without the
960
+ * narrowing an annotated local would get from its initializer.
961
+ */
962
+ function loadedOrigins(httpConfig) {
963
+ return httpConfig.accessControlAllowOrigin;
964
+ }
776
965
  /**
777
966
  * @param {string} string
778
967
  * @returns {string}
@@ -792,8 +981,21 @@ function capitalize(string) {
792
981
  * @returns {Promise}
793
982
  */
794
983
  function doAction(controller, request) {
795
- const ret = controller[request.input.action](request);
796
- if (!ret || typeof ret.then !== "function") {
984
+ // `Reflect.apply(Reflect.get(...))`, not `controller[action](...)`: the
985
+ // action is a runtime-built key and `BaseController` deliberately has no
986
+ // index signature (TD-28). `apply` rather than calling the result of `get`
987
+ // keeps the receiver — losing it is the exact bug sprint 5's Build and Run
988
+ // job caught.
989
+ const { action } = targetOf(request);
990
+ const ret = Reflect.apply(Reflect.get(controller, action), controller, [
991
+ request,
992
+ ]);
993
+ // Same duck-type check as before, spelled so it narrows: a truthy non-object
994
+ // used to reach `ret.then` and read `undefined`, which took this branch too.
995
+ if (!ret ||
996
+ typeof ret !== "object" ||
997
+ !("then" in ret) ||
998
+ typeof ret.then !== "function") {
797
999
  return kerror.reject("plugin", "controller", "invalid_action_response", request.input.controller, request.input.action);
798
1000
  }
799
1001
  return ret;
@@ -809,11 +1011,20 @@ function doAction(controller, request) {
809
1011
  */
810
1012
  function satisfiesMajor(version, requirements) {
811
1013
  let maxRequirement = true, minRequirement = true;
1014
+ // The major digit. A version string with none satisfies no requirement,
1015
+ // either way round — `undefined >= "2"` and `undefined <= "2"` are both
1016
+ // false, because a relational comparison against `undefined` is NaN. That
1017
+ // is what the explicit check preserves; defaulting the digit to `""` would
1018
+ // have turned a string comparison on, and an empty version would then
1019
+ // satisfy every `max`.
1020
+ const major = version[0];
812
1021
  if (requirements.min) {
813
- minRequirement = version[0] >= requirements.min.toString();
1022
+ minRequirement =
1023
+ major !== undefined && major >= requirements.min.toString();
814
1024
  }
815
1025
  if (requirements.max) {
816
- maxRequirement = version[0] <= requirements.max.toString();
1026
+ maxRequirement =
1027
+ major !== undefined && major <= requirements.max.toString();
817
1028
  }
818
1029
  return maxRequirement && minRequirement;
819
1030
  }