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
@@ -14,22 +14,23 @@ export type KUpdateResponse = {
14
14
  _source: unknown;
15
15
  _version: number;
16
16
  };
17
+ /** `size` is in bytes: `store.size_in_bytes`, never the human-readable form. */
17
18
  export type KStatsIndexesCollection = {
18
19
  documentCount: number;
19
20
  name: string;
20
- size: estypes.ByteSize;
21
+ size: number;
21
22
  };
22
23
  export type KStatsIndex = {
23
24
  collections: KStatsIndexesCollection[];
24
25
  name: string;
25
- size: estypes.ByteSize;
26
+ size: number;
26
27
  };
27
28
  export type KStatsIndexes = {
28
29
  [key: string]: KStatsIndex;
29
30
  };
30
31
  export type KStats = {
31
32
  indexes: KStatsIndex[];
32
- size: estypes.ByteSize;
33
+ size: number;
33
34
  };
34
35
  export type { JSONObject } from "../../JSONObject";
35
36
  export type KImportError = {
@@ -8,4 +8,4 @@
8
8
  * - [0] Both value are equals
9
9
  * @returns {number} The index of the value, or -1 if not found
10
10
  */
11
- export declare function binarySearch(array: any[], predicate: (value: any) => number): number;
11
+ export declare function binarySearch<T>(array: readonly T[], predicate: (value: T) => number): number;
@@ -20,7 +20,7 @@
20
20
  * limitations under the License.
21
21
  */
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.binarySearch = void 0;
23
+ exports.binarySearch = binarySearch;
24
24
  /**
25
25
  * Binary Search
26
26
  *
@@ -34,13 +34,15 @@ exports.binarySearch = void 0;
34
34
  function binarySearch(array, predicate) {
35
35
  let lowerBound = 0;
36
36
  let upperBound = array.length - 1;
37
- if (array.length === 1) {
38
- return predicate(array[0]) === 0 ? 0 : -1;
39
- }
40
37
  while (lowerBound <= upperBound) {
41
38
  // 5x faster than Math.floor((lowerBound + upperBound) / 2)
42
39
  const index = (lowerBound + upperBound) >> 1;
43
- const comparison = predicate(array[index]);
40
+ const value = array[index];
41
+ // Only a hole or an `undefined` element: the index is within bounds.
42
+ if (value === undefined) {
43
+ return -1;
44
+ }
45
+ const comparison = predicate(value);
44
46
  if (comparison < 0) {
45
47
  upperBound = index - 1;
46
48
  }
@@ -53,5 +55,4 @@ function binarySearch(array, predicate) {
53
55
  }
54
56
  return -1;
55
57
  }
56
- exports.binarySearch = binarySearch;
57
58
  //# sourceMappingURL=array.js.map
@@ -20,7 +20,11 @@
20
20
  * limitations under the License.
21
21
  */
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.assertInteger = exports.assertString = exports.assertArray = exports.assertArrayOrObject = exports.assertObject = void 0;
23
+ exports.assertObject = assertObject;
24
+ exports.assertArrayOrObject = assertArrayOrObject;
25
+ exports.assertArray = assertArray;
26
+ exports.assertString = assertString;
27
+ exports.assertInteger = assertInteger;
24
28
  const errors_1 = require("../kerror/errors");
25
29
  /**
26
30
  * The first overload is what the callers in `lib/api/request` need: they hand
@@ -37,7 +41,6 @@ function assertObject(attr, data) {
37
41
  }
38
42
  return data;
39
43
  }
40
- exports.assertObject = assertObject;
41
44
  /**
42
45
  * Throws if the provided data is not an object or an array.
43
46
  * Returns the unmodified data if validated
@@ -55,7 +58,6 @@ function assertArrayOrObject(attr, data) {
55
58
  }
56
59
  return data;
57
60
  }
58
- exports.assertArrayOrObject = assertArrayOrObject;
59
61
  /**
60
62
  * The overload above is not a claim the implementation does not make: every
61
63
  * element that reaches the returned array has been checked with
@@ -79,7 +81,6 @@ function assertArray(attr, data, type) {
79
81
  }
80
82
  return clone;
81
83
  }
82
- exports.assertArray = assertArray;
83
84
  /**
84
85
  * Throws if the provided data is not a string
85
86
  * Returns the unmodified data if validated
@@ -97,7 +98,6 @@ function assertString(attr, data) {
97
98
  }
98
99
  return data;
99
100
  }
100
- exports.assertString = assertString;
101
101
  /**
102
102
  * Throws if the provided data is not an integer
103
103
  * Returns the unmodified data if validated
@@ -112,5 +112,4 @@ function assertInteger(attr, data) {
112
112
  }
113
113
  return data;
114
114
  }
115
- exports.assertInteger = assertInteger;
116
115
  //# sourceMappingURL=assertType.js.map
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.promiseAllN = void 0;
3
+ exports.promiseAllN = promiseAllN;
4
4
  /*
5
5
  * Resolve promises with a limited concurrency number
6
6
  *
@@ -70,5 +70,4 @@ function promiseAllN(collection, n = 100) {
70
70
  }
71
71
  return pendingPromise;
72
72
  }
73
- exports.promiseAllN = promiseAllN;
74
73
  //# sourceMappingURL=async.js.map
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { AsyncLocalStorage } from "async_hooks";
3
2
  type Store = Map<string, unknown>;
4
3
  type RunCallback = () => void;
@@ -1,6 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
- /// <reference types="node" />
4
1
  import stream from "stream";
5
2
  type Encoding = BufferEncoding | "buffer";
6
3
  type ChunkData = Buffer | string;
@@ -3,10 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.sha256 = void 0;
6
+ exports.sha256 = sha256;
7
7
  const crypto_1 = __importDefault(require("crypto"));
8
8
  function sha256(string) {
9
9
  return crypto_1.default.createHash("sha256").update(string).digest("hex");
10
10
  }
11
- exports.sha256 = sha256;
12
11
  //# sourceMappingURL=crypto.js.map
@@ -1,4 +1,3 @@
1
- /// <reference types="lib/types/debug" />
2
1
  import "../types/Global";
3
2
  declare function createDebug(namespace: string): import("debug").Debugger;
4
3
  export = createDebug;
@@ -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
  };
@@ -25,6 +25,28 @@ export interface MutexConfig {
25
25
  export declare class MutexLockLostError extends Error {
26
26
  constructor(key: string, cause?: Error);
27
27
  }
28
+ /**
29
+ * Thrown by `withLock` when the lock cannot be acquired within its retry
30
+ * attempts: the callback did not run.
31
+ */
32
+ export declare class MutexAcquireError extends Error {
33
+ constructor(key: string, attempts: number);
34
+ }
35
+ /**
36
+ * Frees every lock taken by `withLock` that this process still holds, and
37
+ * stops it from taking new ones. Only meant to be called right before
38
+ * `process.exit`, which skips the `finally` that would release them.
39
+ *
40
+ * A process that exits holding a lock leaves it in Redis until its TTL
41
+ * expires, and every node waiting on it waits that long (step 15, F-13).
42
+ *
43
+ * From then on, `withLock` never settles and never runs its callback: the
44
+ * process is about to exit, and rejecting would send the caller down a path
45
+ * meant for a lock held by another node.
46
+ *
47
+ * Internal to Kuzzle: not exported by the package.
48
+ */
49
+ export declare function releaseAllLocksBeforeExit(): Promise<void>;
28
50
  /**
29
51
  * Runs `callback` while holding a distributed, reentrant lock on `key`.
30
52
  *
@@ -36,7 +58,8 @@ export declare class MutexLockLostError extends Error {
36
58
  *
37
59
  * The lock's TTL is extended in the background while `callback` runs. If
38
60
  * the lock cannot be acquired within `retryAttempts + 1` attempts, the
39
- * returned promise rejects without running `callback`.
61
+ * returned promise rejects with `MutexAcquireError` without running
62
+ * `callback`.
40
63
  *
41
64
  * If the lock is lost mid-callback (e.g. TTL extension failed and another
42
65
  * node may now hold it), the returned promise rejects with
@@ -44,9 +67,9 @@ export declare class MutexLockLostError extends Error {
44
67
  * be cancelled and keeps running in the background; do not perform
45
68
  * authoritative side effects after observing this rejection.
46
69
  *
47
- * Do not use on the same resource key as the deprecated `Mutex` class
48
- * concurrently: both write to the same Redis key with incompatible
49
- * value/TTL formats and will contend with (but never corrupt) each other.
70
+ * The deprecated `Mutex` class takes the same Redis key with `SET NX`: on
71
+ * the same resource, the two exclude each other, and neither can release
72
+ * the other's lock.
50
73
  *
51
74
  * @param key - resource identifier to be locked (must be identical across
52
75
  * all nodes)
@@ -23,7 +23,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
23
23
  return (mod && mod.__esModule) ? mod : { "default": mod };
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.withLock = exports.MutexLockLostError = void 0;
26
+ exports.MutexAcquireError = exports.MutexLockLostError = void 0;
27
+ exports.releaseAllLocksBeforeExit = releaseAllLocksBeforeExit;
28
+ exports.withLock = withLock;
27
29
  const node_async_hooks_1 = require("node:async_hooks");
28
30
  const redis_semaphore_1 = require("redis-semaphore");
29
31
  const debug_1 = __importDefault(require("./debug"));
@@ -41,6 +43,17 @@ class MutexLockLostError extends Error {
41
43
  }
42
44
  }
43
45
  exports.MutexLockLostError = MutexLockLostError;
46
+ /**
47
+ * Thrown by `withLock` when the lock cannot be acquired within its retry
48
+ * attempts: the callback did not run.
49
+ */
50
+ class MutexAcquireError extends Error {
51
+ constructor(key, attempts) {
52
+ super(`Failed to acquire lock "${key}" after ${attempts} attempts`);
53
+ this.name = "MutexAcquireError";
54
+ }
55
+ }
56
+ exports.MutexAcquireError = MutexAcquireError;
44
57
  /**
45
58
  * redis-semaphore's mutex, adjusted to what `withLock` promises:
46
59
  *
@@ -78,6 +91,29 @@ class ResourceMutex extends redis_semaphore_1.Mutex {
78
91
  */
79
92
  const lockContext = new node_async_hooks_1.AsyncLocalStorage();
80
93
  let clientPromise;
94
+ // Every lock this process holds, so that it can give them back before it
95
+ // exits (see `releaseAllLocksBeforeExit`).
96
+ const held = new Set();
97
+ let exiting = false;
98
+ /**
99
+ * Frees every lock taken by `withLock` that this process still holds, and
100
+ * stops it from taking new ones. Only meant to be called right before
101
+ * `process.exit`, which skips the `finally` that would release them.
102
+ *
103
+ * A process that exits holding a lock leaves it in Redis until its TTL
104
+ * expires, and every node waiting on it waits that long (step 15, F-13).
105
+ *
106
+ * From then on, `withLock` never settles and never runs its callback: the
107
+ * process is about to exit, and rejecting would send the caller down a path
108
+ * meant for a lock held by another node.
109
+ *
110
+ * Internal to Kuzzle: not exported by the package.
111
+ */
112
+ async function releaseAllLocksBeforeExit() {
113
+ exiting = true;
114
+ // Best effort: a lock that cannot be freed still expires with its TTL.
115
+ await Promise.allSettled([...held].map((mutex) => mutex.release()));
116
+ }
81
117
  /**
82
118
  * Lazily fetches and memoizes the internal cache's raw ioredis client.
83
119
  * Self-healing: if the very first call happens before the cache engine has
@@ -103,7 +139,8 @@ async function getClient() {
103
139
  *
104
140
  * The lock's TTL is extended in the background while `callback` runs. If
105
141
  * the lock cannot be acquired within `retryAttempts + 1` attempts, the
106
- * returned promise rejects without running `callback`.
142
+ * returned promise rejects with `MutexAcquireError` without running
143
+ * `callback`.
107
144
  *
108
145
  * If the lock is lost mid-callback (e.g. TTL extension failed and another
109
146
  * node may now hold it), the returned promise rejects with
@@ -111,9 +148,9 @@ async function getClient() {
111
148
  * be cancelled and keeps running in the background; do not perform
112
149
  * authoritative side effects after observing this rejection.
113
150
  *
114
- * Do not use on the same resource key as the deprecated `Mutex` class
115
- * concurrently: both write to the same Redis key with incompatible
116
- * value/TTL formats and will contend with (but never corrupt) each other.
151
+ * The deprecated `Mutex` class takes the same Redis key with `SET NX`: on
152
+ * the same resource, the two exclude each other, and neither can release
153
+ * the other's lock.
117
154
  *
118
155
  * @param key - resource identifier to be locked (must be identical across
119
156
  * all nodes)
@@ -121,8 +158,11 @@ async function getClient() {
121
158
  * @param config - lock options (ignored if this call is reentrant)
122
159
  */
123
160
  async function withLock(key, callback, config = {}) {
124
- const held = lockContext.getStore();
125
- if (held?.has(key)) {
161
+ if (exiting) {
162
+ return new Promise(() => undefined);
163
+ }
164
+ const ancestors = lockContext.getStore();
165
+ if (ancestors?.has(key)) {
126
166
  return callback();
127
167
  }
128
168
  const { retryAttempts = 10, retryDelay = 200, ttl = 30000 } = config;
@@ -142,25 +182,38 @@ async function withLock(key, callback, config = {}) {
142
182
  onLockLost: (error) => {
143
183
  loss.abort(new MutexLockLostError(key, mutex.refreshError ?? error));
144
184
  },
145
- retryInterval: retryDelay,
185
+ // redis-semaphore waits `retryInterval` after every failed attempt, the
186
+ // last one included: with no retry, that wait only delays the failure
187
+ retryInterval: retryAttempts === 0 ? 0 : retryDelay,
146
188
  });
147
189
  if (!(await mutex.tryAcquire())) {
148
- throw new Error(`Failed to acquire lock "${key}" after ${retryAttempts + 1} attempts`);
190
+ throw new MutexAcquireError(key, retryAttempts + 1);
191
+ }
192
+ held.add(mutex);
193
+ // Acquired while `releaseAllLocksBeforeExit` was running: give it back at once
194
+ if (exiting) {
195
+ await releaseQuietly(mutex, key);
196
+ return new Promise(() => undefined);
149
197
  }
150
198
  try {
151
- const nextHeld = new Set(held);
199
+ const nextHeld = new Set(ancestors);
152
200
  nextHeld.add(key);
153
201
  const callbackPromise = lockContext.run(nextHeld, () => callback());
154
202
  // Settles as soon as the lock is lost, without waiting for the callback
155
203
  return await Promise.race([callbackPromise, lockLost]);
156
204
  }
157
205
  finally {
158
- // A failed release only leaves the key to expire with its TTL: it must
159
- // not replace the callback's own outcome
160
- await mutex.release().catch((error) => {
161
- debug("Failed to release lock %s: %s", key, error);
162
- });
206
+ await releaseQuietly(mutex, key);
163
207
  }
164
208
  }
165
- exports.withLock = withLock;
209
+ /**
210
+ * A failed release only leaves the key to expire with its TTL: it must not
211
+ * replace the callback's own outcome
212
+ */
213
+ async function releaseQuietly(mutex, key) {
214
+ held.delete(mutex);
215
+ await mutex.release().catch((error) => {
216
+ debug("Failed to release lock %s: %s", key, error);
217
+ });
218
+ }
166
219
  //# sourceMappingURL=distributedLock.js.map
@@ -34,5 +34,5 @@ export declare function extractMappingFields(mapping: JSONObject): JSONObject;
34
34
  * @returns The values in the same order as the fields
35
35
  * @see https://lodash.com/docs/4.17.15#values
36
36
  */
37
- export declare function pickValues(object: any, fields: string[]): any[];
38
- export declare function dumpCollectionDocuments(index: string, collection: string, query?: any, format?: string, fields?: string[], options?: JSONObject): HttpStream;
37
+ export declare function pickValues(object: unknown, fields: string[]): unknown[];
38
+ export declare function dumpCollectionDocuments(index: string, collection: string, query?: JSONObject, format?: string, fields?: string[], options?: JSONObject): HttpStream;
@@ -15,18 +15,31 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.dumpCollectionDocuments = exports.pickValues = exports.extractMappingFields = exports.flattenObject = void 0;
39
+ exports.flattenObject = flattenObject;
40
+ exports.extractMappingFields = extractMappingFields;
41
+ exports.pickValues = pickValues;
42
+ exports.dumpCollectionDocuments = dumpCollectionDocuments;
30
43
  const get_1 = __importDefault(require("lodash/get"));
31
44
  const isObject_1 = __importDefault(require("lodash/isObject"));
32
45
  const ndjson_1 = __importDefault(require("ndjson"));
@@ -56,7 +69,6 @@ function flattenObject(target) {
56
69
  flattenStep(output, target);
57
70
  return output;
58
71
  }
59
- exports.flattenObject = flattenObject;
60
72
  function flattenStep(output, object, prev = null) {
61
73
  for (const [key, value] of Object.entries(object)) {
62
74
  const newKey = prev ? prev + "." + key : key;
@@ -89,7 +101,6 @@ function extractMappingFields(mapping) {
89
101
  }
90
102
  return newMapping;
91
103
  }
92
- exports.extractMappingFields = extractMappingFields;
93
104
  /**
94
105
  * An iteration-order-safe version of lodash.values
95
106
  *
@@ -101,7 +112,6 @@ exports.extractMappingFields = extractMappingFields;
101
112
  function pickValues(object, fields) {
102
113
  return fields.map((f) => formatValueForCSV((0, get_1.default)(object, f)));
103
114
  }
104
- exports.pickValues = pickValues;
105
115
  /**
106
116
  * Formats the value for correct CSV output, avoiding to return
107
117
  * values that would badly serialize in CSV.
@@ -240,7 +250,7 @@ class JSONLDumper extends AbstractDumper {
240
250
  }
241
251
  }
242
252
  class CSVDumper extends AbstractDumper {
243
- constructor(index, collection, query = {}, writeStream, options, fields) {
253
+ constructor(index, collection, query, writeStream, options, fields) {
244
254
  super(index, collection, query, writeStream, options);
245
255
  this.fields = fields;
246
256
  }
@@ -298,5 +308,4 @@ function dumpCollectionDocuments(index, collection, query = {}, format = "jsonl"
298
308
  }
299
309
  return new types_1.HttpStream(writableStream);
300
310
  }
301
- exports.dumpCollectionDocuments = dumpCollectionDocuments;
302
311
  //# sourceMappingURL=dump-collection.js.map
@@ -23,7 +23,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
23
23
  return (mod && mod.__esModule) ? mod : { "default": mod };
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.getESIndexDynamicSettings = void 0;
26
+ exports.getESIndexDynamicSettings = getESIndexDynamicSettings;
27
27
  const lodash_1 = __importDefault(require("lodash"));
28
28
  // Dynamic index settings specified in the elasticsearch documentation :
29
29
  // https://www.elastic.co/guide/en/elasticsearch/reference/7.5/index-modules.html#index-modules-settings
@@ -58,5 +58,4 @@ const dynamicESSettings = [
58
58
  function getESIndexDynamicSettings(requestSettings) {
59
59
  return lodash_1.default.pick(requestSettings, dynamicESSettings);
60
60
  }
61
- exports.getESIndexDynamicSettings = getESIndexDynamicSettings;
62
61
  //# sourceMappingURL=esRequest.js.map
@@ -2,6 +2,15 @@ interface ExtractedField {
2
2
  key: string;
3
3
  value: unknown;
4
4
  }
5
+ interface ExtractOptions {
6
+ fieldsToIgnore?: string[];
7
+ alsoExtractValues?: boolean;
8
+ }
9
+ /** The recursion's own arguments: not for callers. */
10
+ interface ExtractState {
11
+ path?: string | null;
12
+ extractedFields?: Array<string | ExtractedField>;
13
+ }
5
14
  /**
6
15
  * Extract nested fields of an object in a flat array.
7
16
  * Example: { field : { 1: "nested", 2: "nested" } } => [ 'field.1', 'field.2' ]
@@ -11,11 +20,11 @@ interface ExtractedField {
11
20
  *
12
21
  * @returns Array of field paths, or of { key, value } pairs when alsoExtractValues is true
13
22
  */
14
- declare function extractFields(document: Record<string, unknown>, { fieldsToIgnore, alsoExtractValues, }?: {
15
- fieldsToIgnore?: string[];
16
- alsoExtractValues?: boolean;
17
- }, { path, extractedFields, }?: {
18
- path?: string | null;
19
- extractedFields?: Array<string | ExtractedField>;
20
- }): Array<string | ExtractedField>;
23
+ declare function extractFields(document: Record<string, unknown>, options: ExtractOptions & {
24
+ alsoExtractValues: true;
25
+ }): ExtractedField[];
26
+ declare function extractFields(document: Record<string, unknown>, options?: ExtractOptions & {
27
+ alsoExtractValues?: false;
28
+ }): string[];
29
+ declare function extractFields(document: Record<string, unknown>, options?: ExtractOptions, state?: ExtractState): Array<string | ExtractedField>;
21
30
  export = extractFields;
@@ -20,16 +20,7 @@
20
20
  * limitations under the License.
21
21
  */
22
22
  const safeObject_1 = require("./safeObject");
23
- /**
24
- * Extract nested fields of an object in a flat array.
25
- * Example: { field : { 1: "nested", 2: "nested" } } => [ 'field.1', 'field.2' ]
26
- *
27
- * @param document - Document to extract fields from
28
- * @param options - alsoExtractValues (false), fieldsToIgnore ( [ ] )
29
- *
30
- * @returns Array of field paths, or of { key, value } pairs when alsoExtractValues is true
31
- */
32
- function extractFields(document, { fieldsToIgnore = [], alsoExtractValues = false, } = {}, { path = null, extractedFields = [], } = {}) {
23
+ function extractFields(document, { fieldsToIgnore = [], alsoExtractValues = false } = {}, { path = null, extractedFields = [] } = {}) {
33
24
  for (const [key, value] of Object.entries(document)) {
34
25
  if (fieldsToIgnore.includes(key)) {
35
26
  continue;
@@ -35,15 +35,29 @@ 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
  Object.defineProperty(exports, "__esModule", { value: true });
46
- exports.getIndexes = exports.getCollections = exports.koncordeTest = exports.fromKoncordeIndex = exports.toKoncordeIndex = void 0;
56
+ exports.toKoncordeIndex = toKoncordeIndex;
57
+ exports.fromKoncordeIndex = fromKoncordeIndex;
58
+ exports.koncordeTest = koncordeTest;
59
+ exports.getCollections = getCollections;
60
+ exports.getIndexes = getIndexes;
47
61
  /*
48
62
  Set of utility functions meant to ease up the use of Koncorde v4 in Kuzzle
49
63
  */
@@ -63,7 +77,6 @@ const fatal = kerror.wrap("core", "fatal");
63
77
  function toKoncordeIndex(index, collection) {
64
78
  return `${index}${SEPARATOR}${collection}`;
65
79
  }
66
- exports.toKoncordeIndex = toKoncordeIndex;
67
80
  /**
68
81
  * Returns an index+collection pair from a Koncorde v4 index name
69
82
  *
@@ -85,7 +98,6 @@ function fromKoncordeIndex(index) {
85
98
  index: kindex,
86
99
  };
87
100
  }
88
- exports.fromKoncordeIndex = fromKoncordeIndex;
89
101
  /**
90
102
  * Quick compat method to start a Koncorde test
91
103
  *
@@ -104,7 +116,6 @@ function koncordeTest(koncorde, index, collection, body, _id) {
104
116
  const data = _id ? Object.assign({}, body, { _id }) : body;
105
117
  return koncorde.test(data, indexV4);
106
118
  }
107
- exports.koncordeTest = koncordeTest;
108
119
  /**
109
120
  * Extracts the list of Koncorde indexes and translate them into a
110
121
  * Kuzzle collections list
@@ -120,7 +131,6 @@ function getCollections(koncorde, index) {
120
131
  .filter((i) => i.startsWith(indexPrefix))
121
132
  .map((i) => i.substr(indexPrefix.length));
122
133
  }
123
- exports.getCollections = getCollections;
124
134
  /**
125
135
  * Extracts the list of Koncorde indexes and translate them into a
126
136
  * Kuzzle indexes list
@@ -135,5 +145,4 @@ function getIndexes(koncorde) {
135
145
  .map((i) => i.substr(0, i.indexOf(SEPARATOR)));
136
146
  return (0, lodash_1.uniq)(indexes);
137
147
  }
138
- exports.getIndexes = getIndexes;
139
148
  //# sourceMappingURL=koncordeCompat.js.map
@@ -35,10 +35,10 @@ export interface MutexOptions {
35
35
  * synchronization between servers (see https://redis.io/topics/distlock)
36
36
  *
37
37
  * @deprecated Use `withLock` from `./distributedLock` instead: it supports
38
- * real Redlock semantics and reentrancy. Do not mix `Mutex` and `withLock`
39
- * on the same resource key — they use incompatible acquisition/TTL formats
40
- * and will contend with (though never corrupt) each other's lock on that
41
- * key.
38
+ * real Redlock semantics and reentrancy. `Mutex` and `withLock` take the
39
+ * same Redis key with `SET NX`, so they exclude each other on the same
40
+ * resource (which keeps old and new nodes apart during a rolling upgrade),
41
+ * and neither can release the other's lock.
42
42
  */
43
43
  export declare class Mutex {
44
44
  readonly resource: string;