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