kuzzle 2.17.8 → 2.19.0

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 (64) hide show
  1. package/index.d.ts +1 -0
  2. package/index.js +3 -0
  3. package/lib/api/controllers/adminController.js +9 -0
  4. package/lib/api/controllers/authController.js +8 -2
  5. package/lib/api/controllers/debugController.d.ts +59 -0
  6. package/lib/api/controllers/debugController.js +285 -0
  7. package/lib/api/controllers/documentController.js +49 -31
  8. package/lib/api/controllers/index.js +1 -0
  9. package/lib/api/controllers/indexController.js +10 -6
  10. package/lib/api/controllers/securityController.js +81 -43
  11. package/lib/api/controllers/serverController.js +2 -1
  12. package/lib/api/documentExtractor.js +51 -9
  13. package/lib/api/funnel.js +30 -8
  14. package/lib/api/httpRoutes.js +8 -1
  15. package/lib/api/openapi/OpenApiManager.js +3 -0
  16. package/lib/api/openapi/components/document/get.yaml +1 -1
  17. package/lib/api/openapi/components/document/update.yaml +1 -1
  18. package/lib/api/openapi/components/index.d.ts +1 -0
  19. package/lib/api/openapi/components/index.js +1 -0
  20. package/lib/api/openapi/components/security/index.d.ts +2 -0
  21. package/lib/api/openapi/components/security/index.js +10 -0
  22. package/lib/api/openapi/components/security/upsertUser.yaml +59 -0
  23. package/lib/api/request/kuzzleRequest.d.ts +58 -4
  24. package/lib/api/request/kuzzleRequest.js +163 -31
  25. package/lib/api/request/requestResponse.js +25 -0
  26. package/lib/cluster/idCardHandler.js +1 -1
  27. package/lib/config/default.config.js +3 -0
  28. package/lib/config/documentEventAliases.d.ts +7 -0
  29. package/lib/config/documentEventAliases.js +26 -12
  30. package/lib/core/backend/backend.d.ts +4 -0
  31. package/lib/core/backend/backend.js +9 -0
  32. package/lib/core/backend/backendController.d.ts +7 -1
  33. package/lib/core/backend/backendController.js +15 -3
  34. package/lib/core/network/protocols/httpwsProtocol.js +14 -6
  35. package/lib/core/plugin/plugin.js +7 -0
  36. package/lib/core/shared/sdk/embeddedSdk.d.ts +3 -3
  37. package/lib/core/shared/sdk/embeddedSdk.js +33 -0
  38. package/lib/core/shared/sdk/funnelProtocol.d.ts +1 -2
  39. package/lib/kerror/codes/0-core.json +35 -0
  40. package/lib/kerror/codes/1-services.json +1 -1
  41. package/lib/kerror/codes/2-api.json +6 -0
  42. package/lib/kerror/errors/kuzzleError.d.ts +1 -1
  43. package/lib/kuzzle/kuzzle.d.ts +1 -1
  44. package/lib/kuzzle/kuzzle.js +27 -8
  45. package/lib/model/security/user.js +5 -6
  46. package/lib/model/storage/apiKey.js +1 -6
  47. package/lib/service/storage/elasticsearch.js +143 -47
  48. package/lib/types/DebugModule.d.ts +23 -0
  49. package/lib/types/DebugModule.js +39 -0
  50. package/lib/types/config/SecurityConfiguration.d.ts +10 -0
  51. package/lib/types/index.d.ts +0 -1
  52. package/lib/types/index.js +0 -1
  53. package/lib/util/crypto.d.ts +1 -0
  54. package/lib/util/crypto.js +12 -0
  55. package/lib/util/dump-collection.d.ts +35 -0
  56. package/lib/util/dump-collection.js +11 -8
  57. package/lib/util/name-generator.d.ts +79 -0
  58. package/lib/util/name-generator.js +1409 -1345
  59. package/lib/util/time.d.ts +1 -0
  60. package/lib/util/time.js +9 -0
  61. package/package.json +19 -21
  62. package/lib/core/security/README.md +0 -224
  63. package/lib/core/shared/README.md +0 -3
  64. package/package-lock.json +0 -8403
@@ -182,7 +182,7 @@ class ElasticSearch extends Service {
182
182
  /**
183
183
  * Translate Koncorde filters to Elasticsearch query
184
184
  *
185
- * @param {Object} koncordeFilters - Set of valid Koncorde filters
185
+ * @param {Object} filters - Set of valid Koncorde filters
186
186
  * @returns {Object} Equivalent Elasticsearch query
187
187
  */
188
188
  translateKoncordeFilters (filters) {
@@ -243,7 +243,8 @@ class ElasticSearch extends Service {
243
243
  continue;
244
244
  }
245
245
 
246
- const alias = await this._getAliasFromIndice(indice);
246
+ const aliases = await this._getAliasFromIndice(indice);
247
+ const alias = aliases[0];
247
248
  const indexName = this._extractIndex(alias);
248
249
  const collectionName = this._extractCollection(alias);
249
250
 
@@ -303,20 +304,20 @@ class ElasticSearch extends Service {
303
304
  }
304
305
  }
305
306
 
306
- let fetched = await global.kuzzle.ask('core:cache:internal:get', cacheKey);
307
+ const stringifiedScrollInfo = await global.kuzzle.ask('core:cache:internal:get', cacheKey);
307
308
 
308
- if (! fetched) {
309
+ if (! stringifiedScrollInfo) {
309
310
  throw kerror.get('unknown_scroll_id');
310
311
  }
311
312
 
312
- fetched = Number.parseInt(fetched);
313
+ const scrollInfo = JSON.parse(stringifiedScrollInfo);
313
314
 
314
315
  try {
315
316
  const { body } = await this._client.scroll(esRequest);
316
317
 
317
- fetched += body.hits.hits.length;
318
+ scrollInfo.fetched += body.hits.hits.length;
318
319
 
319
- if (fetched >= body.hits.total.value) {
320
+ if (scrollInfo.fetched >= body.hits.total.value) {
320
321
  debug('Last scroll page fetched: deleting scroll %s', body._scroll_id);
321
322
  await global.kuzzle.ask('core:cache:internal:del', cacheKey);
322
323
  await this.clearScroll(body._scroll_id);
@@ -325,15 +326,15 @@ class ElasticSearch extends Service {
325
326
  await global.kuzzle.ask(
326
327
  'core:cache:internal:store',
327
328
  cacheKey,
328
- fetched,
329
+ JSON.stringify(scrollInfo),
329
330
  {
330
331
  ttl: ms(_scrollTTL) || this.scrollTTL,
331
332
  });
332
333
  }
333
334
 
334
- body.remaining = body.hits.total.value - fetched;
335
+ body.remaining = body.hits.total.value - scrollInfo.fetched;
335
336
 
336
- return await this._formatSearchResult(body);
337
+ return await this._formatSearchResult(body, scrollInfo);
337
338
  }
338
339
  catch (error) {
339
340
  throw this._esWrapper.formatESError(error);
@@ -401,35 +402,101 @@ class ElasticSearch extends Service {
401
402
  await global.kuzzle.ask(
402
403
  'core:cache:internal:store',
403
404
  SCROLL_CACHE_PREFIX + global.kuzzle.hash(body._scroll_id),
404
- body.hits.hits.length,
405
+ JSON.stringify({
406
+ collection,
407
+ fetched: body.hits.hits.length,
408
+ index,
409
+ targets
410
+ }),
405
411
  { ttl });
406
412
 
407
413
  body.remaining = body.hits.total.value - body.hits.hits.length;
408
414
  }
409
415
 
410
- return await this._formatSearchResult(body);
416
+ return await this._formatSearchResult(body, {
417
+ collection,
418
+ index,
419
+ targets
420
+ });
411
421
  }
412
422
  catch (error) {
413
423
  throw this._esWrapper.formatESError(error);
414
424
  }
415
425
  }
416
426
 
417
- async _formatSearchResult (body) {
427
+ /**
428
+ * Generate a map that associate an alias to a pair of index and collection
429
+ *
430
+ * @param {*} targets
431
+ * @returns
432
+ */
433
+ _mapTargetsToAlias (targets) {
434
+ const aliasToTargets = {};
435
+
436
+ for (const target of targets) {
437
+ for (const targetCollection of target.collections) {
438
+ const alias = this._getAlias(target.index, targetCollection);
439
+ if (! aliasToTargets[alias]) {
440
+ aliasToTargets[alias] = {
441
+ collection: targetCollection,
442
+ index: target.index,
443
+ };
444
+ }
445
+ }
446
+ }
447
+
448
+ return aliasToTargets;
449
+ }
450
+
451
+ async _formatSearchResult (body, searchInfo = {}) {
452
+ let aliasToTargets = {};
453
+ const aliasCache = new Map();
454
+
455
+ if (searchInfo.targets) {
456
+ /**
457
+ * We need to map the alias to the target index and collection,
458
+ * so we can later retrieve informations about an index & collection
459
+ * based on its alias.
460
+ */
461
+ aliasToTargets = this._mapTargetsToAlias(searchInfo.targets);
462
+ }
418
463
 
419
464
  const formatHit = async (hit) => {
420
- let alias = null;
465
+ let index = searchInfo.index;
466
+ let collection = searchInfo.collection;
467
+
468
+ /**
469
+ * If the search has been done on multiple targets, we need to
470
+ * retrieve the appropriate index and collection based on the alias
471
+ */
472
+ if (hit._index && searchInfo.targets) {
473
+
474
+ // Caching to reduce call to ES
475
+ let aliases = aliasCache.get(hit._index);
476
+ if (! aliases) {
477
+ // Retrieve all the alias associated to one index
478
+ aliases = await this._getAliasFromIndice(hit._index);
479
+ aliasCache.set(hit._index, aliases);
480
+ }
421
481
 
422
- if (hit._index) {
423
- alias = await this._getAliasFromIndice(hit._index);
482
+ /**
483
+ * Since multiple alias can point to the same index in ES, we need to
484
+ * find the first alias that exists in the map of aliases associated
485
+ * to the targets.
486
+ */
487
+ const alias = aliases.find(_alias => aliasToTargets[_alias]);
488
+ // Retrieve index and collection information based on the matching alias
489
+ index = aliasToTargets[alias].index;
490
+ collection = aliasToTargets[alias].collection;
424
491
  }
425
492
 
426
493
  return {
427
494
  _id: hit._id,
428
495
  _score: hit._score,
429
496
  _source: hit._source,
430
- collection: alias ? this._extractCollection(alias) : undefined,
497
+ collection,
431
498
  highlight: hit.highlight,
432
- index: alias ? this._extractIndex(alias) : undefined,
499
+ index,
433
500
  };
434
501
  };
435
502
 
@@ -1368,10 +1435,9 @@ class ElasticSearch extends Service {
1368
1435
  // rollback the whole operation. Since mappings can't be rollback, we try to
1369
1436
  // update the settings first, then the mappings and we rollback the settings
1370
1437
  // if putMappings fail.
1371
- let indiceSettings;
1438
+ let indexSettings;
1372
1439
  try {
1373
- const response = await this._client.indices.getSettings(esRequest);
1374
- indiceSettings = response.body[esRequest.index].settings;
1440
+ indexSettings = await this._getSettings(esRequest);
1375
1441
  }
1376
1442
  catch (error) {
1377
1443
  throw this._esWrapper.formatESError(error);
@@ -1393,11 +1459,7 @@ class ElasticSearch extends Service {
1393
1459
  }
1394
1460
  }
1395
1461
  catch (error) {
1396
- const allowedSettings = {
1397
- index: _.omit(
1398
- indiceSettings.index,
1399
- ['creation_date', 'provided_name', 'uuid', 'version'])
1400
- };
1462
+ const allowedSettings = this.getAllowedIndexSettings(indexSettings);
1401
1463
 
1402
1464
  // Rollback to previous settings
1403
1465
  if (! _.isEmpty(settings)) {
@@ -1410,6 +1472,20 @@ class ElasticSearch extends Service {
1410
1472
  return null;
1411
1473
  }
1412
1474
 
1475
+ /**
1476
+ * Given index settings we return a new version of index settings
1477
+ * only with allowed settings that can be set (during update or create index).
1478
+ * @param indexSettings the index settings
1479
+ * @returns {{index: *}} a new index settings with only allowed settings.
1480
+ */
1481
+ getAllowedIndexSettings (indexSettings) {
1482
+ return {
1483
+ index: _.omit(
1484
+ indexSettings.index,
1485
+ ['creation_date', 'provided_name', 'uuid', 'version'])
1486
+ };
1487
+ }
1488
+
1413
1489
  /**
1414
1490
  * Sends an empty UpdateByQuery request to update the search index
1415
1491
  *
@@ -1516,7 +1592,7 @@ class ElasticSearch extends Service {
1516
1592
  }
1517
1593
 
1518
1594
  /**
1519
- * Empties the content of a collection. Keep the existing mapping.
1595
+ * Empties the content of a collection. Keep the existing mapping and settings.
1520
1596
  *
1521
1597
  * @param {String} index - Index name
1522
1598
  * @param {String} collection - Collection name
@@ -1525,6 +1601,7 @@ class ElasticSearch extends Service {
1525
1601
  */
1526
1602
  async truncateCollection (index, collection) {
1527
1603
  let mappings;
1604
+ let settings;
1528
1605
 
1529
1606
  const esRequest = {
1530
1607
  index: await this._getIndice(index, collection)
@@ -1532,7 +1609,11 @@ class ElasticSearch extends Service {
1532
1609
 
1533
1610
  try {
1534
1611
  mappings = await this.getMapping(index, collection, { includeKuzzleMeta: true });
1535
-
1612
+ settings = await this._getSettings(esRequest);
1613
+ settings = {
1614
+ ...settings,
1615
+ ...this.getAllowedIndexSettings(settings)
1616
+ };
1536
1617
  await this._client.indices.delete(esRequest);
1537
1618
 
1538
1619
  await this._client.indices.create({
@@ -1541,7 +1622,8 @@ class ElasticSearch extends Service {
1541
1622
  aliases: {
1542
1623
  [this._getAlias(index, collection)]: {}
1543
1624
  },
1544
- mappings
1625
+ mappings,
1626
+ settings
1545
1627
  }
1546
1628
  });
1547
1629
 
@@ -1819,22 +1901,14 @@ class ElasticSearch extends Service {
1819
1901
  index: await this._getIndice(index, collection)
1820
1902
  };
1821
1903
 
1822
- const mutex = new Mutex(`hiddenCollection/delete/${index}`);
1823
1904
  try {
1824
1905
  await this._client.indices.delete(esRequest);
1825
1906
 
1826
- await mutex.lock();
1827
-
1828
- if (! await this._hasHiddenCollection(index)) {
1829
- await this._createHiddenCollection(index);
1830
- }
1907
+ await this._createHiddenCollection(index);
1831
1908
  }
1832
1909
  catch (e) {
1833
1910
  throw this._esWrapper.formatESError(e);
1834
1911
  }
1835
- finally {
1836
- await mutex.unlock();
1837
- }
1838
1912
 
1839
1913
  return null;
1840
1914
  }
@@ -2476,7 +2550,7 @@ class ElasticSearch extends Service {
2476
2550
  *
2477
2551
  * @param {String} index - Index name
2478
2552
  * @param {String} collection - Collection name
2479
- * @param {Array.<String>} documents - Documents IDs
2553
+ * @param {Array.<String>} ids - Documents IDs
2480
2554
  * @param {Object} options - timeout (undefined), refresh (undefined)
2481
2555
  *
2482
2556
  * @returns {Promise.<{ documents, errors }>
@@ -2792,12 +2866,24 @@ class ElasticSearch extends Service {
2792
2866
  throw kerror.get('unknown_index_collection');
2793
2867
  }
2794
2868
  else if (body.length > 1) {
2795
- throw kerror.get('multiple_indice_alias', 'alias', 'indices');
2869
+ throw kerror.get('multiple_indice_alias', `"alias" starting with "${ALIAS_PREFIX}"`, '"indices"');
2796
2870
  }
2797
2871
 
2798
2872
  return body[0].index;
2799
2873
  }
2800
2874
 
2875
+ /**
2876
+ * Given an ES Request returns the settings of the corresponding indice.
2877
+ *
2878
+ * @param esRequest the ES Request with wanted settings.
2879
+ * @return {Promise<*>} the settings of the indice.
2880
+ * @private
2881
+ */
2882
+ async _getSettings (esRequest) {
2883
+ const response = await this._client.indices.getSettings(esRequest);
2884
+ return response.body[esRequest.index].settings;
2885
+ }
2886
+
2801
2887
  /**
2802
2888
  * Given index + collection, returns an available indice name.
2803
2889
  * Use this function when creating the associated indice. Otherwise use `_getAlias`.
@@ -2838,20 +2924,19 @@ class ElasticSearch extends Service {
2838
2924
  * @param {String} indice
2839
2925
  *
2840
2926
  * @returns {String} Alias name (eg: '@&nepali.liia')
2841
- * @throws If there is not exactly one alias associated
2927
+ * @throws If there is not exactly one alias associated that is prefixed with @
2842
2928
  */
2843
2929
  async _getAliasFromIndice (indice) {
2844
2930
  const { body } = await this._client.indices.getAlias({ index: indice });
2845
- const aliases = Object.keys(body[indice].aliases);
2931
+ const aliases =
2932
+ Object.keys(body[indice].aliases)
2933
+ .filter(alias => alias.startsWith(ALIAS_PREFIX));
2846
2934
 
2847
2935
  if (aliases.length < 1) {
2848
2936
  throw kerror.get('unknown_index_collection');
2849
2937
  }
2850
- else if (aliases.length > 1) {
2851
- throw kerror.get('multiple_indice_alias', 'indice', 'aliases');
2852
- }
2853
2938
 
2854
- return aliases[0];
2939
+ return aliases;
2855
2940
  }
2856
2941
 
2857
2942
  /**
@@ -2960,13 +3045,21 @@ class ElasticSearch extends Service {
2960
3045
  }
2961
3046
 
2962
3047
  /**
2963
- * Creates the hidden collection on the provided index.
3048
+ * Creates the hidden collection on the provided index if it does not already
3049
+ * exists
2964
3050
  *
2965
3051
  * @param {String} index Index name
2966
3052
  */
2967
3053
  async _createHiddenCollection (index) {
3054
+ const mutex = new Mutex(`hiddenCollection/${index}`);
2968
3055
 
2969
3056
  try {
3057
+ await mutex.lock();
3058
+
3059
+ if (await this._hasHiddenCollection(index)) {
3060
+ return;
3061
+ }
3062
+
2970
3063
  await this._client.indices.create({
2971
3064
  body: {
2972
3065
  aliases: {
@@ -2983,6 +3076,9 @@ class ElasticSearch extends Service {
2983
3076
  catch (e) {
2984
3077
  throw this._esWrapper.formatESError(e);
2985
3078
  }
3079
+ finally {
3080
+ await mutex.unlock();
3081
+ }
2986
3082
  }
2987
3083
 
2988
3084
  /**
@@ -0,0 +1,23 @@
1
+ /// <reference types="node" />
2
+ import EventEmitter from 'events';
3
+ import Inspector from 'inspector';
4
+ export declare type DebugModuleOptions = {
5
+ methods?: string[];
6
+ events?: string[];
7
+ };
8
+ export declare abstract class DebugModule extends EventEmitter {
9
+ name: string;
10
+ methods: string[];
11
+ events: string[];
12
+ /**
13
+ * Called when the module is loaded, after the debugger has been enabled
14
+ */
15
+ abstract init(inspector: Inspector.Session): Promise<void>;
16
+ /**
17
+ * Called when the module should be cleaned up.
18
+ * - After the Debug Controller has been disabled
19
+ * - Before the debugger is disconnected
20
+ */
21
+ abstract cleanup(): Promise<void>;
22
+ constructor(name: string, options?: DebugModuleOptions);
23
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DebugModule = void 0;
7
+ const events_1 = __importDefault(require("events"));
8
+ class DebugModule extends events_1.default {
9
+ constructor(name, options = {}) {
10
+ super();
11
+ this.name = name;
12
+ this.methods = options.methods || [];
13
+ this.events = options.events || [];
14
+ if (!this.name || this.name.length === 0) {
15
+ throw new Error('DebugModule should have a name');
16
+ }
17
+ if (this.name.charAt(0) !== this.name.charAt(0).toUpperCase()) {
18
+ throw new Error(`Debug Module name "${name}" should start with an uppercase letter`);
19
+ }
20
+ for (const event of this.events) {
21
+ if (event.length === 0) {
22
+ throw new Error(`Event name should not be empty for "${name}"`);
23
+ }
24
+ if (event.charAt(0) !== event.charAt(0).toLowerCase()) {
25
+ throw new Error(`Event name "${event}" should start with a lowercase letter for module "${name}"`);
26
+ }
27
+ }
28
+ for (const method of this.methods) {
29
+ if (method.length === 0) {
30
+ throw new Error(`Method name should not be empty for Debug Module "${name}"`);
31
+ }
32
+ if (method.charAt(0) !== method.charAt(0).toLowerCase()) {
33
+ throw new Error(`Method name "${method}" should start with a lowercase letter for module "${name}"`);
34
+ }
35
+ }
36
+ }
37
+ }
38
+ exports.DebugModule = DebugModule;
39
+ //# sourceMappingURL=DebugModule.js.map
@@ -2,6 +2,16 @@
2
2
  import { JSONObject } from '../../../index';
3
3
  import { RoleDefinition, ProfileDefinition } from '../index';
4
4
  export declare type SecurityConfiguration = {
5
+ /**
6
+ * Debugger configuration
7
+ */
8
+ debug: {
9
+ /**
10
+ * Allow to use the Chrome DevTools Protocol directly
11
+ * through `debug:post`
12
+ */
13
+ native_debug_protocol: boolean;
14
+ };
5
15
  /**
6
16
  * The profileIds applied to a user created with the API action
7
17
  * `security:createRestrictedUser`.
@@ -2,7 +2,6 @@ export * from './Plugin';
2
2
  export * from './Controller';
3
3
  export * from './ControllerDefinition';
4
4
  export * from './ControllerRights';
5
- export * from './RequestPayload';
6
5
  export * from './ResponsePayload';
7
6
  export * from './Deprecation';
8
7
  export * from './EventHandler';
@@ -38,7 +38,6 @@ __exportStar(require("./Plugin"), exports);
38
38
  __exportStar(require("./Controller"), exports);
39
39
  __exportStar(require("./ControllerDefinition"), exports);
40
40
  __exportStar(require("./ControllerRights"), exports);
41
- __exportStar(require("./RequestPayload"), exports);
42
41
  __exportStar(require("./ResponsePayload"), exports);
43
42
  __exportStar(require("./Deprecation"), exports);
44
43
  __exportStar(require("./EventHandler"), exports);
@@ -0,0 +1 @@
1
+ export declare function sha256(string: string): string;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.sha256 = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ function sha256(string) {
9
+ return crypto_1.default.createHash('sha256').update(string).digest('hex');
10
+ }
11
+ exports.sha256 = sha256;
12
+ //# sourceMappingURL=crypto.js.map
@@ -1,3 +1,38 @@
1
1
  import { JSONObject } from '../../index';
2
2
  import { HttpStream } from '../types';
3
+ /**
4
+ * Flatten an object transform:
5
+ * {
6
+ * title: "kuzzle",
7
+ * info : {
8
+ * tag: "news"
9
+ * }
10
+ * }
11
+ *
12
+ * Into an object like:
13
+ * {
14
+ * title: "kuzzle",
15
+ * info.tag: news
16
+ * }
17
+ *
18
+ * @param {Object} target the object we have to flatten
19
+ * @returns {Object} the flattened object
20
+ */
21
+ export declare function flattenObject(target: JSONObject): JSONObject;
22
+ /**
23
+ * Extract fields from mapping by removing the properties from es mapping
24
+ *
25
+ * @param mapping
26
+ * @returns
27
+ */
28
+ export declare function extractMappingFields(mapping: JSONObject): any;
29
+ /**
30
+ * An iteration-order-safe version of lodash.values
31
+ *
32
+ * @param object The object containing the values
33
+ * @param fields The field names to pick in the right order
34
+ * @returns The values in the same order as the fields
35
+ * @see https://lodash.com/docs/4.17.15#values
36
+ */
37
+ export declare function pickValues(object: any, fields: string[]): any[];
3
38
  export declare function dumpCollectionDocuments(index: string, collection: string, query?: any, format?: string, fields?: string[], options?: JSONObject): HttpStream;
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.dumpCollectionDocuments = void 0;
29
+ exports.dumpCollectionDocuments = exports.pickValues = exports.extractMappingFields = exports.flattenObject = void 0;
30
30
  const ndjson_1 = __importDefault(require("ndjson"));
31
31
  const get_1 = __importDefault(require("lodash/get"));
32
32
  const isObject_1 = __importDefault(require("lodash/isObject"));
@@ -56,6 +56,7 @@ function flattenObject(target) {
56
56
  flattenStep(output, target);
57
57
  return output;
58
58
  }
59
+ exports.flattenObject = flattenObject;
59
60
  function flattenStep(output, object, prev = null) {
60
61
  const keys = Object.keys(object);
61
62
  for (let i = 0; i < keys.length; i++) {
@@ -63,8 +64,8 @@ function flattenStep(output, object, prev = null) {
63
64
  const value = object[key];
64
65
  const newKey = prev ? prev + '.' + key : key;
65
66
  if (Object.prototype.toString.call(value) === '[object Object]') {
66
- output[newKey] = value;
67
67
  flattenStep(output, value, newKey);
68
+ continue;
68
69
  }
69
70
  output[newKey] = value;
70
71
  }
@@ -77,19 +78,20 @@ function flattenStep(output, object, prev = null) {
77
78
  */
78
79
  function extractMappingFields(mapping) {
79
80
  const newMapping = {};
81
+ if (mapping.properties) {
82
+ return extractMappingFields(mapping.properties);
83
+ }
80
84
  for (const key of Object.keys(mapping)) {
81
- if (key === 'properties' && (0, isObject_1.default)(mapping[key])) {
82
- newMapping[key] = extractMappingFields(mapping[key]);
83
- }
84
- else if ((0, isObject_1.default)(mapping[key]) && mapping[key].type) {
85
+ if ((0, isObject_1.default)(mapping[key]) && mapping[key].type) {
85
86
  newMapping[key] = mapping[key].type;
86
87
  }
87
- else {
88
- newMapping[key] = mapping[key];
88
+ else if ((0, isObject_1.default)(mapping[key])) {
89
+ newMapping[key] = extractMappingFields(mapping[key]);
89
90
  }
90
91
  }
91
92
  return newMapping;
92
93
  }
94
+ exports.extractMappingFields = extractMappingFields;
93
95
  /**
94
96
  * An iteration-order-safe version of lodash.values
95
97
  *
@@ -101,6 +103,7 @@ function extractMappingFields(mapping) {
101
103
  function pickValues(object, fields) {
102
104
  return fields.map(f => formatValueForCSV((0, get_1.default)(object, f)));
103
105
  }
106
+ exports.pickValues = pickValues;
104
107
  /**
105
108
  * Formats the value for correct CSV output, avoiding to return
106
109
  * values that would badly serialize in CSV.
@@ -0,0 +1,79 @@
1
+ export declare type GenerateRandomNameOpts = {
2
+ /**
3
+ * Optional prefix.
4
+ */
5
+ prefix?: string;
6
+ /**
7
+ * Optional separator. Defaults to `-`.
8
+ */
9
+ separator?: string;
10
+ /**
11
+ * Optional postfix random number range. Set to `false` to disable postfix. Defaults to `{ min: 0, max: 100000 }`
12
+ */
13
+ postfixRandRange?: {
14
+ /**
15
+ * Optional minimum postfix random number (inclusive). Defaults to `0`.
16
+ */
17
+ min?: number;
18
+ /**
19
+ * Maximum postfix random number (exclusive).
20
+ */
21
+ max: number;
22
+ } | false;
23
+ };
24
+ export declare class NameGenerator {
25
+ /**
26
+ * Returns a random name.
27
+ *
28
+ * # Usage:
29
+ *
30
+ * ```js
31
+ * const name = NameGenerator.getRandomName(); // 'verdi'
32
+ * ```
33
+ *
34
+ * @returns a random name
35
+ */
36
+ static getRandomName(): string;
37
+ /**
38
+ * Returns a random adjective.
39
+ *
40
+ * # Usage
41
+ *
42
+ * ```js
43
+ * const adj = NameGenerator.getRandomAdjective(); // 'absent'
44
+ * ```
45
+ *
46
+ * @returns a random adjective
47
+ */
48
+ static getRandomAdjective(): string;
49
+ /**
50
+ * Generates a random formatted name that consists of an optional prefix, a random adjective,
51
+ * a random name and an optional random number separated by separator (default: '-').
52
+ *
53
+ * Format: `[prefix<separator>]<adjective><separator><name>[<separator>random number]`
54
+ *
55
+ * Format example: `something-dashing-euler-1164`
56
+ *
57
+ * ## Usage
58
+ *
59
+ * ```js
60
+ * let name = NameGenerator.generateRandomName({
61
+ * prefix: 'my',
62
+ * separator: '_',
63
+ * postfixRandRange: { min: 1, max: 10 }
64
+ * }); // 'my_abandoned_yogi_5'
65
+ *
66
+ * name = NameGenerator.generateRandomName({
67
+ * separator: ' ',
68
+ * postfixRandRange: false
69
+ * }); // 'amused vampire'
70
+ * ```
71
+ *
72
+ * @param {GenerateRandomNameOpts} opts Optional options
73
+ *
74
+ * @returns a random formatted name
75
+ */
76
+ static generateRandomName({ prefix, separator, postfixRandRange, }?: GenerateRandomNameOpts): string;
77
+ }
78
+ export declare function randomNumber(max: number): number;
79
+ export declare function randomNumber(min: number, max: number): number;