kuzzle 2.15.2 → 2.16.3

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 (49) hide show
  1. package/lib/api/controllers/serverController.js +24 -4
  2. package/lib/api/funnel.js +19 -0
  3. package/lib/{config → api}/httpRoutes.js +29 -14
  4. package/lib/api/openApiGenerator.d.ts +6 -0
  5. package/lib/api/openApiGenerator.js +167 -126
  6. package/lib/api/openapi/document/count.yaml +47 -0
  7. package/lib/api/openapi/document/create.yaml +46 -0
  8. package/lib/api/openapi/document/createOrReplace.yaml +61 -0
  9. package/lib/api/openapi/document/delete.yaml +67 -0
  10. package/lib/api/openapi/document/deleteByQuery.yaml +90 -0
  11. package/lib/api/openapi/document/exists.yaml +35 -0
  12. package/lib/api/openapi/document/get.yaml +68 -0
  13. package/lib/api/openapi/document/index.d.ts +20 -0
  14. package/lib/api/openapi/document/index.js +55 -0
  15. package/lib/api/openapi/document/replace.yaml +66 -0
  16. package/lib/api/openapi/document/scroll.yaml +49 -0
  17. package/lib/api/openapi/document/update.yaml +78 -0
  18. package/lib/api/openapi/index.d.ts +2 -0
  19. package/lib/api/openapi/index.js +18 -0
  20. package/lib/api/openapi/payloads.yaml +32 -0
  21. package/lib/api/request/kuzzleRequest.d.ts +32 -0
  22. package/lib/api/request/kuzzleRequest.js +34 -0
  23. package/lib/api/request/requestInput.d.ts +2 -0
  24. package/lib/api/request/requestInput.js +2 -0
  25. package/lib/config/default.config.js +1 -1
  26. package/lib/core/network/router.js +33 -0
  27. package/lib/core/realtime/hotelClerk.d.ts +7 -0
  28. package/lib/core/realtime/hotelClerk.js +14 -0
  29. package/lib/util/readYamlFile.d.ts +2 -0
  30. package/lib/util/readYamlFile.js +10 -0
  31. package/package-lock.json +160 -175
  32. package/package.json +11 -25
  33. package/.kuzzlerc.sample +0 -988
  34. package/CONTRIBUTING.md +0 -116
  35. package/bin/.lib/colorOutput.js +0 -71
  36. package/bin/.upgrades/connectors/es.js +0 -90
  37. package/bin/.upgrades/connectors/redis.js +0 -112
  38. package/bin/.upgrades/lib/connectorContext.js +0 -38
  39. package/bin/.upgrades/lib/context.js +0 -142
  40. package/bin/.upgrades/lib/formatters.js +0 -103
  41. package/bin/.upgrades/lib/inquirerExtended.js +0 -46
  42. package/bin/.upgrades/lib/logger.js +0 -99
  43. package/bin/.upgrades/lib/progressBar.js +0 -70
  44. package/bin/.upgrades/versions/v1/checkConfiguration.js +0 -85
  45. package/bin/.upgrades/versions/v1/index.js +0 -35
  46. package/bin/.upgrades/versions/v1/upgradeCache.js +0 -149
  47. package/bin/.upgrades/versions/v1/upgradeStorage.js +0 -450
  48. package/protocols/available/.gitignore +0 -4
  49. package/protocols/enabled/.gitignore +0 -4
@@ -1,450 +0,0 @@
1
- /*
2
- * Kuzzle, a backend software, self-hostable and ready to use
3
- * to power modern apps
4
- *
5
- * Copyright 2015-2020 Kuzzle
6
- * mailto: support AT kuzzle.io
7
- * website: http://kuzzle.io
8
- *
9
- * Licensed under the Apache License, Version 2.0 (the "License");
10
- * you may not use this file except in compliance with the License.
11
- * You may obtain a copy of the License at
12
- *
13
- * https://www.apache.org/licenses/LICENSE-2.0
14
- *
15
- * Unless required by applicable law or agreed to in writing, software
16
- * distributed under the License is distributed on an "AS IS" BASIS,
17
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
- * See the License for the specific language governing permissions and
19
- * limitations under the License.
20
- */
21
-
22
- 'use strict';
23
-
24
- const _ = require('lodash');
25
-
26
- const getESConnector = require('../../connectors/es');
27
- const ProgressBar = require('../../lib/progressBar');
28
-
29
- const INTERNAL_PREFIX = '%';
30
- const PUBLIC_PREFIX = '&';
31
- const NAME_SEPARATOR = '.';
32
-
33
- function transformProfile (profile) {
34
- if (!Array.isArray(profile.policies)) {
35
- return profile;
36
- }
37
-
38
- for (const policy of profile.policies.filter(p => p.restrictedTo)) {
39
- for (const restriction of policy.restrictedTo.filter(r => r.collections)) {
40
- restriction.collections =
41
- restriction.collections.map(c => c.toLowerCase());
42
- }
43
- }
44
- return profile;
45
- }
46
-
47
- function getNewIndexName (index, collection) {
48
- const prefix = index[0] === '%' ? '' : PUBLIC_PREFIX;
49
-
50
- return `${prefix}${index}${NAME_SEPARATOR}${collection}`;
51
- }
52
-
53
- function fixIndexName (context, index, collection, newIndex) {
54
- const lowercased = newIndex.toLowerCase();
55
-
56
- if (lowercased !== newIndex) {
57
- // uppercase letters were already forbidden in index names
58
- context.log.warn(`Index "${index}": collection "${collection}" has been renamed to "${collection.toLowerCase()}"`);
59
- }
60
-
61
- return lowercased;
62
- }
63
-
64
- async function moveData (context, index, collection, newIndex, transform) {
65
- let page = await context.source.search({
66
- body: { sort: [ '_doc' ] },
67
- index,
68
- scroll: '1m',
69
- size: context.argv.storagePageSize,
70
- type: collection
71
- });
72
-
73
- const total = page.body.hits.total;
74
- const progressBar = new ProgressBar(
75
- context,
76
- `Importing: ${index}/${collection}`,
77
- total);
78
- let moved = 0;
79
-
80
- while (moved < total) {
81
- const bulk = [];
82
-
83
- for (let i = 0; i < page.body.hits.hits.length; i++) {
84
- const doc = page.body.hits.hits[i];
85
-
86
- if (doc._source._kuzzle_info) {
87
- delete doc._source._kuzzle_info.active;
88
- delete doc._source._kuzzle_info.deletedAt;
89
- }
90
-
91
- if (transform) {
92
- doc._source = transform(doc._source);
93
- }
94
-
95
- bulk.push({
96
- create: {
97
- _id: doc._id,
98
- _index: newIndex,
99
- _type: context._type
100
- }
101
- });
102
- bulk.push(doc._source);
103
- }
104
-
105
- await context.target.bulk({ _source: false, body: bulk });
106
-
107
- moved += page.body.hits.hits.length;
108
-
109
- progressBar.update(moved);
110
-
111
- if (moved < total) {
112
- page = await context.source.scroll({
113
- scroll: '1m',
114
- scroll_id: page.body._scroll_id
115
- });
116
- }
117
- }
118
-
119
- progressBar.destroy();
120
- return total;
121
- }
122
-
123
- async function upgradeMappings (context, index, collection, newIndex) {
124
- const mappingsResponse = await context.source.indices.getMapping({
125
- index,
126
- type: collection
127
- });
128
- const mappings = mappingsResponse.body[index].mappings[collection];
129
-
130
- // replace obsolete mapping properties
131
- if (mappings.properties && mappings.properties._kuzzle_info) {
132
- mappings.properties._kuzzle_info =
133
- context.config.services.storageEngine.commonMapping.properties._kuzzle_info;
134
- }
135
-
136
- await context.target.indices.putMapping({
137
- body: {
138
- _meta: mappings._meta,
139
- dynamic: mappings.dynamic || false,
140
- properties: mappings.properties
141
- },
142
- index: newIndex,
143
- type: context._type,
144
- });
145
- }
146
-
147
- async function createNewIndex (context, newIndex) {
148
- const exists = await context.target.indices.exists({ index: newIndex });
149
-
150
- if (exists.body) {
151
- await context.target.indices.delete({ index: newIndex });
152
- }
153
-
154
- await context.target.indices.create({ index: newIndex });
155
- }
156
-
157
- async function upgrade (context, index, collection, newIndex) {
158
- const fixedIndexName = fixIndexName(context, index, collection, newIndex);
159
-
160
- await createNewIndex(context, fixedIndexName);
161
- await upgradeMappings(context, index, collection, fixedIndexName);
162
-
163
- return await moveData(context, index, collection, fixedIndexName);
164
- }
165
-
166
- async function upgradeInternalStorage (context) {
167
- const config = context.config.services.storageEngine.internalIndex;
168
- const index = `${INTERNAL_PREFIX}${config.name}`;
169
- const mapconfig = config.collections;
170
- const collections = {
171
- config: mapconfig.config,
172
- profiles: mapconfig.profiles,
173
- roles: mapconfig.roles,
174
- users: null,
175
- validations: mapconfig.validations,
176
- };
177
-
178
- for (const [collection, mappings] of Object.entries(collections)) {
179
- const newIndex = getNewIndexName(index, collection);
180
- let total;
181
-
182
- if (mappings) {
183
- await createNewIndex(context, newIndex);
184
- await context.target.indices.putMapping({
185
- body: mappings,
186
- index: newIndex,
187
- type: context._type
188
- });
189
-
190
- total = await moveData(
191
- context,
192
- index,
193
- collection,
194
- newIndex,
195
- collection === 'profiles' && transformProfile);
196
- }
197
- else {
198
- total = await upgrade(context, index, collection, newIndex);
199
- }
200
-
201
- context.log.ok(`... migrated internal data: ${collection} (${total} documents)`);
202
- }
203
-
204
- // bootstrap document
205
- await context.target.create({
206
- body: { version: '2.0.0' },
207
- id: 'internalIndex.dataModelVersion',
208
- index: `${index}.config`,
209
- type: context._type,
210
- });
211
-
212
- await context.target.create({
213
- body: { timestamp: Date.now() },
214
- id: `${config.name}.done`,
215
- index: `${index}.config`,
216
- type: context._type,
217
- });
218
- }
219
-
220
- async function upgradePluginsStorage (context) {
221
- const { body } = await context.source.cat.indices({ format: 'json' });
222
- const indexes = body.map(b => b.index).filter(n => n.startsWith('%plugin:'));
223
-
224
- for (const index of indexes) {
225
- const plugin = index.split(':')[1];
226
- const newIndexBase = `%plugin-${plugin}${NAME_SEPARATOR}`;
227
- const mappings = await context.source.indices.getMapping({ index });
228
- const collections = Object.keys(mappings.body[index].mappings);
229
-
230
- for (const collection of collections) {
231
- const newIndex = newIndexBase + collection;
232
- const total = await upgrade(context, index, collection, newIndex);
233
-
234
- context.log.ok(`... migrated storage for plugin ${plugin}: ${collection} (${total} documents)`);
235
- }
236
- }
237
- }
238
-
239
- async function upgradeAliases (context, upgraded) {
240
- const response = await context.source.indices.getAlias({
241
- index: Object.keys(upgraded)
242
- });
243
-
244
- const aliases = {};
245
- for (const [index, obj] of Object.entries(response.body)) {
246
- if (Object.keys(obj.aliases).length > 0) {
247
- for (const newIndex of upgraded[index].targets) {
248
- aliases[newIndex] = obj.aliases;
249
- }
250
- }
251
- }
252
-
253
- if (Object.keys(aliases).length === 0) {
254
- return;
255
- }
256
-
257
- context.log.notice(`
258
- Index aliases detected. This script can import them to the new structure, but
259
- due to the removal of native collections in Elasticsearch, future aliases will
260
- be duplicated across all of an index upgraded collections.`);
261
-
262
- const choice = await context.inquire.direct({
263
- default: false,
264
- message: 'Upgrade aliases?',
265
- type: 'confirm'
266
- });
267
-
268
- if (!choice) {
269
- return;
270
- }
271
-
272
- for (const [index, obj] of Object.entries(aliases)) {
273
- for (const [name, body] of Object.entries(obj)) {
274
- await context.target.indices.putAlias({
275
- _type: context._type,
276
- body,
277
- index,
278
- name,
279
- });
280
- context.log.ok(`...... alias ${name} on index ${index} upgraded`);
281
- }
282
- }
283
- }
284
-
285
- async function upgradeDataStorage (context) {
286
- const { body } = await context.source.cat.indices({ format: 'json' });
287
- const upgraded = {};
288
- let indexes = body
289
- .map(b => b.index)
290
- .filter(n => !n.startsWith(INTERNAL_PREFIX));
291
-
292
- context.log.notice(`There are ${indexes.length} data indexes that can be upgraded`);
293
- const choices = {
294
- all: 'upgrade all indexes',
295
- askCollection: 'choose which collections can be upgraded',
296
- askIndex: 'choose which indexes can be upgraded',
297
- skip: 'skip all data index upgrades'
298
- };
299
-
300
- const action = await context.inquire.direct({
301
- choices: Object.values(choices),
302
- default: choices.all,
303
- message: 'You want to',
304
- type: 'list'
305
- });
306
-
307
- if (action === choices.skip) {
308
- return;
309
- }
310
-
311
- if (action === choices.askIndex) {
312
- indexes = await context.inquire.direct({
313
- choices: indexes.map(i => ({ checked: true, name: i })),
314
- message: 'Select the indexes to upgrade:',
315
- type: 'checkbox'
316
- });
317
- }
318
-
319
- for (const index of indexes) {
320
- const mappings = await context.source.indices.getMapping({ index });
321
- const allCollections = Object.keys(mappings.body[index].mappings);
322
- let collections = allCollections;
323
-
324
- if (action === choices.askCollection) {
325
- context.log.notice(`Starting to upgrade the index ${index}`);
326
- collections = await context.inquire.direct({
327
- choices: collections.map(c => ({ checked: true, name: c })),
328
- message: 'Select the collections to upgrade:',
329
- type: 'checkbox'
330
- });
331
- }
332
-
333
- upgraded[index] = {
334
- canBeRemoved: collections.length === allCollections.length,
335
- targets: []
336
- };
337
-
338
- for (const collection of collections) {
339
- const newIndex = getNewIndexName(index, collection);
340
- const total = await upgrade(context, index, collection, newIndex);
341
-
342
- upgraded[index].targets.push(newIndex);
343
- context.log.ok(`... migrated data index ${index}: ${collection} (${total} documents)`);
344
- }
345
- }
346
-
347
- await upgradeAliases(context, upgraded);
348
-
349
- return upgraded;
350
- }
351
-
352
- async function destroyPreviousStructure (context, upgraded) {
353
- // there is no point in destroying the previous structure if not performing
354
- // an in-place migration
355
- if (!context.inPlace) {
356
- return;
357
- }
358
-
359
- const { body } = await context.source.cat.indices({ format: 'json' });
360
- const plugins = body.map(b => b.index).filter(n => n.startsWith('%plugin:'));
361
-
362
- let indexes = [
363
- '%kuzzle',
364
- ...plugins,
365
- ...Object.keys(upgraded).filter(i => upgraded[i].canBeRemoved),
366
- ];
367
-
368
-
369
- context.log.notice('Since this is an in-place migration, the previous structure can be removed.');
370
- context.log.notice('(only data indexes with ALL their collections upgraded can be deleted)');
371
-
372
- const choices = {
373
- everything: 'Yes - remove all upgraded structures',
374
- internal: 'Remove only Kuzzle internal data',
375
- kuzzleAndPlugins: 'Remove Kuzzle internal data and plugins storages',
376
- no: 'No - keep everything as is'
377
- };
378
-
379
- const action = await context.inquire.direct({
380
- choices: Object.values(choices),
381
- default: choices[0],
382
- message: 'Destroy? (THIS CANNOT BE REVERTED)',
383
- type: 'list'
384
- });
385
-
386
- if (action === choices.no) {
387
- context.log.ok('Previous structure left intact.');
388
- return;
389
- }
390
-
391
- if (action === choices.kuzzleAndPlugins) {
392
- indexes = [ '%kuzzle', ...plugins ];
393
- }
394
- else if (action === choices.internal) {
395
- indexes = [ '%kuzzle' ];
396
- }
397
-
398
- await context.source.indices.delete({ index: indexes });
399
- context.log.ok('Previous structure destroyed.');
400
- }
401
-
402
- module.exports = async function upgradeStorage (context) {
403
- const storageContext = await getESConnector(context);
404
- const targetInfo = await storageContext.target.info();
405
- const targetMajor = targetInfo.body.version.number.split('.')[0];
406
-
407
- storageContext._type = storageContext.inPlace && targetMajor === '5'
408
- ? 'default'
409
- : undefined;
410
-
411
- context.log.notice(`
412
- This script will now start *COPYING* the existing data to the target storage
413
- space.
414
- If the upgrade is interrupted, this script can be replayed any number of times.
415
- Existing data from the older version of Kuzzle will be unaffected, but if
416
- Kuzzle indexes already exist in the target storage space, they will be
417
- overwritten without notice.`);
418
-
419
- const confirm = await context.inquire.direct({
420
- default: true,
421
- message: 'Continue?',
422
- type: 'confirm'
423
- });
424
-
425
- if (!confirm) {
426
- context.log.error('Aborted by user.');
427
- process.exit(0);
428
- }
429
-
430
- try {
431
- await upgradeInternalStorage(storageContext);
432
- await upgradePluginsStorage(storageContext);
433
- const upgraded = await upgradeDataStorage(storageContext);
434
-
435
- storageContext.log.ok('Storage migration complete.');
436
- await destroyPreviousStructure(storageContext, upgraded);
437
- }
438
- catch (e) {
439
- storageContext.log.error(`Storage upgrade failure: ${e.message}`);
440
-
441
- const reason = _.get(e, 'meta.body.error.reason');
442
- if (reason) {
443
- storageContext.log.error(`Reason: ${reason}`);
444
- }
445
-
446
- storageContext.log.print(e.stack);
447
- storageContext.log.error('Aborted.');
448
- process.exit(1);
449
- }
450
- };
@@ -1,4 +0,0 @@
1
- # Ignore everything in this directory
2
- *
3
- # Except this file
4
- !.gitignore
@@ -1,4 +0,0 @@
1
- # Ignore everything in this directory
2
- *
3
- # Except this file
4
- !.gitignore