@elastic/elasticsearch 7.10.0 → 7.13.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.
- package/README.md +2 -2
- package/api/api/async_search.js +35 -8
- package/api/api/autoscaling.js +15 -15
- package/api/api/bulk.js +4 -4
- package/api/api/cat.js +127 -127
- package/api/api/ccr.js +40 -40
- package/api/api/clear_scroll.js +2 -2
- package/api/api/close_point_in_time.js +2 -2
- package/api/api/cluster.js +36 -36
- package/api/api/count.js +3 -3
- package/api/api/create.js +5 -5
- package/api/api/dangling_indices.js +8 -8
- package/api/api/delete.js +4 -4
- package/api/api/delete_by_query.js +5 -5
- package/api/api/delete_by_query_rethrottle.js +4 -4
- package/api/api/delete_script.js +3 -3
- package/api/api/enrich.js +14 -14
- package/api/api/eql.js +41 -10
- package/api/api/exists.js +4 -4
- package/api/api/exists_source.js +6 -6
- package/api/api/explain.js +4 -4
- package/api/api/features.js +81 -0
- package/api/api/field_caps.js +2 -2
- package/api/api/fleet.js +65 -0
- package/api/api/get.js +4 -4
- package/api/api/get_script.js +3 -3
- package/api/api/get_script_context.js +2 -2
- package/api/api/get_script_languages.js +2 -2
- package/api/api/get_source.js +4 -4
- package/api/api/graph.js +4 -4
- package/api/api/ilm.js +26 -26
- package/api/api/index.js +4 -4
- package/api/api/indices.js +385 -339
- package/api/api/info.js +2 -2
- package/api/api/ingest.js +37 -15
- package/api/api/license.js +14 -14
- package/api/api/logstash.js +125 -0
- package/api/api/mget.js +4 -4
- package/api/api/migration.js +2 -2
- package/api/api/ml.js +344 -204
- package/api/api/monitoring.js +3 -3
- package/api/api/msearch.js +4 -4
- package/api/api/msearch_template.js +4 -4
- package/api/api/mtermvectors.js +3 -3
- package/api/api/nodes.js +12 -12
- package/api/api/open_point_in_time.js +2 -2
- package/api/api/ping.js +2 -2
- package/api/api/put_script.js +5 -5
- package/api/api/rank_eval.js +3 -3
- package/api/api/reindex.js +3 -3
- package/api/api/reindex_rethrottle.js +4 -4
- package/api/api/render_search_template.js +2 -2
- package/api/api/rollup.js +66 -25
- package/api/api/scripts_painless_execute.js +2 -2
- package/api/api/scroll.js +2 -2
- package/api/api/search.js +5 -5
- package/api/api/search_shards.js +2 -2
- package/api/api/search_template.js +4 -4
- package/api/api/searchable_snapshots.js +42 -15
- package/api/api/security.js +295 -85
- package/api/api/shutdown.js +124 -0
- package/api/api/slm.js +21 -21
- package/api/api/snapshot.js +48 -48
- package/api/api/sql.js +9 -9
- package/api/api/ssl.js +2 -2
- package/api/api/tasks.js +7 -7
- package/api/api/termvectors.js +3 -3
- package/api/api/text_structure.js +65 -0
- package/api/api/transform.js +27 -27
- package/api/api/update.js +5 -5
- package/api/api/update_by_query.js +4 -4
- package/api/api/update_by_query_rethrottle.js +4 -4
- package/api/api/watcher.js +50 -28
- package/api/api/xpack.js +4 -4
- package/api/index.js +176 -120
- package/api/new.d.ts +1498 -0
- package/api/requestParams.d.ts +168 -8
- package/api/types.d.ts +13881 -0
- package/api/utils.js +4 -4
- package/free-report-junit.xml +3410 -0
- package/index.d.ts +275 -30
- package/index.js +29 -30
- package/lib/Connection.js +7 -5
- package/lib/Helpers.d.ts +2 -2
- package/lib/Helpers.js +30 -18
- package/lib/Serializer.d.ts +5 -0
- package/lib/Serializer.js +17 -6
- package/lib/Transport.d.ts +2 -1
- package/lib/Transport.js +38 -8
- package/lib/errors.js +14 -1
- package/lib/pool/BaseConnectionPool.js +3 -3
- package/lib/pool/ConnectionPool.js +4 -5
- package/package.json +26 -26
- package/api/kibana.d.ts +0 -479
package/index.js
CHANGED
|
@@ -19,20 +19,24 @@
|
|
|
19
19
|
|
|
20
20
|
'use strict'
|
|
21
21
|
|
|
22
|
-
const nodeMajor = Number(process.versions.node.split('.')[0])
|
|
23
|
-
|
|
24
22
|
const { EventEmitter } = require('events')
|
|
25
23
|
const { URL } = require('url')
|
|
26
24
|
const debug = require('debug')('elasticsearch')
|
|
27
25
|
const Transport = require('./lib/Transport')
|
|
28
26
|
const Connection = require('./lib/Connection')
|
|
29
27
|
const { ConnectionPool, CloudConnectionPool } = require('./lib/pool')
|
|
30
|
-
|
|
31
|
-
const Helpers = nodeMajor < 10 ? /* istanbul ignore next */ null : require('./lib/Helpers')
|
|
28
|
+
const Helpers = require('./lib/Helpers')
|
|
32
29
|
const Serializer = require('./lib/Serializer')
|
|
33
30
|
const errors = require('./lib/errors')
|
|
34
31
|
const { ConfigurationError } = errors
|
|
35
32
|
const { prepareHeaders } = Connection.internals
|
|
33
|
+
let clientVersion = require('./package.json').version
|
|
34
|
+
/* istanbul ignore next */
|
|
35
|
+
if (clientVersion.includes('-')) {
|
|
36
|
+
// clean prerelease
|
|
37
|
+
clientVersion = clientVersion.slice(0, clientVersion.indexOf('-')) + 'p'
|
|
38
|
+
}
|
|
39
|
+
const nodeVersion = process.versions.node
|
|
36
40
|
|
|
37
41
|
const kInitialOptions = Symbol('elasticsearchjs-initial-options')
|
|
38
42
|
const kChild = Symbol('elasticsearchjs-child')
|
|
@@ -41,24 +45,6 @@ const kEventEmitter = Symbol('elasticsearchjs-event-emitter')
|
|
|
41
45
|
|
|
42
46
|
const ESAPI = require('./api')
|
|
43
47
|
|
|
44
|
-
/* istanbul ignore next */
|
|
45
|
-
if (nodeMajor < 10) {
|
|
46
|
-
process.emitWarning('You are using a version of Node.js that is currently in EOL. ' +
|
|
47
|
-
'The support for this version will be dropped in 7.12. ' +
|
|
48
|
-
'Please refer to https://ela.st/nodejs-support for additional information.',
|
|
49
|
-
'DeprecationWarning'
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/* istanbul ignore next */
|
|
54
|
-
if (nodeMajor >= 10 && nodeMajor < 12) {
|
|
55
|
-
process.emitWarning('You are using a version of Node.js that will reach EOL in April 2021. ' +
|
|
56
|
-
'The support for this version will be dropped in 7.13. ' +
|
|
57
|
-
'Please refer to https://ela.st/nodejs-support for additional information.',
|
|
58
|
-
'DeprecationWarning'
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
48
|
class Client extends ESAPI {
|
|
63
49
|
constructor (opts = {}) {
|
|
64
50
|
super({ ConfigurationError })
|
|
@@ -125,20 +111,28 @@ class Client extends ESAPI {
|
|
|
125
111
|
auth: null,
|
|
126
112
|
opaqueIdPrefix: null,
|
|
127
113
|
context: null,
|
|
128
|
-
proxy: null
|
|
114
|
+
proxy: null,
|
|
115
|
+
enableMetaHeader: true,
|
|
116
|
+
disablePrototypePoisoningProtection: false
|
|
129
117
|
}, opts)
|
|
130
118
|
|
|
131
119
|
this[kInitialOptions] = options
|
|
132
120
|
this[kExtensions] = []
|
|
133
121
|
this.name = options.name
|
|
134
122
|
|
|
123
|
+
if (options.enableMetaHeader) {
|
|
124
|
+
options.headers['x-elastic-client-meta'] = `es=${clientVersion},js=${nodeVersion},t=${clientVersion},hc=${nodeVersion}`
|
|
125
|
+
}
|
|
126
|
+
|
|
135
127
|
if (opts[kChild] !== undefined) {
|
|
136
128
|
this.serializer = options[kChild].serializer
|
|
137
129
|
this.connectionPool = options[kChild].connectionPool
|
|
138
130
|
this[kEventEmitter] = options[kChild].eventEmitter
|
|
139
131
|
} else {
|
|
140
132
|
this[kEventEmitter] = new EventEmitter()
|
|
141
|
-
this.serializer = new options.Serializer(
|
|
133
|
+
this.serializer = new options.Serializer({
|
|
134
|
+
disablePrototypePoisoningProtection: options.disablePrototypePoisoningProtection
|
|
135
|
+
})
|
|
142
136
|
this.connectionPool = new options.ConnectionPool({
|
|
143
137
|
pingTimeout: options.pingTimeout,
|
|
144
138
|
resurrectStrategy: options.resurrectStrategy,
|
|
@@ -177,10 +171,13 @@ class Client extends ESAPI {
|
|
|
177
171
|
context: options.context
|
|
178
172
|
})
|
|
179
173
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
174
|
+
this.helpers = new Helpers({
|
|
175
|
+
client: this,
|
|
176
|
+
maxRetries: options.maxRetries,
|
|
177
|
+
metaHeader: options.enableMetaHeader
|
|
178
|
+
? `es=${clientVersion},js=${nodeVersion},t=${clientVersion},hc=${nodeVersion}`
|
|
179
|
+
: null
|
|
180
|
+
})
|
|
184
181
|
}
|
|
185
182
|
|
|
186
183
|
get emit () {
|
|
@@ -205,7 +202,7 @@ class Client extends ESAPI {
|
|
|
205
202
|
opts = {}
|
|
206
203
|
}
|
|
207
204
|
|
|
208
|
-
|
|
205
|
+
let [namespace, method] = name.split('.')
|
|
209
206
|
if (method == null) {
|
|
210
207
|
method = namespace
|
|
211
208
|
namespace = null
|
|
@@ -314,7 +311,9 @@ const events = {
|
|
|
314
311
|
RESPONSE: 'response',
|
|
315
312
|
REQUEST: 'request',
|
|
316
313
|
SNIFF: 'sniff',
|
|
317
|
-
RESURRECT: 'resurrect'
|
|
314
|
+
RESURRECT: 'resurrect',
|
|
315
|
+
SERIALIZATION: 'serialization',
|
|
316
|
+
DESERIALIZATION: 'deserialization'
|
|
318
317
|
}
|
|
319
318
|
|
|
320
319
|
module.exports = {
|
package/lib/Connection.js
CHANGED
|
@@ -25,7 +25,7 @@ const hpagent = require('hpagent')
|
|
|
25
25
|
const http = require('http')
|
|
26
26
|
const https = require('https')
|
|
27
27
|
const debug = require('debug')('elasticsearch')
|
|
28
|
-
const
|
|
28
|
+
const { pipeline } = require('stream')
|
|
29
29
|
const INVALID_PATH_REGEX = /[^\u0021-\u00ff]/
|
|
30
30
|
const {
|
|
31
31
|
ConnectionError,
|
|
@@ -82,6 +82,7 @@ class Connection {
|
|
|
82
82
|
|
|
83
83
|
request (params, callback) {
|
|
84
84
|
this._openRequests++
|
|
85
|
+
let cleanedListeners = false
|
|
85
86
|
|
|
86
87
|
const requestParams = this.buildRequestObject(params)
|
|
87
88
|
// https://github.com/nodejs/node/commit/b961d9fd83
|
|
@@ -132,9 +133,9 @@ class Connection {
|
|
|
132
133
|
|
|
133
134
|
// starts the request
|
|
134
135
|
if (isStream(params.body) === true) {
|
|
135
|
-
|
|
136
|
+
pipeline(params.body, request, err => {
|
|
136
137
|
/* istanbul ignore if */
|
|
137
|
-
if (err != null) {
|
|
138
|
+
if (err != null && cleanedListeners === false) {
|
|
138
139
|
cleanListeners()
|
|
139
140
|
this._openRequests--
|
|
140
141
|
callback(err, null)
|
|
@@ -151,6 +152,7 @@ class Connection {
|
|
|
151
152
|
request.removeListener('timeout', onTimeout)
|
|
152
153
|
request.removeListener('error', onError)
|
|
153
154
|
request.removeListener('abort', onAbort)
|
|
155
|
+
cleanedListeners = true
|
|
154
156
|
}
|
|
155
157
|
}
|
|
156
158
|
|
|
@@ -211,8 +213,8 @@ class Connection {
|
|
|
211
213
|
}
|
|
212
214
|
|
|
213
215
|
const paramsKeys = Object.keys(params)
|
|
214
|
-
for (
|
|
215
|
-
|
|
216
|
+
for (let i = 0, len = paramsKeys.length; i < len; i++) {
|
|
217
|
+
const key = paramsKeys[i]
|
|
216
218
|
if (key === 'path') {
|
|
217
219
|
request.pathname = resolve(request.pathname, params[key])
|
|
218
220
|
} else if (key === 'querystring' && !!params[key] === true) {
|
package/lib/Helpers.d.ts
CHANGED
|
@@ -25,8 +25,8 @@ export default class Helpers {
|
|
|
25
25
|
search<TDocument = unknown, TRequestBody extends RequestBody = Record<string, any>>(params: Search<TRequestBody>, options?: TransportRequestOptions): Promise<TDocument[]>
|
|
26
26
|
scrollSearch<TDocument = unknown, TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(params: Search<TRequestBody>, options?: TransportRequestOptions): AsyncIterable<ScrollSearchResponse<TDocument, TResponse, TContext>>
|
|
27
27
|
scrollDocuments<TDocument = unknown, TRequestBody extends RequestBody = Record<string, any>>(params: Search<TRequestBody>, options?: TransportRequestOptions): AsyncIterable<TDocument>
|
|
28
|
-
msearch(options?: MsearchHelperOptions): MsearchHelper
|
|
29
|
-
bulk<TDocument = unknown>(options: BulkHelperOptions<TDocument
|
|
28
|
+
msearch(options?: MsearchHelperOptions, reqOptions?: TransportRequestOptions): MsearchHelper
|
|
29
|
+
bulk<TDocument = unknown>(options: BulkHelperOptions<TDocument>, reqOptions?: TransportRequestOptions): BulkHelper<BulkStats>
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export interface ScrollSearchResponse<TDocument = unknown, TResponse = Record<string, any>, TContext = Context> extends ApiResponse<TResponse, TContext> {
|
package/lib/Helpers.js
CHANGED
|
@@ -28,12 +28,14 @@ const { ResponseError, ConfigurationError } = require('./errors')
|
|
|
28
28
|
const pImmediate = promisify(setImmediate)
|
|
29
29
|
const sleep = promisify(setTimeout)
|
|
30
30
|
const kClient = Symbol('elasticsearch-client')
|
|
31
|
+
const kMetaHeader = Symbol('meta header')
|
|
31
32
|
/* istanbul ignore next */
|
|
32
33
|
const noop = () => {}
|
|
33
34
|
|
|
34
35
|
class Helpers {
|
|
35
36
|
constructor (opts) {
|
|
36
37
|
this[kClient] = opts.client
|
|
38
|
+
this[kMetaHeader] = opts.metaHeader
|
|
37
39
|
this.maxRetries = opts.maxRetries
|
|
38
40
|
}
|
|
39
41
|
|
|
@@ -71,6 +73,10 @@ class Helpers {
|
|
|
71
73
|
* @return {iterator} the async iterator
|
|
72
74
|
*/
|
|
73
75
|
async * scrollSearch (params, options = {}) {
|
|
76
|
+
if (this[kMetaHeader] !== null) {
|
|
77
|
+
options.headers = options.headers || {}
|
|
78
|
+
options.headers['x-elastic-client-meta'] = this[kMetaHeader] + ',h=s'
|
|
79
|
+
}
|
|
74
80
|
// TODO: study scroll search slices
|
|
75
81
|
const wait = options.wait || 5000
|
|
76
82
|
const maxRetries = options.maxRetries || this.maxRetries
|
|
@@ -99,7 +105,7 @@ class Helpers {
|
|
|
99
105
|
stop = true
|
|
100
106
|
await this[kClient].clearScroll(
|
|
101
107
|
{ body: { scroll_id } },
|
|
102
|
-
{ ignore: [400] }
|
|
108
|
+
{ ignore: [400], ...options }
|
|
103
109
|
)
|
|
104
110
|
}
|
|
105
111
|
|
|
@@ -152,7 +158,7 @@ class Helpers {
|
|
|
152
158
|
*/
|
|
153
159
|
async * scrollDocuments (params, options) {
|
|
154
160
|
appendFilterPath('hits.hits._source', params, true)
|
|
155
|
-
for await (const { documents } of this.scrollSearch(params)) {
|
|
161
|
+
for await (const { documents } of this.scrollSearch(params, options)) {
|
|
156
162
|
for (const document of documents) {
|
|
157
163
|
yield document
|
|
158
164
|
}
|
|
@@ -163,9 +169,10 @@ class Helpers {
|
|
|
163
169
|
* Creates a msearch helper instance. Once you configure it, you can use the provided
|
|
164
170
|
* `search` method to add new searches in the queue.
|
|
165
171
|
* @param {object} options - The configuration of the msearch operations.
|
|
172
|
+
* @param {object} reqOptions - The client optional configuration for this request.
|
|
166
173
|
* @return {object} The possible operations to run.
|
|
167
174
|
*/
|
|
168
|
-
msearch (options = {}) {
|
|
175
|
+
msearch (options = {}, reqOptions = {}) {
|
|
169
176
|
const client = this[kClient]
|
|
170
177
|
const {
|
|
171
178
|
operations = 5,
|
|
@@ -372,7 +379,7 @@ class Helpers {
|
|
|
372
379
|
// This function never returns an error, if the msearch operation fails,
|
|
373
380
|
// the error is dispatched to all search executors.
|
|
374
381
|
function tryMsearch (msearchBody, callbacks, done) {
|
|
375
|
-
client.msearch(Object.assign({}, msearchOptions, { body: msearchBody }), (err, results) => {
|
|
382
|
+
client.msearch(Object.assign({}, msearchOptions, { body: msearchBody }), reqOptions, (err, results) => {
|
|
376
383
|
const retryBody = []
|
|
377
384
|
const retryCallbacks = []
|
|
378
385
|
if (err) {
|
|
@@ -409,11 +416,16 @@ class Helpers {
|
|
|
409
416
|
* Creates a bulk helper instance. Once you configure it, you can pick which operation
|
|
410
417
|
* to execute with the given dataset, index, create, update, and delete.
|
|
411
418
|
* @param {object} options - The configuration of the bulk operation.
|
|
419
|
+
* @param {object} reqOptions - The client optional configuration for this request.
|
|
412
420
|
* @return {object} The possible operations to run with the datasource.
|
|
413
421
|
*/
|
|
414
|
-
bulk (options) {
|
|
422
|
+
bulk (options, reqOptions = {}) {
|
|
415
423
|
const client = this[kClient]
|
|
416
|
-
const {
|
|
424
|
+
const { serializer } = client
|
|
425
|
+
if (this[kMetaHeader] !== null) {
|
|
426
|
+
reqOptions.headers = reqOptions.headers || {}
|
|
427
|
+
reqOptions.headers['x-elastic-client-meta'] = this[kMetaHeader] + ',h=bp'
|
|
428
|
+
}
|
|
417
429
|
const {
|
|
418
430
|
datasource,
|
|
419
431
|
onDocument,
|
|
@@ -493,19 +505,19 @@ class Helpers {
|
|
|
493
505
|
? Object.keys(action[0])[0]
|
|
494
506
|
: Object.keys(action)[0]
|
|
495
507
|
if (operation === 'index' || operation === 'create') {
|
|
496
|
-
actionBody = serialize(action)
|
|
497
|
-
payloadBody = typeof chunk === 'string' ? chunk : serialize(chunk)
|
|
508
|
+
actionBody = serializer.serialize(action)
|
|
509
|
+
payloadBody = typeof chunk === 'string' ? chunk : serializer.serialize(chunk)
|
|
498
510
|
chunkBytes += Buffer.byteLength(actionBody) + Buffer.byteLength(payloadBody)
|
|
499
511
|
bulkBody.push(actionBody, payloadBody)
|
|
500
512
|
} else if (operation === 'update') {
|
|
501
|
-
actionBody = serialize(action[0])
|
|
513
|
+
actionBody = serializer.serialize(action[0])
|
|
502
514
|
payloadBody = typeof chunk === 'string'
|
|
503
515
|
? `{"doc":${chunk}}`
|
|
504
|
-
: serialize({ doc: chunk, ...action[1] })
|
|
516
|
+
: serializer.serialize({ doc: chunk, ...action[1] })
|
|
505
517
|
chunkBytes += Buffer.byteLength(actionBody) + Buffer.byteLength(payloadBody)
|
|
506
518
|
bulkBody.push(actionBody, payloadBody)
|
|
507
519
|
} else if (operation === 'delete') {
|
|
508
|
-
actionBody = serialize(action)
|
|
520
|
+
actionBody = serializer.serialize(action)
|
|
509
521
|
chunkBytes += Buffer.byteLength(actionBody)
|
|
510
522
|
bulkBody.push(actionBody)
|
|
511
523
|
} else {
|
|
@@ -538,7 +550,7 @@ class Helpers {
|
|
|
538
550
|
index: typeof refreshOnCompletion === 'string'
|
|
539
551
|
? refreshOnCompletion
|
|
540
552
|
: '_all'
|
|
541
|
-
})
|
|
553
|
+
}, reqOptions)
|
|
542
554
|
}
|
|
543
555
|
|
|
544
556
|
stats.time = Date.now() - startTime
|
|
@@ -657,13 +669,13 @@ class Helpers {
|
|
|
657
669
|
return
|
|
658
670
|
}
|
|
659
671
|
for (let i = 0, len = bulkBody.length; i < len; i = i + 2) {
|
|
660
|
-
const operation = Object.keys(deserialize(bulkBody[i]))[0]
|
|
672
|
+
const operation = Object.keys(serializer.deserialize(bulkBody[i]))[0]
|
|
661
673
|
onDrop({
|
|
662
674
|
status: 429,
|
|
663
675
|
error: null,
|
|
664
|
-
operation: deserialize(bulkBody[i]),
|
|
676
|
+
operation: serializer.deserialize(bulkBody[i]),
|
|
665
677
|
document: operation !== 'delete'
|
|
666
|
-
? deserialize(bulkBody[i + 1])
|
|
678
|
+
? serializer.deserialize(bulkBody[i + 1])
|
|
667
679
|
/* istanbul ignore next */
|
|
668
680
|
: null,
|
|
669
681
|
retried: isRetrying
|
|
@@ -676,7 +688,7 @@ class Helpers {
|
|
|
676
688
|
|
|
677
689
|
function tryBulk (bulkBody, callback) {
|
|
678
690
|
if (shouldAbort === true) return callback(null, [])
|
|
679
|
-
client.bulk(Object.assign({}, bulkOptions, { body: bulkBody }), (err, { body }) => {
|
|
691
|
+
client.bulk(Object.assign({}, bulkOptions, { body: bulkBody }), reqOptions, (err, { body }) => {
|
|
680
692
|
if (err) return callback(err, null)
|
|
681
693
|
if (body.errors === false) {
|
|
682
694
|
stats.successful += body.items.length
|
|
@@ -704,9 +716,9 @@ class Helpers {
|
|
|
704
716
|
onDrop({
|
|
705
717
|
status: status,
|
|
706
718
|
error: action[operation].error,
|
|
707
|
-
operation: deserialize(bulkBody[indexSlice]),
|
|
719
|
+
operation: serializer.deserialize(bulkBody[indexSlice]),
|
|
708
720
|
document: operation !== 'delete'
|
|
709
|
-
? deserialize(bulkBody[indexSlice + 1])
|
|
721
|
+
? serializer.deserialize(bulkBody[indexSlice + 1])
|
|
710
722
|
: null,
|
|
711
723
|
retried: isRetrying
|
|
712
724
|
})
|
package/lib/Serializer.d.ts
CHANGED
|
@@ -17,7 +17,12 @@
|
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
+
export interface SerializerOptions {
|
|
21
|
+
disablePrototypePoisoningProtection: boolean | 'proto' | 'constructor'
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
export default class Serializer {
|
|
25
|
+
constructor (opts?: SerializerOptions)
|
|
21
26
|
serialize(object: any): string;
|
|
22
27
|
deserialize(json: string): any;
|
|
23
28
|
ndserialize(array: any[]): string;
|
package/lib/Serializer.js
CHANGED
|
@@ -23,12 +23,22 @@ const { stringify } = require('querystring')
|
|
|
23
23
|
const debug = require('debug')('elasticsearch')
|
|
24
24
|
const sjson = require('secure-json-parse')
|
|
25
25
|
const { SerializationError, DeserializationError } = require('./errors')
|
|
26
|
+
const kJsonOptions = Symbol('secure json parse options')
|
|
26
27
|
|
|
27
28
|
class Serializer {
|
|
29
|
+
constructor (opts = {}) {
|
|
30
|
+
const disable = opts.disablePrototypePoisoningProtection
|
|
31
|
+
this[kJsonOptions] = {
|
|
32
|
+
protoAction: disable === true || disable === 'proto' ? 'ignore' : 'error',
|
|
33
|
+
constructorAction: disable === true || disable === 'constructor' ? 'ignore' : 'error'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
28
37
|
serialize (object) {
|
|
29
38
|
debug('Serializing', object)
|
|
39
|
+
let json
|
|
30
40
|
try {
|
|
31
|
-
|
|
41
|
+
json = JSON.stringify(object)
|
|
32
42
|
} catch (err) {
|
|
33
43
|
throw new SerializationError(err.message, object)
|
|
34
44
|
}
|
|
@@ -37,8 +47,9 @@ class Serializer {
|
|
|
37
47
|
|
|
38
48
|
deserialize (json) {
|
|
39
49
|
debug('Deserializing', json)
|
|
50
|
+
let object
|
|
40
51
|
try {
|
|
41
|
-
|
|
52
|
+
object = sjson.parse(json, this[kJsonOptions])
|
|
42
53
|
} catch (err) {
|
|
43
54
|
throw new DeserializationError(err.message, json)
|
|
44
55
|
}
|
|
@@ -50,8 +61,8 @@ class Serializer {
|
|
|
50
61
|
if (Array.isArray(array) === false) {
|
|
51
62
|
throw new SerializationError('The argument provided is not an array')
|
|
52
63
|
}
|
|
53
|
-
|
|
54
|
-
for (
|
|
64
|
+
let ndjson = ''
|
|
65
|
+
for (let i = 0, len = array.length; i < len; i++) {
|
|
55
66
|
if (typeof array[i] === 'string') {
|
|
56
67
|
ndjson += array[i] + '\n'
|
|
57
68
|
} else {
|
|
@@ -67,8 +78,8 @@ class Serializer {
|
|
|
67
78
|
if (typeof object === 'string') return object
|
|
68
79
|
// arrays should be serialized as comma separated list
|
|
69
80
|
const keys = Object.keys(object)
|
|
70
|
-
for (
|
|
71
|
-
|
|
81
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
82
|
+
const key = keys[i]
|
|
72
83
|
// elasticsearch will complain for keys without a value
|
|
73
84
|
if (object[key] === undefined) {
|
|
74
85
|
delete object[key]
|
package/lib/Transport.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export type ApiError = errors.ConfigurationError | errors.ConnectionError |
|
|
|
28
28
|
errors.NoLivingConnectionsError | errors.ResponseError |
|
|
29
29
|
errors.TimeoutError | errors.RequestAbortedError
|
|
30
30
|
|
|
31
|
-
export type Context =
|
|
31
|
+
export type Context = unknown
|
|
32
32
|
|
|
33
33
|
export interface nodeSelectorFn {
|
|
34
34
|
(connections: Connection[]): Connection;
|
|
@@ -120,6 +120,7 @@ export interface TransportRequestCallback {
|
|
|
120
120
|
|
|
121
121
|
export interface TransportRequestPromise<T> extends Promise<T> {
|
|
122
122
|
abort: () => void;
|
|
123
|
+
finally(onFinally?: (() => void) | undefined | null): Promise<T>;
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
export interface TransportGetConnectionOptions {
|
package/lib/Transport.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
const debug = require('debug')('elasticsearch')
|
|
23
23
|
const os = require('os')
|
|
24
24
|
const { gzip, unzip, createGzip } = require('zlib')
|
|
25
|
+
const buffer = require('buffer')
|
|
25
26
|
const ms = require('ms')
|
|
26
27
|
const {
|
|
27
28
|
ConnectionError,
|
|
@@ -35,12 +36,15 @@ const noop = () => {}
|
|
|
35
36
|
|
|
36
37
|
const clientVersion = require('../package.json').version
|
|
37
38
|
const userAgent = `elasticsearch-js/${clientVersion} (${os.platform()} ${os.release()}-${os.arch()}; Node.js ${process.version})`
|
|
39
|
+
const MAX_BUFFER_LENGTH = buffer.constants.MAX_LENGTH
|
|
40
|
+
const MAX_STRING_LENGTH = buffer.constants.MAX_STRING_LENGTH
|
|
38
41
|
|
|
39
42
|
class Transport {
|
|
40
43
|
constructor (opts) {
|
|
41
44
|
if (typeof opts.compression === 'string' && opts.compression !== 'gzip') {
|
|
42
45
|
throw new ConfigurationError(`Invalid compression: '${opts.compression}'`)
|
|
43
46
|
}
|
|
47
|
+
|
|
44
48
|
this.emit = opts.emit
|
|
45
49
|
this.connectionPool = opts.connectionPool
|
|
46
50
|
this.serializer = opts.serializer
|
|
@@ -87,7 +91,7 @@ class Transport {
|
|
|
87
91
|
callback = options
|
|
88
92
|
options = {}
|
|
89
93
|
}
|
|
90
|
-
|
|
94
|
+
let p = null
|
|
91
95
|
|
|
92
96
|
// promises support
|
|
93
97
|
if (callback === undefined) {
|
|
@@ -143,9 +147,10 @@ class Transport {
|
|
|
143
147
|
// the size of the stream, we risk to take too much memory.
|
|
144
148
|
// Furthermore, copying everytime the stream is very a expensive operation.
|
|
145
149
|
const maxRetries = isStream(params.body) || isStream(params.bulkBody)
|
|
146
|
-
? 0
|
|
150
|
+
? 0
|
|
151
|
+
: (typeof options.maxRetries === 'number' ? options.maxRetries : this.maxRetries)
|
|
147
152
|
const compression = options.compression !== undefined ? options.compression : this.compression
|
|
148
|
-
|
|
153
|
+
let request = { abort: noop }
|
|
149
154
|
const transportReturn = {
|
|
150
155
|
then (onFulfilled, onRejected) {
|
|
151
156
|
return p.then(onFulfilled, onRejected)
|
|
@@ -158,6 +163,9 @@ class Transport {
|
|
|
158
163
|
request.abort()
|
|
159
164
|
debug('Aborting request', params)
|
|
160
165
|
return this
|
|
166
|
+
},
|
|
167
|
+
finally (onFinally) {
|
|
168
|
+
return p.finally(onFinally)
|
|
161
169
|
}
|
|
162
170
|
}
|
|
163
171
|
|
|
@@ -218,6 +226,22 @@ class Transport {
|
|
|
218
226
|
|
|
219
227
|
const contentEncoding = (result.headers['content-encoding'] || '').toLowerCase()
|
|
220
228
|
const isCompressed = contentEncoding.indexOf('gzip') > -1 || contentEncoding.indexOf('deflate') > -1
|
|
229
|
+
|
|
230
|
+
/* istanbul ignore else */
|
|
231
|
+
if (result.headers['content-length'] !== undefined) {
|
|
232
|
+
const contentLength = Number(result.headers['content-length'])
|
|
233
|
+
if (isCompressed && contentLength > MAX_BUFFER_LENGTH) {
|
|
234
|
+
response.destroy()
|
|
235
|
+
return onConnectionError(
|
|
236
|
+
new RequestAbortedError(`The content length (${contentLength}) is bigger than the maximum allowed buffer (${MAX_BUFFER_LENGTH})`, result)
|
|
237
|
+
)
|
|
238
|
+
} else if (contentLength > MAX_STRING_LENGTH) {
|
|
239
|
+
response.destroy()
|
|
240
|
+
return onConnectionError(
|
|
241
|
+
new RequestAbortedError(`The content length (${contentLength}) is bigger than the maximum allowed string (${MAX_STRING_LENGTH})`, result)
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
221
245
|
// if the response is compressed, we must handle it
|
|
222
246
|
// as buffer for allowing decompression later
|
|
223
247
|
let payload = isCompressed ? [] : ''
|
|
@@ -249,6 +273,8 @@ class Transport {
|
|
|
249
273
|
if (!isCompressed) {
|
|
250
274
|
response.setEncoding('utf8')
|
|
251
275
|
}
|
|
276
|
+
|
|
277
|
+
this.emit('deserialization', null, result)
|
|
252
278
|
response.on('data', onData)
|
|
253
279
|
response.on('error', onEnd)
|
|
254
280
|
response.on('end', onEnd)
|
|
@@ -280,8 +306,8 @@ class Transport {
|
|
|
280
306
|
return callback(err, result)
|
|
281
307
|
}
|
|
282
308
|
} else {
|
|
283
|
-
// cast to boolean if the request method was HEAD
|
|
284
|
-
result.body = isHead === true ? true : payload
|
|
309
|
+
// cast to boolean if the request method was HEAD and there was no error
|
|
310
|
+
result.body = isHead === true && result.statusCode < 400 ? true : payload
|
|
285
311
|
}
|
|
286
312
|
|
|
287
313
|
// we should ignore the statusCode if the user has configured the `ignore` field with
|
|
@@ -321,6 +347,7 @@ class Transport {
|
|
|
321
347
|
}
|
|
322
348
|
}
|
|
323
349
|
|
|
350
|
+
this.emit('serialization', null, result)
|
|
324
351
|
const headers = Object.assign({}, this.headers, lowerCaseHeaders(options.headers))
|
|
325
352
|
|
|
326
353
|
if (options.opaqueId !== undefined) {
|
|
@@ -335,6 +362,7 @@ class Transport {
|
|
|
335
362
|
try {
|
|
336
363
|
params.body = this.serializer.serialize(params.body)
|
|
337
364
|
} catch (err) {
|
|
365
|
+
this.emit('request', err, result)
|
|
338
366
|
process.nextTick(callback, err, result)
|
|
339
367
|
return transportReturn
|
|
340
368
|
}
|
|
@@ -350,6 +378,7 @@ class Transport {
|
|
|
350
378
|
try {
|
|
351
379
|
params.body = this.serializer.ndserialize(params.bulkBody)
|
|
352
380
|
} catch (err) {
|
|
381
|
+
this.emit('request', err, result)
|
|
353
382
|
process.nextTick(callback, err, result)
|
|
354
383
|
return transportReturn
|
|
355
384
|
}
|
|
@@ -389,6 +418,7 @@ class Transport {
|
|
|
389
418
|
gzip(params.body, (err, buffer) => {
|
|
390
419
|
/* istanbul ignore next */
|
|
391
420
|
if (err) {
|
|
421
|
+
this.emit('request', err, result)
|
|
392
422
|
return callback(err, result)
|
|
393
423
|
}
|
|
394
424
|
params.headers['content-encoding'] = compression
|
|
@@ -499,7 +529,7 @@ function defaultNodeFilter (node) {
|
|
|
499
529
|
}
|
|
500
530
|
|
|
501
531
|
function roundRobinSelector () {
|
|
502
|
-
|
|
532
|
+
let current = -1
|
|
503
533
|
return function _roundRobinSelector (connections) {
|
|
504
534
|
if (++current >= connections.length) {
|
|
505
535
|
current = 0
|
|
@@ -514,8 +544,8 @@ function randomSelector (connections) {
|
|
|
514
544
|
}
|
|
515
545
|
|
|
516
546
|
function generateRequestId () {
|
|
517
|
-
|
|
518
|
-
|
|
547
|
+
const maxInt = 2147483647
|
|
548
|
+
let nextReqId = 0
|
|
519
549
|
return function genReqId (params, options) {
|
|
520
550
|
return (nextReqId = (nextReqId + 1) & maxInt)
|
|
521
551
|
}
|
package/lib/errors.js
CHANGED
|
@@ -90,7 +90,16 @@ class ResponseError extends ElasticsearchClientError {
|
|
|
90
90
|
super('Response Error')
|
|
91
91
|
Error.captureStackTrace(this, ResponseError)
|
|
92
92
|
this.name = 'ResponseError'
|
|
93
|
-
|
|
93
|
+
if (meta.body && meta.body.error && meta.body.error.type) {
|
|
94
|
+
if (Array.isArray(meta.body.error.root_cause)) {
|
|
95
|
+
this.message = meta.body.error.type + ': '
|
|
96
|
+
this.message += meta.body.error.root_cause.map(entry => `[${entry.type}] Reason: ${entry.reason}`).join('; ')
|
|
97
|
+
} else {
|
|
98
|
+
this.message = meta.body.error.type
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
this.message = 'Response Error'
|
|
102
|
+
}
|
|
94
103
|
this.meta = meta
|
|
95
104
|
}
|
|
96
105
|
|
|
@@ -108,6 +117,10 @@ class ResponseError extends ElasticsearchClientError {
|
|
|
108
117
|
get headers () {
|
|
109
118
|
return this.meta.headers
|
|
110
119
|
}
|
|
120
|
+
|
|
121
|
+
toString () {
|
|
122
|
+
return JSON.stringify(this.meta.body)
|
|
123
|
+
}
|
|
111
124
|
}
|
|
112
125
|
|
|
113
126
|
class RequestAbortedError extends ElasticsearchClientError {
|
|
@@ -128,7 +128,7 @@ class BaseConnectionPool {
|
|
|
128
128
|
*/
|
|
129
129
|
empty (callback) {
|
|
130
130
|
debug('Emptying the connection pool')
|
|
131
|
-
|
|
131
|
+
let openConnections = this.size
|
|
132
132
|
this.connections.forEach(connection => {
|
|
133
133
|
connection.close(() => {
|
|
134
134
|
if (--openConnections === 0) {
|
|
@@ -201,7 +201,7 @@ class BaseConnectionPool {
|
|
|
201
201
|
const ids = Object.keys(nodes)
|
|
202
202
|
const hosts = []
|
|
203
203
|
|
|
204
|
-
for (
|
|
204
|
+
for (let i = 0, len = ids.length; i < len; i++) {
|
|
205
205
|
const node = nodes[ids[i]]
|
|
206
206
|
// If there is no protocol in
|
|
207
207
|
// the `publish_address` new URL will throw
|
|
@@ -210,7 +210,7 @@ class BaseConnectionPool {
|
|
|
210
210
|
// - hostname/ip:port
|
|
211
211
|
// if we encounter the second case, we should
|
|
212
212
|
// use the hostname instead of the ip
|
|
213
|
-
|
|
213
|
+
let address = node.http.publish_address
|
|
214
214
|
const parts = address.split('/')
|
|
215
215
|
// the url is in the form of hostname/ip:port
|
|
216
216
|
if (parts.length > 1) {
|
|
@@ -80,7 +80,7 @@ class ConnectionPool extends BaseConnectionPool {
|
|
|
80
80
|
// list a node that no longer exist. The following check verify
|
|
81
81
|
// that the connection is still part of the pool before
|
|
82
82
|
// marking it as dead.
|
|
83
|
-
for (
|
|
83
|
+
for (let i = 0; i < this.size; i++) {
|
|
84
84
|
if (this.connections[i].id === id) {
|
|
85
85
|
this.dead.push(id)
|
|
86
86
|
break
|
|
@@ -138,7 +138,7 @@ class ConnectionPool extends BaseConnectionPool {
|
|
|
138
138
|
path: '/',
|
|
139
139
|
timeout: this.pingTimeout
|
|
140
140
|
}, (err, response) => {
|
|
141
|
-
|
|
141
|
+
let isAlive = true
|
|
142
142
|
const statusCode = response !== null ? response.statusCode : 0
|
|
143
143
|
if (err != null ||
|
|
144
144
|
(statusCode === 502 || statusCode === 503 || statusCode === 504)) {
|
|
@@ -170,8 +170,7 @@ class ConnectionPool extends BaseConnectionPool {
|
|
|
170
170
|
isAlive: true,
|
|
171
171
|
connection
|
|
172
172
|
})
|
|
173
|
-
// eslint-disable-
|
|
174
|
-
callback(true, connection)
|
|
173
|
+
callback(true, connection) // eslint-disable-line
|
|
175
174
|
}
|
|
176
175
|
}
|
|
177
176
|
|
|
@@ -199,7 +198,7 @@ class ConnectionPool extends BaseConnectionPool {
|
|
|
199
198
|
|
|
200
199
|
// TODO: can we cache this?
|
|
201
200
|
const connections = []
|
|
202
|
-
for (
|
|
201
|
+
for (let i = 0; i < this.size; i++) {
|
|
203
202
|
const connection = this.connections[i]
|
|
204
203
|
if (noAliveConnections || connection.status === Connection.statuses.ALIVE) {
|
|
205
204
|
if (filter(connection) === true) {
|