kuzzle 2.31.0-elasticsearch-8.2 → 2.32.0-elasticsearch-8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -267,11 +267,15 @@ function initMapping() {
267
267
  kassert.assertBodyAttributeType(request, "entries", "array");
268
268
 
269
269
  val.forEach((v) => {
270
- if (typeof v !== "object" || !v.field || !v.value) {
270
+ if (
271
+ typeof v !== "object" ||
272
+ !v.field ||
273
+ (!v.value && v.value !== 0)
274
+ ) {
271
275
  throw kerror.get(
272
276
  "invalid_argument",
273
277
  "entries",
274
- "<array of object>",
278
+ "<array of objects>",
275
279
  );
276
280
  }
277
281
 
@@ -348,7 +352,11 @@ function initMapping() {
348
352
  kassert.assertBodyHasAttribute(request, "entries");
349
353
  kassert.assertBodyAttributeType(request, "entries", "array");
350
354
  val.forEach((entry) => {
351
- if (typeof entry !== "object" || !entry.key || !entry.value) {
355
+ if (
356
+ typeof entry !== "object" ||
357
+ !entry.key ||
358
+ (!entry.value && entry.value !== 0)
359
+ ) {
352
360
  throw kerror.get(
353
361
  "invalid_argument",
354
362
  "entries",
package/lib/api/funnel.js CHANGED
@@ -753,6 +753,10 @@ class Funnel {
753
753
  */
754
754
  async executePluginRequest(request) {
755
755
  try {
756
+ if (request.input.triggerEvents) {
757
+ const response = await this.processRequest(request);
758
+ return { ...response.result };
759
+ }
756
760
  return await doAction(this.getController(request), request);
757
761
  } catch (e) {
758
762
  this.handleErrorDump(e);
@@ -135,6 +135,8 @@ export declare class RequestInput {
135
135
  */
136
136
  get action(): string | null;
137
137
  set action(str: string);
138
+ get triggerEvents(): boolean | undefined;
139
+ set triggerEvents(bool: boolean);
138
140
  /**
139
141
  * Request body.
140
142
  * In Http it's the request body parsed.
@@ -54,6 +54,7 @@ const _body = "body\u200b";
54
54
  const _headers = "headers\u200b";
55
55
  const _controller = "controller\u200b";
56
56
  const _action = "action\u200b";
57
+ const _triggerEvents = "triggerEvents\u200b";
57
58
  // any property not listed here will be copied into
58
59
  // RequestInput.args
59
60
  const resourceProperties = new Set([
@@ -126,6 +127,7 @@ class RequestInput {
126
127
  this[_body] = null;
127
128
  this[_controller] = null;
128
129
  this[_action] = null;
130
+ this[_triggerEvents] = null;
129
131
  // default value to null for former "resources" to avoid breaking
130
132
  this.args = {};
131
133
  this.resource = new RequestResource(this.args);
@@ -147,6 +149,7 @@ class RequestInput {
147
149
  this.body = data.body;
148
150
  this.controller = data.controller;
149
151
  this.action = data.action;
152
+ this.triggerEvents = data.triggerEvents;
150
153
  }
151
154
  /**
152
155
  * Authentication token.
@@ -223,6 +226,12 @@ class RequestInput {
223
226
  this[_action] = assert.assertString("action", str);
224
227
  }
225
228
  }
229
+ get triggerEvents() {
230
+ return this[_triggerEvents];
231
+ }
232
+ set triggerEvents(bool) {
233
+ this[_triggerEvents] = bool === true ? true : undefined;
234
+ }
226
235
  /**
227
236
  * Request body.
228
237
  * In Http it's the request body parsed.
@@ -29,7 +29,6 @@ type UpdateOptions = {
29
29
  */
30
30
  export declare class ProfileRepository extends ObjectRepository<Profile> {
31
31
  private module;
32
- private profiles;
33
32
  /**
34
33
  * @constructor
35
34
  */
@@ -42,7 +41,9 @@ export declare class ProfileRepository extends ObjectRepository<Profile> {
42
41
  * @returns {Promise.<Promise>}
43
42
  * @throws {NotFoundError} If the corresponding profile doesn't exist
44
43
  */
45
- load(id: string): Promise<Profile>;
44
+ load(id: string, options?: {
45
+ key?: string;
46
+ }): Promise<Profile>;
46
47
  /**
47
48
  * Loads a Profile object given its id.
48
49
  * Stores the promise of the profile being loaded in the memcache
@@ -140,16 +141,6 @@ export declare class ProfileRepository extends ObjectRepository<Profile> {
140
141
  * @returns {Promise<Profile>}
141
142
  */
142
143
  fromDTO(dto: JSONObject): Promise<Profile>;
143
- /**
144
- * @override
145
- */
146
- truncate(opts: JSONObject): Promise<void>;
147
- /**
148
- * Invalidate the cache entries for the given profile. If none is provided,
149
- * the entire cache is emptied.
150
- * @param {string} [profileId]
151
- */
152
- invalidate(profileId?: string): void;
153
144
  /**
154
145
  * Optimize each policy to get a O(1) index access time
155
146
  * and a O(log(n)) collection search time.
@@ -168,8 +159,8 @@ export declare class ProfileRepository extends ObjectRepository<Profile> {
168
159
  * @param policy
169
160
  */
170
161
  private optimizePolicy;
171
- toDTO(dto: Profile): Promise<JSONObject>;
172
- deleteFromDatabase(id: string, options: JSONObject): Promise<any>;
162
+ toDTO(dto: Profile): JSONObject;
163
+ deleteFromDatabase(id: string, options: JSONObject): any;
173
164
  search(searchBody: JSONObject, options: JSONObject): Promise<{
174
165
  aggregations: any;
175
166
  hits: any[];
@@ -51,7 +51,6 @@ const bluebird_1 = __importDefault(require("bluebird"));
51
51
  const lodash_1 = require("lodash");
52
52
  const kerror = __importStar(require("../../kerror"));
53
53
  const profile_1 = require("../../model/security/profile");
54
- const cacheDbEnum_1 = require("../cache/cacheDbEnum");
55
54
  const ObjectRepository_1 = require("../shared/ObjectRepository");
56
55
  /**
57
56
  * @class ProfileRepository
@@ -62,12 +61,8 @@ class ProfileRepository extends ObjectRepository_1.ObjectRepository {
62
61
  * @constructor
63
62
  */
64
63
  constructor(securityModule) {
65
- super({
66
- cache: cacheDbEnum_1.cacheDbEnum.NONE,
67
- store: global.kuzzle.internalIndex,
68
- });
64
+ super({ store: global.kuzzle.internalIndex });
69
65
  this.module = securityModule;
70
- this.profiles = new Map();
71
66
  this.collection = "profiles";
72
67
  this.ObjectConstructor = profile_1.Profile;
73
68
  }
@@ -111,7 +106,7 @@ class ProfileRepository extends ObjectRepository_1.ObjectRepository {
111
106
  *
112
107
  * @param {String} [id] - profile identifier
113
108
  */
114
- global.kuzzle.onAsk("core:security:profile:invalidate", (id) => this.invalidate(id));
109
+ global.kuzzle.onAsk("core:security:profile:invalidate", (id) => this.deleteFromCache(id));
115
110
  /**
116
111
  * Gets multiple profiles
117
112
  * @param {Array} ids
@@ -156,13 +151,18 @@ class ProfileRepository extends ObjectRepository_1.ObjectRepository {
156
151
  * @returns {Promise.<Promise>}
157
152
  * @throws {NotFoundError} If the corresponding profile doesn't exist
158
153
  */
159
- async load(id) {
160
- if (this.profiles.has(id)) {
161
- return this.profiles.get(id);
154
+ async load(id, options = {}) {
155
+ const profile = await this.loadFromCache(id, options);
156
+ if (profile === null) {
157
+ const profileFromDatabase = await this.loadOneFromDatabase(id);
158
+ if (profileFromDatabase !== null) {
159
+ await this.persistToCache(profileFromDatabase);
160
+ profileFromDatabase.optimizedPolicies = this.optimizePolicies(profileFromDatabase.policies);
161
+ }
162
+ return profileFromDatabase;
162
163
  }
163
- const profile = await super.load(id);
164
164
  profile.optimizedPolicies = this.optimizePolicies(profile.policies);
165
- this.profiles.set(id, profile);
165
+ await this.refreshCacheTTL(profile);
166
166
  return profile;
167
167
  }
168
168
  /**
@@ -185,14 +185,7 @@ class ProfileRepository extends ObjectRepository_1.ObjectRepository {
185
185
  throw kerror.get("api", "assert", "invalid_type", "profileIds", "string[]");
186
186
  }
187
187
  for (const id of profileIds) {
188
- let profile = this.profiles.get(id);
189
- if (!profile) {
190
- profile = this.loadOneFromDatabase(id).then((p) => {
191
- p.optimizedPolicies = this.optimizePolicies(p.policies);
192
- this.profiles.set(id, p);
193
- return p;
194
- });
195
- }
188
+ const profile = this.load(id);
196
189
  profiles.push(profile);
197
190
  }
198
191
  return bluebird_1.default.all(profiles);
@@ -342,7 +335,7 @@ class ProfileRepository extends ObjectRepository_1.ObjectRepository {
342
335
  }
343
336
  }
344
337
  await this.deleteFromDatabase(profile._id, { refresh });
345
- this.profiles.delete(profile._id);
338
+ await this.deleteFromCache(profile._id);
346
339
  }
347
340
  /**
348
341
  * From a Profile object, returns a serialized object ready to be persisted
@@ -384,9 +377,9 @@ class ProfileRepository extends ObjectRepository_1.ObjectRepository {
384
377
  retryOnConflict,
385
378
  });
386
379
  const updatedProfile = await this.loadOneFromDatabase(profile._id);
380
+ await this.persistToCache(updatedProfile);
387
381
  // Recompute optimized policies based on new policies
388
382
  updatedProfile.optimizedPolicies = this.optimizePolicies(updatedProfile.policies);
389
- this.profiles.set(profile._id, updatedProfile);
390
383
  return updatedProfile;
391
384
  }
392
385
  /**
@@ -410,32 +403,6 @@ class ProfileRepository extends ObjectRepository_1.ObjectRepository {
410
403
  }
411
404
  return profile;
412
405
  }
413
- /**
414
- * @override
415
- */
416
- async truncate(opts) {
417
- try {
418
- await super.truncate(opts);
419
- }
420
- finally {
421
- // always clear the RAM cache: even if truncate fails in the middle of it,
422
- // some of the cached profiles might not be valid anymore
423
- this.invalidate();
424
- }
425
- }
426
- /**
427
- * Invalidate the cache entries for the given profile. If none is provided,
428
- * the entire cache is emptied.
429
- * @param {string} [profileId]
430
- */
431
- invalidate(profileId) {
432
- if (!profileId) {
433
- this.profiles.clear();
434
- }
435
- else {
436
- this.profiles.delete(profileId);
437
- }
438
- }
439
406
  /**
440
407
  * Optimize each policy to get a O(1) index access time
441
408
  * and a O(log(n)) collection search time.
@@ -496,10 +463,10 @@ class ProfileRepository extends ObjectRepository_1.ObjectRepository {
496
463
  // Every method described after are for testing purpose only
497
464
  // Otherwise we cannot stub them
498
465
  // ============================================
499
- async toDTO(dto) {
466
+ toDTO(dto) {
500
467
  return super.toDTO(dto);
501
468
  }
502
- async deleteFromDatabase(id, options) {
469
+ deleteFromDatabase(id, options) {
503
470
  return super.deleteFromDatabase(id, options);
504
471
  }
505
472
  async search(searchBody, options) {
@@ -43,7 +43,7 @@ class RoleRepository extends ObjectRepository {
43
43
  */
44
44
  constructor(securityModule) {
45
45
  super({
46
- cache: cacheDbEnum.NONE,
46
+ cache: cacheDbEnum.INTERNAL,
47
47
  store: global.kuzzle.internalIndex,
48
48
  });
49
49
 
@@ -69,5 +69,5 @@ export declare class TokenRepository extends ObjectRepository<Token> {
69
69
  *
70
70
  * So we need to override the TTL auto-refresh function to disable it
71
71
  */
72
- refreshCacheTTL(): void;
72
+ refreshCacheTTL(): Promise<void>;
73
73
  }
@@ -374,7 +374,7 @@ class TokenRepository extends ObjectRepository_1.ObjectRepository {
374
374
  *
375
375
  * So we need to override the TTL auto-refresh function to disable it
376
376
  */
377
- refreshCacheTTL() {
377
+ async refreshCacheTTL() {
378
378
  // This comment is here to please Sonarqube. It requires a comment
379
379
  // explaining why a function is empty, but there is no sense
380
380
  // duplicating what has been just said in the JSDoc.
@@ -117,7 +117,7 @@ export declare class ObjectRepository<TObject extends {
117
117
  refreshCacheTTL(object: JSONObject, options?: {
118
118
  key?: string;
119
119
  ttl?: number;
120
- }): any;
120
+ }): Promise<any>;
121
121
  /**
122
122
  * @param object
123
123
  * @param options.key - if provided, stores the object to the given key instead of the default one (<collection>/<id>)
@@ -127,7 +127,7 @@ class ObjectRepository {
127
127
  let response;
128
128
  try {
129
129
  response = await global.kuzzle.ask(`core:cache:${this.cacheDb}:get`, key);
130
- if (response === null) {
130
+ if (response === null || response === undefined) {
131
131
  return null;
132
132
  }
133
133
  return await this.fromDTO({ ...JSON.parse(response) });
@@ -0,0 +1,70 @@
1
+ import EventEmitter from "eventemitter3";
2
+ import { AskEventDefinition, AskEventHandler, CallEventHandler, EventDefinition, HookEventHandler, PipeEventHandler } from "../../types/EventHandler";
3
+ declare class KuzzleEventEmitter extends EventEmitter {
4
+ private coreAnswerers;
5
+ private coreSyncedAnswerers;
6
+ private corePipes;
7
+ private pipeRunner;
8
+ private pluginPipes;
9
+ private pluginPipeDefinitions;
10
+ private superEmit;
11
+ constructor(maxConcurrentPipes: number, pipesBufferSize: number);
12
+ /**
13
+ * Registers a core method on a pipe
14
+ * Note: core methods cannot listen to wildcarded events, only exact matching
15
+ * works here.
16
+ */
17
+ onPipe<TEventDefinition extends EventDefinition = EventDefinition>(event: TEventDefinition["name"], fn: PipeEventHandler<TEventDefinition>): void;
18
+ /**
19
+ * Registers a core 'ask' event answerer
20
+ * There can only be 0 or 1 answerer per ask event.
21
+ */
22
+ onAsk<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], fn: AskEventHandler<TAskEventDefinition>): void;
23
+ /**
24
+ * Registers a core 'callback' answerer
25
+ * There can only be 0 or 1 answerer per callback event.
26
+ */
27
+ onCall<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], fn: CallEventHandler<TAskEventDefinition>): void;
28
+ /**
29
+ * Emits an event and all its wildcarded versions
30
+ *
31
+ * @warning Critical section of code
32
+ */
33
+ emit(event: string | symbol, ...args: any[]): boolean;
34
+ /**
35
+ * Emits a pipe event, which triggers the following, in that order:
36
+ * 1. Plugin pipes are invoked one after another (waterfall). Each plugin must
37
+ * resolve the pipe (with a callback or a promise) with a similar payload
38
+ * than the one received
39
+ * 2. Core pipes are invoked in parallel. They are awaited for (promises-only)
40
+ * but their responses are neither evaluated nor used
41
+ * 3. Hooks are invoked in parallel. They are not awaited.
42
+ *
43
+ * Accepts a callback argument (to be used by pipes invoked before the funnel
44
+ * overload-protection mechanism). If a callback is provided, this method
45
+ * doesn't return a promise.
46
+ *
47
+ * @warning Critical section of code
48
+ */
49
+ pipe<TEventDefinition extends EventDefinition = EventDefinition>(event: TEventDefinition["name"], ...payload: TEventDefinition["args"]): Promise<TEventDefinition["args"][0]> | null;
50
+ /**
51
+ * Emits an "ask" event to get information about the provided payload
52
+ */
53
+ ask<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], ...args: [payload?: TAskEventDefinition["payload"], ...rest: any]): Promise<TAskEventDefinition["result"]>;
54
+ /**
55
+ * Calls a callback to get information about the provided payload
56
+ */
57
+ call<TAskEventDefinition extends AskEventDefinition = AskEventDefinition>(event: TAskEventDefinition["name"], ...args: [payload?: TAskEventDefinition["payload"], ...rest: any]): TAskEventDefinition["result"];
58
+ /**
59
+ * Registers a plugin hook.
60
+ * Catch any error in the handler and emit the hook:onError event.
61
+ */
62
+ registerPluginHook<TEventDefinition extends EventDefinition = EventDefinition>(pluginName: string, event: TEventDefinition["name"], fn: HookEventHandler<TEventDefinition>): void;
63
+ registerPluginPipe<TEventDefinition extends EventDefinition = EventDefinition>(event: TEventDefinition["name"], handler: PipeEventHandler<TEventDefinition>): string;
64
+ unregisterPluginPipe(pipeId: string): void;
65
+ /**
66
+ * Checks if an ask event has an answerer
67
+ */
68
+ hasAskAnswerer(event: string): boolean;
69
+ }
70
+ export default KuzzleEventEmitter;