kuzzle 2.14.10 → 2.14.14

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 (37) hide show
  1. package/.kuzzlerc.sample +6 -0
  2. package/lib/api/funnel.js +9 -5
  3. package/lib/cluster/node.js +5 -0
  4. package/lib/cluster/state.d.ts +2 -11
  5. package/lib/config/default.config.js +3 -1
  6. package/lib/config/index.js +6 -1
  7. package/lib/core/auth/tokenManager.d.ts +7 -0
  8. package/lib/core/auth/tokenManager.js +25 -8
  9. package/lib/core/network/router.js +0 -4
  10. package/lib/core/realtime/channel.d.ts +64 -0
  11. package/lib/core/realtime/channel.js +109 -0
  12. package/lib/core/realtime/connectionRooms.d.ts +28 -0
  13. package/lib/core/realtime/connectionRooms.js +68 -0
  14. package/lib/core/realtime/hotelClerk.d.ts +140 -0
  15. package/lib/core/realtime/hotelClerk.js +427 -630
  16. package/lib/core/realtime/index.js +1 -1
  17. package/lib/core/realtime/notifier.js +6 -6
  18. package/lib/core/realtime/room.d.ts +66 -0
  19. package/lib/core/realtime/room.js +103 -0
  20. package/lib/core/realtime/subscription.d.ts +25 -0
  21. package/lib/core/realtime/subscription.js +48 -0
  22. package/lib/core/statistics/statistics.js +43 -5
  23. package/lib/kerror/codes/1-services.json +11 -0
  24. package/lib/kerror/codes/2-api.json +1 -1
  25. package/lib/kuzzle/kuzzle.js +2 -2
  26. package/lib/types/KuzzleDocument.d.ts +5 -0
  27. package/lib/types/KuzzleDocument.js +3 -0
  28. package/lib/types/index.d.ts +4 -0
  29. package/lib/types/index.js +4 -0
  30. package/lib/types/realtime/RealtimeScope.d.ts +4 -0
  31. package/lib/types/realtime/RealtimeScope.js +3 -0
  32. package/lib/types/realtime/RealtimeUsers.d.ts +4 -0
  33. package/lib/types/realtime/RealtimeUsers.js +3 -0
  34. package/lib/types/realtime/RoomList.d.ts +20 -0
  35. package/lib/types/realtime/RoomList.js +3 -0
  36. package/package-lock.json +361 -152
  37. package/package.json +15 -15
@@ -22,7 +22,7 @@
22
22
  'use strict';
23
23
 
24
24
  const Notifier = require('./notifier');
25
- const HotelClerk = require('./hotelClerk');
25
+ const { HotelClerk } = require('./hotelClerk');
26
26
 
27
27
  class RealtimeModule {
28
28
  constructor () {
@@ -185,14 +185,14 @@ class NotifierController {
185
185
  * @returns {Promise}
186
186
  */
187
187
  async notifyTokenExpired (connectionId) {
188
-
188
+
189
189
  await this._dispatch(
190
190
  'notify:server',
191
191
  [KUZZLE_NOTIFICATION_CHANNEL], // Sending notification on Kuzzle notification channel
192
192
  new ServerNotification('TokenExpired', 'Authentication Token Expired'),
193
193
  connectionId);
194
-
195
- await this.module.hotelClerk.removeUser(connectionId);
194
+
195
+ await this.module.hotelClerk.removeConnection(connectionId);
196
196
  }
197
197
 
198
198
  /**
@@ -426,10 +426,10 @@ class NotifierController {
426
426
  continue;
427
427
  }
428
428
 
429
- for (const [channelId, channel] of Object.entries(hotelClerkRoom.channels)) {
429
+ for (const [channelId, channel] of hotelClerkRoom.channels.entries()) {
430
+ const executeOnNode = fromCluster ? channel.cluster : true;
430
431
  const matchScope = channel.scope === 'all'
431
432
  || channel.scope === notification.scope;
432
- const executeOnNode = fromCluster ? channel.cluster : true;
433
433
 
434
434
  if (matchScope && executeOnNode) {
435
435
  channels.push(channelId);
@@ -459,7 +459,7 @@ class NotifierController {
459
459
  const hotelClerkRoom = this.module.hotelClerk.rooms.get(room);
460
460
 
461
461
  if (hotelClerkRoom !== undefined) {
462
- for (const [id, channel] of Object.entries(hotelClerkRoom.channels)) {
462
+ for (const [id, channel] of hotelClerkRoom.channels.entries()) {
463
463
  const match = channel.users === 'all'
464
464
  || channel.users === notification.user;
465
465
  const executeOnNode = fromCluster ? channel.cluster : true;
@@ -0,0 +1,66 @@
1
+ import { Channel } from './channel';
2
+ /**
3
+ * A room represents a subscription scope made on a combination of:
4
+ * - index
5
+ * - collection
6
+ * - filters
7
+ *
8
+ * A room may contain differents channels that describe which notifications should
9
+ * be sent. (e.g. only document leaving the scope, users joining the room)
10
+ *
11
+ * The rooms also contains the list of connections who subscribed to it.
12
+ *
13
+ * @property id
14
+ * @property index
15
+ * @property collection
16
+ * @property connections
17
+ * @property channels
18
+ */
19
+ export declare class Room {
20
+ /**
21
+ * Room unique identifier.
22
+ *
23
+ * Koncorde hash for the desired scope (index + collection + filters)
24
+ */
25
+ id: string;
26
+ index: string;
27
+ collection: string;
28
+ /**
29
+ * List of connections subscribing to this room.
30
+ */
31
+ private connections;
32
+ /**
33
+ * Map of channels configuration for this room.
34
+ *
35
+ * Map<channel, Channel>
36
+ *
37
+ * @example
38
+ *
39
+ * channels: {
40
+ * '<channel>': {
41
+ *
42
+ * // request scope filter, default: 'all'
43
+ * scope: 'all|in|out|none',
44
+ *
45
+ * // filter users notifications, default: 'none'
46
+ * users: 'all|in|out|none',
47
+ *
48
+ * // should propagate notification to the cluster
49
+ * // (used for plugin subscriptions)
50
+ * cluster: true|false
51
+ * }
52
+ * },
53
+ */
54
+ channels: Map<string, Channel>;
55
+ constructor(id: string, index: string, collection: string, channels?: Map<string, Channel>, connections?: Set<string>);
56
+ /**
57
+ * Number of connections subscribing to the room
58
+ */
59
+ get size(): number;
60
+ /**
61
+ * Creates a new configuration channel on the room if it doesn't already exists
62
+ */
63
+ createChannel(channel: Channel): void;
64
+ addConnection(connectionId: string): void;
65
+ removeConnection(connectionId: string): void;
66
+ }
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ /*
3
+ * Kuzzle, a backend software, self-hostable and ready to use
4
+ * to power modern apps
5
+ *
6
+ * Copyright 2015-2020 Kuzzle
7
+ * mailto: support AT kuzzle.io
8
+ * website: http://kuzzle.io
9
+ *
10
+ * Licensed under the Apache License, Version 2.0 (the "License");
11
+ * you may not use this file except in compliance with the License.
12
+ * You may obtain a copy of the License at
13
+ *
14
+ * https://www.apache.org/licenses/LICENSE-2.0
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ * See the License for the specific language governing permissions and
20
+ * limitations under the License.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.Room = void 0;
24
+ /**
25
+ * A room represents a subscription scope made on a combination of:
26
+ * - index
27
+ * - collection
28
+ * - filters
29
+ *
30
+ * A room may contain differents channels that describe which notifications should
31
+ * be sent. (e.g. only document leaving the scope, users joining the room)
32
+ *
33
+ * The rooms also contains the list of connections who subscribed to it.
34
+ *
35
+ * @property id
36
+ * @property index
37
+ * @property collection
38
+ * @property connections
39
+ * @property channels
40
+ */
41
+ class Room {
42
+ constructor(id, index, collection, channels, connections) {
43
+ /**
44
+ * List of connections subscribing to this room.
45
+ */
46
+ this.connections = new Set();
47
+ /**
48
+ * Map of channels configuration for this room.
49
+ *
50
+ * Map<channel, Channel>
51
+ *
52
+ * @example
53
+ *
54
+ * channels: {
55
+ * '<channel>': {
56
+ *
57
+ * // request scope filter, default: 'all'
58
+ * scope: 'all|in|out|none',
59
+ *
60
+ * // filter users notifications, default: 'none'
61
+ * users: 'all|in|out|none',
62
+ *
63
+ * // should propagate notification to the cluster
64
+ * // (used for plugin subscriptions)
65
+ * cluster: true|false
66
+ * }
67
+ * },
68
+ */
69
+ this.channels = new Map();
70
+ this.id = id;
71
+ this.index = index;
72
+ this.collection = collection;
73
+ if (channels) {
74
+ this.channels = channels;
75
+ }
76
+ if (connections) {
77
+ this.connections = connections;
78
+ }
79
+ }
80
+ /**
81
+ * Number of connections subscribing to the room
82
+ */
83
+ get size() {
84
+ return this.connections.size;
85
+ }
86
+ /**
87
+ * Creates a new configuration channel on the room if it doesn't already exists
88
+ */
89
+ createChannel(channel) {
90
+ if (this.channels.has(channel.name)) {
91
+ return;
92
+ }
93
+ this.channels.set(channel.name, channel);
94
+ }
95
+ addConnection(connectionId) {
96
+ this.connections.add(connectionId);
97
+ }
98
+ removeConnection(connectionId) {
99
+ this.connections.delete(connectionId);
100
+ }
101
+ }
102
+ exports.Room = Room;
103
+ //# sourceMappingURL=room.js.map
@@ -0,0 +1,25 @@
1
+ import { JSONObject } from 'kuzzle-sdk';
2
+ /**
3
+ * Represents a realtime subscription of a connection to a room.
4
+ *
5
+ * This object is used in the Internal Event System to give informations about
6
+ * added/removed subscriptions.
7
+ *
8
+ * @property connectionId
9
+ * @property roomId
10
+ * @property index
11
+ * @property collection
12
+ * @property filters
13
+ * @property kuid
14
+ */
15
+ export declare class Subscription {
16
+ connectionId: string;
17
+ roomId: string;
18
+ index: string;
19
+ collection: string;
20
+ filters: JSONObject;
21
+ kuid: string;
22
+ constructor(index: string, collection: string, filters: JSONObject, roomId: string, connectionId: string, user: {
23
+ _id: string;
24
+ });
25
+ }
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ /*
3
+ * Kuzzle, a backend software, self-hostable and ready to use
4
+ * to power modern apps
5
+ *
6
+ * Copyright 2015-2020 Kuzzle
7
+ * mailto: support AT kuzzle.io
8
+ * website: http://kuzzle.io
9
+ *
10
+ * Licensed under the Apache License, Version 2.0 (the "License");
11
+ * you may not use this file except in compliance with the License.
12
+ * You may obtain a copy of the License at
13
+ *
14
+ * https://www.apache.org/licenses/LICENSE-2.0
15
+ *
16
+ * Unless required by applicable law or agreed to in writing, software
17
+ * distributed under the License is distributed on an "AS IS" BASIS,
18
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ * See the License for the specific language governing permissions and
20
+ * limitations under the License.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.Subscription = void 0;
24
+ /**
25
+ * Represents a realtime subscription of a connection to a room.
26
+ *
27
+ * This object is used in the Internal Event System to give informations about
28
+ * added/removed subscriptions.
29
+ *
30
+ * @property connectionId
31
+ * @property roomId
32
+ * @property index
33
+ * @property collection
34
+ * @property filters
35
+ * @property kuid
36
+ */
37
+ class Subscription {
38
+ constructor(index, collection, filters, roomId, connectionId, user) {
39
+ this.connectionId = connectionId;
40
+ this.roomId = roomId;
41
+ this.index = index;
42
+ this.collection = collection;
43
+ this.filters = filters;
44
+ this.kuid = user && user._id || null;
45
+ }
46
+ }
47
+ exports.Subscription = Subscription;
48
+ //# sourceMappingURL=subscription.js.map
@@ -21,19 +21,21 @@
21
21
 
22
22
  'use strict';
23
23
 
24
- const kerror = require('../../kerror').wrap('api', 'assert');
24
+ const errorApiAssert = require('../../kerror').wrap('api', 'assert');
25
+ const errorStats = require('../../kerror').wrap('services', 'stats');
25
26
 
26
27
  /**
27
28
  * @class Statistics
28
29
  * @param {Kuzzle} kuzzle
29
30
  */
30
31
  class Statistics {
31
- constructor() {
32
+ constructor () {
32
33
  // uses '{' and '}' to force all statistics frames to be stored on 1 redis
33
34
  // node
34
35
  // (see https://redis.io/topics/cluster-spec#keys-distribution-model)
35
36
  this.cacheKeyPrefix = '{stats/}';
36
37
 
38
+ this.enabled = global.kuzzle.config.stats.enabled;
37
39
  this.ttl = global.kuzzle.config.stats.ttl * 1000;
38
40
  this.interval = global.kuzzle.config.stats.statsInterval * 1000;
39
41
  this.lastFrame = null;
@@ -53,6 +55,10 @@ class Statistics {
53
55
  * @param {Request} request
54
56
  */
55
57
  startRequest (request) {
58
+ if (! this.enabled) {
59
+ return;
60
+ }
61
+
56
62
  const protocol = request && request.context.connection.protocol;
57
63
 
58
64
  if (!protocol) {
@@ -75,6 +81,10 @@ class Statistics {
75
81
  * @param {Request} request
76
82
  */
77
83
  completedRequest (request) {
84
+ if (! this.enabled) {
85
+ return;
86
+ }
87
+
78
88
  const protocol = request && request.context.connection.protocol;
79
89
 
80
90
  if (!protocol) {
@@ -101,6 +111,10 @@ class Statistics {
101
111
  * @param {Request} request
102
112
  */
103
113
  failedRequest (request) {
114
+ if (! this.enabled) {
115
+ return;
116
+ }
117
+
104
118
  const protocol = request && request.context.connection.protocol;
105
119
 
106
120
  if (!protocol) {
@@ -127,6 +141,10 @@ class Statistics {
127
141
  * @param {RequestContext} requestContext
128
142
  */
129
143
  newConnection (requestContext) {
144
+ if (! this.enabled) {
145
+ return;
146
+ }
147
+
130
148
  if (!requestContext.connection.protocol) {
131
149
  return;
132
150
  }
@@ -147,6 +165,10 @@ class Statistics {
147
165
  * @param {RequestContext} requestContext
148
166
  */
149
167
  dropConnection (requestContext) {
168
+ if (! this.enabled) {
169
+ return;
170
+ }
171
+
150
172
  if (!requestContext.connection.protocol) {
151
173
  return;
152
174
  }
@@ -166,7 +188,11 @@ class Statistics {
166
188
  *
167
189
  * @returns {Promise}
168
190
  */
169
- async getLastStats() {
191
+ async getLastStats () {
192
+ if (! this.enabled) {
193
+ throw errorStats.get('not_available');
194
+ }
195
+
170
196
  const frame = Object.assign(
171
197
  {timestamp: (new Date()).getTime()},
172
198
  this.currentStats);
@@ -189,6 +215,10 @@ class Statistics {
189
215
  * @returns {Promise<Object>}
190
216
  */
191
217
  async getStats (request) {
218
+ if (! this.enabled) {
219
+ throw errorStats.get('not_available');
220
+ }
221
+
192
222
  const response = {
193
223
  hits: [],
194
224
  total: null
@@ -211,11 +241,11 @@ class Statistics {
211
241
  }
212
242
 
213
243
  if (startTime !== undefined && isNaN(startTime)) {
214
- throw kerror.get('invalid_argument', 'startTime', 'number');
244
+ throw errorApiAssert.get('invalid_argument', 'startTime', 'number');
215
245
  }
216
246
 
217
247
  if (stopTime !== undefined && isNaN(stopTime)) {
218
- throw kerror.get('invalid_argument', 'stopTime', 'number');
248
+ throw errorApiAssert.get('invalid_argument', 'stopTime', 'number');
219
249
  }
220
250
 
221
251
  if (startTime !== undefined && startTime >= currentDate) {
@@ -286,6 +316,10 @@ class Statistics {
286
316
  * Init statistics component
287
317
  */
288
318
  init () {
319
+ if (! this.enabled) {
320
+ return;
321
+ }
322
+
289
323
  this.timer = setInterval(async () => {
290
324
  try {
291
325
  await this.writeStats();
@@ -301,6 +335,10 @@ class Statistics {
301
335
  }
302
336
 
303
337
  async writeStats () {
338
+ if (! this.enabled) {
339
+ return;
340
+ }
341
+
304
342
  const stats = JSON.stringify(this.currentStats);
305
343
 
306
344
  this.lastFrame = Date.now();
@@ -306,6 +306,17 @@
306
306
  "class": "InternalError"
307
307
  }
308
308
  }
309
+ },
310
+ "statistics": {
311
+ "code": 4,
312
+ "errors": {
313
+ "not_available": {
314
+ "description": "The statistics module is not enabled. See \"config.stats.enabled\".",
315
+ "code": 1,
316
+ "message": "Statistics module is not available.",
317
+ "class": "InternalError"
318
+ }
319
+ }
309
320
  }
310
321
  }
311
322
  }
@@ -124,7 +124,7 @@
124
124
  "class": "NotFoundError"
125
125
  },
126
126
  "incompatible_sdk_version": {
127
- "description": "SDK is incompatible with the current Kuzzle version",
127
+ "description": "SDK is incompatible with the current Kuzzle version. You can set \"config.server.strictSdkVersion\" to false to disable this safety check at your own risk.",
128
128
  "code": 6,
129
129
  "message": "Incompatible SDK client. Your SDK version (%s) does not match Kuzzle requirement (%s).",
130
130
  "class": "BadRequestError"
@@ -169,11 +169,11 @@ class Kuzzle extends kuzzleEventEmitter_1.default {
169
169
  async shutdown() {
170
170
  this._state = kuzzleStateEnum_1.default.SHUTTING_DOWN;
171
171
  this.log.info('Initiating shutdown...');
172
+ // Ask the network layer to stop accepting new request
173
+ this.entryPoint.dispatch('shutdown');
172
174
  await this.pipe('kuzzle:shutdown');
173
175
  // @deprecated
174
176
  this.emit('core:shutdown');
175
- // Ask the network layer to stop accepting new request
176
- this.entryPoint.dispatch('shutdown');
177
177
  while (this.funnel.remainingRequests !== 0) {
178
178
  this.log.info(`[shutdown] Waiting: ${this.funnel.remainingRequests} remaining requests`);
179
179
  await bluebird_1.default.delay(1000);
@@ -0,0 +1,5 @@
1
+ import { JSONObject } from 'kuzzle-sdk';
2
+ export interface KuzzleDocument {
3
+ _id: string;
4
+ _source: JSONObject;
5
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=KuzzleDocument.js.map
@@ -8,3 +8,7 @@ export * from './EventHandler';
8
8
  export * from './User';
9
9
  export * from './Token';
10
10
  export * from './Global';
11
+ export * from './realtime/RealtimeScope';
12
+ export * from './realtime/RealtimeUsers';
13
+ export * from './realtime/RoomList';
14
+ export * from './KuzzleDocument';
@@ -40,4 +40,8 @@ __exportStar(require("./EventHandler"), exports);
40
40
  __exportStar(require("./User"), exports);
41
41
  __exportStar(require("./Token"), exports);
42
42
  __exportStar(require("./Global"), exports);
43
+ __exportStar(require("./realtime/RealtimeScope"), exports);
44
+ __exportStar(require("./realtime/RealtimeUsers"), exports);
45
+ __exportStar(require("./realtime/RoomList"), exports);
46
+ __exportStar(require("./KuzzleDocument"), exports);
43
47
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Subscribe to notification of document entering, leaving the scope or both.
3
+ */
4
+ export declare type RealtimeScope = 'in' | 'out' | 'all';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=RealtimeScope.js.map
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Subscribe to users entering or leaving the room
3
+ */
4
+ export declare type RealtimeUsers = 'in' | 'out' | 'all' | 'none';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=RealtimeUsers.js.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * List of realtime rooms and the number of connections subscribing
3
+ *
4
+ * @example
5
+ * {
6
+ * <index>: {
7
+ * <collection>: {
8
+ * <roomId>: <number of connections>
9
+ * }
10
+ * }
11
+ * }
12
+ *
13
+ */
14
+ export declare type RoomList = {
15
+ [index: string]: {
16
+ [collection: string]: {
17
+ [roomId: string]: number;
18
+ };
19
+ };
20
+ };
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=RoomList.js.map