kuzzle 2.56.0 → 2.57.0-beta.1
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.
- package/dist/bin/copy-binaries.js +71 -4
- package/dist/bin/start-kuzzle-server +191 -97
- package/dist/index.d.ts +31 -1
- package/dist/index.js +45 -2
- package/dist/lib/api/controllers/adminController.d.ts +4 -3
- package/dist/lib/api/controllers/adminController.js +1 -2
- package/dist/lib/api/controllers/authController.d.ts +37 -16
- package/dist/lib/api/controllers/authController.js +88 -39
- package/dist/lib/api/controllers/baseController.d.ts +10 -5
- package/dist/lib/api/controllers/baseController.js +36 -15
- package/dist/lib/api/controllers/bulkController.d.ts +11 -7
- package/dist/lib/api/controllers/bulkController.js +28 -5
- package/dist/lib/api/controllers/clusterController.d.ts +2 -2
- package/dist/lib/api/controllers/clusterController.js +3 -3
- package/dist/lib/api/controllers/collectionController.d.ts +57 -21
- package/dist/lib/api/controllers/collectionController.js +40 -11
- package/dist/lib/api/controllers/debugController.d.ts +1 -1
- package/dist/lib/api/controllers/documentController.d.ts +137 -28
- package/dist/lib/api/controllers/documentController.js +156 -125
- package/dist/lib/api/controllers/index.d.ts +27 -12
- package/dist/lib/api/controllers/index.js +28 -13
- package/dist/lib/api/controllers/indexController.d.ts +17 -10
- package/dist/lib/api/controllers/indexController.js +13 -11
- package/dist/lib/api/controllers/memoryStorageController.d.ts +2 -5
- package/dist/lib/api/controllers/memoryStorageController.js +199 -127
- package/dist/lib/api/controllers/realtimeController.d.ts +19 -9
- package/dist/lib/api/controllers/realtimeController.js +8 -4
- package/dist/lib/api/controllers/securityController.d.ts +42 -29
- package/dist/lib/api/controllers/securityController.js +35 -19
- package/dist/lib/api/controllers/serverController.d.ts +114 -19
- package/dist/lib/api/controllers/serverController.js +69 -29
- package/dist/lib/api/documentExtractor.d.ts +9 -7
- package/dist/lib/api/documentExtractor.js +105 -41
- package/dist/lib/api/funnel.d.ts +131 -29
- package/dist/lib/api/funnel.js +436 -225
- package/dist/lib/api/httpRoutes.d.ts +16 -11
- package/dist/lib/api/httpRoutes.js +272 -2
- package/dist/lib/api/openapi/OpenApiManager.d.ts +1 -1
- package/dist/lib/api/openapi/openApiGenerator.d.ts +1 -1
- package/dist/lib/api/rateLimiter.d.ts +15 -5
- package/dist/lib/api/rateLimiter.js +42 -14
- package/dist/lib/api/request/kuzzleRequest.d.ts +83 -12
- package/dist/lib/api/request/kuzzleRequest.js +88 -23
- package/dist/lib/api/request/requestContext.d.ts +20 -5
- package/dist/lib/api/request/requestContext.js +14 -4
- package/dist/lib/api/request/requestInput.d.ts +37 -6
- package/dist/lib/api/request/requestInput.js +22 -9
- package/dist/lib/api/request/requestResponse.d.ts +45 -9
- package/dist/lib/api/request/requestResponse.js +34 -3
- package/dist/lib/cluster/command.d.ts +131 -37
- package/dist/lib/cluster/command.js +243 -71
- package/dist/lib/cluster/idCardHandler.d.ts +18 -5
- package/dist/lib/cluster/idCardHandler.js +52 -19
- package/dist/lib/cluster/index.d.ts +8 -2
- package/dist/lib/cluster/index.js +6 -2
- package/dist/lib/cluster/node.d.ts +127 -49
- package/dist/lib/cluster/node.js +412 -179
- package/dist/lib/cluster/protobuf/command.proto +18 -0
- package/dist/lib/cluster/protobuf/commandMessages.d.ts +104 -0
- package/dist/lib/cluster/protobuf/commandMessages.js +30 -0
- package/dist/lib/cluster/protobuf/syncMessages.d.ts +184 -0
- package/dist/lib/cluster/protobuf/syncMessages.js +23 -0
- package/dist/lib/cluster/publisher.d.ts +118 -78
- package/dist/lib/cluster/publisher.js +174 -72
- package/dist/lib/cluster/state.d.ts +15 -9
- package/dist/lib/cluster/state.js +12 -8
- package/dist/lib/cluster/subscriber.d.ts +185 -131
- package/dist/lib/cluster/subscriber.js +357 -95
- package/dist/lib/cluster/workers/IDCardRenewer.d.ts +39 -8
- package/dist/lib/cluster/workers/IDCardRenewer.js +88 -23
- package/dist/lib/config/default.config.d.ts +2 -2
- package/dist/lib/config/default.config.js +10 -3
- package/dist/lib/config/documentEventAliases.d.ts +1 -1
- package/dist/lib/config/index.d.ts +2 -5
- package/dist/lib/config/index.js +30 -17
- package/dist/lib/core/auth/formatProcessing.d.ts +3 -3
- package/dist/lib/core/auth/passportResponse.d.ts +1 -1
- package/dist/lib/core/auth/passportWrapper.d.ts +1 -1
- package/dist/lib/core/auth/passportWrapper.js +14 -13
- package/dist/lib/core/auth/tokenManager.d.ts +24 -3
- package/dist/lib/core/auth/tokenManager.js +47 -19
- package/dist/lib/core/backend/applicationManager.d.ts +2 -2
- package/dist/lib/core/backend/backend.d.ts +16 -5
- package/dist/lib/core/backend/backend.js +14 -6
- package/dist/lib/core/backend/backendCluster.d.ts +1 -1
- package/dist/lib/core/backend/backendConfig.d.ts +17 -5
- package/dist/lib/core/backend/backendConfig.js +1 -0
- package/dist/lib/core/backend/backendController.d.ts +1 -1
- package/dist/lib/core/backend/backendController.js +8 -1
- package/dist/lib/core/backend/backendErrors.d.ts +15 -8
- package/dist/lib/core/backend/backendErrors.js +5 -0
- package/dist/lib/core/backend/backendHook.d.ts +1 -1
- package/dist/lib/core/backend/backendImport.d.ts +1 -1
- package/dist/lib/core/backend/backendOpenApi.d.ts +3 -2
- package/dist/lib/core/backend/backendPipe.d.ts +1 -1
- package/dist/lib/core/backend/backendPipe.js +9 -1
- package/dist/lib/core/backend/backendPlugin.d.ts +2 -2
- package/dist/lib/core/backend/backendSubscription.d.ts +2 -2
- package/dist/lib/core/backend/backendVault.d.ts +1 -1
- package/dist/lib/core/backend/backendVault.js +8 -1
- package/dist/lib/core/cache/cacheEngine.d.ts +7 -4
- package/dist/lib/core/cache/cacheEngine.js +25 -8
- package/dist/lib/core/debug/kuzzleDebugger.d.ts +2 -1
- package/dist/lib/core/debug/kuzzleDebugger.js +31 -17
- package/dist/lib/core/network/accessLogger.d.ts +33 -18
- package/dist/lib/core/network/accessLogger.js +135 -73
- package/dist/lib/core/network/clientConnection.d.ts +13 -11
- package/dist/lib/core/network/clientConnection.js +33 -9
- package/dist/lib/core/network/context.d.ts +17 -22
- package/dist/lib/core/network/context.js +43 -26
- package/dist/lib/core/network/entryPoint.d.ts +38 -16
- package/dist/lib/core/network/entryPoint.js +119 -48
- package/dist/lib/core/network/httpRouter/index.d.ts +20 -50
- package/dist/lib/core/network/httpRouter/index.js +61 -75
- package/dist/lib/core/network/httpRouter/routeHandler.d.ts +17 -32
- package/dist/lib/core/network/httpRouter/routeHandler.js +26 -36
- package/dist/lib/core/network/httpRouter/routePart.d.ts +9 -18
- package/dist/lib/core/network/httpRouter/routePart.js +61 -43
- package/dist/lib/core/network/httpRouter/routeTypes.d.ts +3 -0
- package/dist/lib/core/network/httpRouter/routeTypes.js +23 -0
- package/dist/lib/core/network/networkEntryPoint.d.ts +20 -0
- package/dist/lib/core/network/networkEntryPoint.js +23 -0
- package/dist/lib/core/network/protocolManifest.d.ts +5 -4
- package/dist/lib/core/network/protocolManifest.js +6 -3
- package/dist/lib/core/network/protocols/httpMessage.d.ts +25 -18
- package/dist/lib/core/network/protocols/httpMessage.js +14 -11
- package/dist/lib/core/network/protocols/httpwsProtocol.d.ts +84 -93
- package/dist/lib/core/network/protocols/httpwsProtocol.js +284 -129
- package/dist/lib/core/network/protocols/internalProtocol.d.ts +26 -15
- package/dist/lib/core/network/protocols/internalProtocol.js +17 -16
- package/dist/lib/core/network/protocols/mqttProtocol.d.ts +56 -32
- package/dist/lib/core/network/protocols/mqttProtocol.js +91 -44
- package/dist/lib/core/network/protocols/protocol.d.ts +85 -21
- package/dist/lib/core/network/protocols/protocol.js +83 -27
- package/dist/lib/core/network/router.d.ts +13 -22
- package/dist/lib/core/network/router.js +59 -46
- package/dist/lib/core/plugin/plugin.d.ts +57 -51
- package/dist/lib/core/plugin/plugin.js +218 -103
- package/dist/lib/core/plugin/pluginContext.d.ts +54 -11
- package/dist/lib/core/plugin/pluginContext.js +99 -58
- package/dist/lib/core/plugin/pluginManifest.d.ts +6 -2
- package/dist/lib/core/plugin/pluginManifest.js +18 -11
- package/dist/lib/core/plugin/pluginRepository.d.ts +35 -44
- package/dist/lib/core/plugin/pluginRepository.js +35 -50
- package/dist/lib/core/plugin/pluginsManager.d.ts +128 -46
- package/dist/lib/core/plugin/pluginsManager.js +468 -231
- package/dist/lib/core/plugin/privilegedContext.d.ts +4 -9
- package/dist/lib/core/plugin/privilegedContext.js +5 -10
- package/dist/lib/core/realtime/actionEnum.d.ts +12 -21
- package/dist/lib/core/realtime/actionEnum.js +6 -7
- package/dist/lib/core/realtime/channel.d.ts +11 -5
- package/dist/lib/core/realtime/channel.js +17 -2
- package/dist/lib/core/realtime/connectionRooms.d.ts +2 -2
- package/dist/lib/core/realtime/hotelClerk.d.ts +12 -6
- package/dist/lib/core/realtime/hotelClerk.js +29 -11
- package/dist/lib/core/realtime/index.d.ts +8 -3
- package/dist/lib/core/realtime/index.js +12 -5
- package/dist/lib/core/realtime/notification/document.d.ts +54 -25
- package/dist/lib/core/realtime/notification/document.js +10 -13
- package/dist/lib/core/realtime/notification/index.d.ts +9 -3
- package/dist/lib/core/realtime/notification/index.js +10 -4
- package/dist/lib/core/realtime/notification/server.d.ts +7 -10
- package/dist/lib/core/realtime/notification/server.js +4 -7
- package/dist/lib/core/realtime/notification/user.d.ts +45 -21
- package/dist/lib/core/realtime/notification/user.js +8 -9
- package/dist/lib/core/realtime/notifier.d.ts +52 -40
- package/dist/lib/core/realtime/notifier.js +60 -25
- package/dist/lib/core/realtime/room.d.ts +1 -1
- package/dist/lib/core/realtime/subscription.d.ts +11 -6
- package/dist/lib/core/realtime/subscription.js +5 -1
- package/dist/lib/core/security/index.d.ts +14 -6
- package/dist/lib/core/security/index.js +27 -13
- package/dist/lib/core/security/profileRepository.d.ts +24 -19
- package/dist/lib/core/security/profileRepository.js +23 -10
- package/dist/lib/core/security/roleRepository.d.ts +60 -23
- package/dist/lib/core/security/roleRepository.js +122 -53
- package/dist/lib/core/security/securityLoader.d.ts +33 -18
- package/dist/lib/core/security/securityLoader.js +43 -16
- package/dist/lib/core/security/tokenRepository.d.ts +21 -7
- package/dist/lib/core/security/tokenRepository.js +50 -23
- package/dist/lib/core/security/userRepository.d.ts +44 -21
- package/dist/lib/core/security/userRepository.js +59 -19
- package/dist/lib/core/shared/KoncordeWrapper.d.ts +1 -1
- package/dist/lib/core/shared/ObjectRepository.d.ts +80 -18
- package/dist/lib/core/shared/ObjectRepository.js +57 -29
- package/dist/lib/core/shared/abstractManifest.d.ts +21 -8
- package/dist/lib/core/shared/abstractManifest.js +57 -17
- package/dist/lib/core/shared/sdk/embeddedSdk.d.ts +3 -1
- package/dist/lib/core/shared/sdk/embeddedSdk.js +8 -7
- package/dist/lib/core/shared/sdk/funnelProtocol.d.ts +2 -1
- package/dist/lib/core/shared/sdk/funnelProtocol.js +12 -3
- package/dist/lib/core/shared/sdk/impersonatedSdk.d.ts +11 -5
- package/dist/lib/core/shared/sdk/impersonatedSdk.js +22 -9
- package/dist/lib/core/shared/store.d.ts +45 -29
- package/dist/lib/core/shared/store.js +48 -27
- package/dist/lib/core/statistics/statistics.d.ts +1 -1
- package/dist/lib/core/storage/clientAdapter.d.ts +39 -21
- package/dist/lib/core/storage/clientAdapter.js +88 -48
- package/dist/lib/core/storage/indexCache.d.ts +8 -0
- package/dist/lib/core/storage/indexCache.js +16 -7
- package/dist/lib/core/storage/storageEngine.d.ts +7 -6
- package/dist/lib/core/storage/storageEngine.js +11 -8
- package/dist/lib/core/validation/baseType.d.ts +22 -22
- package/dist/lib/core/validation/baseType.js +11 -26
- package/dist/lib/core/validation/specification.d.ts +148 -0
- package/dist/lib/core/validation/specification.js +34 -0
- package/dist/lib/core/validation/typeOptions.d.ts +62 -0
- package/dist/lib/core/validation/typeOptions.js +23 -0
- package/dist/lib/core/validation/types/anything.d.ts +3 -6
- package/dist/lib/core/validation/types/anything.js +7 -7
- package/dist/lib/core/validation/types/boolean.d.ts +5 -12
- package/dist/lib/core/validation/types/boolean.js +7 -12
- package/dist/lib/core/validation/types/date.d.ts +19 -11
- package/dist/lib/core/validation/types/date.js +212 -161
- package/dist/lib/core/validation/types/email.d.ts +7 -11
- package/dist/lib/core/validation/types/email.js +13 -17
- package/dist/lib/core/validation/types/enum.d.ts +7 -11
- package/dist/lib/core/validation/types/enum.js +39 -20
- package/dist/lib/core/validation/types/geoPoint.d.ts +5 -13
- package/dist/lib/core/validation/types/geoPoint.js +10 -15
- package/dist/lib/core/validation/types/geoShape.d.ts +22 -21
- package/dist/lib/core/validation/types/geoShape.js +113 -129
- package/dist/lib/core/validation/types/geoShapeUtils.d.ts +15 -0
- package/dist/lib/core/validation/types/geoShapeUtils.js +75 -0
- package/dist/lib/core/validation/types/integer.d.ts +7 -5
- package/dist/lib/core/validation/types/integer.js +7 -13
- package/dist/lib/core/validation/types/ipAddress.d.ts +7 -11
- package/dist/lib/core/validation/types/ipAddress.js +13 -17
- package/dist/lib/core/validation/types/numeric.d.ts +7 -11
- package/dist/lib/core/validation/types/numeric.js +22 -29
- package/dist/lib/core/validation/types/object.d.ts +8 -15
- package/dist/lib/core/validation/types/object.js +12 -21
- package/dist/lib/core/validation/types/string.d.ts +7 -11
- package/dist/lib/core/validation/types/string.js +22 -29
- package/dist/lib/core/validation/types/url.d.ts +7 -11
- package/dist/lib/core/validation/types/url.js +14 -18
- package/dist/lib/core/validation/validation.d.ts +119 -80
- package/dist/lib/core/validation/validation.js +470 -412
- package/dist/lib/core/validation/validationUtils.d.ts +31 -0
- package/dist/lib/core/validation/validationUtils.js +190 -0
- package/dist/lib/kerror/codes/4-plugin.json +0 -12
- package/dist/lib/kerror/codes/index.d.ts +12 -2
- package/dist/lib/kerror/codes/index.js +5 -4
- package/dist/lib/kerror/errors/badRequestError.d.ts +1 -1
- package/dist/lib/kerror/errors/badRequestError.js +1 -1
- package/dist/lib/kerror/errors/externalServiceError.d.ts +1 -1
- package/dist/lib/kerror/errors/externalServiceError.js +1 -1
- package/dist/lib/kerror/errors/forbiddenError.d.ts +1 -1
- package/dist/lib/kerror/errors/forbiddenError.js +1 -1
- package/dist/lib/kerror/errors/gatewayTimeoutError.d.ts +1 -1
- package/dist/lib/kerror/errors/gatewayTimeoutError.js +1 -1
- package/dist/lib/kerror/errors/internalError.d.ts +1 -1
- package/dist/lib/kerror/errors/internalError.js +1 -1
- package/dist/lib/kerror/errors/kuzzleError.d.ts +32 -3
- package/dist/lib/kerror/errors/kuzzleError.js +21 -7
- package/dist/lib/kerror/errors/multipleErrorsError.d.ts +2 -2
- package/dist/lib/kerror/errors/multipleErrorsError.js +2 -2
- package/dist/lib/kerror/errors/notFoundError.d.ts +1 -1
- package/dist/lib/kerror/errors/notFoundError.js +1 -1
- package/dist/lib/kerror/errors/partialError.d.ts +8 -2
- package/dist/lib/kerror/errors/partialError.js +22 -9
- package/dist/lib/kerror/errors/pluginImplementationError.d.ts +9 -1
- package/dist/lib/kerror/errors/pluginImplementationError.js +9 -3
- package/dist/lib/kerror/errors/preconditionError.d.ts +1 -1
- package/dist/lib/kerror/errors/preconditionError.js +1 -1
- package/dist/lib/kerror/errors/serviceUnavailableError.d.ts +1 -1
- package/dist/lib/kerror/errors/serviceUnavailableError.js +1 -1
- package/dist/lib/kerror/errors/sizeLimitError.d.ts +1 -1
- package/dist/lib/kerror/errors/sizeLimitError.js +1 -1
- package/dist/lib/kerror/errors/tooManyRequestsError.d.ts +1 -1
- package/dist/lib/kerror/errors/tooManyRequestsError.js +1 -1
- package/dist/lib/kerror/errors/unauthorizedError.d.ts +1 -1
- package/dist/lib/kerror/errors/unauthorizedError.js +1 -1
- package/dist/lib/kerror/index.d.ts +19 -13
- package/dist/lib/kerror/index.js +60 -19
- package/dist/lib/kuzzle/Logger.d.ts +2 -2
- package/dist/lib/kuzzle/dumpGenerator.d.ts +12 -8
- package/dist/lib/kuzzle/dumpGenerator.js +130 -62
- package/dist/lib/kuzzle/event/KuzzleEventEmitter.d.ts +18 -9
- package/dist/lib/kuzzle/event/KuzzleEventEmitter.js +45 -18
- package/dist/lib/kuzzle/event/pipeRunner.d.ts +37 -16
- package/dist/lib/kuzzle/event/pipeRunner.js +73 -26
- package/dist/lib/kuzzle/event/waterfall.d.ts +11 -1
- package/dist/lib/kuzzle/event/waterfall.js +38 -13
- package/dist/lib/kuzzle/internalIndexHandler.d.ts +11 -174
- package/dist/lib/kuzzle/internalIndexHandler.js +58 -29
- package/dist/lib/kuzzle/kuzzle.d.ts +25 -10
- package/dist/lib/kuzzle/kuzzle.js +74 -17
- package/dist/lib/kuzzle/kuzzleStateEnum.d.ts +16 -12
- package/dist/lib/kuzzle/kuzzleStateEnum.js +5 -7
- package/dist/lib/kuzzle/vault.d.ts +5 -1
- package/dist/lib/kuzzle/vault.js +29 -17
- package/dist/lib/model/security/profile.d.ts +34 -5
- package/dist/lib/model/security/profile.js +6 -5
- package/dist/lib/model/security/rights.d.ts +12 -4
- package/dist/lib/model/security/rights.js +7 -6
- package/dist/lib/model/security/role.d.ts +8 -4
- package/dist/lib/model/security/role.js +12 -6
- package/dist/lib/model/security/token.d.ts +8 -0
- package/dist/lib/model/security/user.d.ts +8 -2
- package/dist/lib/model/security/user.js +7 -4
- package/dist/lib/model/storage/apiKey.d.ts +55 -26
- package/dist/lib/model/storage/apiKey.js +97 -24
- package/dist/lib/model/storage/baseModel.d.ts +77 -66
- package/dist/lib/model/storage/baseModel.js +21 -34
- package/dist/lib/service/cache/redis.d.ts +53 -36
- package/dist/lib/service/cache/redis.js +148 -71
- package/dist/lib/service/service.d.ts +14 -19
- package/dist/lib/service/service.js +41 -22
- package/dist/lib/service/storage/7/elasticsearch.d.ts +136 -93
- package/dist/lib/service/storage/7/elasticsearch.js +218 -165
- package/dist/lib/service/storage/7/esWrapper.d.ts +30 -13
- package/dist/lib/service/storage/7/esWrapper.js +58 -37
- package/dist/lib/service/storage/8/elasticsearch.d.ts +153 -119
- package/dist/lib/service/storage/8/elasticsearch.js +286 -213
- package/dist/lib/service/storage/8/esWrapper.d.ts +30 -13
- package/dist/lib/service/storage/8/esWrapper.js +59 -38
- package/dist/lib/service/storage/commons/queryTranslator.d.ts +3 -3
- package/dist/lib/service/storage/commons/queryTranslator.js +71 -35
- package/dist/lib/types/ApiRoute.d.ts +12 -0
- package/dist/lib/types/ApiRoute.js +23 -0
- package/dist/lib/types/ClientConnection.d.ts +1 -1
- package/dist/lib/types/EventHandler.d.ts +10 -0
- package/dist/lib/types/Global.d.ts +8 -3
- package/dist/lib/types/HttpMessage.d.ts +2 -2
- package/dist/lib/types/HttpStream.d.ts +1 -1
- package/dist/lib/types/HttpStream.js +3 -1
- package/dist/lib/types/JSONObject.d.ts +9 -0
- package/dist/lib/types/JSONObject.js +23 -0
- package/dist/lib/types/Kuzzle.d.ts +5 -3
- package/dist/lib/types/KuzzleDocument.d.ts +1 -1
- package/dist/lib/types/KuzzleWebSocket.d.ts +24 -0
- package/dist/lib/types/KuzzleWebSocket.js +23 -0
- package/dist/lib/types/OpenApiDefinition.d.ts +1 -1
- package/dist/lib/types/Plugin.d.ts +33 -8
- package/dist/lib/types/PluginInstance.d.ts +67 -0
- package/dist/lib/types/PluginInstance.js +23 -0
- package/dist/lib/types/Policy.d.ts +1 -1
- package/dist/lib/types/Target.d.ts +8 -0
- package/dist/lib/types/Token.d.ts +14 -2
- package/dist/lib/types/config/HttpConfiguration.d.ts +5 -0
- package/dist/lib/types/config/KuzzleConfiguration.d.ts +102 -1
- package/dist/lib/types/config/PluginsConfiguration.d.ts +3 -2
- package/dist/lib/types/config/SecurityConfiguration.d.ts +6 -2
- package/dist/lib/types/config/ServerConfiguration.d.ts +2 -2
- package/dist/lib/types/config/ServicesConfiguration.d.ts +1 -1
- package/dist/lib/types/config/cache/BaseCacheRedisConfiguration.d.ts +131 -0
- package/dist/lib/types/config/cache/BaseCacheRedisConfiguration.js +3 -0
- package/dist/lib/types/config/internalCache/InternalCacheRedisConfiguration.d.ts +2 -106
- package/dist/lib/types/config/publicCache/PublicCacheRedisConfiguration.d.ts +2 -26
- package/dist/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.d.ts +3 -0
- package/dist/lib/types/controllers/Controller.d.ts +12 -3
- package/dist/lib/types/controllers/ControllerDefinition.d.ts +2 -2
- package/dist/lib/types/controllers/{adminControlller.type.js → adminController.type.js} +1 -1
- package/dist/lib/types/controllers/authController.type.d.ts +2 -2
- package/dist/lib/types/core/auth/formatProcessing.type.d.ts +7 -1
- package/dist/lib/types/errors/ErrorDomains.d.ts +1 -1
- package/dist/lib/types/events/EventGenericDocument.d.ts +10 -9
- package/dist/lib/types/events/EventProtocol.d.ts +4 -4
- package/dist/lib/types/index.d.ts +7 -0
- package/dist/lib/types/index.js +7 -0
- package/dist/lib/types/shared/StoreCollectionsDefinition.d.ts +1 -1
- package/dist/lib/types/storage/7/Elasticsearch.d.ts +62 -13
- package/dist/lib/types/storage/8/Elasticsearch.d.ts +62 -13
- package/dist/lib/util/Inflector.d.ts +4 -1
- package/dist/lib/util/Inflector.js +0 -3
- package/dist/lib/util/assertType.d.ts +24 -27
- package/dist/lib/util/assertType.js +28 -39
- package/dist/lib/util/async.js +19 -6
- package/dist/lib/util/asyncStore.js +1 -1
- package/dist/lib/util/bufferedPassThrough.d.ts +9 -0
- package/dist/lib/util/bufferedPassThrough.js +27 -13
- package/dist/lib/util/bytes.d.ts +1 -1
- package/dist/lib/util/bytes.js +6 -2
- package/dist/lib/util/debug.d.ts +3 -1
- package/dist/lib/util/debug.js +42 -10
- package/dist/lib/util/deprecate.d.ts +9 -1
- package/dist/lib/util/deprecate.js +10 -6
- package/dist/lib/util/didYouMean.d.ts +2 -1
- package/dist/lib/util/didYouMean.js +8 -4
- package/dist/lib/util/distributedLock.d.ts +56 -0
- package/dist/lib/util/distributedLock.js +166 -0
- package/dist/lib/util/dump-collection.d.ts +1 -1
- package/dist/lib/util/dump-collection.js +4 -5
- package/dist/lib/util/extractFields.d.ts +15 -11
- package/dist/lib/util/extractFields.js +8 -9
- package/dist/lib/util/koncordeCompat.d.ts +2 -2
- package/dist/lib/util/koncordeCompat.js +33 -0
- package/dist/lib/util/memoize.d.ts +7 -6
- package/dist/lib/util/memoize.js +3 -3
- package/dist/lib/util/mutex.d.ts +22 -2
- package/dist/lib/util/mutex.js +39 -1
- package/dist/lib/util/name-generator.js +14 -2
- package/dist/lib/util/promback.d.ts +20 -11
- package/dist/lib/util/promback.js +14 -7
- package/dist/lib/util/requestAssertions.d.ts +30 -10
- package/dist/lib/util/requestAssertions.js +125 -121
- package/dist/lib/util/safeObject.d.ts +3 -3
- package/dist/lib/util/safeObject.js +7 -3
- package/dist/lib/util/stackTrace.d.ts +13 -5
- package/dist/lib/util/stackTrace.js +17 -12
- package/dist/lib/util/thrown.d.ts +13 -0
- package/dist/lib/util/thrown.js +46 -0
- package/dist/package.json +24 -17
- package/package.json +24 -17
- package/dist/lib/util/wildcard.d.ts +0 -1
- package/dist/lib/util/wildcard.js +0 -46
- /package/dist/lib/types/controllers/{adminControlller.type.d.ts → adminController.type.d.ts} +0 -0
package/dist/lib/api/funnel.js
CHANGED
|
@@ -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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
|
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
|
|
112
|
+
this.rateLimiter = new rateLimiter_1.default();
|
|
68
113
|
this.lastDumpedErrors = {};
|
|
69
|
-
this.
|
|
70
|
-
this.
|
|
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
|
|
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
|
|
141
|
+
this.controllers.set("security", new SecurityController());
|
|
97
142
|
this.controllers.set("server", new ServerController());
|
|
98
|
-
this.controllers.set("admin", new AdminController
|
|
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.
|
|
103
|
-
return
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
Object.
|
|
109
|
-
|
|
110
|
-
|
|
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 ===
|
|
208
|
+
if (global.kuzzle.state === kuzzleStateEnum_1.default.SHUTTING_DOWN) {
|
|
141
209
|
throw processError.get("shutting_down");
|
|
142
210
|
}
|
|
143
|
-
if (global.kuzzle.state ===
|
|
211
|
+
if (global.kuzzle.state === kuzzleStateEnum_1.default.NOT_ENOUGH_NODES) {
|
|
144
212
|
throw processError.get("not_enough_nodes");
|
|
145
213
|
}
|
|
146
|
-
const isRequestFromDebugSession =
|
|
214
|
+
const isRequestFromDebugSession = (0, get_1.default)(request, "context.connection.misc.internal.debugSession", false);
|
|
147
215
|
if (this.overloaded) {
|
|
148
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
324
|
-
|
|
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.
|
|
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
|
-
|
|
347
|
-
|
|
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
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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-
|
|
435
|
+
.replace(/[^a-z0-9-_]/g, "-")
|
|
356
436
|
.split("-")
|
|
357
437
|
.filter((value) => value !== "")
|
|
358
|
-
.join("-")
|
|
359
|
-
|
|
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
|
-
|
|
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
|
-
|
|
416
|
-
|
|
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
|
-
|
|
420
|
-
|
|
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
|
|
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,
|
|
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
|
-
!
|
|
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
|
-
|
|
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
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
|
471
|
-
_request.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
595
|
-
|
|
596
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
660
|
-
const sdkName = request.input.volatile
|
|
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.
|
|
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
|
-
|
|
710
|
-
|
|
711
|
-
|
|
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 (
|
|
748
|
-
return
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
796
|
-
|
|
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 =
|
|
1022
|
+
minRequirement =
|
|
1023
|
+
major !== undefined && major >= requirements.min.toString();
|
|
814
1024
|
}
|
|
815
1025
|
if (requirements.max) {
|
|
816
|
-
maxRequirement =
|
|
1026
|
+
maxRequirement =
|
|
1027
|
+
major !== undefined && major <= requirements.max.toString();
|
|
817
1028
|
}
|
|
818
1029
|
return maxRequirement && minRequirement;
|
|
819
1030
|
}
|