kuzzle 2.16.8 → 2.17.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 (167) hide show
  1. package/README.md +11 -0
  2. package/lib/api/controllers/adminController.js +7 -6
  3. package/lib/api/controllers/authController.js +11 -11
  4. package/lib/api/controllers/baseController.js +60 -3
  5. package/lib/api/controllers/clusterController.js +1 -1
  6. package/lib/api/controllers/collectionController.js +7 -5
  7. package/lib/api/controllers/documentController.js +130 -17
  8. package/lib/api/controllers/indexController.js +1 -1
  9. package/lib/api/controllers/memoryStorageController.js +39 -38
  10. package/lib/api/controllers/realtimeController.js +1 -1
  11. package/lib/api/controllers/securityController.js +49 -49
  12. package/lib/api/controllers/serverController.js +73 -27
  13. package/lib/api/documentExtractor.js +3 -3
  14. package/lib/api/funnel.js +40 -21
  15. package/lib/api/httpRoutes.js +9 -4
  16. package/lib/api/openapi/OpenApiManager.d.ts +11 -0
  17. package/lib/api/openapi/OpenApiManager.js +96 -0
  18. package/lib/api/openapi/{document → components/document}/count.yaml +2 -2
  19. package/lib/api/openapi/{document → components/document}/create.yaml +2 -2
  20. package/lib/api/openapi/{document → components/document}/createOrReplace.yaml +2 -2
  21. package/lib/api/openapi/{document → components/document}/delete.yaml +1 -1
  22. package/lib/api/openapi/{document → components/document}/deleteByQuery.yaml +2 -2
  23. package/lib/api/openapi/{document → components/document}/exists.yaml +1 -1
  24. package/lib/api/openapi/{document → components/document}/get.yaml +1 -1
  25. package/lib/api/openapi/{document → components/document}/index.d.ts +2 -0
  26. package/lib/api/openapi/{document → components/document}/index.js +7 -2
  27. package/lib/api/openapi/{document → components/document}/replace.yaml +2 -2
  28. package/lib/api/openapi/{document → components/document}/scroll.yaml +1 -1
  29. package/lib/api/openapi/{document → components/document}/update.yaml +2 -2
  30. package/lib/api/openapi/components/document/validate.yaml +42 -0
  31. package/lib/api/openapi/components/index.d.ts +2 -0
  32. package/lib/api/openapi/components/index.js +18 -0
  33. package/lib/api/openapi/{payloads.yaml → components/payloads.yaml} +0 -0
  34. package/lib/api/openapi/index.d.ts +1 -2
  35. package/lib/api/openapi/index.js +1 -5
  36. package/lib/api/openapi/openApiGenerator.d.ts +7 -0
  37. package/lib/api/openapi/openApiGenerator.js +133 -0
  38. package/lib/api/request/kuzzleRequest.d.ts +11 -11
  39. package/lib/api/request/kuzzleRequest.js +38 -48
  40. package/lib/cluster/node.js +9 -9
  41. package/lib/cluster/publisher.js +1 -1
  42. package/lib/cluster/subscriber.js +1 -1
  43. package/lib/cluster/workers/IDCardRenewer.js +13 -4
  44. package/lib/config/default.config.js +1 -0
  45. package/lib/config/index.js +6 -6
  46. package/lib/core/auth/passportResponse.js +6 -6
  47. package/lib/core/auth/passportWrapper.js +5 -5
  48. package/lib/core/backend/backend.d.ts +5 -1
  49. package/lib/core/backend/backend.js +12 -8
  50. package/lib/core/backend/backendConfig.d.ts +5 -1
  51. package/lib/core/backend/backendConfig.js +4 -0
  52. package/lib/core/backend/backendOpenApi.d.ts +9 -0
  53. package/lib/core/backend/backendOpenApi.js +69 -0
  54. package/lib/core/backend/index.d.ts +1 -0
  55. package/lib/core/backend/index.js +1 -0
  56. package/lib/core/network/accessLogger.js +6 -6
  57. package/lib/core/network/clientConnection.js +1 -1
  58. package/lib/core/network/entryPoint.js +5 -5
  59. package/lib/core/network/httpRouter/index.js +5 -5
  60. package/lib/core/network/httpRouter/routeHandler.js +3 -3
  61. package/lib/core/network/httpRouter/routePart.js +5 -5
  62. package/lib/core/network/protocolManifest.js +1 -1
  63. package/lib/core/network/protocols/httpMessage.js +2 -2
  64. package/lib/core/network/protocols/httpwsProtocol.js +207 -46
  65. package/lib/core/network/protocols/mqttProtocol.js +3 -3
  66. package/lib/core/network/protocols/protocol.js +3 -3
  67. package/lib/core/network/router.js +7 -6
  68. package/lib/core/plugin/plugin.js +38 -64
  69. package/lib/core/plugin/pluginContext.d.ts +10 -1
  70. package/lib/core/plugin/pluginContext.js +2 -0
  71. package/lib/core/plugin/pluginManifest.js +3 -3
  72. package/lib/core/plugin/pluginRepository.js +5 -5
  73. package/lib/core/plugin/pluginsManager.js +29 -28
  74. package/lib/core/realtime/notification/server.js +1 -1
  75. package/lib/core/realtime/notification/user.js +1 -1
  76. package/lib/core/realtime/notifier.js +5 -5
  77. package/lib/core/security/index.js +1 -1
  78. package/lib/core/security/profileRepository.d.ts +176 -0
  79. package/lib/core/security/profileRepository.js +426 -443
  80. package/lib/core/security/roleRepository.js +16 -16
  81. package/lib/core/security/securityLoader.js +3 -3
  82. package/lib/core/security/tokenRepository.js +18 -21
  83. package/lib/core/security/userRepository.js +8 -8
  84. package/lib/core/shared/abstractManifest.js +4 -4
  85. package/lib/core/shared/repository.js +6 -6
  86. package/lib/core/shared/sdk/funnelProtocol.js +1 -1
  87. package/lib/core/shared/sdk/impersonatedSdk.js +1 -1
  88. package/lib/core/shared/store.js +30 -23
  89. package/lib/core/statistics/statistics.js +17 -17
  90. package/lib/core/storage/clientAdapter.js +45 -10
  91. package/lib/core/validation/baseType.js +5 -5
  92. package/lib/core/validation/types/anything.js +1 -1
  93. package/lib/core/validation/types/boolean.js +2 -2
  94. package/lib/core/validation/types/date.js +9 -9
  95. package/lib/core/validation/types/email.js +5 -5
  96. package/lib/core/validation/types/enum.js +6 -6
  97. package/lib/core/validation/types/geoPoint.js +2 -2
  98. package/lib/core/validation/types/geoShape.js +28 -25
  99. package/lib/core/validation/types/integer.js +4 -4
  100. package/lib/core/validation/types/ipAddress.js +7 -6
  101. package/lib/core/validation/types/numeric.js +4 -4
  102. package/lib/core/validation/types/object.js +5 -5
  103. package/lib/core/validation/types/string.js +5 -5
  104. package/lib/core/validation/types/url.js +7 -6
  105. package/lib/core/validation/validation.js +95 -84
  106. package/lib/kerror/codes/1-services.json +12 -0
  107. package/lib/kerror/codes/2-api.json +12 -0
  108. package/lib/kerror/codes/3-network.json +12 -0
  109. package/lib/kerror/codes/4-plugin.json +6 -0
  110. package/lib/kerror/codes/index.js +11 -11
  111. package/lib/kerror/index.js +1 -1
  112. package/lib/kuzzle/dumpGenerator.js +3 -3
  113. package/lib/kuzzle/event/kuzzleEventEmitter.js +4 -4
  114. package/lib/kuzzle/event/pipeRunner.js +1 -1
  115. package/lib/kuzzle/event/waterfall.js +6 -6
  116. package/lib/kuzzle/kuzzle.js +36 -5
  117. package/lib/kuzzle/log.js +3 -3
  118. package/lib/kuzzle/vault.js +3 -3
  119. package/lib/model/security/profile.d.ts +54 -0
  120. package/lib/model/security/profile.js +174 -233
  121. package/lib/model/security/rights.js +1 -1
  122. package/lib/model/security/role.d.ts +40 -0
  123. package/lib/model/security/role.js +159 -191
  124. package/lib/model/security/user.d.ts +29 -0
  125. package/lib/model/security/user.js +84 -52
  126. package/lib/model/storage/apiKey.js +2 -2
  127. package/lib/model/storage/baseModel.js +3 -3
  128. package/lib/service/cache/redis.js +7 -7
  129. package/lib/service/storage/elasticsearch.js +152 -90
  130. package/lib/service/storage/esWrapper.js +2 -3
  131. package/lib/types/ControllerDefinition.d.ts +3 -3
  132. package/lib/types/ControllerRights.d.ts +22 -0
  133. package/lib/types/ControllerRights.js +23 -0
  134. package/lib/types/HttpStream.d.ts +32 -0
  135. package/lib/types/HttpStream.js +70 -0
  136. package/lib/types/OpenApiDefinition.d.ts +43 -0
  137. package/lib/types/{config/StorageService/StorageServiceElasticsearchConfiguration.js → OpenApiDefinition.js} +1 -1
  138. package/lib/types/Policy.d.ts +25 -0
  139. package/lib/types/Policy.js +23 -0
  140. package/lib/types/PolicyRestrictions.d.ts +21 -0
  141. package/lib/types/PolicyRestrictions.js +23 -0
  142. package/lib/types/Target.d.ts +15 -0
  143. package/lib/types/Target.js +23 -0
  144. package/lib/types/config/KuzzleConfiguration.d.ts +4 -0
  145. package/lib/types/config/ServicesConfiguration.d.ts +2 -2
  146. package/lib/types/config/{StorageService/StorageServiceElasticsearchConfiguration.d.ts → storageEngine/StorageEngineElasticsearchConfiguration.d.ts} +10 -3
  147. package/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.js +3 -0
  148. package/lib/types/index.d.ts +7 -1
  149. package/lib/types/index.js +7 -1
  150. package/lib/util/array.d.ts +11 -0
  151. package/lib/util/array.js +57 -0
  152. package/lib/util/assertType.js +6 -6
  153. package/lib/util/bufferedPassThrough.d.ts +76 -0
  154. package/lib/util/bufferedPassThrough.js +161 -0
  155. package/lib/util/deprecate.js +7 -5
  156. package/lib/util/didYouMean.js +1 -1
  157. package/lib/util/dump-collection.d.ts +3 -0
  158. package/lib/util/dump-collection.js +265 -0
  159. package/lib/util/extractFields.js +2 -2
  160. package/lib/util/inflector.d.ts +8 -0
  161. package/lib/util/inflector.js +16 -0
  162. package/lib/util/requestAssertions.js +7 -7
  163. package/lib/util/wildcard.js +55 -0
  164. package/package-lock.json +881 -431
  165. package/package.json +23 -20
  166. package/lib/api/openApiGenerator.d.ts +0 -7
  167. package/lib/api/openApiGenerator.js +0 -197
@@ -95,7 +95,7 @@ class ElasticSearch extends Service {
95
95
  return new StorageClient({ defer, ...config });
96
96
  }
97
97
 
98
- constructor(config, scope = scopeEnum.PUBLIC) {
98
+ constructor (config, scope = scopeEnum.PUBLIC) {
99
99
  super('elasticsearch', config);
100
100
 
101
101
  this._scope = scope;
@@ -172,7 +172,7 @@ class ElasticSearch extends Service {
172
172
 
173
173
  const { body: { version } } = await this._client.info();
174
174
 
175
- if (version && !semver.satisfies(semver.coerce(version.number), '>= 7.0.0')) {
175
+ if (version && ! semver.satisfies(semver.coerce(version.number), '>= 7.0.0')) {
176
176
  throw kerror.get('version_mismatch', version.number);
177
177
  }
178
178
 
@@ -252,7 +252,7 @@ class ElasticSearch extends Service {
252
252
  continue;
253
253
  }
254
254
 
255
- if (!indexes[indexName]) {
255
+ if (! indexes[indexName]) {
256
256
  indexes[indexName] = {
257
257
  collections: [],
258
258
  name: indexName,
@@ -305,7 +305,7 @@ class ElasticSearch extends Service {
305
305
 
306
306
  let fetched = await global.kuzzle.ask('core:cache:internal:get', cacheKey);
307
307
 
308
- if (!fetched) {
308
+ if (! fetched) {
309
309
  throw kerror.get('unknown_scroll_id');
310
310
  }
311
311
 
@@ -333,7 +333,7 @@ class ElasticSearch extends Service {
333
333
 
334
334
  body.remaining = body.hits.total.value - fetched;
335
335
 
336
- return this._formatSearchResult(body);
336
+ return await this._formatSearchResult(body);
337
337
  }
338
338
  catch (error) {
339
339
  throw this._esWrapper.formatESError(error);
@@ -351,15 +351,31 @@ class ElasticSearch extends Service {
351
351
  * @returns {Promise.<{ scrollId, hits, aggregations, suggest, total }>}
352
352
  */
353
353
  async search (
354
- index,
355
- collection,
356
- searchBody,
357
- { from, size, scroll } = {})
358
- {
354
+ { index, collection, searchBody, targets } = {},
355
+ { from, size, scroll } = {}
356
+ ) {
357
+ let esIndexes;
358
+
359
+ if (targets && targets.length > 0) {
360
+ const indexes = new Set();
361
+ for (const target of targets) {
362
+ for (const targetCollection of target.collections) {
363
+ const alias = this._getAlias(target.index, targetCollection);
364
+
365
+ indexes.add(alias);
366
+ }
367
+ }
368
+
369
+ esIndexes = Array.from(indexes).join(',');
370
+ }
371
+ else {
372
+ esIndexes = this._getAlias(index, collection);
373
+ }
374
+
359
375
  const esRequest = {
360
376
  body: this._sanitizeSearchBody(searchBody),
361
377
  from,
362
- index: this._getAlias(index, collection),
378
+ index: esIndexes,
363
379
  scroll,
364
380
  size,
365
381
  trackTotalHits: true,
@@ -391,38 +407,47 @@ class ElasticSearch extends Service {
391
407
  body.remaining = body.hits.total.value - body.hits.hits.length;
392
408
  }
393
409
 
394
- return this._formatSearchResult(body);
410
+ return await this._formatSearchResult(body);
395
411
  }
396
412
  catch (error) {
397
413
  throw this._esWrapper.formatESError(error);
398
414
  }
399
415
  }
400
416
 
401
- _formatSearchResult (body) {
402
- function formatHit (hit) {
417
+ async _formatSearchResult (body) {
418
+
419
+ const formatHit = async (hit) => {
420
+ let alias = null;
421
+
422
+ if (hit._index) {
423
+ alias = await this._getAliasFromIndice(hit._index);
424
+ }
425
+
403
426
  return {
404
427
  _id: hit._id,
405
428
  _score: hit._score,
406
429
  _source: hit._source,
430
+ collection: alias ? this._extractCollection(alias) : undefined,
407
431
  highlight: hit.highlight,
432
+ index: alias ? this._extractIndex(alias) : undefined,
408
433
  };
409
- }
434
+ };
410
435
 
411
- function formatInnerHits (innerHits) {
436
+ async function formatInnerHits (innerHits) {
412
437
  if (! innerHits) {
413
438
  return undefined;
414
439
  }
415
440
 
416
441
  const formattedInnerHits = {};
417
442
  for (const [name, innerHit] of Object.entries(innerHits)) {
418
- formattedInnerHits[name] = innerHit.hits.hits.map(formatHit);
443
+ formattedInnerHits[name] = await Bluebird.map(innerHit.hits.hits, formatHit);
419
444
  }
420
445
  return formattedInnerHits;
421
446
  }
422
447
 
423
- const hits = body.hits.hits.map(hit => ({
424
- inner_hits: formatInnerHits(hit.inner_hits),
425
- ...formatHit(hit)
448
+ const hits = await Bluebird.map(body.hits.hits, async hit => ({
449
+ inner_hits: await formatInnerHits(hit.inner_hits),
450
+ ...await formatHit(hit)
426
451
  }));
427
452
 
428
453
  return {
@@ -491,7 +516,7 @@ class ElasticSearch extends Service {
491
516
 
492
517
  const esRequest = {
493
518
  body: {
494
- docs: ids.map(_id => ({ _id, _index: this._getAlias(index, collection)}))
519
+ docs: ids.map(_id => ({ _id, _index: this._getAlias(index, collection) }))
495
520
  }
496
521
  };
497
522
 
@@ -569,8 +594,7 @@ class ElasticSearch extends Service {
569
594
  index,
570
595
  collection,
571
596
  content,
572
- { id, refresh, userId=null } = {})
573
- {
597
+ { id, refresh, userId = null } = {}) {
574
598
  assertIsObject(content);
575
599
 
576
600
  const esRequest = {
@@ -624,8 +648,7 @@ class ElasticSearch extends Service {
624
648
  collection,
625
649
  id,
626
650
  content,
627
- { refresh, userId=null, injectKuzzleMeta=true } = {})
628
- {
651
+ { refresh, userId = null, injectKuzzleMeta = true } = {}) {
629
652
  const esRequest = {
630
653
  body: content,
631
654
  id,
@@ -679,8 +702,7 @@ class ElasticSearch extends Service {
679
702
  collection,
680
703
  id,
681
704
  content,
682
- { refresh, userId=null, retryOnConflict } = {})
683
- {
705
+ { refresh, userId = null, retryOnConflict } = {}) {
684
706
  const esRequest = {
685
707
  _source: true,
686
708
  body: { doc: content },
@@ -731,8 +753,7 @@ class ElasticSearch extends Service {
731
753
  collection,
732
754
  id,
733
755
  content,
734
- { defaultValues = {}, refresh, userId=null, retryOnConflict } = {})
735
- {
756
+ { defaultValues = {}, refresh, userId = null, retryOnConflict } = {}) {
736
757
  const esRequest = {
737
758
  _source: true,
738
759
  body: {
@@ -794,8 +815,7 @@ class ElasticSearch extends Service {
794
815
  collection,
795
816
  id,
796
817
  content,
797
- { refresh, userId=null } = {})
798
- {
818
+ { refresh, userId = null } = {}) {
799
819
  const alias = this._getAlias(index, collection);
800
820
  const esRequest = {
801
821
  body: content,
@@ -851,8 +871,7 @@ class ElasticSearch extends Service {
851
871
  index,
852
872
  collection,
853
873
  id,
854
- { refresh } = {})
855
- {
874
+ { refresh } = {}) {
856
875
  const esRequest = {
857
876
  id,
858
877
  index: this._getAlias(index, collection),
@@ -892,8 +911,7 @@ class ElasticSearch extends Service {
892
911
  index,
893
912
  collection,
894
913
  query,
895
- { refresh, size = 1000, fetch=true } = {})
896
- {
914
+ { refresh, size = 1000, fetch = true } = {}) {
897
915
  const esRequest = {
898
916
  body: this._sanitizeSearchBody({ query }),
899
917
  index: this._getAlias(index, collection),
@@ -901,7 +919,7 @@ class ElasticSearch extends Service {
901
919
  size
902
920
  };
903
921
 
904
- if (!isPlainObject(query)) {
922
+ if (! isPlainObject(query)) {
905
923
  throw kerror.get('missing_argument', 'body.query');
906
924
  }
907
925
 
@@ -947,8 +965,7 @@ class ElasticSearch extends Service {
947
965
  collection,
948
966
  id,
949
967
  fields,
950
- { refresh, userId=null } = {})
951
- {
968
+ { refresh, userId = null } = {}) {
952
969
  const alias = this._getAlias(index, collection);
953
970
  const esRequest = {
954
971
  id,
@@ -988,7 +1005,8 @@ class ElasticSearch extends Service {
988
1005
  _source: body._source,
989
1006
  _version: updated._version
990
1007
  };
991
- } catch (error) {
1008
+ }
1009
+ catch (error) {
992
1010
  throw this._esWrapper.formatESError(error);
993
1011
  }
994
1012
  }
@@ -1009,8 +1027,7 @@ class ElasticSearch extends Service {
1009
1027
  collection,
1010
1028
  query,
1011
1029
  changes,
1012
- { refresh, size = 1000, userId=null } = {})
1013
- {
1030
+ { refresh, size = 1000, userId = null } = {}) {
1014
1031
 
1015
1032
  try {
1016
1033
  const esRequest = {
@@ -1063,8 +1080,7 @@ class ElasticSearch extends Service {
1063
1080
  collection,
1064
1081
  query,
1065
1082
  changes,
1066
- { refresh = 'false' } = {})
1067
- {
1083
+ { refresh = 'false' } = {}) {
1068
1084
  const script = {
1069
1085
  params: {},
1070
1086
  source: ''
@@ -1072,7 +1088,7 @@ class ElasticSearch extends Service {
1072
1088
 
1073
1089
  const flatChanges = extractFields(changes, { alsoExtractValues: true });
1074
1090
 
1075
- for (const {key, value} of flatChanges) {
1091
+ for (const { key, value } of flatChanges) {
1076
1092
  script.source += `ctx._source.${key} = params['${key}'];`;
1077
1093
  script.params[key] = value;
1078
1094
  }
@@ -1125,8 +1141,7 @@ class ElasticSearch extends Service {
1125
1141
  collection,
1126
1142
  query,
1127
1143
  callback,
1128
- { size=10, scrollTTl= '5s' } = {})
1129
- {
1144
+ { size = 10, scrollTTl = '5s' } = {}) {
1130
1145
  const esRequest = {
1131
1146
  body: this._sanitizeSearchBody({ query }),
1132
1147
  from: 0,
@@ -1149,7 +1164,7 @@ class ElasticSearch extends Service {
1149
1164
  results = await new Bluebird((resolve, reject) => {
1150
1165
  this._client.search(
1151
1166
  esRequest,
1152
- async function getMoreUntilDone(error, { body: { hits, _scroll_id } }) {
1167
+ async function getMoreUntilDone (error, { body: { hits, _scroll_id } }) {
1153
1168
  if (error) {
1154
1169
  reject(error);
1155
1170
  return;
@@ -1233,7 +1248,7 @@ class ElasticSearch extends Service {
1233
1248
  *
1234
1249
  * @returns {Promise}
1235
1250
  */
1236
- async createCollection (index, collection, { mappings={}, settings={} } = {}) {
1251
+ async createCollection (index, collection, { mappings = {}, settings = {} } = {}) {
1237
1252
  this._assertValidIndexAndCollection(index, collection);
1238
1253
 
1239
1254
  if (collection === HIDDEN_COLLECTION) {
@@ -1308,7 +1323,7 @@ class ElasticSearch extends Service {
1308
1323
  *
1309
1324
  * @returns {Promise.<{ dynamic, _meta, properties }>}
1310
1325
  */
1311
- async getMapping (index, collection, { includeKuzzleMeta=false } = {}) {
1326
+ async getMapping (index, collection, { includeKuzzleMeta = false } = {}) {
1312
1327
  const
1313
1328
  indice = await this._getIndice(index, collection),
1314
1329
  esRequest = {
@@ -1344,7 +1359,7 @@ class ElasticSearch extends Service {
1344
1359
  *
1345
1360
  * @returns {Promise}
1346
1361
  */
1347
- async updateCollection (index, collection, { mappings={}, settings={} } = {}) {
1362
+ async updateCollection (index, collection, { mappings = {}, settings = {} } = {}) {
1348
1363
  const esRequest = {
1349
1364
  index: await this._getIndice(index, collection)
1350
1365
  };
@@ -1362,12 +1377,12 @@ class ElasticSearch extends Service {
1362
1377
  throw this._esWrapper.formatESError(error);
1363
1378
  }
1364
1379
 
1365
- if (!_.isEmpty(settings)) {
1380
+ if (! _.isEmpty(settings)) {
1366
1381
  await this.updateSettings(index, collection, settings);
1367
1382
  }
1368
1383
 
1369
1384
  try {
1370
- if (!_.isEmpty(mappings)) {
1385
+ if (! _.isEmpty(mappings)) {
1371
1386
  const previousMappings = await this.getMapping(index, collection);
1372
1387
 
1373
1388
  await this.updateMapping(index, collection, mappings);
@@ -1385,7 +1400,7 @@ class ElasticSearch extends Service {
1385
1400
  };
1386
1401
 
1387
1402
  // Rollback to previous settings
1388
- if (!_.isEmpty(settings)) {
1403
+ if (! _.isEmpty(settings)) {
1389
1404
  await this.updateSettings(index, collection, allowedSettings);
1390
1405
  }
1391
1406
 
@@ -1551,8 +1566,7 @@ class ElasticSearch extends Service {
1551
1566
  index,
1552
1567
  collection,
1553
1568
  documents,
1554
- { refresh, timeout, userId=null } = {})
1555
- {
1569
+ { refresh, timeout, userId = null } = {}) {
1556
1570
  const alias = this._getAlias(index, collection);
1557
1571
  const actionNames = ['index', 'create', 'update', 'delete'];
1558
1572
  const dateNow = Date.now();
@@ -1920,7 +1934,7 @@ class ElasticSearch extends Service {
1920
1934
  };
1921
1935
 
1922
1936
  try {
1923
- const { body: exists} = await this._client.exists(esRequest);
1937
+ const { body: exists } = await this._client.exists(esRequest);
1924
1938
 
1925
1939
  return exists;
1926
1940
  }
@@ -1929,6 +1943,60 @@ class ElasticSearch extends Service {
1929
1943
  }
1930
1944
  }
1931
1945
 
1946
+ /**
1947
+ * Returns the list of documents existing with the ids given in the body param
1948
+ * NB: Due to internal Kuzzle mechanism, can only be called on a single
1949
+ * index/collection, using the body { ids: [.. } syntax.
1950
+ *
1951
+ * @param {String} index - Index name
1952
+ * @param {String} collection - Collection name
1953
+ * @param {Array.<String>} ids - Document IDs
1954
+ *
1955
+ * @returns {Promise.<{ items: Array<{ _id, _source, _version }>, errors }>}
1956
+ */
1957
+ async mExists (index, collection, ids) {
1958
+ if (ids.length === 0) {
1959
+ return { errors: [], item: [] };
1960
+ }
1961
+
1962
+ const esRequest = {
1963
+ _source: false,
1964
+ body: {
1965
+ docs: ids.map(_id => ({ _id })),
1966
+ },
1967
+ index: this._getAlias(index, collection)
1968
+ };
1969
+
1970
+ debug('mExists: %o', esRequest);
1971
+
1972
+ let body;
1973
+
1974
+ try {
1975
+ ({ body } = await this._client.mget(esRequest)); // NOSONAR
1976
+ }
1977
+ catch (e) {
1978
+ throw this._esWrapper.formatESError(e);
1979
+ }
1980
+
1981
+ const errors = [];
1982
+ const items = [];
1983
+
1984
+ for (let i = 0; i < body.docs.length; i++) {
1985
+ const doc = body.docs[i];
1986
+
1987
+ if (doc.found) {
1988
+ items.push(
1989
+ doc._id,
1990
+ );
1991
+ }
1992
+ else {
1993
+ errors.push(doc._id);
1994
+ }
1995
+ }
1996
+
1997
+ return { errors, items };
1998
+ }
1999
+
1932
2000
  /**
1933
2001
  * Returns true if the index exists
1934
2002
  *
@@ -1985,8 +2053,7 @@ class ElasticSearch extends Service {
1985
2053
  index,
1986
2054
  collection,
1987
2055
  documents,
1988
- { refresh, timeout, userId=null } = {})
1989
- {
2056
+ { refresh, timeout, userId = null } = {}) {
1990
2057
  const
1991
2058
  alias = this._getAlias(index, collection),
1992
2059
  kuzzleMeta = {
@@ -2004,9 +2071,9 @@ class ElasticSearch extends Service {
2004
2071
  } = this._extractMDocuments(documents, kuzzleMeta, { prepareMGet: true });
2005
2072
 
2006
2073
  // prepare the mget request, but only for document having a specified id
2007
- const {body} = documentsToGet.length > 0
2008
- ? await this._client.mget({body: {docs: documentsToGet}, index: alias})
2009
- : {body: {docs: []}};
2074
+ const { body } = documentsToGet.length > 0
2075
+ ? await this._client.mget({ body: { docs: documentsToGet }, index: alias })
2076
+ : { body: { docs: [] } };
2010
2077
 
2011
2078
  const
2012
2079
  existingDocuments = body.docs,
@@ -2080,8 +2147,7 @@ class ElasticSearch extends Service {
2080
2147
  index,
2081
2148
  collection,
2082
2149
  documents,
2083
- { refresh, timeout, userId=null, injectKuzzleMeta=true, limits=true } = {})
2084
- {
2150
+ { refresh, timeout, userId = null, injectKuzzleMeta = true, limits = true } = {}) {
2085
2151
  let kuzzleMeta = {};
2086
2152
 
2087
2153
  if (injectKuzzleMeta) {
@@ -2144,8 +2210,7 @@ class ElasticSearch extends Service {
2144
2210
  index,
2145
2211
  collection,
2146
2212
  documents,
2147
- { refresh, retryOnConflict = 0, timeout, userId=null } = {})
2148
- {
2213
+ { refresh, retryOnConflict = 0, timeout, userId = null } = {}) {
2149
2214
  const
2150
2215
  alias = this._getAlias(index, collection),
2151
2216
  toImport = [],
@@ -2236,8 +2301,7 @@ class ElasticSearch extends Service {
2236
2301
  index,
2237
2302
  collection,
2238
2303
  documents,
2239
- { refresh, retryOnConflict = 0, timeout, userId=null } = {})
2240
- {
2304
+ { refresh, retryOnConflict = 0, timeout, userId = null } = {}) {
2241
2305
  const alias = this._getAlias(index, collection);
2242
2306
  const esRequest = {
2243
2307
  body: [],
@@ -2330,8 +2394,7 @@ class ElasticSearch extends Service {
2330
2394
  index,
2331
2395
  collection,
2332
2396
  documents,
2333
- { refresh, timeout, userId=null } = {})
2334
- {
2397
+ { refresh, timeout, userId = null } = {}) {
2335
2398
  const
2336
2399
  alias = this._getAlias(index, collection),
2337
2400
  kuzzleMeta = {
@@ -2355,7 +2418,7 @@ class ElasticSearch extends Service {
2355
2418
  return { errors: rejected, items: [] };
2356
2419
  }
2357
2420
 
2358
- const {body} = await this._client.mget({
2421
+ const { body } = await this._client.mget({
2359
2422
  body: { docs: documentsToGet },
2360
2423
  index: alias
2361
2424
  });
@@ -2421,8 +2484,7 @@ class ElasticSearch extends Service {
2421
2484
  index,
2422
2485
  collection,
2423
2486
  ids,
2424
- { refresh, timeout } = {})
2425
- {
2487
+ { refresh, timeout } = {}) {
2426
2488
  const
2427
2489
  query = { ids: { values: [] } },
2428
2490
  validIds = [],
@@ -2450,7 +2512,7 @@ class ElasticSearch extends Service {
2450
2512
  /* end critical code section */
2451
2513
  await this.refreshCollection(index, collection);
2452
2514
 
2453
- const {items} = await this.mGet(index, collection, validIds);
2515
+ const { items } = await this.mGet(index, collection, validIds);
2454
2516
 
2455
2517
  let idx = 0;
2456
2518
 
@@ -2501,7 +2563,7 @@ class ElasticSearch extends Service {
2501
2563
  *
2502
2564
  * @returns {Promise.<Object[]>} results
2503
2565
  */
2504
- async _mExecute (esRequest, documents, partialErrors, { limits=true } = {}) {
2566
+ async _mExecute (esRequest, documents, partialErrors, { limits = true } = {}) {
2505
2567
  assertWellFormedRefresh(esRequest);
2506
2568
 
2507
2569
  if ( limits
@@ -2584,7 +2646,7 @@ class ElasticSearch extends Service {
2584
2646
  *
2585
2647
  * @returns {Object} { rejected, extractedDocuments, documentsToGet }
2586
2648
  */
2587
- _extractMDocuments (documents, metadata, { prepareMGet=false, requireId=false, prepareMUpsert=false } = {}) {
2649
+ _extractMDocuments (documents, metadata, { prepareMGet = false, requireId = false, prepareMUpsert = false } = {}) {
2588
2650
  const
2589
2651
  rejected = [],
2590
2652
  extractedDocuments = [],
@@ -2598,21 +2660,21 @@ class ElasticSearch extends Service {
2598
2660
  for (let i = 0; i < documents.length; i++) {
2599
2661
  const document = documents[i];
2600
2662
 
2601
- if (!isPlainObject(document.body) && !prepareMUpsert) {
2663
+ if (! isPlainObject(document.body) && ! prepareMUpsert) {
2602
2664
  rejected.push({
2603
2665
  document,
2604
2666
  reason: 'document body must be an object',
2605
2667
  status: 400
2606
2668
  });
2607
2669
  }
2608
- else if (!isPlainObject(document.changes) && prepareMUpsert) {
2670
+ else if (! isPlainObject(document.changes) && prepareMUpsert) {
2609
2671
  rejected.push({
2610
2672
  document,
2611
2673
  reason: 'document changes must be an object',
2612
2674
  status: 400
2613
2675
  });
2614
2676
  }
2615
- else if (prepareMUpsert && document.default && !isPlainObject(document.default)) {
2677
+ else if (prepareMUpsert && document.default && ! isPlainObject(document.default)) {
2616
2678
  rejected.push({
2617
2679
  document,
2618
2680
  reason: 'document default must be an object',
@@ -2678,7 +2740,7 @@ class ElasticSearch extends Service {
2678
2740
  : [...ROOT_MAPPING_PROPERTIES, ...CHILD_MAPPING_PROPERTIES];
2679
2741
 
2680
2742
  for (const property of properties) {
2681
- if (check && !mappingProperties.includes(property)) {
2743
+ if (check && ! mappingProperties.includes(property)) {
2682
2744
  const currentPath = [...path, property].join('.');
2683
2745
 
2684
2746
  throw kerror.get(
@@ -2778,7 +2840,7 @@ class ElasticSearch extends Service {
2778
2840
  * @throws If there is not exactly one alias associated
2779
2841
  */
2780
2842
  async _getAliasFromIndice (indice) {
2781
- const { body } = await this._client.indices.getAlias({ index: indice});
2843
+ const { body } = await this._client.indices.getAlias({ index: indice });
2782
2844
  const aliases = Object.keys(body[indice].aliases);
2783
2845
 
2784
2846
  if (aliases.length < 1) {
@@ -2808,9 +2870,9 @@ class ElasticSearch extends Service {
2808
2870
  indice[INDEX_PREFIX_POSITION_IN_INDICE] === this._indexPrefix
2809
2871
  && ! aliases.some(alias => alias.indice === indice));
2810
2872
 
2811
- const esRequest = { body: { actions : [] } };
2873
+ const esRequest = { body: { actions: [] } };
2812
2874
  for (const indice of indicesWithoutAlias) {
2813
- esRequest.body.actions.push({ add : { alias: `${ALIAS_PREFIX}${indice}`, index: indice } });
2875
+ esRequest.body.actions.push({ add: { alias: `${ALIAS_PREFIX}${indice}`, index: indice } });
2814
2876
  }
2815
2877
 
2816
2878
  if (esRequest.body.actions.length > 0) {
@@ -2829,11 +2891,11 @@ class ElasticSearch extends Service {
2829
2891
  * @param {String} collection
2830
2892
  */
2831
2893
  _assertValidIndexAndCollection (index, collection = null) {
2832
- if (!this.isIndexNameValid(index)) {
2894
+ if (! this.isIndexNameValid(index)) {
2833
2895
  throw kerror.get('invalid_index_name', index);
2834
2896
  }
2835
2897
 
2836
- if (collection !== null && !this.isCollectionNameValid(collection)) {
2898
+ if (collection !== null && ! this.isCollectionNameValid(collection)) {
2837
2899
  throw kerror.get('invalid_collection_name', collection);
2838
2900
  }
2839
2901
  }
@@ -2848,7 +2910,7 @@ class ElasticSearch extends Service {
2848
2910
  _extractIndex (alias) {
2849
2911
  return alias.substr(
2850
2912
  INDEX_PREFIX_POSITION_IN_ALIAS + 1,
2851
- alias.indexOf(NAME_SEPARATOR) - INDEX_PREFIX_POSITION_IN_ALIAS -1 );
2913
+ alias.indexOf(NAME_SEPARATOR) - INDEX_PREFIX_POSITION_IN_ALIAS - 1 );
2852
2914
  }
2853
2915
 
2854
2916
  /**
@@ -2966,7 +3028,7 @@ class ElasticSearch extends Service {
2966
3028
  _sanitizeSearchBody (searchBody) {
2967
3029
  // Only allow a whitelist of top level properties
2968
3030
  for (const key of Object.keys(searchBody)) {
2969
- if (!this.searchBodyKeys.includes(key)) {
3031
+ if (searchBody[key] !== undefined && ! this.searchBodyKeys.includes(key)) {
2970
3032
  throw kerror.get('invalid_search_query', key);
2971
3033
  }
2972
3034
  }
@@ -3032,7 +3094,7 @@ class ElasticSearch extends Service {
3032
3094
  async clearScroll (id) {
3033
3095
  if (id) {
3034
3096
  debug('clearing scroll: %s', id);
3035
- await this._client.clearScroll({scrollId: id});
3097
+ await this._client.clearScroll({ scrollId: id });
3036
3098
  }
3037
3099
  }
3038
3100
 
@@ -3177,7 +3239,7 @@ function findDynamic (mappings, path = [], results = {}) {
3177
3239
  * @param {Object} esRequest
3178
3240
  * @throws
3179
3241
  */
3180
- function assertNoRouting(esRequest) {
3242
+ function assertNoRouting (esRequest) {
3181
3243
  if (esRequest.body._routing) {
3182
3244
  throw kerror.get('no_routing');
3183
3245
  }
@@ -3189,7 +3251,7 @@ function assertNoRouting(esRequest) {
3189
3251
  * @param {Object} esRequest
3190
3252
  * @throws
3191
3253
  */
3192
- function assertWellFormedRefresh(esRequest) {
3254
+ function assertWellFormedRefresh (esRequest) {
3193
3255
  if (! ['wait_for', 'false', false, undefined].includes(esRequest.refresh)) {
3194
3256
  throw kerror.get('invalid_argument', 'refresh', '"wait_for", false');
3195
3257
  }
@@ -3238,7 +3300,7 @@ function _isObjectNameValid (name) {
3238
3300
  let valid = true;
3239
3301
 
3240
3302
  for (let i = 0; valid && i < FORBIDDEN_CHARS.length; i++) {
3241
- valid = !name.includes(FORBIDDEN_CHARS[i]);
3303
+ valid = ! name.includes(FORBIDDEN_CHARS[i]);
3242
3304
  }
3243
3305
 
3244
3306
  return valid;
@@ -154,7 +154,7 @@ const errorMessagesMapping = [
154
154
  ];
155
155
 
156
156
  class ESWrapper {
157
- constructor(client) {
157
+ constructor (client) {
158
158
  this.client = client;
159
159
  }
160
160
 
@@ -257,8 +257,7 @@ class ESWrapper {
257
257
 
258
258
  // empty query throws exception with ES 7
259
259
  if ( error.meta.body.error.type === 'parsing_exception'
260
- && _.get(error, 'meta.body.error.caused_by.type') === 'illegal_argument_exception')
261
- {
260
+ && _.get(error, 'meta.body.error.caused_by.type') === 'illegal_argument_exception') {
262
261
  errorMessage = error.meta.body.error.caused_by.reason;
263
262
  }
264
263
  }
@@ -8,7 +8,7 @@ import { KuzzleRequest } from '../api/request';
8
8
  * actions: {
9
9
  * sayHello: {
10
10
  * handler: async request => `Hello, ${request.input.args.name}`,
11
- * http: [{ verb: 'POST', path: '/greeting/hello/:name' }]
11
+ * http: [{ verb: 'post', path: '/greeting/hello/:name' }]
12
12
  * }
13
13
  * }
14
14
  * }
@@ -22,7 +22,7 @@ export declare type ControllerDefinition = {
22
22
  * sayHello: {
23
23
  * handler: async request => `Hello, ${request.input.args.name}`,
24
24
  * http: [{
25
- * verb: 'POST',
25
+ * verb: 'post',
26
26
  * path: '/greeting/hello/:name',
27
27
  * openapi: {
28
28
  * description: "Simply say hello",
@@ -68,7 +68,7 @@ export declare type HttpRoute = {
68
68
  /**
69
69
  * HTTP verb.
70
70
  */
71
- verb: 'get' | 'post' | 'put' | 'delete' | 'head';
71
+ verb: 'get' | 'head' | 'post' | 'put' | 'delete' | 'patch' | 'options';
72
72
  /**
73
73
  * Route path.
74
74
  * A route starting with `/` will be prefixed by `/_` otherwise the route