kuzzle 2.18.1 → 2.19.2

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 (42) 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/debugController.d.ts +59 -0
  5. package/lib/api/controllers/debugController.js +285 -0
  6. package/lib/api/controllers/documentController.js +43 -29
  7. package/lib/api/controllers/index.js +1 -0
  8. package/lib/api/controllers/securityController.js +2 -2
  9. package/lib/api/documentExtractor.js +49 -8
  10. package/lib/api/funnel.js +30 -8
  11. package/lib/api/httpRoutes.js +6 -0
  12. package/lib/api/request/kuzzleRequest.d.ts +12 -4
  13. package/lib/api/request/kuzzleRequest.js +17 -13
  14. package/lib/cluster/idCardHandler.js +1 -1
  15. package/lib/config/default.config.js +3 -0
  16. package/lib/config/documentEventAliases.d.ts +7 -0
  17. package/lib/config/documentEventAliases.js +26 -12
  18. package/lib/core/backend/backend.d.ts +4 -0
  19. package/lib/core/backend/backend.js +9 -0
  20. package/lib/core/network/protocols/httpwsProtocol.js +6 -0
  21. package/lib/core/shared/sdk/embeddedSdk.d.ts +1 -1
  22. package/lib/core/shared/sdk/embeddedSdk.js +33 -0
  23. package/lib/kerror/codes/0-core.json +35 -0
  24. package/lib/kerror/codes/2-api.json +6 -0
  25. package/lib/kuzzle/kuzzle.d.ts +1 -1
  26. package/lib/kuzzle/kuzzle.js +27 -8
  27. package/lib/model/storage/apiKey.js +1 -6
  28. package/lib/service/storage/elasticsearch.js +40 -13
  29. package/lib/types/DebugModule.d.ts +23 -0
  30. package/lib/types/DebugModule.js +39 -0
  31. package/lib/types/config/SecurityConfiguration.d.ts +10 -0
  32. package/lib/util/crypto.d.ts +1 -0
  33. package/lib/util/crypto.js +12 -0
  34. package/lib/util/name-generator.d.ts +79 -0
  35. package/lib/util/name-generator.js +1409 -1345
  36. package/lib/util/time.d.ts +1 -0
  37. package/lib/util/time.js +9 -0
  38. package/npm-shrinkwrap.json +19422 -0
  39. package/package.json +4 -6
  40. package/lib/core/security/README.md +0 -224
  41. package/lib/core/shared/README.md +0 -3
  42. package/package-lock.json +0 -8422
package/index.d.ts CHANGED
@@ -6,5 +6,6 @@ export * from './lib/api/request';
6
6
  export * from './lib/kerror/errors';
7
7
  export * from './lib/util/mutex';
8
8
  export * from './lib/util/inflector';
9
+ export { NameGenerator } from './lib/util/name-generator';
9
10
  export * from 'kuzzle-sdk';
10
11
  export * from './lib/core/shared/KoncordeWrapper';
package/index.js CHANGED
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.NameGenerator = void 0;
17
18
  __exportStar(require("./lib/core/backend"), exports);
18
19
  __exportStar(require("./lib/types"), exports);
19
20
  __exportStar(require("./lib/core/plugin/pluginContext"), exports);
@@ -22,6 +23,8 @@ __exportStar(require("./lib/api/request"), exports);
22
23
  __exportStar(require("./lib/kerror/errors"), exports);
23
24
  __exportStar(require("./lib/util/mutex"), exports);
24
25
  __exportStar(require("./lib/util/inflector"), exports);
26
+ var name_generator_1 = require("./lib/util/name-generator");
27
+ Object.defineProperty(exports, "NameGenerator", { enumerable: true, get: function () { return name_generator_1.NameGenerator; } });
25
28
  __exportStar(require("kuzzle-sdk"), exports);
26
29
  __exportStar(require("./lib/core/shared/KoncordeWrapper"), exports);
27
30
  //# sourceMappingURL=index.js.map
@@ -26,6 +26,7 @@ const Bluebird = require('bluebird');
26
26
  const kerror = require('../../kerror');
27
27
  const { NativeController } = require('./baseController');
28
28
  const { Mutex } = require('../../util/mutex');
29
+ const { BACKEND_IMPORT_KEY } = require('../../kuzzle/kuzzle');
29
30
 
30
31
  /**
31
32
  * @class AdminController
@@ -97,6 +98,10 @@ class AdminController extends NativeController {
97
98
  options);
98
99
 
99
100
  await global.kuzzle.internalIndex.createInitialSecurities();
101
+
102
+ await this.ask(
103
+ 'core:cache:internal:del',
104
+ `${BACKEND_IMPORT_KEY}:permissions`);
100
105
  }
101
106
  finally {
102
107
  await mutex.unlock();
@@ -119,6 +124,10 @@ class AdminController extends NativeController {
119
124
  const indexes = await this.ask('core:storage:public:index:list');
120
125
  await this.ask('core:storage:public:index:mDelete', indexes);
121
126
 
127
+ await this.ask(
128
+ 'core:cache:internal:del',
129
+ `${BACKEND_IMPORT_KEY}:mappings`);
130
+
122
131
  return { acknowledge: true };
123
132
  }
124
133
  finally {
@@ -0,0 +1,59 @@
1
+ import { KuzzleRequest } from '../request';
2
+ import { NativeController } from './baseController';
3
+ /**
4
+ * @class DebugController
5
+ */
6
+ export declare class DebugController extends NativeController {
7
+ private inspector;
8
+ private debuggerStatus;
9
+ /**
10
+ * Map<eventName, Set<connectionId>>
11
+ */
12
+ private events;
13
+ /**
14
+ * Map of functions from the DebugModules
15
+ */
16
+ private kuzzlePostMethods;
17
+ /**
18
+ * List of DebugModule for DebugController
19
+ * Used to add new methods and events to the protocol
20
+ */
21
+ private modules;
22
+ constructor();
23
+ init(): Promise<void>;
24
+ nodeVersion(): Promise<string>;
25
+ /**
26
+ * Connect the debugger
27
+ */
28
+ enable(): Promise<void>;
29
+ /**
30
+ * Disconnect the debugger and clears all the events listeners
31
+ */
32
+ disable(): Promise<void>;
33
+ /**
34
+ * Trigger action from debugger directly following the Chrome Debug Protocol
35
+ * See: https://chromedevtools.github.io/devtools-protocol/v8/
36
+ */
37
+ post(request: KuzzleRequest): Promise<any>;
38
+ /**
39
+ * Make the websocket connection listen and receive events from Chrome Debug Protocol
40
+ * See events from: https://chromedevtools.github.io/devtools-protocol/v8/
41
+ */
42
+ addListener(request: KuzzleRequest): Promise<void>;
43
+ /**
44
+ * Remove the websocket connection from the events' listeners
45
+ */
46
+ removeListener(request: KuzzleRequest): Promise<void>;
47
+ /**
48
+ * Execute a method using the Chrome Debug Protocol
49
+ * @param method Chrome Debug Protocol method to execute
50
+ * @param params
51
+ * @returns
52
+ */
53
+ private inspectorPost;
54
+ /**
55
+ * Sends a direct notification to a websocket connection without having to listen to a specific room
56
+ */
57
+ private notifyConnection;
58
+ private notifyGlobalListeners;
59
+ }
@@ -0,0 +1,285 @@
1
+ "use strict";
2
+ /*
3
+ * Kuzzle, a backend software, self-hostable and ready to use
4
+ * to power modern apps
5
+ *
6
+ * Copyright 2015-2022 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
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ var desc = Object.getOwnPropertyDescriptor(m, k);
25
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
26
+ desc = { enumerable: true, get: function() { return m[k]; } };
27
+ }
28
+ Object.defineProperty(o, k2, desc);
29
+ }) : (function(o, m, k, k2) {
30
+ if (k2 === undefined) k2 = k;
31
+ o[k2] = m[k];
32
+ }));
33
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
34
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
35
+ }) : function(o, v) {
36
+ o["default"] = v;
37
+ });
38
+ var __importStar = (this && this.__importStar) || function (mod) {
39
+ if (mod && mod.__esModule) return mod;
40
+ var result = {};
41
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
42
+ __setModuleDefault(result, mod);
43
+ return result;
44
+ };
45
+ var __importDefault = (this && this.__importDefault) || function (mod) {
46
+ return (mod && mod.__esModule) ? mod : { "default": mod };
47
+ };
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.DebugController = void 0;
50
+ const baseController_1 = require("./baseController");
51
+ const inspector_1 = __importDefault(require("inspector"));
52
+ const kerror = __importStar(require("../../kerror"));
53
+ const get_1 = __importDefault(require("lodash/get"));
54
+ const DEBUGGER_EVENT = 'kuzzle-debugger-event';
55
+ /**
56
+ * @class DebugController
57
+ */
58
+ class DebugController extends baseController_1.NativeController {
59
+ constructor() {
60
+ super([
61
+ 'nodeVersion',
62
+ 'enable',
63
+ 'disable',
64
+ 'post',
65
+ 'addListener',
66
+ 'removeListener',
67
+ ]);
68
+ this.debuggerStatus = false;
69
+ /**
70
+ * Map<eventName, Set<connectionId>>
71
+ */
72
+ this.events = new Map();
73
+ /**
74
+ * Map of functions from the DebugModules
75
+ */
76
+ this.kuzzlePostMethods = new Map();
77
+ /**
78
+ * List of DebugModule for DebugController
79
+ * Used to add new methods and events to the protocol
80
+ */
81
+ this.modules = [];
82
+ }
83
+ async init() {
84
+ super.init();
85
+ this.inspector = new inspector_1.default.Session();
86
+ // Remove connection id from the list of listeners for each event
87
+ global.kuzzle.on('connection:remove', connectionId => {
88
+ if (!this.debuggerStatus) {
89
+ return;
90
+ }
91
+ for (const listener of this.events.values()) {
92
+ listener.delete(connectionId);
93
+ }
94
+ });
95
+ this.inspector.on('inspectorNotification', async (payload) => {
96
+ if (!this.debuggerStatus) {
97
+ return;
98
+ }
99
+ await this.notifyGlobalListeners(payload.method, payload);
100
+ const listeners = this.events.get(payload.method);
101
+ if (!listeners) {
102
+ return;
103
+ }
104
+ const promises = [];
105
+ for (const connectionId of listeners) {
106
+ promises.push(this.notifyConnection(connectionId, DEBUGGER_EVENT, {
107
+ event: payload.method,
108
+ result: payload
109
+ }));
110
+ }
111
+ // No need to catch, notify is already try-catched
112
+ await Promise.all(promises);
113
+ });
114
+ }
115
+ async nodeVersion() {
116
+ return process.version;
117
+ }
118
+ /**
119
+ * Connect the debugger
120
+ */
121
+ async enable() {
122
+ if (this.debuggerStatus) {
123
+ return;
124
+ }
125
+ this.inspector.connect();
126
+ this.debuggerStatus = true;
127
+ for (const module of this.modules) {
128
+ await module.init(this.inspector);
129
+ for (const methodName of module.methods) {
130
+ if (!module[methodName]) {
131
+ throw new Error(`Missing implementation of method "${methodName}" inside DebugModule "${module.name}"`);
132
+ }
133
+ this.kuzzlePostMethods.set(`Kuzzle.${module.name}.${methodName}`, module[methodName].bind(module));
134
+ }
135
+ for (const eventName of module.events) {
136
+ module.on(eventName, async (payload) => {
137
+ if (!this.debuggerStatus) {
138
+ return;
139
+ }
140
+ const event = `Kuzzle.${module.name}.${eventName}`;
141
+ await this.notifyGlobalListeners(event, payload);
142
+ const listeners = this.events.get(event);
143
+ if (!listeners) {
144
+ return;
145
+ }
146
+ const promises = [];
147
+ for (const connectionId of listeners) {
148
+ promises.push(this.notifyConnection(connectionId, DEBUGGER_EVENT, {
149
+ event,
150
+ result: payload
151
+ }));
152
+ }
153
+ // No need to catch, notify is already try-catched
154
+ await Promise.all(promises);
155
+ });
156
+ }
157
+ }
158
+ }
159
+ /**
160
+ * Disconnect the debugger and clears all the events listeners
161
+ */
162
+ async disable() {
163
+ if (!this.debuggerStatus) {
164
+ return;
165
+ }
166
+ for (const module of this.modules) {
167
+ for (const eventName of module.events) {
168
+ module.removeAllListeners(eventName);
169
+ }
170
+ await module.cleanup();
171
+ }
172
+ this.inspector.disconnect();
173
+ this.debuggerStatus = false;
174
+ this.events.clear();
175
+ this.kuzzlePostMethods.clear();
176
+ }
177
+ /**
178
+ * Trigger action from debugger directly following the Chrome Debug Protocol
179
+ * See: https://chromedevtools.github.io/devtools-protocol/v8/
180
+ */
181
+ async post(request) {
182
+ if (!this.debuggerStatus) {
183
+ throw kerror.get('core', 'debugger', 'not_enabled');
184
+ }
185
+ const method = request.getBodyString('method');
186
+ const params = request.getBodyObject('params', {});
187
+ if (method.startsWith('Kuzzle.')) {
188
+ const debugModuleMethod = this.kuzzlePostMethods.get(method);
189
+ if (debugModuleMethod) {
190
+ return debugModuleMethod(params);
191
+ }
192
+ throw kerror.get('core', 'debugger', 'method_not_found', method);
193
+ }
194
+ if (!(0, get_1.default)(global.kuzzle.config, 'security.debug.native_debug_protocol')) {
195
+ throw kerror.get('core', 'debugger', 'native_debug_protocol_usage_denied');
196
+ }
197
+ return this.inspectorPost(method, params);
198
+ }
199
+ /**
200
+ * Make the websocket connection listen and receive events from Chrome Debug Protocol
201
+ * See events from: https://chromedevtools.github.io/devtools-protocol/v8/
202
+ */
203
+ async addListener(request) {
204
+ if (request.context.connection.protocol !== 'websocket') {
205
+ throw kerror.get('api', 'assert', 'unsupported_protocol', request.context.connection.protocol, 'debug:addListener');
206
+ }
207
+ if (!this.debuggerStatus) {
208
+ throw kerror.get('core', 'debugger', 'not_enabled');
209
+ }
210
+ const event = request.getBodyString('event');
211
+ let listeners = this.events.get(event);
212
+ if (!listeners) {
213
+ listeners = new Set();
214
+ this.events.set(event, listeners);
215
+ }
216
+ listeners.add(request.context.connection.id);
217
+ }
218
+ /**
219
+ * Remove the websocket connection from the events' listeners
220
+ */
221
+ async removeListener(request) {
222
+ if (request.context.connection.protocol !== 'websocket') {
223
+ throw kerror.get('api', 'assert', 'unsupported_protocol', request.context.connection.protocol, 'debug:removeListener');
224
+ }
225
+ if (!this.debuggerStatus) {
226
+ throw kerror.get('core', 'debugger', 'not_enabled');
227
+ }
228
+ const event = request.getBodyString('event');
229
+ const listeners = this.events.get(event);
230
+ if (listeners) {
231
+ listeners.delete(request.context.connection.id);
232
+ }
233
+ }
234
+ /**
235
+ * Execute a method using the Chrome Debug Protocol
236
+ * @param method Chrome Debug Protocol method to execute
237
+ * @param params
238
+ * @returns
239
+ */
240
+ async inspectorPost(method, params) {
241
+ if (!this.debuggerStatus) {
242
+ throw kerror.get('core', 'debugger', 'not_enabled');
243
+ }
244
+ let resolve;
245
+ const promise = new Promise(res => {
246
+ resolve = res;
247
+ });
248
+ this.inspector.post(method, params, (err, res) => {
249
+ if (err) {
250
+ resolve({ error: JSON.stringify(Object.getOwnPropertyDescriptors(err)) });
251
+ }
252
+ else {
253
+ resolve(res);
254
+ }
255
+ });
256
+ return promise;
257
+ }
258
+ /**
259
+ * Sends a direct notification to a websocket connection without having to listen to a specific room
260
+ */
261
+ async notifyConnection(connectionId, event, payload) {
262
+ global.kuzzle.entryPoint._notify({
263
+ channels: [event],
264
+ connectionId,
265
+ payload,
266
+ });
267
+ }
268
+ async notifyGlobalListeners(event, payload) {
269
+ const listeners = this.events.get('*');
270
+ if (!listeners) {
271
+ return;
272
+ }
273
+ const promises = [];
274
+ for (const connectionId of listeners) {
275
+ promises.push(this.notifyConnection(connectionId, DEBUGGER_EVENT, {
276
+ event,
277
+ result: payload
278
+ }));
279
+ }
280
+ // No need to catch, notify is already try-catched
281
+ await Promise.all(promises);
282
+ }
283
+ }
284
+ exports.DebugController = DebugController;
285
+ //# sourceMappingURL=debugController.js.map
@@ -30,37 +30,51 @@ const {
30
30
  } = require('../../util/requestAssertions');
31
31
  const extractFields = require('../../util/extractFields');
32
32
  const { dumpCollectionDocuments } = require('../../util/dump-collection');
33
+ /**
34
+ * @description actions available on the document Controller (used by generic events)
35
+ * @key actions
36
+ * @value event type (empty for actions that are not linked to events)
37
+ */
38
+ const actions = {
39
+ count: '',
40
+ create: 'write',
41
+ createOrReplace: 'write',
42
+ delete: 'delete',
43
+ deleteByQuery: 'delete',
44
+ deleteFields: 'update',
45
+ exists: 'get',
46
+ export: 'get',
47
+ get: 'get',
48
+ mCreate: 'write',
49
+ mCreateOrReplace: 'write',
50
+ mDelete: 'delete',
51
+ mExists: 'get',
52
+ mGet: 'get',
53
+ mReplace: 'write',
54
+ mUpdate: 'update',
55
+ mUpsert: 'update',
56
+ replace: 'write',
57
+ scroll: '',
58
+ search: 'get',
59
+ update: 'update',
60
+ updateByQuery: 'update',
61
+ upsert: 'update',
62
+ validate: '',
63
+ };
64
+
33
65
  /**
34
66
  * @class DocumentController
35
67
  */
36
68
  class DocumentController extends NativeController {
37
69
  constructor () {
38
- super([
39
- 'count',
40
- 'create',
41
- 'createOrReplace',
42
- 'delete',
43
- 'deleteByQuery',
44
- 'deleteFields',
45
- 'exists',
46
- 'export',
47
- 'get',
48
- 'mCreate',
49
- 'mCreateOrReplace',
50
- 'mDelete',
51
- 'mExists',
52
- 'mGet',
53
- 'mReplace',
54
- 'mUpdate',
55
- 'mUpsert',
56
- 'replace',
57
- 'scroll',
58
- 'search',
59
- 'update',
60
- 'upsert',
61
- 'updateByQuery',
62
- 'validate'
63
- ]);
70
+ super(Object.keys(actions));
71
+ }
72
+
73
+ /**
74
+ * @returns {Record<string, unknown>}
75
+ */
76
+ static get actions () {
77
+ return actions;
64
78
  }
65
79
 
66
80
  /**
@@ -69,8 +83,8 @@ class DocumentController extends NativeController {
69
83
  */
70
84
  async search (request) {
71
85
  const { from, size, scrollTTL, searchBody } = request.getSearchParams();
72
- const index = request.input.args.index;
73
- const collection = request.input.args.collection;
86
+ const index = request.getIndex({ required: false });
87
+ const collection = request.getCollection({ required: false });
74
88
  const targets = request.getArray('targets', []);
75
89
  const lang = request.getLangParam();
76
90
 
@@ -118,7 +132,7 @@ class DocumentController extends NativeController {
118
132
  searchBody,
119
133
  { from, scroll: scrollTTL, size });
120
134
  }
121
-
135
+
122
136
  return {
123
137
  aggregations: result.aggregations,
124
138
  hits: result.hits,
@@ -27,6 +27,7 @@ module.exports = {
27
27
  BulkController: require('./bulkController'),
28
28
  ClusterController: require('./clusterController'),
29
29
  CollectionController: require('./collectionController'),
30
+ DebugController: require('./debugController').DebugController,
30
31
  DocumentController: require('./documentController'),
31
32
  IndexController: require('./indexController'),
32
33
  MemoryStorageController: require('./memoryStorageController'),
@@ -32,7 +32,7 @@ const formatProcessing = require('../../core/auth/formatProcessing');
32
32
  const ApiKey = require('../../model/storage/apiKey');
33
33
  const kerror = require('../../kerror');
34
34
  const { has } = require('../../util/safeObject');
35
- const { generateRandomName } = require('../../util/name-generator');
35
+ const { NameGenerator } = require('../../util/name-generator');
36
36
 
37
37
  /**
38
38
  * @class SecurityController
@@ -1273,7 +1273,7 @@ class SecurityController extends NativeController {
1273
1273
  const credentials = request.getBodyObject('credentials', {});
1274
1274
  const strategies = Object.keys(credentials);
1275
1275
  const generator = humanReadableId
1276
- ? () => generateRandomName('kuid')
1276
+ ? () => NameGenerator.generateRandomName({ prefix: 'kuid' })
1277
1277
  : () => 'kuid-' + uuidv4();
1278
1278
 
1279
1279
  let id = '';
@@ -26,6 +26,27 @@ const kerror = require('../kerror');
26
26
  const assertionError = kerror.wrap('api', 'assert');
27
27
 
28
28
  const extractors = ([
29
+ {
30
+ methods: {
31
+ extractFromRequest: request => [
32
+ {
33
+ _id: request.input.args._id,
34
+ _source: request.input.body.fields,
35
+ },
36
+ ],
37
+ extractFromResult: request => [request.result],
38
+ insertInRequest: ([documents], request) => {
39
+ request.input.args._id = documents._id;
40
+ request.input.body.fields = documents._source;
41
+ return request;
42
+ },
43
+ insertInResult: ([document], request) => {
44
+ request.setResult(document, { status: request.status });
45
+ return request;
46
+ },
47
+ },
48
+ targets: [ 'deleteFields' ]
49
+ },
29
50
  {
30
51
  methods: {
31
52
  extractFromRequest: request => [{ _id: request.input.args._id }],
@@ -39,7 +60,7 @@ const extractors = ([
39
60
  return request;
40
61
  }
41
62
  },
42
- targets: ['delete', 'get']
63
+ targets: [ 'delete', 'get', 'exists' ]
43
64
  },
44
65
  {
45
66
  methods: {
@@ -118,7 +139,7 @@ const extractors = ([
118
139
  return request;
119
140
  }
120
141
  },
121
- targets: ['mDelete', 'mGet']
142
+ targets: [ 'mDelete', 'mGet', 'mExists' ]
122
143
  },
123
144
  {
124
145
  methods: {
@@ -128,21 +149,41 @@ const extractors = ([
128
149
  for (let it = 0; it < request.input.body.documents.length; it++) {
129
150
  const document = request.input.body.documents[it];
130
151
 
131
- documents.push({ _id: document._id, _source: document.body });
152
+ if (request.input.action === 'mUpsert') {
153
+ documents.push({
154
+ _id: document._id,
155
+ _source: document.changes,
156
+ });
157
+ }
158
+ else {
159
+ documents.push({ _id: document._id, _source: document.body });
160
+ }
132
161
  }
133
162
 
134
163
  return documents;
135
164
  },
136
165
  extractFromResult: request => request.result.successes,
137
166
  insertInRequest: (documents, request) => {
167
+ const tmpDocuments = request.input.body.documents;
168
+
138
169
  request.input.body.documents = [];
139
170
 
140
171
  for (let it = 0; it < documents.length; it++) {
141
172
  const document = documents[it];
142
173
 
143
- request.input.body.documents.push({
144
- _id: document._id,
145
- body: document._source });
174
+ if (request.input.action === 'mUpsert') {
175
+ request.input.body.documents.push({
176
+ _id: document._id,
177
+ changes: document._source,
178
+ default: tmpDocuments[it].default,
179
+ });
180
+ }
181
+ else {
182
+ request.input.body.documents.push({
183
+ _id: document._id,
184
+ body: document._source,
185
+ });
186
+ }
146
187
  }
147
188
 
148
189
  return request;
@@ -158,7 +199,7 @@ const extractors = ([
158
199
  return request;
159
200
  }
160
201
  },
161
- targets: ['mCreate', 'mCreateOrReplace', 'mReplace', 'mUpdate', 'updateByQuery']
202
+ targets: [ 'mCreate', 'mCreateOrReplace', 'mReplace', 'mUpdate', 'updateByQuery', 'mUpsert' ]
162
203
  },
163
204
  {
164
205
  methods: {
@@ -178,7 +219,7 @@ const extractors = ([
178
219
  return request;
179
220
  },
180
221
  },
181
- targets: ['search', 'deleteByQuery'],
222
+ targets: [ 'search', 'deleteByQuery', 'export' ],
182
223
  },
183
224
  {
184
225
  methods: {