kuzzle 2.59.0 → 2.60.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/dist/bin/copy-binaries.js +17 -7
  2. package/dist/bin/start-kuzzle-server +17 -7
  3. package/dist/index.d.ts +2 -1
  4. package/dist/index.js +6 -2
  5. package/dist/lib/api/controllers/adminController.d.ts +9 -3
  6. package/dist/lib/api/controllers/adminController.js +42 -26
  7. package/dist/lib/api/controllers/authController.d.ts +15 -5
  8. package/dist/lib/api/controllers/authController.js +35 -20
  9. package/dist/lib/api/controllers/baseController.js +17 -7
  10. package/dist/lib/api/controllers/bulkController.js +17 -7
  11. package/dist/lib/api/controllers/collectionController.js +17 -7
  12. package/dist/lib/api/controllers/debugController.js +17 -7
  13. package/dist/lib/api/controllers/documentController.js +17 -7
  14. package/dist/lib/api/controllers/indexController.d.ts +1 -1
  15. package/dist/lib/api/controllers/memoryStorageController.js +17 -7
  16. package/dist/lib/api/controllers/securityController.d.ts +30 -28
  17. package/dist/lib/api/controllers/securityController.js +18 -8
  18. package/dist/lib/api/controllers/serverController.d.ts +0 -1
  19. package/dist/lib/api/controllers/serverController.js +17 -7
  20. package/dist/lib/api/documentExtractor.js +17 -7
  21. package/dist/lib/api/funnel.js +19 -9
  22. package/dist/lib/api/httpRoutes.d.ts +2 -1
  23. package/dist/lib/api/openapi/OpenApiManager.d.ts +2 -1
  24. package/dist/lib/api/openapi/openApiGenerator.js +1 -2
  25. package/dist/lib/api/request/kuzzleRequest.d.ts +9 -2
  26. package/dist/lib/api/request/kuzzleRequest.js +21 -7
  27. package/dist/lib/api/request/requestContext.d.ts +7 -2
  28. package/dist/lib/api/request/requestContext.js +17 -7
  29. package/dist/lib/api/request/requestInput.d.ts +1 -1
  30. package/dist/lib/api/request/requestInput.js +17 -7
  31. package/dist/lib/api/request/requestResponse.d.ts +2 -2
  32. package/dist/lib/api/request/requestResponse.js +21 -10
  33. package/dist/lib/cluster/command.d.ts +0 -2
  34. package/dist/lib/cluster/command.js +17 -7
  35. package/dist/lib/cluster/idCardHandler.d.ts +3 -2
  36. package/dist/lib/cluster/idCardHandler.js +1 -1
  37. package/dist/lib/cluster/node.js +69 -64
  38. package/dist/lib/cluster/protobuf/command.proto +23 -22
  39. package/dist/lib/cluster/protobuf/sync.proto +91 -85
  40. package/dist/lib/cluster/publisher.js +17 -7
  41. package/dist/lib/cluster/state.js +17 -7
  42. package/dist/lib/cluster/subscriber.d.ts +0 -2
  43. package/dist/lib/cluster/subscriber.js +17 -7
  44. package/dist/lib/cluster/workers/IDCardRenewer.d.ts +0 -1
  45. package/dist/lib/config/index.js +20 -14
  46. package/dist/lib/core/auth/formatProcessing.d.ts +1 -1
  47. package/dist/lib/core/auth/formatProcessing.js +3 -3
  48. package/dist/lib/core/auth/passportResponse.d.ts +0 -1
  49. package/dist/lib/core/auth/passportWrapper.js +22 -8
  50. package/dist/lib/core/backend/backend.js +17 -7
  51. package/dist/lib/core/backend/backendConfig.d.ts +1 -1
  52. package/dist/lib/core/backend/backendConfig.js +17 -7
  53. package/dist/lib/core/backend/backendController.js +17 -7
  54. package/dist/lib/core/backend/backendErrors.js +17 -7
  55. package/dist/lib/core/backend/backendHook.js +17 -7
  56. package/dist/lib/core/backend/backendImport.js +17 -7
  57. package/dist/lib/core/backend/backendPipe.d.ts +4 -1
  58. package/dist/lib/core/backend/backendPipe.js +17 -7
  59. package/dist/lib/core/backend/backendPlugin.js +17 -7
  60. package/dist/lib/core/backend/backendStorage.js +8 -8
  61. package/dist/lib/core/backend/backendSubscription.js +17 -7
  62. package/dist/lib/core/backend/backendVault.js +17 -7
  63. package/dist/lib/core/backend/internalLogger.d.ts +7 -7
  64. package/dist/lib/core/debug/kuzzleDebugger.js +17 -7
  65. package/dist/lib/core/network/accessLogger.d.ts +0 -1
  66. package/dist/lib/core/network/accessLogger.js +17 -7
  67. package/dist/lib/core/network/clientConnection.js +17 -7
  68. package/dist/lib/core/network/context.d.ts +0 -1
  69. package/dist/lib/core/network/entryPoint.js +17 -7
  70. package/dist/lib/core/network/httpRouter/routePart.js +17 -7
  71. package/dist/lib/core/network/protocols/httpMessage.d.ts +0 -2
  72. package/dist/lib/core/network/protocols/httpwsProtocol.d.ts +0 -3
  73. package/dist/lib/core/network/protocols/httpwsProtocol.js +29 -12
  74. package/dist/lib/core/network/protocols/mqttProtocol.d.ts +1 -2
  75. package/dist/lib/core/network/protocols/mqttProtocol.js +31 -10
  76. package/dist/lib/core/network/router.js +17 -7
  77. package/dist/lib/core/plugin/plugin.js +17 -7
  78. package/dist/lib/core/plugin/pluginContext.d.ts +20 -9
  79. package/dist/lib/core/plugin/pluginContext.js +39 -24
  80. package/dist/lib/core/plugin/pluginsManager.js +17 -7
  81. package/dist/lib/core/realtime/channel.js +17 -7
  82. package/dist/lib/core/realtime/hotelClerk.d.ts +3 -2
  83. package/dist/lib/core/realtime/hotelClerk.js +17 -7
  84. package/dist/lib/core/realtime/notifier.js +17 -7
  85. package/dist/lib/core/security/profileRepository.js +17 -7
  86. package/dist/lib/core/security/roleRepository.js +17 -7
  87. package/dist/lib/core/security/securityLoader.js +17 -7
  88. package/dist/lib/core/security/tokenRepository.js +18 -8
  89. package/dist/lib/core/security/userRepository.js +17 -7
  90. package/dist/lib/core/shared/ObjectRepository.js +20 -7
  91. package/dist/lib/core/shared/abstractManifest.js +17 -7
  92. package/dist/lib/core/shared/sdk/embeddedSdk.js +20 -8
  93. package/dist/lib/core/shared/sdk/funnelProtocol.js +17 -7
  94. package/dist/lib/core/shared/store.d.ts +11 -1
  95. package/dist/lib/core/shared/store.js +26 -30
  96. package/dist/lib/core/statistics/statistics.d.ts +0 -1
  97. package/dist/lib/core/statistics/statistics.js +17 -7
  98. package/dist/lib/core/storage/clientAdapter.d.ts +4 -6
  99. package/dist/lib/core/storage/clientAdapter.js +24 -18
  100. package/dist/lib/core/storage/indexCache.js +17 -7
  101. package/dist/lib/core/validation/specification.js +1 -2
  102. package/dist/lib/core/validation/types/date.js +17 -7
  103. package/dist/lib/core/validation/types/enum.js +17 -7
  104. package/dist/lib/core/validation/types/geoShape.js +17 -7
  105. package/dist/lib/core/validation/types/geoShapeUtils.js +6 -7
  106. package/dist/lib/core/validation/validation.js +17 -7
  107. package/dist/lib/core/validation/validationUtils.js +24 -15
  108. package/dist/lib/kerror/codes/index.js +20 -10
  109. package/dist/lib/kerror/errors/kuzzleError.js +18 -8
  110. package/dist/lib/kerror/index.js +31 -18
  111. package/dist/lib/kuzzle/Logger.js +4 -3
  112. package/dist/lib/kuzzle/dumpGenerator.js +17 -7
  113. package/dist/lib/kuzzle/event/KuzzleEventEmitter.d.ts +3 -3
  114. package/dist/lib/kuzzle/event/KuzzleEventEmitter.js +17 -7
  115. package/dist/lib/kuzzle/event/pipeRunner.js +17 -7
  116. package/dist/lib/kuzzle/internalIndexHandler.js +37 -32
  117. package/dist/lib/kuzzle/kuzzle.d.ts +13 -8
  118. package/dist/lib/kuzzle/kuzzle.js +103 -128
  119. package/dist/lib/model/security/profile.js +17 -7
  120. package/dist/lib/model/security/role.js +17 -7
  121. package/dist/lib/model/security/user.js +17 -7
  122. package/dist/lib/model/storage/apiKey.d.ts +1 -1
  123. package/dist/lib/model/storage/apiKey.js +17 -7
  124. package/dist/lib/service/cache/redis.js +40 -9
  125. package/dist/lib/service/service.js +17 -7
  126. package/dist/lib/service/storage/7/elasticsearch.d.ts +36 -25
  127. package/dist/lib/service/storage/7/elasticsearch.js +73 -55
  128. package/dist/lib/service/storage/8/elasticsearch.d.ts +47 -36
  129. package/dist/lib/service/storage/8/elasticsearch.js +73 -55
  130. package/dist/lib/service/storage/Elasticsearch.d.ts +10 -4
  131. package/dist/lib/types/HttpStream.d.ts +0 -1
  132. package/dist/lib/types/Plugin.js +17 -7
  133. package/dist/lib/types/config/SecurityConfiguration.d.ts +0 -2
  134. package/dist/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.d.ts +5 -0
  135. package/dist/lib/types/controllers/GetCurrentUserResponse.d.ts +5 -0
  136. package/dist/lib/types/controllers/GetCurrentUserResponse.js +3 -0
  137. package/dist/lib/types/controllers/ResetSecurityResult.d.ts +5 -0
  138. package/dist/lib/types/controllers/ResetSecurityResult.js +3 -0
  139. package/dist/lib/types/controllers/adminController.type.d.ts +7 -5
  140. package/dist/lib/types/controllers/authController.type.d.ts +7 -5
  141. package/dist/lib/types/core/auth/Serialized.d.ts +14 -0
  142. package/dist/lib/types/core/auth/Serialized.js +3 -0
  143. package/dist/lib/types/core/auth/formatProcessing.type.d.ts +5 -11
  144. package/dist/lib/types/events/EventProtocol.d.ts +0 -2
  145. package/dist/lib/types/index.d.ts +1 -0
  146. package/dist/lib/types/index.js +1 -0
  147. package/dist/lib/types/storage/8/Elasticsearch.d.ts +4 -3
  148. package/dist/lib/util/array.d.ts +1 -1
  149. package/dist/lib/util/array.js +7 -6
  150. package/dist/lib/util/assertType.js +5 -6
  151. package/dist/lib/util/async.js +1 -2
  152. package/dist/lib/util/asyncStore.d.ts +0 -1
  153. package/dist/lib/util/bufferedPassThrough.d.ts +0 -3
  154. package/dist/lib/util/crypto.js +1 -2
  155. package/dist/lib/util/debug.d.ts +0 -1
  156. package/dist/lib/util/debug.js +17 -7
  157. package/dist/lib/util/distributedLock.d.ts +27 -4
  158. package/dist/lib/util/distributedLock.js +69 -16
  159. package/dist/lib/util/dump-collection.d.ts +2 -2
  160. package/dist/lib/util/dump-collection.js +22 -13
  161. package/dist/lib/util/esRequest.js +1 -2
  162. package/dist/lib/util/extractFields.d.ts +16 -7
  163. package/dist/lib/util/extractFields.js +1 -10
  164. package/dist/lib/util/koncordeCompat.js +22 -13
  165. package/dist/lib/util/mutex.d.ts +4 -4
  166. package/dist/lib/util/mutex.js +21 -11
  167. package/dist/lib/util/name-generator.js +2 -2
  168. package/dist/lib/util/requestAssertions.js +27 -18
  169. package/dist/lib/util/safeObject.js +3 -4
  170. package/dist/lib/util/stackTrace.js +2 -3
  171. package/dist/lib/util/thrown.js +1 -2
  172. package/dist/lib/util/time.js +1 -2
  173. package/dist/package.json +22 -15
  174. package/package.json +22 -15
@@ -35,13 +35,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
35
35
  }) : function(o, v) {
36
36
  o["default"] = v;
37
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
- };
38
+ var __importStar = (this && this.__importStar) || (function () {
39
+ var ownKeys = function(o) {
40
+ ownKeys = Object.getOwnPropertyNames || function (o) {
41
+ var ar = [];
42
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
43
+ return ar;
44
+ };
45
+ return ownKeys(o);
46
+ };
47
+ return function (mod) {
48
+ if (mod && mod.__esModule) return mod;
49
+ var result = {};
50
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51
+ __setModuleDefault(result, mod);
52
+ return result;
53
+ };
54
+ })();
45
55
  var __importDefault = (this && this.__importDefault) || function (mod) {
46
56
  return (mod && mod.__esModule) ? mod : { "default": mod };
47
57
  };
@@ -39,7 +39,7 @@ declare class KuzzleEventEmitter extends EventEmitter {
39
39
  *
40
40
  * @warning Critical section of code
41
41
  */
42
- emit(event: string | symbol, ...args: any[]): boolean;
42
+ emit(event: string | symbol, ...args: unknown[]): boolean;
43
43
  /**
44
44
  * Emits a pipe event, which triggers the following, in that order:
45
45
  * 1. Plugin pipes are invoked one after another (waterfall). Each plugin must
@@ -59,11 +59,11 @@ declare class KuzzleEventEmitter extends EventEmitter {
59
59
  /**
60
60
  * Emits an "ask" event to get information about the provided payload
61
61
  */
62
- ask<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], ...args: [payload?: TAskEventDefinition["payload"], ...rest: any]): Promise<TAskEventDefinition["result"]>;
62
+ ask<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], ...args: [payload?: TAskEventDefinition["payload"], ...rest: unknown[]]): Promise<TAskEventDefinition["result"]>;
63
63
  /**
64
64
  * Calls a callback to get information about the provided payload
65
65
  */
66
- call<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], ...args: [payload?: TAskEventDefinition["payload"], ...rest: any]): TAskEventDefinition["result"];
66
+ call<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], ...args: [payload?: TAskEventDefinition["payload"], ...rest: unknown[]]): TAskEventDefinition["result"];
67
67
  /**
68
68
  * Registers a plugin hook.
69
69
  * Catch any error in the handler and emit the hook:onError event.
@@ -35,13 +35,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
35
35
  }) : function(o, v) {
36
36
  o["default"] = v;
37
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
- };
38
+ var __importStar = (this && this.__importStar) || (function () {
39
+ var ownKeys = function(o) {
40
+ ownKeys = Object.getOwnPropertyNames || function (o) {
41
+ var ar = [];
42
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
43
+ return ar;
44
+ };
45
+ return ownKeys(o);
46
+ };
47
+ return function (mod) {
48
+ if (mod && mod.__esModule) return mod;
49
+ var result = {};
50
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51
+ __setModuleDefault(result, mod);
52
+ return result;
53
+ };
54
+ })();
45
55
  var __importDefault = (this && this.__importDefault) || function (mod) {
46
56
  return (mod && mod.__esModule) ? mod : { "default": mod };
47
57
  };
@@ -35,13 +35,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
35
35
  }) : function(o, v) {
36
36
  o["default"] = v;
37
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
- };
38
+ var __importStar = (this && this.__importStar) || (function () {
39
+ var ownKeys = function(o) {
40
+ ownKeys = Object.getOwnPropertyNames || function (o) {
41
+ var ar = [];
42
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
43
+ return ar;
44
+ };
45
+ return ownKeys(o);
46
+ };
47
+ return function (mod) {
48
+ if (mod && mod.__esModule) return mod;
49
+ var result = {};
50
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51
+ __setModuleDefault(result, mod);
52
+ return result;
53
+ };
54
+ })();
45
55
  var __importDefault = (this && this.__importDefault) || function (mod) {
46
56
  return (mod && mod.__esModule) ? mod : { "default": mod };
47
57
  };
@@ -35,13 +35,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
35
35
  }) : function(o, v) {
36
36
  o["default"] = v;
37
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
- };
38
+ var __importStar = (this && this.__importStar) || (function () {
39
+ var ownKeys = function(o) {
40
+ ownKeys = Object.getOwnPropertyNames || function (o) {
41
+ var ar = [];
42
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
43
+ return ar;
44
+ };
45
+ return ownKeys(o);
46
+ };
47
+ return function (mod) {
48
+ if (mod && mod.__esModule) return mod;
49
+ var result = {};
50
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51
+ __setModuleDefault(result, mod);
52
+ return result;
53
+ };
54
+ })();
45
55
  var __importDefault = (this && this.__importDefault) || function (mod) {
46
56
  return (mod && mod.__esModule) ? mod : { "default": mod };
47
57
  };
@@ -52,7 +62,7 @@ const storeScopeEnum_1 = require("../core/storage/storeScopeEnum");
52
62
  const specification_1 = require("../core/validation/specification");
53
63
  const kerror = __importStar(require("../kerror"));
54
64
  const debug_1 = __importDefault(require("../util/debug"));
55
- const mutex_1 = require("../util/mutex"); // NOSONAR: see init()
65
+ const distributedLock_1 = require("../util/distributedLock");
56
66
  const debug = (0, debug_1.default)("kuzzle:bootstrap:internalIndex");
57
67
  const securitiesBootstrap = {
58
68
  profiles: {
@@ -112,32 +122,27 @@ class InternalIndexHandler extends store_1.Store {
112
122
  }
113
123
  async init() {
114
124
  await super.init(this.config.collections);
115
- // NOSONAR: `Mutex` is deprecated in favour of `withLock`, but the two use
116
- // incompatible acquisition/TTL formats and must not contend on the same
117
- // key — swapping it is a behaviour change, deferred to #2894.
118
- const lockOptions = { timeout: -1, ttl: 30000 };
119
- const mutex = new mutex_1.Mutex("InternalIndexBootstrap", lockOptions); // NOSONAR
120
- await mutex.lock();
121
- try {
122
- const bootstrapped = await this.exists("config", this._BOOTSTRAP_DONE_ID);
123
- if (bootstrapped) {
124
- await this._initSecret();
125
- return;
125
+ // No retry limit: the node holding it is bootstrapping the internal
126
+ // index, and this one cannot start before that is done
127
+ await (0, distributedLock_1.withLock)("InternalIndexBootstrap", async () => {
128
+ try {
129
+ const bootstrapped = await this.exists("config", this._BOOTSTRAP_DONE_ID);
130
+ if (bootstrapped) {
131
+ await this._initSecret();
132
+ return;
133
+ }
134
+ await bluebird_1.default.resolve(this._bootstrapSequence()).timeout(this.timeout);
135
+ await this.create("config", { timestamp: Date.now() }, {
136
+ id: this._BOOTSTRAP_DONE_ID,
137
+ });
126
138
  }
127
- await bluebird_1.default.resolve(this._bootstrapSequence()).timeout(this.timeout);
128
- await this.create("config", { timestamp: Date.now() }, {
129
- id: this._BOOTSTRAP_DONE_ID,
130
- });
131
- }
132
- catch (error) {
133
- if (error instanceof bluebird_1.default.TimeoutError) {
134
- throw kerror.get("services", "storage", "bootstrap_timeout", "internalIndex");
139
+ catch (error) {
140
+ if (error instanceof bluebird_1.default.TimeoutError) {
141
+ throw kerror.get("services", "storage", "bootstrap_timeout", "internalIndex");
142
+ }
143
+ throw error;
135
144
  }
136
- throw error;
137
- }
138
- finally {
139
- await mutex.unlock();
140
- }
145
+ }, { retryAttempts: Number.POSITIVE_INFINITY, ttl: 30000 });
141
146
  }
142
147
  /**
143
148
  * @override
@@ -95,8 +95,12 @@ declare class Kuzzle extends KuzzleEventEmitter {
95
95
  * @param {Object} - Additional options (import, installations, plugins, secretsFile, support, vaultKey)
96
96
  *
97
97
  * @this {Kuzzle}
98
+ *
99
+ * The public signature takes `unknown`, which every call that compiled with
100
+ * v2.56.0's `any` still satisfies. `Backend.start()` is the one caller, and
101
+ * it hands the application wrapper the implementation reads.
98
102
  */
99
- start(application: any, options?: StartOptions): Promise<void>;
103
+ start(application: unknown, options?: StartOptions): Promise<void>;
100
104
  /**
101
105
  * Generates the node ID.
102
106
  *
@@ -121,18 +125,19 @@ declare class Kuzzle extends KuzzleEventEmitter {
121
125
  * @returns {Promise<void>}
122
126
  */
123
127
  install(installations?: InstallationConfig[]): Promise<void>;
124
- ask(event: string, ...args: [payload?: any, ...rest: any]): Promise<any>;
125
- emit(event: string, ...args: any[]): boolean;
126
- pipe(event: string, ...args: any[]): Promise<any>;
128
+ ask(event: string, ...args: [payload?: unknown, ...rest: unknown[]]): Promise<any>;
129
+ emit(event: string, ...args: unknown[]): boolean;
130
+ pipe(event: string, ...args: unknown[]): Promise<any>;
127
131
  private importUserMappings;
128
132
  private importMappings;
129
133
  private importFixtures;
130
134
  private importPermissions;
135
+ private isConfigsEmpty;
131
136
  /**
132
- * Check if every import has been done, if one of them is not finished yet, wait for it
137
+ * Records the hash of the payload just imported (or found already imported)
138
+ * in both Redis and `%kuzzle.imports`, so that the next node or the next
139
+ * start can tell the import is done for this very payload
133
140
  */
134
- private _waitForImportToFinish;
135
- private isConfigsEmpty;
136
141
  private persistHashedImport;
137
142
  /**
138
143
  * Load into the app several imports
@@ -144,7 +149,7 @@ declare class Kuzzle extends KuzzleEventEmitter {
144
149
  */
145
150
  loadInitialState(toImport?: ImportConfig, toSupport?: SupportConfig): Promise<void>;
146
151
  dump(suffix: string): Promise<string>;
147
- hash(input: any): number;
152
+ hash(input: unknown): number;
148
153
  get state(): kuzzleStateEnum;
149
154
  set state(value: kuzzleStateEnum);
150
155
  /**
@@ -35,13 +35,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
35
35
  }) : function(o, v) {
36
36
  o["default"] = v;
37
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
- };
38
+ var __importStar = (this && this.__importStar) || (function () {
39
+ var ownKeys = function(o) {
40
+ ownKeys = Object.getOwnPropertyNames || function (o) {
41
+ var ar = [];
42
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
43
+ return ar;
44
+ };
45
+ return ownKeys(o);
46
+ };
47
+ return function (mod) {
48
+ if (mod && mod.__esModule) return mod;
49
+ var result = {};
50
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51
+ __setModuleDefault(result, mod);
52
+ return result;
53
+ };
54
+ })();
45
55
  var __importDefault = (this && this.__importDefault) || function (mod) {
46
56
  return (mod && mod.__esModule) ? mod : { "default": mod };
47
57
  };
@@ -73,6 +83,7 @@ const validation_1 = __importDefault(require("../core/validation/validation"));
73
83
  const kerror = __importStar(require("../kerror"));
74
84
  const asyncStore_1 = __importDefault(require("../util/asyncStore"));
75
85
  const crypto_1 = require("../util/crypto");
86
+ const distributedLock_1 = require("../util/distributedLock");
76
87
  const mutex_1 = require("../util/mutex");
77
88
  const dumpGenerator_1 = __importDefault(require("./dumpGenerator"));
78
89
  const KuzzleEventEmitter_1 = __importDefault(require("./event/KuzzleEventEmitter"));
@@ -138,15 +149,7 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
138
149
  userMappings: this.importUserMappings.bind(this),
139
150
  };
140
151
  }
141
- /**
142
- * Initializes all the needed components of Kuzzle.
143
- *
144
- * @param {Application} - Application Plugin instance
145
- * @param {Object} - Additional options (import, installations, plugins, secretsFile, support, vaultKey)
146
- *
147
- * @this {Kuzzle}
148
- */
149
- async start(application, options = { import: {} }) {
152
+ async start(application, options) {
150
153
  this.registerSignalHandlers();
151
154
  try {
152
155
  this.log.info(`[ℹ] Starting Kuzzle ${this.version} ...`);
@@ -164,7 +167,7 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
164
167
  await new security_1.default().init();
165
168
  // This will init the cluster module if enabled
166
169
  await this.initKuzzleNode();
167
- this.vault = vault_1.default.load(options.vaultKey, options.secretsFile, this.config.vault?.newAlgorithm);
170
+ this.vault = vault_1.default.load(options?.vaultKey, options?.secretsFile, this.config.vault?.newAlgorithm);
168
171
  this.validation.init();
169
172
  await this.tokenManager.init();
170
173
  await this.funnel.init();
@@ -175,15 +178,15 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
175
178
  await this.entryPoint.init();
176
179
  await this.debugger.init();
177
180
  this.pluginsManager.application = application;
178
- const pluginImports = await this.pluginsManager.init(options.plugins);
179
- const imports = lodash_1.default.merge({}, pluginImports, options.import);
181
+ const pluginImports = await this.pluginsManager.init(options?.plugins);
182
+ const imports = lodash_1.default.merge({}, pluginImports, options?.import);
180
183
  // Authentification plugins must be loaded before users import to avoid
181
184
  // credentials related error which would prevent Kuzzle from starting
182
- await this.loadInitialState(imports, options.support);
185
+ await this.loadInitialState(imports, options?.support);
183
186
  await this.ask("core:security:verify");
184
187
  this.router.init();
185
188
  this.log.info("[✔] Core components loaded");
186
- await this.install(options.installations);
189
+ await this.install(options?.installations);
187
190
  // `application` is the very wrapper handed to the plugins manager six
188
191
  // lines up, so reading the name back off the manager was a round trip
189
192
  // through a getter that can answer `undefined`.
@@ -241,7 +244,10 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
241
244
  }
242
245
  // The other nodes may be waiting on a lock this one holds: a node leaving
243
246
  // mid-startup is often in the middle of one (F-13).
244
- await mutex_1.Mutex.releaseAllBeforeExit(); // NOSONAR: frees locks taken through the deprecated API
247
+ await Promise.all([
248
+ (0, distributedLock_1.releaseAllLocksBeforeExit)(),
249
+ mutex_1.Mutex.releaseAllBeforeExit(), // NOSONAR: frees locks taken through the deprecated API
250
+ ]);
245
251
  this.log.info("Halted.");
246
252
  // flush both application and Kuzzle core loggers before leaving (Could happen even if some core/application components are not initialized)
247
253
  await this?.log?.flush?.();
@@ -266,9 +272,9 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
266
272
  if (!installations?.length) {
267
273
  return;
268
274
  }
269
- const mutex = new mutex_1.Mutex("backend:installations");
270
- await mutex.lock();
271
- try {
275
+ // No retry limit: another node is running the installations, and this
276
+ // one must not start before they are recorded
277
+ await (0, distributedLock_1.withLock)("backend:installations", async () => {
272
278
  for (const installation of installations) {
273
279
  const isAlreadyInstalled = await this.ask("core:storage:private:document:exist", "kuzzle", "installations", installation.id);
274
280
  if (!isAlreadyInstalled) {
@@ -286,10 +292,7 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
286
292
  this.log.info(`[✔] Install code "${installation.id}" successfully executed`);
287
293
  }
288
294
  }
289
- }
290
- finally {
291
- await mutex.unlock();
292
- }
295
+ }, { retryAttempts: Number.POSITIVE_INFINITY });
293
296
  }
294
297
  // For testing purpose
295
298
  async ask(event, ...args) {
@@ -322,11 +325,8 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
322
325
  }
323
326
  else if (!lodash_1.default.isEmpty(toSupport.mappings)) {
324
327
  await this.ask("core:storage:public:mappings:import", toSupport.mappings, {
325
- /**
326
- * If it's the first time the mapping are loaded and another node is already importing the mapping into the database
327
- * we just want to load the mapping in our own index cache and not in the database.
328
- */
329
- indexCacheOnly: status.initialized || !status.locked,
328
+ // Already imported (by this node or another one): only fill the cache
329
+ indexCacheOnly: status.initialized,
330
330
  propagate: false, // Each node needs to do the import themselves
331
331
  rawMappings: true,
332
332
  refresh: true,
@@ -335,11 +335,8 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
335
335
  }
336
336
  else if (!lodash_1.default.isEmpty(toImport.mappings)) {
337
337
  await this.ask("core:storage:public:mappings:import", toImport.mappings, {
338
- /**
339
- * If it's the first time the mapping are loaded and another node is already importing the mapping into the database
340
- * we just want to load the mapping in our own index cache and not in the database.
341
- */
342
- indexCacheOnly: status.initialized || !status.locked,
338
+ // Already imported (by this node or another one): only fill the cache
339
+ indexCacheOnly: status.initialized,
343
340
  propagate: false, // Each node needs to do the import themselves
344
341
  refresh: true,
345
342
  });
@@ -392,19 +389,6 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
392
389
  this.log.info("[✔] Permissions import successful");
393
390
  }
394
391
  }
395
- /**
396
- * Check if every import has been done, if one of them is not finished yet, wait for it
397
- */
398
- async _waitForImportToFinish() {
399
- const importTypes = Object.keys(this.importTypes);
400
- for (const importType of importTypes) {
401
- // If the import is done, we pop it from the queue to check the next one
402
- if (await this.ask("core:cache:internal:get", `backend:init:import:${importType}`)) {
403
- return;
404
- }
405
- await bluebird_1.default.delay(1000);
406
- }
407
- }
408
392
  isConfigsEmpty(importConfig, supportConfig) {
409
393
  if (lodash_1.default.isEmpty(importConfig.mappings) &&
410
394
  lodash_1.default.isEmpty(importConfig.profiles) &&
@@ -418,10 +402,16 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
418
402
  }
419
403
  return false;
420
404
  }
421
- async persistHashedImport({ existingRedisHash, existingESHash, importPayloadHash, type, }) {
422
- if (!existingRedisHash && !existingESHash) {
423
- // If the import is not initialized in the redis cache and in the ES, we initialize it
424
- this.log.info(`${type} import is not initialized, initializing...`);
405
+ /**
406
+ * Records the hash of the payload just imported (or found already imported)
407
+ * in both Redis and `%kuzzle.imports`, so that the next node or the next
408
+ * start can tell the import is done for this very payload
409
+ */
410
+ async persistHashedImport({ existingRedisHash, existingESHash, importPayloadHash, initialized, type, }) {
411
+ // Not initialized: the payload was just imported, and a hash left by a
412
+ // previous payload must be replaced, or every start would import it again
413
+ if (!initialized || !existingESHash) {
414
+ this.log.info(`Recording the ${type} import in %kuzzle.imports...`);
425
415
  // `createOrReplace`, not `create`: this document has a fixed id, so a
426
416
  // conflict on it means another node initialized the same import — an
427
417
  // outcome to converge on, not an error to die on. `create` made that
@@ -429,24 +419,9 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
429
419
  await this.ask("core:storage:private:document:createOrReplace", "kuzzle", "imports", `backend:init:import:${type}`, {
430
420
  hash: importPayloadHash,
431
421
  });
432
- await this.ask("core:cache:internal:store", `backend:init:import:${type}`, importPayloadHash);
433
422
  }
434
- else if (existingRedisHash && !existingESHash) {
435
- // If the import is initialized in the redis cache but not in the ES
436
- // We initialize it in the ES
437
- this.log.info(`${type} import is not initialized in %kuzzle.imports, initializing...`);
438
- const redisCache = await this.ask("core:cache:internal:get", `backend:init:import:${type}`);
439
- // Same reasoning as above: a fixed id, so a conflict is convergence.
440
- await this.ask("core:storage:private:document:createOrReplace", "kuzzle", "imports", `backend:init:import:${type}`, {
441
- hash: redisCache,
442
- });
443
- }
444
- else if (!existingRedisHash && existingESHash) {
445
- // If the import is initialized in the ES but not in the redis cache
446
- // We initialize it in the redis cache
447
- this.log.info(`${type} import is not initialized in the redis cache, initializing...`);
448
- const esDocument = await this.ask("core:storage:private:document:get", "kuzzle", "imports", `backend:init:import:${type}`);
449
- await this.ask("core:cache:internal:store", `backend:init:import:${type}`, esDocument._source.hash);
423
+ if (!initialized || !existingRedisHash) {
424
+ await this.ask("core:cache:internal:store", `backend:init:import:${type}`, importPayloadHash);
450
425
  }
451
426
  }
452
427
  /**
@@ -461,42 +436,37 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
461
436
  if (this.isConfigsEmpty(toImport, toSupport)) {
462
437
  return;
463
438
  }
464
- const lockedMutex = [];
465
- try {
466
- for (const [type, importMethod] of Object.entries(this.importTypes)) {
467
- const importPayload = {};
468
- switch (type) {
469
- case "fixtures":
470
- lodash_1.default.set(importPayload, "toSupport.fixtures", toSupport.fixtures);
471
- break;
472
- case "mappings":
473
- lodash_1.default.set(importPayload, "toSupport.mappings", toSupport.mappings);
474
- lodash_1.default.set(importPayload, "toImport.mappings", toImport.mappings);
475
- break;
476
- case "permissions":
477
- lodash_1.default.set(importPayload, "toSupport.securities", toSupport.securities);
478
- lodash_1.default.set(importPayload, "toImport.profiles", toImport.profiles);
479
- lodash_1.default.set(importPayload, "toImport.roles", toImport.roles);
480
- lodash_1.default.set(importPayload, "toImport.users", toImport.users);
481
- break;
482
- }
483
- // `?? ""`: `json-stable-stringify` answers undefined for a value it
484
- // cannot serialise, and the payload is built right above.
485
- const importPayloadHash = (0, crypto_1.sha256)((0, json_stable_stringify_1.default)(importPayload) ?? "");
486
- // `timeout: 0` means a single acquisition attempt: exactly one node
487
- // runs the import and the others carry on with `locked: false`.
488
- // The TTL has to outlive the import itself, because this lock is held
489
- // until the `finally` below — across every import type and the wait
490
- // that follows. It is still an upper bound rather than a guarantee,
491
- // which is why the bookkeeping write below is idempotent (TD-69).
492
- // NOSONAR: `Mutex` is deprecated in favour of `withLock`, but the two
493
- // use incompatible acquisition/TTL formats and must not contend on the
494
- // same key — every other node still takes this lock with `Mutex`, so
495
- // swapping one site would remove the exclusion it exists for. Deferred
496
- // to #2894, like the remaining call sites.
497
- const lockOptions = { timeout: 0, ttl: 60000 };
498
- const mutex = new mutex_1.Mutex(`backend:import:${type}`, lockOptions); // NOSONAR
499
- const locked = await mutex.lock();
439
+ const importTypes = Object.entries(this.importTypes);
440
+ // Imports the types from `index` on. Each type's lock is taken around the
441
+ // remaining types, so that every lock taken is held until all the imports
442
+ // are done: a node waiting for the first lock starts only once the node
443
+ // ahead of it has imported everything.
444
+ const importFrom = async (index) => {
445
+ const next = importTypes[index];
446
+ if (!next) {
447
+ return;
448
+ }
449
+ const [type, importMethod] = next;
450
+ const importPayload = {};
451
+ switch (type) {
452
+ case "fixtures":
453
+ lodash_1.default.set(importPayload, "toSupport.fixtures", toSupport.fixtures);
454
+ break;
455
+ case "mappings":
456
+ lodash_1.default.set(importPayload, "toSupport.mappings", toSupport.mappings);
457
+ lodash_1.default.set(importPayload, "toImport.mappings", toImport.mappings);
458
+ break;
459
+ case "permissions":
460
+ lodash_1.default.set(importPayload, "toSupport.securities", toSupport.securities);
461
+ lodash_1.default.set(importPayload, "toImport.profiles", toImport.profiles);
462
+ lodash_1.default.set(importPayload, "toImport.roles", toImport.roles);
463
+ lodash_1.default.set(importPayload, "toImport.users", toImport.users);
464
+ break;
465
+ }
466
+ // `?? ""`: `json-stable-stringify` answers undefined for a value it
467
+ // cannot serialise, and the payload is built right above.
468
+ const importPayloadHash = (0, crypto_1.sha256)((0, json_stable_stringify_1.default)(importPayload) ?? "");
469
+ const importType = async () => {
500
470
  // Read the bookkeeping *after* the lock, never before: a read taken
501
471
  // before acquiring it is not protected by it, and the holder that
502
472
  // acted on a stale "not initialized" used to create a document the
@@ -515,26 +485,31 @@ class Kuzzle extends KuzzleEventEmitter_1.default {
515
485
  initialized = esDocument._source.hash === importPayloadHash;
516
486
  }
517
487
  await importMethod({ toImport, toSupport }, {
518
- firstCall: !initialized && locked,
519
- initialized: initialized,
520
- locked,
488
+ firstCall: !initialized,
489
+ initialized,
521
490
  });
522
- if (locked) {
523
- lockedMutex.push(mutex);
524
- await this.persistHashedImport({
525
- existingESHash,
526
- existingRedisHash,
527
- importPayloadHash,
528
- type,
529
- });
530
- }
531
- }
532
- await this._waitForImportToFinish();
533
- this.log.info("[✔] Import successful");
534
- }
535
- finally {
536
- await Promise.all(lockedMutex.map((mutex) => mutex.unlock()));
537
- }
491
+ await this.persistHashedImport({
492
+ existingESHash,
493
+ existingRedisHash,
494
+ importPayloadHash,
495
+ initialized,
496
+ type,
497
+ });
498
+ await importFrom(index + 1);
499
+ };
500
+ // No retry limit: the node holding it is running this import, and this
501
+ // one must not start before it is done. Once it gets the lock, it finds
502
+ // the import done for this payload and only fills its cache; if the
503
+ // node ahead died mid-import, it runs the import itself. The lock is
504
+ // refreshed while held; a lost lock fails the startup with
505
+ // `MutexLockLostError` (the bookkeeping write stays idempotent, TD-69).
506
+ await (0, distributedLock_1.withLock)(`backend:import:${type}`, importType, {
507
+ retryAttempts: Number.POSITIVE_INFINITY,
508
+ ttl: 60000,
509
+ });
510
+ };
511
+ await importFrom(0);
512
+ this.log.info("[✔] Import successful");
538
513
  }
539
514
  dump(suffix) {
540
515
  return this.dumpGenerator.dump(suffix);
@@ -35,13 +35,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
35
35
  }) : function(o, v) {
36
36
  o["default"] = v;
37
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
- };
38
+ var __importStar = (this && this.__importStar) || (function () {
39
+ var ownKeys = function(o) {
40
+ ownKeys = Object.getOwnPropertyNames || function (o) {
41
+ var ar = [];
42
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
43
+ return ar;
44
+ };
45
+ return ownKeys(o);
46
+ };
47
+ return function (mod) {
48
+ if (mod && mod.__esModule) return mod;
49
+ var result = {};
50
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51
+ __setModuleDefault(result, mod);
52
+ return result;
53
+ };
54
+ })();
45
55
  var __importDefault = (this && this.__importDefault) || function (mod) {
46
56
  return (mod && mod.__esModule) ? mod : { "default": mod };
47
57
  };