Repository: elastic/elasticsearch-js
Pull request #1505 (2021-07-24 16:13:53)

Changelog for 7.14
As titled.


Patch:
diff --git a/api/api/search_mvt.js b/api/api/search_mvt.js
new file mode 100644
index 00000000..242622b0
--- /dev/null
+++ b/api/api/search_mvt.js
@@ -0,0 +1,87 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+'use strict'
+
+/* eslint camelcase: 0 */
+/* eslint no-unused-vars: 0 */
+
+const { handleError, snakeCaseKeys, normalizeArguments, kConfigurationError } = require('../utils')
+const acceptedQuerystring = ['exact_bounds', 'extent', 'grid_precision', 'grid_type', 'size', 'pretty', 'human', 'error_trace', 'source', 'filter_path']
+const snakeCase = { exactBounds: 'exact_bounds', gridPrecision: 'grid_precision', gridType: 'grid_type', errorTrace: 'error_trace', filterPath: 'filter_path' }
+
+function searchMvtApi (params, options, callback) {
+  ;[params, options, callback] = normalizeArguments(params, options, callback)
+
+  // check required parameters
+  if (params.index == null) {
+    const err = new this[kConfigurationError]('Missing required parameter: index')
+    return handleError(err, callback)
+  }
+  if (params.field == null) {
+    const err = new this[kConfigurationError]('Missing required parameter: field')
+    return handleError(err, callback)
+  }
+  if (params.zoom == null) {
+    const err = new this[kConfigurationError]('Missing required parameter: zoom')
+    return handleError(err, callback)
+  }
+  if (params.x == null) {
+    const err = new this[kConfigurationError]('Missing required parameter: x')
+    return handleError(err, callback)
+  }
+  if (params.y == null) {
+    const err = new this[kConfigurationError]('Missing required parameter: y')
+    return handleError(err, callback)
+  }
+
+  // check required url components
+  if (params.y != null && (params.x == null || params.zoom == null || params.field == null || params.index == null)) {
+    const err = new this[kConfigurationError]('Missing required parameter of the url: x, zoom, field, index')
+    return handleError(err, callback)
+  } else if (params.x != null && (params.zoom == null || params.field == null || params.index == null)) {
+    const err = new this[kConfigurationError]('Missing required parameter of the url: zoom, field, index')
+    return handleError(err, callback)
+  } else if (params.zoom != null && (params.field == null || params.index == null)) {
+    const err = new this[kConfigurationError]('Missing required parameter of the url: field, index')
+    return handleError(err, callback)
+  } else if (params.field != null && (params.index == null)) {
+    const err = new this[kConfigurationError]('Missing required parameter of the url: index')
+    return handleError(err, callback)
+  }
+
+  let { method, body, index, field, zoom, x, y, ...querystring } = params
+  querystring = snakeCaseKeys(acceptedQuerystring, snakeCase, querystring)
+
+  let path = ''
+  if (method == null) method = body == null ? 'GET' : 'POST'
+  path = '/' + encodeURIComponent(index) + '/' + '_mvt' + '/' + encodeURIComponent(field) + '/' + encodeURIComponent(zoom) + '/' + encodeURIComponent(x) + '/' + encodeURIComponent(y)
+
+  // build request object
+  const request = {
+    method,
+    path,
+    body: body || '',
+    querystring
+  }
+
+  return this.transport.request(request, options, callback)
+}
+
+module.exports = searchMvtApi
diff --git a/api/index.js b/api/index.js
index 0ea8e1b8..2b37a5bf 100644
--- a/api/index.js
+++ b/api/index.js
@@ -74,6 +74,7 @@ const RollupApi = require('./api/rollup')
 const scriptsPainlessExecuteApi = require('./api/scripts_painless_execute')
 const scrollApi = require('./api/scroll')
 const searchApi = require('./api/search')
+const searchMvtApi = require('./api/search_mvt')
 const searchShardsApi = require('./api/search_shards')
 const searchTemplateApi = require('./api/search_template')
 const SearchableSnapshotsApi = require('./api/searchable_snapshots')
@@ -200,6 +201,7 @@ ESAPI.prototype.renderSearchTemplate = renderSearchTemplateApi
 ESAPI.prototype.scriptsPainlessExecute = scriptsPainlessExecuteApi
 ESAPI.prototype.scroll = scrollApi
 ESAPI.prototype.search = searchApi
+ESAPI.prototype.searchMvt = searchMvtApi
 ESAPI.prototype.searchShards = searchShardsApi
 ESAPI.prototype.searchTemplate = searchTemplateApi
 ESAPI.prototype.termsEnum = termsEnumApi
@@ -397,6 +399,7 @@ Object.defineProperties(ESAPI.prototype, {
     }
   },
   scripts_painless_execute: { get () { return this.scriptsPainlessExecute } },
+  search_mvt: { get () { return this.searchMvt } },
   search_shards: { get () { return this.searchShards } },
   search_template: { get () { return this.searchTemplate } },
   searchableSnapshots: {
diff --git a/api/kibana.d.ts b/api/kibana.d.ts
index ebae7c89..7b4c6ea4 100644
--- a/api/kibana.d.ts
+++ b/api/kibana.d.ts
@@ -345,7 +345,7 @@ interface KibanaClient {
     info<TContext = unknown>(params?: T.MlInfoRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlInfoResponse, TContext>>
     openJob<TContext = unknown>(params: T.MlOpenJobRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlOpenJobResponse, TContext>>
     postCalendarEvents<TContext = unknown>(params?: T.MlPostCalendarEventsRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPostCalendarEventsResponse, TContext>>
-    postData<TContext = unknown>(params: T.MlPostJobDataRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPostJobDataResponse, TContext>>
+    postData<TContext = unknown>(params: T.MlPostDataRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPostDataResponse, TContext>>
     previewDataFrameAnalytics<TContext = unknown>(params?: T.MlPreviewDataFrameAnalyticsRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPreviewDataFrameAnalyticsResponse, TContext>>
     previewDatafeed<TDocument = unknown, TContext = unknown>(params?: T.MlPreviewDatafeedRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPreviewDatafeedResponse<TDocument>, TContext>>
     putCalendar<TContext = unknown>(params: T.MlPutCalendarRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPutCalendarResponse, TContext>>
@@ -356,7 +356,7 @@ interface KibanaClient {
     putJob<TContext = unknown>(params: T.MlPutJobRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPutJobResponse, TContext>>
     putTrainedModel<TContext = unknown>(params?: TODO, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TODO, TContext>>
     putTrainedModelAlias<TContext = unknown>(params: T.MlPutTrainedModelAliasRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPutTrainedModelAliasResponse, TContext>>
-    resetJob<TContext = unknown>(params?: TODO, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TODO, TContext>>
+    resetJob<TContext = unknown>(params: T.MlResetJobRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlResetJobResponse, TContext>>
     revertModelSnapshot<TContext = unknown>(params: T.MlRevertModelSnapshotRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlRevertModelSnapshotResponse, TContext>>
     setUpgradeMode<TContext = unknown>(params?: T.MlSetUpgradeModeRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlSetUpgradeModeResponse, TContext>>
     startDataFrameAnalytics<TContext = unknown>(params: T.MlStartDataFrameAnalyticsRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlStartDataFrameAnalyticsResponse, TContext>>
@@ -366,7 +366,7 @@ interface KibanaClient {
     updateDataFrameAnalytics<TContext = unknown>(params: T.MlUpdateDataFrameAnalyticsRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlUpdateDataFrameAnalyticsResponse, TContext>>
     updateDatafeed<TContext = unknown>(params?: TODO, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TODO, TContext>>
     updateFilter<TContext = unknown>(params: T.MlUpdateFilterRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlUpdateFilterResponse, TContext>>
-    updateJob<TContext = unknown>(params?: TODO, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TODO, TContext>>
+    updateJob<TContext = unknown>(params: T.MlUpdateJobRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlUpdateJobResponse, TContext>>
     updateModelSnapshot<TContext = unknown>(params: T.MlUpdateModelSnapshotRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlUpdateModelSnapshotResponse, TContext>>
     upgradeJobSnapshot<TContext = unknown>(params: T.MlUpgradeJobSnapshotRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlUpgradeJobSnapshotResponse, TContext>>
     validate<TContext = unknown>(params?: T.MlValidateJobRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlValidateJobResponse, TContext>>
diff --git a/api/new.d.ts b/api/new.d.ts
index 5a9e4923..a7d882b0 100644
--- a/api/new.d.ts
+++ b/api/new.d.ts
@@ -950,9 +950,9 @@ declare class Client {
     postCalendarEvents<TContext = unknown>(callback: callbackFn<T.MlPostCalendarEventsResponse, TContext>): TransportRequestCallback
     postCalendarEvents<TContext = unknown>(params: T.MlPostCalendarEventsRequest, callback: callbackFn<T.MlPostCalendarEventsResponse, TContext>): TransportRequestCallback
     postCalendarEvents<TContext = unknown>(params: T.MlPostCalendarEventsRequest, options: TransportRequestOptions, callback: callbackFn<T.MlPostCalendarEventsResponse, TContext>): TransportRequestCallback
-    postData<TContext = unknown>(params: T.MlPostJobDataRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPostJobDataResponse, TContext>>
-    postData<TContext = unknown>(params: T.MlPostJobDataRequest, callback: callbackFn<T.MlPostJobDataResponse, TContext>): TransportRequestCallback
-    postData<TContext = unknown>(params: T.MlPostJobDataRequest, options: TransportRequestOptions, callback: callbackFn<T.MlPostJobDataResponse, TContext>): TransportRequestCallback
+    postData<TContext = unknown>(params: T.MlPostDataRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPostDataResponse, TContext>>
+    postData<TContext = unknown>(params: T.MlPostDataRequest, callback: callbackFn<T.MlPostDataResponse, TContext>): TransportRequestCallback
+    postData<TContext = unknown>(params: T.MlPostDataRequest, options: TransportRequestOptions, callback: callbackFn<T.MlPostDataResponse, TContext>): TransportRequestCallback
     previewDataFrameAnalytics<TContext = unknown>(params?: T.MlPreviewDataFrameAnalyticsRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPreviewDataFrameAnalyticsResponse, TContext>>
     previewDataFrameAnalytics<TContext = unknown>(callback: callbackFn<T.MlPreviewDataFrameAnalyticsResponse, TContext>): TransportRequestCallback
     previewDataFrameAnalytics<TContext = unknown>(params: T.MlPreviewDataFrameAnalyticsRequest, callback: callbackFn<T.MlPreviewDataFrameAnalyticsResponse, TContext>): TransportRequestCallback
@@ -986,10 +986,9 @@ declare class Client {
     putTrainedModelAlias<TContext = unknown>(params: T.MlPutTrainedModelAliasRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlPutTrainedModelAliasResponse, TContext>>
     putTrainedModelAlias<TContext = unknown>(params: T.MlPutTrainedModelAliasRequest, callback: callbackFn<T.MlPutTrainedModelAliasResponse, TContext>): TransportRequestCallback
     putTrainedModelAlias<TContext = unknown>(params: T.MlPutTrainedModelAliasRequest, options: TransportRequestOptions, callback: callbackFn<T.MlPutTrainedModelAliasResponse, TContext>): TransportRequestCallback
-    resetJob<TContext = unknown>(params?: TODO, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TODO, TContext>>
-    resetJob<TContext = unknown>(callback: callbackFn<TODO, TContext>): TransportRequestCallback
-    resetJob<TContext = unknown>(params: TODO, callback: callbackFn<TODO, TContext>): TransportRequestCallback
-    resetJob<TContext = unknown>(params: TODO, options: TransportRequestOptions, callback: callbackFn<TODO, TContext>): TransportRequestCallback
+    resetJob<TContext = unknown>(params: T.MlResetJobRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlResetJobResponse, TContext>>
+    resetJob<TContext = unknown>(params: T.MlResetJobRequest, callback: callbackFn<T.MlResetJobResponse, TContext>): TransportRequestCallback
+    resetJob<TContext = unknown>(params: T.MlResetJobRequest, options: TransportRequestOptions, callback: callbackFn<T.MlResetJobResponse, TContext>): TransportRequestCallback
     revertModelSnapshot<TContext = unknown>(params: T.MlRevertModelSnapshotRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlRevertModelSnapshotResponse, TContext>>
     revertModelSnapshot<TContext = unknown>(params: T.MlRevertModelSnapshotRequest, callback: callbackFn<T.MlRevertModelSnapshotResponse, TContext>): TransportRequestCallback
     revertModelSnapshot<TContext = unknown>(params: T.MlRevertModelSnapshotRequest, options: TransportRequestOptions, callback: callbackFn<T.MlRevertModelSnapshotResponse, TContext>): TransportRequestCallback
@@ -1019,10 +1018,9 @@ declare class Client {
     updateFilter<TContext = unknown>(params: T.MlUpdateFilterRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlUpdateFilterResponse, TContext>>
     updateFilter<TContext = unknown>(params: T.MlUpdateFilterRequest, callback: callbackFn<T.MlUpdateFilterResponse, TContext>): TransportRequestCallback
     updateFilter<TContext = unknown>(params: T.MlUpdateFilterRequest, options: TransportRequestOptions, callback: callbackFn<T.MlUpdateFilterResponse, TContext>): TransportRequestCallback
-    updateJob<TContext = unknown>(params?: TODO, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TODO, TContext>>
-    updateJob<TContext = unknown>(callback: callbackFn<TODO, TContext>): TransportRequestCallback
-    updateJob<TContext = unknown>(params: TODO, callback: callbackFn<TODO, TContext>): TransportRequestCallback
-    updateJob<TContext = unknown>(params: TODO, options: TransportRequestOptions, callback: callbackFn<TODO, TContext>): TransportRequestCallback
+    updateJob<TContext = unknown>(params: T.MlUpdateJobRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlUpdateJobResponse, TContext>>
+    updateJob<TContext = unknown>(params: T.MlUpdateJobRequest, callback: callbackFn<T.MlUpdateJobResponse, TContext>): TransportRequestCallback
+    updateJob<TContext = unknown>(params: T.MlUpdateJobRequest, options: TransportRequestOptions, callback: callbackFn<T.MlUpdateJobResponse, TContext>): TransportRequestCallback
     updateModelSnapshot<TContext = unknown>(params: T.MlUpdateModelSnapshotRequest, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<T.MlUpdateModelSnapshotResponse, TContext>>
     updateModelSnapshot<TContext = unknown>(params: T.MlUpdateModelSnapshotRequest, callback: callbackFn<T.MlUpdateModelSnapshotResponse, TContext>): TransportRequestCallback
     updateModelSnapshot<TContext = unknown>(params: T.MlUpdateModelSnapshotRequest, options: TransportRequestOptions, callback: callbackFn<T.MlUpdateModelSnapshotResponse, TContext>): TransportRequestCallback
diff --git a/api/requestParams.d.ts b/api/requestParams.d.ts
index f8036f85..52e925b4 100644
--- a/api/requestParams.d.ts
+++ b/api/requestParams.d.ts
@@ -2236,6 +2236,20 @@ export interface Search<T = RequestBody> extends Generic {
   body?: T;
 }
 
+export interface SearchMvt<T = RequestBody> extends Generic {
+  index: string | string[];
+  field: string;
+  zoom: integer;
+  x: integer;
+  y: integer;
+  exact_bounds?: boolean;
+  extent?: number;
+  grid_precision?: number;
+  grid_type?: 'grid' | 'point';
+  size?: number;
+  body?: T;
+}
+
 export interface SearchShards extends Generic {
   index?: string | string[];
   preference?: string;
diff --git a/api/types.d.ts b/api/types.d.ts
index b32273e3..5678de76 100644
--- a/api/types.d.ts
+++ b/api/types.d.ts
@@ -1014,7 +1014,7 @@ export interface SearchRequest extends RequestBase {
     query?: QueryDslQueryContainer
     rescore?: SearchRescore | SearchRescore[]
     script_fields?: Record<string, ScriptField>
-    search_after?: (integer | string)[]
+    search_after?: SearchSortResults
     size?: integer
     slice?: SlicedScroll
     sort?: SearchSort
@@ -1129,6 +1129,12 @@ export interface SearchDocValueField {
   format?: string
 }
 
+export interface SearchFieldAndFormat {
+  field: Field
+  format?: string
+  include_unmapped?: boolean
+}
+
 export interface SearchFieldCollapse {
   field: Field
   inner_hits?: SearchInnerHits | SearchInnerHits[]
@@ -1242,15 +1248,17 @@ export interface SearchInnerHits {
   size?: integer
   from?: integer
   collapse?: SearchFieldCollapse
-  docvalue_fields?: Fields
+  docvalue_fields?: (SearchFieldAndFormat | Field)[]
   explain?: boolean
   highlight?: SearchHighlight
   ignore_unmapped?: boolean
-  script_fields?: Record<string, ScriptField>
+  script_fields?: Record<Field, ScriptField>
   seq_no_primary_term?: boolean
   fields?: Fields
   sort?: SearchSort
   _source?: boolean | SearchSourceFilter
+  stored_field?: Fields
+  track_scores?: boolean
   version?: boolean
 }
 
@@ -1820,6 +1828,8 @@ export interface DateField {
   include_unmapped?: boolean
 }
 
+export type DateFormat = string
+
 export type DateMath = string
 
 export type DateMathTime = string
@@ -1934,6 +1944,8 @@ export type GeoDistanceType = 'arc' | 'plane'
 
 export type GeoHashPrecision = number
 
+export type GeoShape = any
+
 export type GeoShapeRelation = 'intersects' | 'disjoint' | 'within' | 'contains'
 
 export type GeoTilePrecision = number
@@ -2024,7 +2036,6 @@ export type LifecycleOperationMode = 'RUNNING' | 'STOPPING' | 'STOPPED'
 
 export interface MainError extends ErrorCause {
   headers?: Record<string, string>
-  root_cause: ErrorCause[]
 }
 
 export interface MergesStats {
@@ -2171,7 +2182,7 @@ export interface Retries {
   search: long
 }
 
-export type Routing = string | number
+export type Routing = string
 
 export type Script = InlineScript | IndexedScript | string
 
@@ -2182,6 +2193,7 @@ export interface ScriptBase {
 
 export interface ScriptField {
   script: Script
+  ignore_failure?: boolean
 }
 
 export type ScriptLanguage = 'painless' | 'expression' | 'mustache' | 'java'
@@ -2304,6 +2316,8 @@ export type Time = string | integer
 
 export type TimeSpan = string
 
+export type TimeZone = string
+
 export type Timestamp = string
 
 export interface Transform {
@@ -2366,7 +2380,6 @@ export interface WriteResponseBase {
   _type?: Type
   _version: VersionNumber
   forced_refresh?: boolean
-  error?: ErrorCause
 }
 
 export type double = number
@@ -3533,7 +3546,7 @@ export interface AnalysisStopTokenFilter extends AnalysisTokenFilterBase {
   stopwords_path?: string
 }
 
-export type AnalysisStopWords = string | string[]
+export type AnalysisStopWords = string[]
 
 export type AnalysisSynonymFormat = 'solr' | 'wordnet'
 
@@ -4031,36 +4044,49 @@ export interface QueryDslBoolQuery extends QueryDslQueryBase {
 }
 
 export interface QueryDslBoostingQuery extends QueryDslQueryBase {
-  negative_boost?: double
-  negative?: QueryDslQueryContainer
-  positive?: QueryDslQueryContainer
+  negative_boost: double
+  negative: QueryDslQueryContainer
+  positive: QueryDslQueryContainer
 }
 
 export interface QueryDslBoundingBox {
   bottom_right?: QueryDslGeoLocation
   top_left?: QueryDslGeoLocation
+  top_right?: QueryDslGeoLocation
+  bottom_left?: QueryDslGeoLocation
+  top?: double
+  left?: double
+  right?: double
+  bottom?: double
   wkt?: string
 }
 
 export type QueryDslChildScoreMode = 'none' | 'avg' | 'sum' | 'max' | 'min'
 
-export interface QueryDslCombinedFieldsQuery {
-  query: string
+export type QueryDslCombinedFieldsOperator = 'or' | 'and'
+
+export interface QueryDslCombinedFieldsQuery extends QueryDslQueryBase {
   fields: Field[]
-  operator?: string
+  query: string
+  auto_generate_synonyms_phrase_query?: boolean
+  operator?: QueryDslCombinedFieldsOperator
+  mimimum_should_match?: MinimumShouldMatch
+  zero_terms_query?: QueryDslCombinedFieldsZeroTerms
 }
 
+export type QueryDslCombinedFieldsZeroTerms = 'none' | 'all'
+
 export interface QueryDslCommonTermsQuery extends QueryDslQueryBase {
   analyzer?: string
   cutoff_frequency?: double
   high_freq_operator?: QueryDslOperator
   low_freq_operator?: QueryDslOperator
   minimum_should_match?: MinimumShouldMatch
-  query?: string
+  query: string
 }
 
 export interface QueryDslConstantScoreQuery extends QueryDslQueryBase {
-  filter?: QueryDslQueryContainer
+  filter: QueryDslQueryContainer
 }
 
 export interface QueryDslDateDecayFunctionKeys extends QueryDslDecayFunctionBase {
@@ -4068,6 +4094,18 @@ export interface QueryDslDateDecayFunctionKeys extends QueryDslDecayFunctionBase
 export type QueryDslDateDecayFunction = QueryDslDateDecayFunctionKeys |
     { [property: string]: QueryDslDecayPlacement<DateMath, Time> }
 
+export interface QueryDslDateDistanceFeatureQuery extends QueryDslDistanceFeatureQueryBase<DateMath, Time> {
+}
+
+export interface QueryDslDateRangeQuery extends QueryDslRangeQueryBase {
+  gt?: DateMath
+  gte?: DateMath
+  lt?: DateMath
+  lte?: DateMath
+  format?: DateFormat
+  time_zone?: TimeZone
+}
+
 export type QueryDslDecayFunction = QueryDslDateDecayFunction | QueryDslNumericDecayFunction | QueryDslGeoDecayFunction
 
 export interface QueryDslDecayFunctionBase extends QueryDslScoreFunctionBase {
@@ -4082,22 +4120,24 @@ export interface QueryDslDecayPlacement<TOrigin = unknown, TScale = unknown> {
 }
 
 export interface QueryDslDisMaxQuery extends QueryDslQueryBase {
-  queries?: QueryDslQueryContainer[]
+  queries: QueryDslQueryContainer[]
   tie_breaker?: double
 }
 
-export interface QueryDslDistanceFeatureQuery extends QueryDslQueryBase {
-  origin?: number[] | QueryDslGeoCoordinate | DateMath
-  pivot?: Distance | Time
-  field?: Field
+export type QueryDslDistanceFeatureQuery = QueryDslGeoDistanceFeatureQuery | QueryDslDateDistanceFeatureQuery
+
+export interface QueryDslDistanceFeatureQueryBase<TOrigin = unknown, TDistance = unknown> extends QueryDslQueryBase {
+  origin: TOrigin
+  pivot: TDistance
+  field: Field
 }
 
 export interface QueryDslExistsQuery extends QueryDslQueryBase {
-  field?: Field
+  field: Field
 }
 
 export interface QueryDslFieldLookup {
-  id?: Id
+  id: Id
   index?: IndexName
   path?: Field
   routing?: Routing
@@ -4142,16 +4182,15 @@ export interface QueryDslFuzzyQuery extends QueryDslQueryBase {
   rewrite?: MultiTermQueryRewrite
   transpositions?: boolean
   fuzziness?: Fuzziness
-  value: any
+  value: string
 }
 
-export interface QueryDslGeoBoundingBoxQuery extends QueryDslQueryBase {
-  bounding_box?: QueryDslBoundingBox
+export interface QueryDslGeoBoundingBoxQueryKeys extends QueryDslQueryBase {
   type?: QueryDslGeoExecution
   validation_method?: QueryDslGeoValidationMethod
-  top_left?: LatLon
-  bottom_right?: LatLon
 }
+export type QueryDslGeoBoundingBoxQuery = QueryDslGeoBoundingBoxQueryKeys |
+    { [property: string]: QueryDslBoundingBox }
 
 export type QueryDslGeoCoordinate = string | double[] | QueryDslThreeDimensionalPoint
 
@@ -4160,6 +4199,9 @@ export interface QueryDslGeoDecayFunctionKeys extends QueryDslDecayFunctionBase
 export type QueryDslGeoDecayFunction = QueryDslGeoDecayFunctionKeys |
     { [property: string]: QueryDslDecayPlacement<QueryDslGeoLocation, Distance> }
 
+export interface QueryDslGeoDistanceFeatureQuery extends QueryDslDistanceFeatureQueryBase<QueryDslGeoCoordinate, Distance> {
+}
+
 export interface QueryDslGeoDistanceQueryKeys extends QueryDslQueryBase {
   distance?: Distance
   distance_type?: GeoDistanceType
@@ -4172,22 +4214,28 @@ export type QueryDslGeoExecution = 'memory' | 'indexed'
 
 export type QueryDslGeoLocation = string | double[] | QueryDslTwoDimensionalPoint
 
-export interface QueryDslGeoPolygonQuery extends QueryDslQueryBase {
-  points?: QueryDslGeoLocation[]
-  validation_method?: QueryDslGeoValidationMethod
+export interface QueryDslGeoPolygonPoints {
+  points: QueryDslGeoLocation[]
 }
 
-export interface QueryDslGeoShape {
-  type?: string
+export interface QueryDslGeoPolygonQueryKeys extends QueryDslQueryBase {
+  validation_method?: QueryDslGeoValidationMethod
 }
+export type QueryDslGeoPolygonQuery = QueryDslGeoPolygonQueryKeys |
+    { [property: string]: QueryDslGeoPolygonPoints }
 
-export interface QueryDslGeoShapeQuery extends QueryDslQueryBase {
-  ignore_unmapped?: boolean
+export interface QueryDslGeoShapeFieldQuery {
+  shape?: GeoShape
   indexed_shape?: QueryDslFieldLookup
   relation?: GeoShapeRelation
-  shape?: QueryDslGeoShape
 }
 
+export interface QueryDslGeoShapeQueryKeys extends QueryDslQueryBase {
+  ignore_unmapped?: boolean
+}
+export type QueryDslGeoShapeQuery = QueryDslGeoShapeQueryKeys |
+    { [property: string]: QueryDslGeoShapeFieldQuery }
+
 export type QueryDslGeoValidationMethod = 'coerce' | 'ignore_malformed' | 'strict'
 
 export interface QueryDslHasChildQuery extends QueryDslQueryBase {
@@ -4195,32 +4243,32 @@ export interface QueryDslHasChildQuery extends QueryDslQueryBase {
   inner_hits?: SearchInnerHits
   max_children?: integer
   min_children?: integer
-  query?: QueryDslQueryContainer
+  query: QueryDslQueryContainer
   score_mode?: QueryDslChildScoreMode
-  type?: RelationName
+  type: RelationName
 }
 
 export interface QueryDslHasParentQuery extends QueryDslQueryBase {
   ignore_unmapped?: boolean
   inner_hits?: SearchInnerHits
-  parent_type?: RelationName
-  query?: QueryDslQueryContainer
+  parent_type: RelationName
+  query: QueryDslQueryContainer
   score?: boolean
 }
 
 export interface QueryDslIdsQuery extends QueryDslQueryBase {
-  values?: Id[] | long[]
+  values?: Ids
 }
 
 export interface QueryDslIntervalsAllOf {
-  intervals?: QueryDslIntervalsContainer[]
+  intervals: QueryDslIntervalsContainer[]
   max_gaps?: integer
   ordered?: boolean
   filter?: QueryDslIntervalsFilter
 }
 
 export interface QueryDslIntervalsAnyOf {
-  intervals?: QueryDslIntervalsContainer[]
+  intervals: QueryDslIntervalsContainer[]
   filter?: QueryDslIntervalsFilter
 }
 
@@ -4249,7 +4297,7 @@ export interface QueryDslIntervalsFuzzy {
   analyzer?: string
   fuzziness?: Fuzziness
   prefix_length?: integer
-  term?: string
+  term: string
   transpositions?: boolean
   use_field?: Field
 }
@@ -4258,14 +4306,14 @@ export interface QueryDslIntervalsMatch {
   analyzer?: string
   max_gaps?: integer
   ordered?: boolean
-  query?: string
+  query: string
   use_field?: Field
   filter?: QueryDslIntervalsFilter
 }
 
 export interface QueryDslIntervalsPrefix {
   analyzer?: string
-  prefix?: string
+  prefix: string
   use_field?: Field
 }
 
@@ -4280,7 +4328,7 @@ export interface QueryDslIntervalsQuery extends QueryDslQueryBase {
 
 export interface QueryDslIntervalsWildcard {
   analyzer?: string
-  pattern?: string
+  pattern: string
   use_field?: Field
 }
 
@@ -4288,16 +4336,17 @@ export type QueryDslLike = string | QueryDslLikeDocument
 
 export interface QueryDslLikeDocument {
   doc?: any
-  fields?: Fields
-  _id?: Id | number
+  fields?: Field[]
+  _id?: Id
   _type?: Type
   _index?: IndexName
   per_field_analyzer?: Record<Field, string>
   routing?: Routing
+  version?: VersionNumber
+  version_type?: VersionType
 }
 
 export interface QueryDslMatchAllQuery extends QueryDslQueryBase {
-  norm_field?: string
 }
 
 export interface QueryDslMatchBoolPrefixQuery extends QueryDslQueryBase {
@@ -4309,7 +4358,7 @@ export interface QueryDslMatchBoolPrefixQuery extends QueryDslQueryBase {
   minimum_should_match?: MinimumShouldMatch
   operator?: QueryDslOperator
   prefix_length?: integer
-  query?: string
+  query: string
 }
 
 export interface QueryDslMatchNoneQuery extends QueryDslQueryBase {
@@ -4318,15 +4367,16 @@ export interface QueryDslMatchNoneQuery extends QueryDslQueryBase {
 export interface QueryDslMatchPhrasePrefixQuery extends QueryDslQueryBase {
   analyzer?: string
   max_expansions?: integer
-  query?: string
+  query: string
   slop?: integer
   zero_terms_query?: QueryDslZeroTermsQuery
 }
 
 export interface QueryDslMatchPhraseQuery extends QueryDslQueryBase {
   analyzer?: string
-  query?: string
+  query: string
   slop?: integer
+  zero_terms_query?: QueryDslZeroTermsQuery
 }
 
 export interface QueryDslMatchQuery extends QueryDslQueryBase {
@@ -4341,16 +4391,17 @@ export interface QueryDslMatchQuery extends QueryDslQueryBase {
   minimum_should_match?: MinimumShouldMatch
   operator?: QueryDslOperator
   prefix_length?: integer
-  query?: string | float | boolean
+  query: string | float | boolean
   zero_terms_query?: QueryDslZeroTermsQuery
 }
 
 export interface QueryDslMoreLikeThisQuery extends QueryDslQueryBase {
   analyzer?: string
   boost_terms?: double
-  fields?: Fields
+  fail_on_unsupported_field?: boolean
+  fields?: Field[]
   include?: boolean
-  like?: QueryDslLike | QueryDslLike[]
+  like: QueryDslLike | QueryDslLike[]
   max_doc_freq?: integer
   max_query_terms?: integer
   max_word_length?: integer
@@ -4379,40 +4430,38 @@ export interface QueryDslMultiMatchQuery extends QueryDslQueryBase {
   minimum_should_match?: MinimumShouldMatch
   operator?: QueryDslOperator
   prefix_length?: integer
-  query?: string
+  query: string
   slop?: integer
   tie_breaker?: double
   type?: QueryDslTextQueryType
-  use_dis_max?: boolean
   zero_terms_query?: QueryDslZeroTermsQuery
 }
 
 export type QueryDslMultiValueMode = 'min' | 'max' | 'avg' | 'sum'
 
-export interface QueryDslNamedQueryKeys<TQuery = unknown> {
-  boost?: float
-  _name?: string
-  ignore_unmapped?: boolean
-}
-export type QueryDslNamedQuery<TQuery = unknown> = QueryDslNamedQueryKeys<TQuery> |
-    { [property: string]: TQuery }
-
 export interface QueryDslNestedQuery extends QueryDslQueryBase {
   ignore_unmapped?: boolean
   inner_hits?: SearchInnerHits
-  path?: Field
-  query?: QueryDslQueryContainer
+  path: Field
+  query: QueryDslQueryContainer
   score_mode?: QueryDslNestedScoreMode
 }
 
 export type QueryDslNestedScoreMode = 'avg' | 'sum' | 'min' | 'max' | 'none'
 
+export interface QueryDslNumberRangeQuery extends QueryDslRangeQueryBase {
+  gt?: double
+  gte?: double
+  lt?: double
+  lte?: double
+}
+
 export interface QueryDslNumericDecayFunctionKeys extends QueryDslDecayFunctionBase {
 }
 export type QueryDslNumericDecayFunction = QueryDslNumericDecayFunctionKeys |
     { [property: string]: QueryDslDecayPlacement<double, double> }
 
-export type QueryDslOperator = 'and' | 'or' | 'AND' | 'OR'
+export type QueryDslOperator = 'and' | 'or'
 
 export interface QueryDslParentIdQuery extends QueryDslQueryBase {
   id?: Id
@@ -4423,22 +4472,24 @@ export interface QueryDslParentIdQuery extends QueryDslQueryBase {
 export interface QueryDslPercolateQuery extends QueryDslQueryBase {
   document?: any
   documents?: any[]
-  field?: Field
+  field: Field
   id?: Id
   index?: IndexName
+  name?: string
   preference?: string
   routing?: Routing
   version?: VersionNumber
 }
 
 export interface QueryDslPinnedQuery extends QueryDslQueryBase {
-  ids?: Id[] | long[]
-  organic?: QueryDslQueryContainer
+  ids: Id[]
+  organic: QueryDslQueryContainer
 }
 
 export interface QueryDslPrefixQuery extends QueryDslQueryBase {
   rewrite?: MultiTermQueryRewrite
   value: string
+  case_insensitive?: boolean
 }
 
 export interface QueryDslQueryBase {
@@ -4453,38 +4504,38 @@ export interface QueryDslQueryContainer {
   combined_fields?: QueryDslCombinedFieldsQuery
   constant_score?: QueryDslConstantScoreQuery
   dis_max?: QueryDslDisMaxQuery
-  distance_feature?: Record<Field, QueryDslDistanceFeatureQuery | string> | QueryDslDistanceFeatureQuery
+  distance_feature?: QueryDslDistanceFeatureQuery
   exists?: QueryDslExistsQuery
   function_score?: QueryDslFunctionScoreQuery
   fuzzy?: Record<Field, QueryDslFuzzyQuery | string>
-  geo_bounding_box?: QueryDslNamedQuery<QueryDslGeoBoundingBoxQuery | string>
+  geo_bounding_box?: QueryDslGeoBoundingBoxQuery
   geo_distance?: QueryDslGeoDistanceQuery
-  geo_polygon?: QueryDslNamedQuery<QueryDslGeoPolygonQuery | string>
-  geo_shape?: QueryDslNamedQuery<QueryDslGeoShapeQuery | string>
+  geo_polygon?: QueryDslGeoPolygonQuery
+  geo_shape?: QueryDslGeoShapeQuery
   has_child?: QueryDslHasChildQuery
   has_parent?: QueryDslHasParentQuery
   ids?: QueryDslIdsQuery
-  intervals?: QueryDslNamedQuery<QueryDslIntervalsQuery | string>
-  match?: QueryDslNamedQuery<QueryDslMatchQuery | string | float | boolean>
+  intervals?: Record<Field, QueryDslIntervalsQuery>
+  match?: Record<Field, QueryDslMatchQuery | string | float | boolean>
   match_all?: QueryDslMatchAllQuery
-  match_bool_prefix?: QueryDslNamedQuery<QueryDslMatchBoolPrefixQuery | string>
+  match_bool_prefix?: Record<Field, QueryDslMatchBoolPrefixQuery | string>
   match_none?: QueryDslMatchNoneQuery
-  match_phrase?: QueryDslNamedQuery<QueryDslMatchPhraseQuery | string>
-  match_phrase_prefix?: QueryDslNamedQuery<QueryDslMatchPhrasePrefixQuery | string>
+  match_phrase?: Record<Field, QueryDslMatchPhraseQuery | string>
+  match_phrase_prefix?: Record<Field, QueryDslMatchPhrasePrefixQuery | string>
   more_like_this?: QueryDslMoreLikeThisQuery
   multi_match?: QueryDslMultiMatchQuery
   nested?: QueryDslNestedQuery
   parent_id?: QueryDslParentIdQuery
   percolate?: QueryDslPercolateQuery
   pinned?: QueryDslPinnedQuery
-  prefix?: QueryDslNamedQuery<QueryDslPrefixQuery | string>
+  prefix?: Record<Field, QueryDslPrefixQuery | string>
   query_string?: QueryDslQueryStringQuery
-  range?: QueryDslNamedQuery<QueryDslRangeQuery>
-  rank_feature?: QueryDslNamedQuery<QueryDslRankFeatureQuery | string>
-  regexp?: QueryDslNamedQuery<QueryDslRegexpQuery | string>
+  range?: Record<Field, QueryDslRangeQuery>
+  rank_feature?: QueryDslRankFeatureQuery
+  regexp?: Record<Field, QueryDslRegexpQuery | string>
   script?: QueryDslScriptQuery
   script_score?: QueryDslScriptScoreQuery
-  shape?: QueryDslNamedQuery<QueryDslShapeQuery | string>
+  shape?: QueryDslShapeQuery
   simple_query_string?: QueryDslSimpleQueryStringQuery
   span_containing?: QueryDslSpanContainingQuery
   field_masking_span?: QueryDslSpanFieldMaskingQuery
@@ -4493,13 +4544,12 @@ export interface QueryDslQueryContainer {
   span_near?: QueryDslSpanNearQuery
   span_not?: QueryDslSpanNotQuery
   span_or?: QueryDslSpanOrQuery
-  span_term?: QueryDslNamedQuery<QueryDslSpanTermQuery | string>
+  span_term?: Record<Field, QueryDslSpanTermQuery | string>
   span_within?: QueryDslSpanWithinQuery
-  template?: QueryDslQueryTemplate
-  term?: QueryDslNamedQuery<QueryDslTermQuery | string | float | boolean>
-  terms?: QueryDslNamedQuery<QueryDslTermsQuery | string[] | long[]>
-  terms_set?: QueryDslNamedQuery<QueryDslTermsSetQuery | string>
-  wildcard?: QueryDslNamedQuery<QueryDslWildcardQuery | string>
+  term?: Record<Field, QueryDslTermQuery | string | float | boolean>
+  terms?: QueryDslTermsQuery
+  terms_set?: Record<Field, QueryDslTermsSetQuery>
+  wildcard?: Record<Field, QueryDslWildcardQuery | string>
   type?: QueryDslTypeQuery
 }
 
@@ -4512,7 +4562,7 @@ export interface QueryDslQueryStringQuery extends QueryDslQueryBase {
   default_operator?: QueryDslOperator
   enable_position_increments?: boolean
   escape?: boolean
-  fields?: Fields
+  fields?: Field[]
   fuzziness?: Fuzziness
   fuzzy_max_expansions?: integer
   fuzzy_prefix_length?: integer
@@ -4522,33 +4572,24 @@ export interface QueryDslQueryStringQuery extends QueryDslQueryBase {
   max_determinized_states?: integer
   minimum_should_match?: MinimumShouldMatch
   phrase_slop?: double
-  query?: string
+  query: string
   quote_analyzer?: string
   quote_field_suffix?: string
   rewrite?: MultiTermQueryRewrite
   tie_breaker?: double
-  time_zone?: string
+  time_zone?: TimeZone
   type?: QueryDslTextQueryType
 }
 
-export interface QueryDslQueryTemplate {
-  source: string
-}
-
 export interface QueryDslRandomScoreFunction extends QueryDslScoreFunctionBase {
   field?: Field
   seed?: long | string
 }
 
-export interface QueryDslRangeQuery extends QueryDslQueryBase {
-  gt?: double | DateMath
-  gte?: double | DateMath
-  lt?: double | DateMath
-  lte?: double | DateMath
+export type QueryDslRangeQuery = QueryDslDateRangeQuery | QueryDslNumberRangeQuery
+
+export interface QueryDslRangeQueryBase extends QueryDslQueryBase {
   relation?: QueryDslRangeRelation
-  time_zone?: string
-  from?: double | DateMath
-  to?: double | DateMath
 }
 
 export type QueryDslRangeRelation = 'within' | 'contains' | 'intersects'
@@ -4556,14 +4597,36 @@ export type QueryDslRangeRelation = 'within' | 'contains' | 'intersects'
 export interface QueryDslRankFeatureFunction {
 }
 
+export interface QueryDslRankFeatureFunctionLinear extends QueryDslRankFeatureFunction {
+}
+
+export interface QueryDslRankFeatureFunctionLogarithm extends QueryDslRankFeatureFunction {
+  scaling_factor: float
+}
+
+export interface QueryDslRankFeatureFunctionSaturation extends QueryDslRankFeatureFunction {
+  pivot?: float
+}
+
+export interface QueryDslRankFeatureFunctionSigmoid extends QueryDslRankFeatureFunction {
+  pivot: float
+  exponent: float
+}
+
 export interface QueryDslRankFeatureQuery extends QueryDslQueryBase {
-  function?: QueryDslRankFeatureFunction
+  field: Field
+  saturation?: QueryDslRankFeatureFunctionSaturation
+  log?: QueryDslRankFeatureFunctionLogarithm
+  linear?: QueryDslRankFeatureFunctionLinear
+  sigmoid?: QueryDslRankFeatureFunctionSigmoid
 }
 
 export interface QueryDslRegexpQuery extends QueryDslQueryBase {
+  case_insensitive?: boolean
   flags?: string
   max_determinized_states?: integer
-  value?: string
+  rewrite?: MultiTermQueryRewrite
+  value: string
 }
 
 export interface QueryDslScoreFunctionBase {
@@ -4572,7 +4635,7 @@ export interface QueryDslScoreFunctionBase {
 }
 
 export interface QueryDslScriptQuery extends QueryDslQueryBase {
-  script?: Script
+  script: Script
 }
 
 export interface QueryDslScriptScoreFunction extends QueryDslScoreFunctionBase {
@@ -4580,16 +4643,22 @@ export interface QueryDslScriptScoreFunction extends QueryDslScoreFunctionBase {
 }
 
 export interface QueryDslScriptScoreQuery extends QueryDslQueryBase {
-  query?: QueryDslQueryContainer
-  script?: Script
+  min_score?: float
+  query: QueryDslQueryContainer
+  script: Script
 }
 
-export interface QueryDslShapeQuery extends QueryDslQueryBase {
+export interface QueryDslShapeFieldQuery {
   ignore_unmapped?: boolean
   indexed_shape?: QueryDslFieldLookup
   relation?: ShapeRelation
-  shape?: QueryDslGeoShape
+  shape?: GeoShape
+}
+
+export interface QueryDslShapeQueryKeys extends QueryDslQueryBase {
 }
+export type QueryDslShapeQuery = QueryDslShapeQueryKeys |
+    { [property: string]: QueryDslShapeFieldQuery }
 
 export type QueryDslSimpleQueryStringFlags = 'NONE' | 'AND' | 'OR' | 'NOT' | 'PREFIX' | 'PHRASE' | 'PRECEDENCE' | 'ESCAPE' | 'WHITESPACE' | 'FUZZY' | 'NEAR' | 'SLOP' | 'ALL'
 
@@ -4598,70 +4667,65 @@ export interface QueryDslSimpleQueryStringQuery extends QueryDslQueryBase {
   analyze_wildcard?: boolean
   auto_generate_synonyms_phrase_query?: boolean
   default_operator?: QueryDslOperator
-  fields?: Fields
+  fields?: Field[]
   flags?: QueryDslSimpleQueryStringFlags | string
   fuzzy_max_expansions?: integer
   fuzzy_prefix_length?: integer
   fuzzy_transpositions?: boolean
   lenient?: boolean
   minimum_should_match?: MinimumShouldMatch
-  query?: string
+  query: string
   quote_field_suffix?: string
 }
 
 export interface QueryDslSpanContainingQuery extends QueryDslQueryBase {
-  big?: QueryDslSpanQuery
-  little?: QueryDslSpanQuery
+  big: QueryDslSpanQuery
+  little: QueryDslSpanQuery
 }
 
 export interface QueryDslSpanFieldMaskingQuery extends QueryDslQueryBase {
-  field?: Field
-  query?: QueryDslSpanQuery
+  field: Field
+  query: QueryDslSpanQuery
 }
 
 export interface QueryDslSpanFirstQuery extends QueryDslQueryBase {
-  end?: integer
-  match?: QueryDslSpanQuery
-}
-
-export interface QueryDslSpanGapQuery extends QueryDslQueryBase {
-  field?: Field
-  width?: integer
+  end: integer
+  match: QueryDslSpanQuery
 }
 
 export interface QueryDslSpanMultiTermQuery extends QueryDslQueryBase {
-  match?: QueryDslQueryContainer
+  match: QueryDslQueryContainer
 }
 
 export interface QueryDslSpanNearQuery extends QueryDslQueryBase {
-  clauses?: QueryDslSpanQuery[]
+  clauses: QueryDslSpanQuery[]
   in_order?: boolean
   slop?: integer
 }
 
 export interface QueryDslSpanNotQuery extends QueryDslQueryBase {
   dist?: integer
-  exclude?: QueryDslSpanQuery
-  include?: QueryDslSpanQuery
+  exclude: QueryDslSpanQuery
+  include: QueryDslSpanQuery
   post?: integer
   pre?: integer
 }
 
 export interface QueryDslSpanOrQuery extends QueryDslQueryBase {
-  clauses?: QueryDslSpanQuery[]
+  clauses: QueryDslSpanQuery[]
 }
 
-export interface QueryDslSpanQuery extends QueryDslQueryBase {
-  span_containing?: QueryDslNamedQuery<QueryDslSpanContainingQuery | string>
-  field_masking_span?: QueryDslNamedQuery<QueryDslSpanFieldMaskingQuery | string>
-  span_first?: QueryDslNamedQuery<QueryDslSpanFirstQuery | string>
-  span_gap?: QueryDslNamedQuery<QueryDslSpanGapQuery | integer>
+export interface QueryDslSpanQuery {
+  span_containing?: QueryDslSpanContainingQuery
+  field_masking_span?: QueryDslSpanFieldMaskingQuery
+  span_first?: QueryDslSpanFirstQuery
+  span_gap?: Record<Field, integer>
   span_multi?: QueryDslSpanMultiTermQuery
-  span_near?: QueryDslNamedQuery<QueryDslSpanNearQuery | string>
-  span_not?: QueryDslNamedQuery<QueryDslSpanNotQuery | string>
-  span_or?: QueryDslNamedQuery<QueryDslSpanOrQuery | string>
-  span_term?: QueryDslNamedQuery<QueryDslSpanTermQuery | string>
-  span_within?: QueryDslNamedQuery<QueryDslSpanWithinQuery | string>
+  span_near?: QueryDslSpanNearQuery
+  span_not?: QueryDslSpanNotQuery
+  span_or?: QueryDslSpanOrQuery
+  span_term?: Record<Field, QueryDslSpanTermQuery | string>
+  span_within?: QueryDslSpanWithinQuery
 }
 
 export interface QueryDslSpanTermQuery extends QueryDslQueryBase {
@@ -4669,27 +4733,37 @@ export interface QueryDslSpanTermQuery extends QueryDslQueryBase {
 }
 
 export interface QueryDslSpanWithinQuery extends QueryDslQueryBase {
-  big?: QueryDslSpanQuery
-  little?: QueryDslSpanQuery
+  big: QueryDslSpanQuery
+  little: QueryDslSpanQuery
 }
 
 export interface QueryDslTermQuery extends QueryDslQueryBase {
-  value?: string | float | boolean
+  value: string | float | boolean
+  case_insensitive?: boolean
 }
 
-export interface QueryDslTermsQuery extends QueryDslQueryBase {
-  terms?: string[]
-  index?: IndexName
-  id?: Id
-  path?: string
+export interface QueryDslTermsLookup {
+  index: IndexName
+  id: Id
+  path: Field
   routing?: Routing
 }
 
-export interface QueryDslTermsSetQuery extends QueryDslQueryBase {
+export interface QueryDslTermsQueryKeys extends QueryDslQueryBase {
+}
+export type QueryDslTermsQuery = QueryDslTermsQueryKeys |
+    { [property: string]: string[] | long[] | QueryDslTermsLookup }
+
+export interface QueryDslTermsSetFieldQuery {
   minimum_should_match_field?: Field
   minimum_should_match_script?: Script
-  terms?: string[]
+  terms: string[]
+}
+
+export interface QueryDslTermsSetQueryKeys extends QueryDslQueryBase {
 }
+export type QueryDslTermsSetQuery = QueryDslTermsSetQueryKeys |
+    { [property: string]: QueryDslTermsSetFieldQuery }
 
 export type QueryDslTextQueryType = 'best_fields' | 'most_fields' | 'cross_fields' | 'phrase' | 'phrase_prefix' | 'bool_prefix'
 
@@ -4709,6 +4783,7 @@ export interface QueryDslTypeQuery extends QueryDslQueryBase {
 }
 
 export interface QueryDslWildcardQuery extends QueryDslQueryBase {
+  case_insensitive?: boolean
   rewrite?: MultiTermQueryRewrite
   value: string
 }
@@ -4809,7 +4884,7 @@ export interface AsyncSearchSubmitRequest extends RequestBase {
     rescore?: SearchRescore[]
     routing?: Routing
     script_fields?: Record<string, ScriptField>
-    search_after?: any[]
+    search_after?: SearchSortResults
     search_type?: SearchType
     sequence_number_primary_term?: boolean
     size?: integer
@@ -8480,7 +8555,6 @@ export interface IndicesDataStreamsStatsDataStreamsStatsItem {
 export interface IndicesDataStreamsStatsRequest extends RequestBase {
   name?: IndexName
   expand_wildcards?: ExpandWildcards
-  human?: boolean
 }
 
 export interface IndicesDataStreamsStatsResponse {
@@ -10057,20 +10131,21 @@ export interface MigrationDeprecationInfoResponse {
 
 export interface MlAnalysisConfig {
   bucket_span: TimeSpan
+  categorization_analyzer?: MlCategorizationAnalyzer | string
   categorization_field_name?: Field
   categorization_filters?: string[]
   detectors: MlDetector[]
-  influencers: Field[]
+  influencers?: Field[]
+  model_prune_window?: Time
   latency?: Time
   multivariate_by_fields?: boolean
   per_partition_categorization?: MlPerPartitionCategorization
   summary_count_field_name?: Field
-  categorization_analyzer?: MlCategorizationAnalyzer | string
 }
 
 export interface MlAnalysisLimits {
   categorization_examples_limit?: long
-  model_memory_limit: string
+  model_memory_limit?: string
 }
 
 export interface MlAnalysisMemoryLimit {
@@ -10158,9 +10233,9 @@ export interface MlCalendarEvent {
 }
 
 export interface MlCategorizationAnalyzer {
+  char_filter?: (string | AnalysisCharFilter)[]
   filter?: (string | AnalysisTokenFilter)[]
   tokenizer?: string | AnalysisTokenizer
-  char_filter?: (string | AnalysisCharFilter)[]
 }
 
 export type MlCategorizationStatus = 'ok' | 'warn'
@@ -10191,26 +10266,28 @@ export type MlChunkingMode = 'auto' | 'manual' | 'off'
 
 export type MlConditionOperator = 'gt' | 'gte' | 'lt' | 'lte'
 
-export interface MlCustomSettings {
+export interface MlCustomSettingsKeys {
   custom_urls?: XpackUsageUrlConfig[]
   created_by?: string
   job_tags?: Record<string, string>
 }
+export type MlCustomSettings = MlCustomSettingsKeys |
+    { [property: string]: any }
 
 export interface MlDataCounts {
   bucket_count: long
-  earliest_record_timestamp: long
+  earliest_record_timestamp?: long
   empty_bucket_count: long
   input_bytes: long
   input_field_count: long
   input_record_count: long
   invalid_date_count: long
   job_id: Id
-  last_data_time: long
-  latest_empty_bucket_timestamp: long
-  latest_record_timestamp: long
-  latest_sparse_bucket_timestamp: long
-  latest_bucket_timestamp: long
+  last_data_time?: long
+  latest_empty_bucket_timestamp?: long
+  latest_record_timestamp?: long
+  latest_sparse_bucket_timestamp?: long
+  latest_bucket_timestamp?: long
   missing_field_count: long
   out_of_order_timestamp_count: long
   processed_field_count: long
@@ -10244,6 +10321,25 @@ export interface MlDatafeed {
   indices_options?: MlDatafeedIndicesOptions
 }
 
+export interface MlDatafeedConfig {
+  aggregations?: Record<string, AggregationsAggregationContainer>
+  aggs?: Record<string, AggregationsAggregationContainer>
+  chunking_config?: MlChunkingConfig
+  datafeed_id?: Id
+  delayed_data_check_config?: MlDelayedDataCheckConfig
+  frequency?: Timestamp
+  indexes?: Indices
+  indices?: Indices
+  indices_options?: MlDatafeedIndicesOptions
+  job_id?: Id
+  max_empty_searches?: integer
+  query?: QueryDslQueryContainer
+  query_delay?: Timestamp
+  runtime_mappings?: MappingRuntimeFields
+  script_fields?: Record<string, ScriptField>
+  scroll_size?: integer
+}
+
 export interface MlDatafeedIndicesOptions {
   allow_no_indices?: boolean
   expand_wildcards?: ExpandWildcards
@@ -10251,14 +10347,20 @@ export interface MlDatafeedIndicesOptions {
   ignore_throttled?: boolean
 }
 
+export interface MlDatafeedRunningState {
+  real_time_configured: boolean
+  real_time_running: boolean
+}
+
 export type MlDatafeedState = 'started' | 'stopped' | 'starting' | 'stopping'
 
 export interface MlDatafeedStats {
-  assignment_explanation: string
+  assignment_explanation?: string
   datafeed_id: Id
-  node: MlDiscoveryNode
+  node?: MlDiscoveryNode
   state: MlDatafeedState
   timing_stats: MlDatafeedTimingStats
+  running_state?: MlDatafeedRunningState
 }
 
 export interface MlDatafeedTimingStats {
@@ -10267,7 +10369,7 @@ export interface MlDatafeedTimingStats {
   job_id: Id
   search_count: long
   total_search_time_ms: double
-  average_search_time_per_bucket_ms: number
+  average_search_time_per_bucket_ms?: number
 }
 
 export interface MlDataframeAnalysis {
@@ -10532,10 +10634,11 @@ export interface MlDetector {
   detector_index?: integer
   exclude_frequent?: MlExcludeFrequent
   field_name?: Field
-  function: string
-  use_null?: boolean
+  function?: string
   over_field_name?: Field
   partition_field_name?: Field
+  use_null?: boolean
+  description?: string
 }
 
 export interface MlDiscoveryNode {
@@ -10556,7 +10659,7 @@ export interface MlFilter {
 
 export interface MlFilterRef {
   filter_id: Id
-  filter_type: MlFilterType
+  filter_type?: MlFilterType
 }
 
 export type MlFilterType = 'include' | 'exclude'
@@ -10592,27 +10695,56 @@ export interface MlInfluence {
 }
 
 export interface MlJob {
-  allow_lazy_open?: boolean
+  allow_lazy_open: boolean
   analysis_config: MlAnalysisConfig
   analysis_limits?: MlAnalysisLimits
-  background_persist_interval: Time
-  create_time: integer
+  background_persist_interval?: Time
+  blocked?: MlJobBlocked
+  create_time?: integer
+  custom_settings?: MlCustomSettings
+  daily_model_snapshot_retention_after_days?: long
   data_description: MlDataDescription
-  description: string
-  finished_time: integer
+  datafeed_config?: MlDatafeed
+  deleting?: boolean
+  description?: string
+  finished_time?: integer
+  groups?: string[]
   job_id: Id
-  job_type: string
-  model_snapshot_id: Id
+  job_type?: string
+  job_version?: VersionString
+  model_plot_config?: MlModelPlotConfig
+  model_snapshot_id?: Id
   model_snapshot_retention_days: long
-  renormalization_window_days: long
-  results_index_name?: IndexName
+  renormalization_window_days?: long
+  results_index_name: IndexName
   results_retention_days?: long
-  groups?: string[]
-  model_plot_config?: MlModelPlotConfig
+}
+
+export interface MlJobBlocked {
+  reason: MlJobBlockedReason
+  task_id?: TaskId
+}
+
+export type MlJobBlockedReason = 'delete' | 'reset' | 'revert'
+
+export interface MlJobConfig {
+  allow_lazy_open?: boolean
+  analysis_config: MlAnalysisConfig
+  analysis_limits?: MlAnalysisLimits
+  background_persist_interval?: Time
   custom_settings?: MlCustomSettings
-  job_version?: VersionString
-  deleting?: boolean
   daily_model_snapshot_retention_after_days?: long
+  data_description: MlDataDescription
+  datafeed_config?: MlDatafeedConfig
+  description?: string
+  groups?: string[]
+  job_id?: Id
+  job_type?: string
+  model_plot_config?: MlModelPlotConfig
+  model_snapshot_retention_days?: long
+  renormalization_window_days?: long
+  results_index_name?: IndexName
+  results_retention_days?: long
 }
 
 export interface MlJobForecastStatistics {
@@ -10634,12 +10766,12 @@ export interface MlJobStatistics {
 }
 
 export interface MlJobStats {
-  assignment_explanation: string
+  assignment_explanation?: string
   data_counts: MlDataCounts
   forecasts_stats: MlJobForecastStatistics
   job_id: string
   model_size_stats: MlModelSizeStats
-  node: MlDiscoveryNode
+  node?: MlDiscoveryNode
   open_time?: DateString
   state: MlJobState
   timing_stats: MlJobTimingStats
@@ -10647,22 +10779,22 @@ export interface MlJobStats {
 }
 
 export interface MlJobTimingStats {
-  average_bucket_processing_time_ms: double
+  average_bucket_processing_time_ms?: double
   bucket_count: long
-  exponential_average_bucket_processing_time_ms: double
+  exponential_average_bucket_processing_time_ms?: double
   exponential_average_bucket_processing_time_per_hour_ms: double
   job_id: Id
   total_bucket_processing_time_ms: double
-  maximum_bucket_processing_time_ms: double
-  minimum_bucket_processing_time_ms: double
+  maximum_bucket_processing_time_ms?: double
+  minimum_bucket_processing_time_ms?: double
 }
 
 export type MlMemoryStatus = 'ok' | 'soft_limit' | 'hard_limit'
 
 export interface MlModelPlotConfig {
-  terms?: Field
-  enabled: boolean
   annotations_enabled?: boolean
+  enabled?: boolean
+  terms?: Field
 }
 
 export interface MlModelSizeStats {
@@ -10671,9 +10803,9 @@ export interface MlModelSizeStats {
   log_time: Time
   memory_status: MlMemoryStatus
   model_bytes: long
-  model_bytes_exceeded: long
-  model_bytes_memory_limit: long
-  peak_model_bytes: long
+  model_bytes_exceeded?: long
+  model_bytes_memory_limit?: long
+  peak_model_bytes?: long
   assignment_memory_basis?: string
   result_type: string
   total_by_field_count: long
@@ -10692,10 +10824,10 @@ export interface MlModelSizeStats {
 export interface MlModelSnapshot {
   description?: string
   job_id: Id
-  latest_record_time_stamp: integer
-  latest_result_time_stamp: integer
+  latest_record_time_stamp?: integer
+  latest_result_time_stamp?: integer
   min_version: VersionString
-  model_size_stats: MlModelSizeStats
+  model_size_stats?: MlModelSizeStats
   retain: boolean
   snapshot_doc_count: long
   snapshot_id: Id
@@ -10962,7 +11094,7 @@ export interface MlEvaluateDataFrameConfusionMatrixPrediction {
   count: integer
 }
 
-export interface MlEvaluateDataFrameConfusionMatrixTreshold {
+export interface MlEvaluateDataFrameConfusionMatrixThreshold {
   tp: integer
   fp: integer
   tn: integer
@@ -11019,7 +11151,7 @@ export interface MlEvaluateDataFrameDataframeOutlierDetectionSummary {
   auc_roc?: MlEvaluateDataFrameDataframeEvaluationSummaryAucRoc
   precision?: Record<string, double>
   recall?: Record<string, double>
-  confusion_matrix?: Record<string, MlEvaluateDataFrameConfusionMatrixTreshold>
+  confusion_matrix?: Record<string, MlEvaluateDataFrameConfusionMatrixThreshold>
 }
 
 export interface MlEvaluateDataFrameDataframeRegressionSummary {
@@ -11418,6 +11550,7 @@ export interface MlOpenJobRequest extends RequestBase {
 
 export interface MlOpenJobResponse {
   opened: boolean
+  node: Id
 }
 
 export interface MlPostCalendarEventsRequest extends RequestBase {
@@ -11431,18 +11564,22 @@ export interface MlPostCalendarEventsResponse {
   events: MlCalendarEvent[]
 }
 
-export interface MlPostJobDataRequest extends RequestBase {
+export type MlPostDataInput = any | MlPostDataMultipleInputs
+
+export interface MlPostDataMultipleInputs {
+  data: any[]
+}
+
+export interface MlPostDataRequest extends RequestBase {
   job_id: Id
   reset_end?: DateString
   reset_start?: DateString
-  body?: {
-    data?: any[]
-  }
+  body?: MlPostDataInput
 }
 
-export interface MlPostJobDataResponse {
+export interface MlPostDataResponse {
   bucket_count: long
-  earliest_record_timestamp: integer
+  earliest_record_timestamp?: integer
   empty_bucket_count: long
   input_bytes: long
   input_field_count: long
@@ -11450,7 +11587,7 @@ export interface MlPostJobDataResponse {
   invalid_date_count: long
   job_id: Id
   last_data_time: integer
-  latest_record_timestamp: integer
+  latest_record_timestamp?: integer
   missing_field_count: long
   out_of_order_timestamp_count: long
   processed_field_count: long
@@ -11480,25 +11617,24 @@ export interface MlPreviewDataFrameAnalyticsResponse {
 export interface MlPreviewDatafeedRequest extends RequestBase {
   datafeed_id?: Id
   body?: {
-    job_config?: MlJob
-    datafeed_config?: MlDatafeed
+    job_config?: MlJobConfig
+    datafeed_config?: MlDatafeedConfig
   }
 }
 
-export interface MlPreviewDatafeedResponse<TDocument = unknown> {
-  data: TDocument[]
-}
+export type MlPreviewDatafeedResponse<TDocument = unknown> = TDocument[]
 
 export interface MlPutCalendarRequest extends RequestBase {
   calendar_id: Id
   body?: {
+    job_ids?: Ids
     description?: string
   }
 }
 
 export interface MlPutCalendarResponse {
   calendar_id: Id
-  description: string
+  description?: string
   job_ids: Ids
 }
 
@@ -11548,12 +11684,13 @@ export interface MlPutDatafeedRequest extends RequestBase {
   ignore_throttled?: boolean
   ignore_unavailable?: boolean
   body?: {
+    aggs?: Record<string, AggregationsAggregationContainer>
     aggregations?: Record<string, AggregationsAggregationContainer>
     chunking_config?: MlChunkingConfig
     delayed_data_check_config?: MlDelayedDataCheckConfig
     frequency?: Time
-    indices?: string[]
-    indexes?: string[]
+    indices?: Indices
+    indexes?: Indices
     indices_options?: MlDatafeedIndicesOptions
     job_id?: Id
     max_empty_searches?: integer
@@ -11566,15 +11703,15 @@ export interface MlPutDatafeedRequest extends RequestBase {
 }
 
 export interface MlPutDatafeedResponse {
-  aggregations: Record<string, AggregationsAggregationContainer>
+  aggregations?: Record<string, AggregationsAggregationContainer>
   chunking_config: MlChunkingConfig
   delayed_data_check_config?: MlDelayedDataCheckConfig
   datafeed_id: Id
-  frequency: Time
+  frequency?: Time
   indices: string[]
   job_id: Id
   indices_options?: MlDatafeedIndicesOptions
-  max_empty_searches: integer
+  max_empty_searches?: integer
   query: QueryDslQueryContainer
   query_delay: Time
   runtime_mappings?: MappingRuntimeFields
@@ -11591,7 +11728,7 @@ export interface MlPutFilterRequest extends RequestBase {
 }
 
 export interface MlPutFilterResponse {
-  description: string
+  description?: string
   filter_id: Id
   items: string[]
 }
@@ -11604,12 +11741,14 @@ export interface MlPutJobRequest extends RequestBase {
     analysis_limits?: MlAnalysisLimits
     background_persist_interval: Time
     custom_settings?: MlCustomSettings
-    data_description?: MlDataDescription
     daily_model_snapshot_retention_after_days?: long
-    groups?: string[]
+    data_description: MlDataDescription
+    datafeed_config?: MlDatafeedConfig
     description?: string
+    groups?: string[]
     model_plot_config?: MlModelPlotConfig
     model_snapshot_retention_days?: long
+    renormalization_window_days?: long
     results_index_name?: IndexName
     results_retention_days?: long
   }
@@ -11618,20 +11757,22 @@ export interface MlPutJobRequest extends RequestBase {
 export interface MlPutJobResponse {
   allow_lazy_open: boolean
   analysis_config: MlAnalysisConfig
-  analysis_limits?: MlAnalysisLimits
-  background_persist_interval: Time
+  analysis_limits: MlAnalysisLimits
+  background_persist_interval?: Time
   create_time: DateString
   custom_settings?: MlCustomSettings
+  daily_model_snapshot_retention_after_days: long
   data_description: MlDataDescription
-  daily_model_snapshot_retention_after_days?: long
+  datafeed_config?: MlDatafeed
+  description?: string
   groups?: string[]
-  description: string
   job_id: Id
   job_type: string
+  job_version: string
   model_plot_config?: MlModelPlotConfig
-  model_snapshot_id: Id
+  model_snapshot_id?: Id
   model_snapshot_retention_days: long
-  renormalization_window_days: long
+  renormalization_window_days?: long
   results_index_name: string
   results_retention_days?: long
 }
@@ -11656,9 +11797,18 @@ export interface MlPutTrainedModelAliasRequest extends RequestBase {
 export interface MlPutTrainedModelAliasResponse extends AcknowledgedResponseBase {
 }
 
+export interface MlResetJobRequest extends RequestBase {
+  job_id: Id
+  wait_for_completion?: boolean
+}
+
+export interface MlResetJobResponse extends AcknowledgedResponseBase {
+}
+
 export interface MlRevertModelSnapshotRequest extends RequestBase {
   job_id: Id
   snapshot_id: Id
+  delete_intervening_results?: boolean
   body?: {
     delete_intervening_results?: boolean
   }
@@ -11785,7 +11935,27 @@ export interface MlUpdateJobRequest extends RequestBase {
 }
 
 export interface MlUpdateJobResponse {
-  stub: boolean
+  allow_lazy_open: boolean
+  analysis_config: MlAnalysisConfig
+  analysis_limits: MlAnalysisLimits
+  background_persist_interval?: Time
+  create_time: Time
+  custom_settings?: MlCustomSettings
+  daily_model_snapshot_retention_after_days: long
+  data_description: MlDataDescription
+  datafeed_config?: MlDatafeed
+  description?: string
+  groups?: string[]
+  job_id: Id
+  job_type: string
+  job_version: string
+  finished_time?: Time
+  model_plot_config?: MlModelPlotConfig
+  model_snapshot_id?: Id
+  model_snapshot_retention_days: long
+  renormalization_window_days?: long
+  results_index_name: string
+  results_retention_days?: long
 }
 
 export interface MlUpdateModelSnapshotRequest extends RequestBase {
@@ -15270,6 +15440,9 @@ export interface SpecUtilsCommonQueryParameters {
   source_query_string?: string
 }
 
+export interface SpecUtilsAdditionalProperty<TKey = unknown, TValue = unknown> {
+}
+
 export interface SpecUtilsCommonCatQueryParameters {
   format?: string
   h?: Names
diff --git a/docs/basic-config.asciidoc b/docs/basic-config.asciidoc
index e4e1d301..c800b38c 100644
--- a/docs/basic-config.asciidoc
+++ b/docs/basic-config.asciidoc
@@ -255,6 +255,10 @@ const client = new Client({
 |`boolean`, `'proto'`, `'constructor'` - By the default the client will protect you against prototype poisoning attacks. Read https://web.archive.org/web/20200319091159/https://hueniverse.com/square-brackets-are-the-enemy-ff5b9fd8a3e8?gi=184a27ee2a08[this article] to learn more. If needed you can disable prototype poisoning protection entirely or one of the two checks. Read the `secure-json-parse` https://github.com/fastify/secure-json-parse[documentation] to learn more. +
 _Default:_ `false`
 
+|`caFingerprint`
+|`string` - If configured, verify that the fingerprint of the CA certificate that has signed the certificate of the server matches the supplied fingerprint. Only accepts SHA256 digest fingerprints. +
+_Default:_ `null`
+
 |===
 
 [discrete]
@@ -276,4 +280,3 @@ const client = new Client({
   disablePrototypePoisoningProtection: true
 })
 ----
-
diff --git a/docs/changelog.asciidoc b/docs/changelog.asciidoc
index c8a59893..6fd03842 100644
--- a/docs/changelog.asciidoc
+++ b/docs/changelog.asciidoc
@@ -1,6 +1,59 @@
 [[changelog-client]]
 == Release notes
 
+[discrete]
+=== 7.14.0
+
+[discrete]
+==== Features
+
+[discrete]
+===== Support for Elasticsearch `v7.14`
+
+You can find all the API changes
+https://www.elastic.co/guide/en/elasticsearch/reference/7.14/release-notes-7.14.0.html[here].
+
+[discrete]
+===== Verify connection to Elasticsearch https://github.com/elastic/elasticsearch-js/pull/1487[#1487]
+
+The client will verify if it's working with a supported release of Elasticsearch.
+Elastic language clients are guaranteed to be able to communicate with Elasticsearch or Elastic solutions running on the same major version and greater or equal minor version.
+
+Language clients are forward compatible; meaning that clients support communicating with greater minor versions of Elasticsearch. Elastic language clients are not guaranteed to be backwards compatible.
+
+[discrete]
+===== Add api compatibility header support https://github.com/elastic/elasticsearch-js/pull/1478[#1478]
+
+If you configure the `ELASTIC_CLIENT_APIVERSIONING` to `true` the client will send a compatibility header
+to allow you to use a 7.x client against a 8.x cluster. In this way it will be easier to migrate your code to a newer release of Elasticsearch.
+
+[discrete]
+===== Add support for bearer auth https://github.com/elastic/elasticsearch-js/pull/1488[#1488]
+
+Bearer authentication, useful for https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-service-token.html[service account tokens].
+Be aware that it does not handle automatic token refresh:
+
+[source,js]
+----
+auth: {
+  bearer: 'token'
+}
+----
+
+[discrete]
+===== Bulk update improvements https://github.com/elastic/elasticsearch-js/pull/1428[#1428]
+
+The final stats object will let you know how many `noop` operations happened.
+Also, a new `.stats` getter has been added to allow you to read the stats before
+the operation finishes.
+
+[source,js]
+----
+const b = client.helpers.bulk({ ... })
+...
+console.log(b.stats)
+----
+
 [discrete]
 === 7.13.0
 
@@ -10,7 +63,7 @@
 [discrete]
 ===== Remove Node.js v10 support https://github.com/elastic/elasticsearch-js/pull/1471[#1471]
 
-According to our 
+According to our
 https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/installation.html#nodejs-support[support matrix].
 
 [discrete]
@@ -19,7 +72,7 @@ https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/inst
 [discrete]
 ===== Support for Elasticsearch `v7.13`
 
-You can find all the API changes 
+You can find all the API changes
 https://www.elastic.co/guide/en/elasticsearch/reference/7.13/release-notes-7.13.0.html[here].
 
 [discrete]
@@ -56,7 +109,7 @@ This is now fixed and in case of error you will get the full body response.
 [discrete]
 ===== Remove Node.js v8 support https://github.com/elastic/elasticsearch-js/pull/1402[#1402]
 
-According to our 
+According to our
 https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/installation.html#nodejs-support[support matrix].
 
 [discrete]
@@ -65,7 +118,7 @@ https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/inst
 [discrete]
 ===== Support for Elasticsearch `v7.12`
 
-You can find all the API changes 
+You can find all the API changes
 https://www.elastic.co/guide/en/elasticsearch/reference/7.12/release-notes-7.12.0.html[here].
 
 [discrete]
@@ -91,15 +144,15 @@ Now the thenable offers a `.finally` method as well.
 [discrete]
 ===== Support for Elasticsearch `v7.11`
 
-You can find all the API changes 
+You can find all the API changes
 https://www.elastic.co/guide/en/elasticsearch/reference/7.11/release-notes-7.11.0.html[here].
 
 [discrete]
 ===== Added new observability events https://github.com/elastic/elasticsearch-js/pull/1365[#1365]
 
-Two new observability events has been introduced: `serialization` and 
-`deserialization`. The event order is described in the following graph, in some 
-edge cases, the order is not guaranteed. You can find in 
+Two new observability events has been introduced: `serialization` and
+`deserialization`. The event order is described in the following graph, in some
+edge cases, the order is not guaranteed. You can find in
 https://github.com/elastic/elasticsearch-js/blob/master/test/acceptance/events-order.test.js[`test/acceptance/events-order.test.js`]
 how the order changes based on the situation.
 
@@ -122,7 +175,7 @@ serialization
 [discrete]
 ===== Added x-elastic-client-meta header https://github.com/elastic/elasticsearch-js/pull/1373[#1373]
 
-Adds the `x-elastic-client-meta` HTTP header which is used by Elastic Cloud and 
+Adds the `x-elastic-client-meta` HTTP header which is used by Elastic Cloud and
 can be disabled with the `enableMetaHeader` parameter set to `false`.
 
 [discrete]
@@ -131,9 +184,9 @@ can be disabled with the `enableMetaHeader` parameter set to `false`.
 [discrete]
 ===== Fixes req.abort() with a body that is a stream calls callback(err) twice https://github.com/elastic/elasticsearch-js/pull/1376[#1376]
 
-When using a body that is a stream to client.search(), and calling req.abort(), 
-the callback is called twice. Once for the RequestAbortedError, as expected, and 
-once for a "premature close" error from end-of-stream, used by pump, used by the 
+When using a body that is a stream to client.search(), and calling req.abort(),
+the callback is called twice. Once for the RequestAbortedError, as expected, and
+once for a "premature close" error from end-of-stream, used by pump, used by the
 client. This issue has now been fixed.
 
 [discrete]
@@ -145,14 +198,14 @@ client. This issue has now been fixed.
 [discrete]
 ===== Support for Elasticsearch `v7.10`.
 
-You can find all the API changes 
+You can find all the API changes
 https://www.elastic.co/guide/en/elasticsearch/reference/7.10/release-notes-7.10.0.html[here].
 
 [discrete]
 =====  Added proxy support https://github.com/elastic/elasticsearch-js/pull/1260[#1260]
 
-If you need to pass through an http(s) proxy for connecting to {es}, the client 
-offers out of the box a handy configuration for helping you with it. Under the 
+If you need to pass through an http(s) proxy for connecting to {es}, the client
+offers out of the box a handy configuration for helping you with it. Under the
 hood it uses the https://github.com/delvedor/hpagent[`hpagent`] module.
 
 [source,js]
@@ -179,15 +232,15 @@ const client = new Client({
 [discrete]
 ===== Scroll search should clear the scroll at the end https://github.com/elastic/elasticsearch-js/pull/1331[#1331]
 
-From now on the scroll search helper will automatically close the scroll on 
+From now on the scroll search helper will automatically close the scroll on
 {es}, by doing so, {es} will free resources faster.
 
 [discrete]
 ===== Handle connectivity issues while reading the body https://github.com/elastic/elasticsearch-js/pull/1343[#1343]
 
-It might happen that the underlying socket stops working due to an external 
-cause while reading the body. This could lead to an unwanted 
-`DeserialzationError`. From now, this will be handled as a generic 
+It might happen that the underlying socket stops working due to an external
+cause while reading the body. This could lead to an unwanted
+`DeserialzationError`. From now, this will be handled as a generic
 `ConnectionError`.
 
 [discrete]
@@ -196,13 +249,13 @@ cause while reading the body. This could lead to an unwanted
 [discrete]
 ===== Add warning log about nodejs version support https://github.com/elastic/elasticsearch-js/pull/1349[#1349]
 
-`7.11` will be the last version of the client that will support Node.js v8, 
-while `7.12` will be the last one that supports Node.js v10. If you are eusing 
-this versions you will see a `DeprecationWaring` in your logs. We strongly 
-recommend to upgrade to newer versions of Node.js as usng an EOL version will 
+`7.11` will be the last version of the client that will support Node.js v8,
+while `7.12` will be the last one that supports Node.js v10. If you are using
+this versions you will see a `DeprecationWaring` in your logs. We strongly
+recommend to upgrade to newer versions of Node.js as usng an EOL version will
 expose you to securty risks.
 
-Please refer to https://ela.st/nodejs-support[ela.st/nodejs-support] for 
+Please refer to https://ela.st/nodejs-support[ela.st/nodejs-support] for
 additional information.
 
 [discrete]
@@ -214,16 +267,16 @@ additional information.
 [discrete]
 ===== Improve child performances https://github.com/elastic/elasticsearch-js/pull/1314[#1314]
 
-The client code has been refactored to speed up the performances of the child 
-method. Before this pr, creating many children per second would have caused a 
-high memory consumption and a spike in CPU usage. This pr changes the way the 
-client is created by refactoring the code generation, now the clients methods 
-are no longer added to the instance with a for loop but via prototypal 
-inheritance. Thus, the overall performances are way better, now creating a child 
+The client code has been refactored to speed up the performances of the child
+method. Before this pr, creating many children per second would have caused a
+high memory consumption and a spike in CPU usage. This pr changes the way the
+client is created by refactoring the code generation, now the clients methods
+are no longer added to the instance with a for loop but via prototypal
+inheritance. Thus, the overall performances are way better, now creating a child
 is ~5 times faster, and it consumes ~70% less memory.
 
-This change should not cause any breaking change unless you were mocking the 
-client methods. In such case you should refactor it, or use 
+This change should not cause any breaking change unless you were mocking the
+client methods. In such case you should refactor it, or use
 https://github.com/elastic/elasticsearch-js-mock[elasticsearch-js-mock].
 
 Finally, this change should also fix once and of all the bundlers support.
@@ -231,15 +284,15 @@ Finally, this change should also fix once and of all the bundlers support.
 [discrete]
 ===== Throw all errors asynchronously https://github.com/elastic/elasticsearch-js/pull/1295[#1295]
 
-Some validation errors were thrown synchronously, causing the callback to be 
-called in th same tick. This issue is known as _"The release fo Zalgo"_ (see 
+Some validation errors were thrown synchronously, causing the callback to be
+called in th same tick. This issue is known as _"The release fo Zalgo"_ (see
 https://blog.izs.me/2013/08/designing-apis-for-asynchrony[here]).
 
 [discrete]
 ===== Fix `maxRetries` request option handling https://github.com/elastic/elasticsearch-js/pull/1296[#1296]
 
-The `maxRetries` parameter can be configured on a per requets basis, if set to 
-zero it was defaulting to the client default. Now the client is honoring the 
+The `maxRetries` parameter can be configured on a per requets basis, if set to
+zero it was defaulting to the client default. Now the client is honoring the
 request specific configuration.
 
 [discrete]
@@ -250,7 +303,7 @@ The Connection requets option types were not accepting `null` as valid value.
 [discrete]
 ===== Fixed `size` and `maxRetries` parameters in helpers https://github.com/elastic/elasticsearch-js/pull/1284[#1284]
 
-The `size` parameter was being passed too the scroll request, which was causing 
+The `size` parameter was being passed too the scroll request, which was causing
 an error. Value of `maxRetries` set to 0 was resulting in no request at all.
 
 [discrete]
@@ -276,8 +329,8 @@ const client = new Client({
 [discrete]
 ===== Add support for a global context option https://github.com/elastic/elasticsearch-js/pull/1256[#1256]
 
-Before this, you could set a `context` option in each request, but there was no 
-way of setting it globally. Now you can by configuring the `context` object in 
+Before this, you could set a `context` option in each request, but there was no
+way of setting it globally. Now you can by configuring the `context` object in
 the global configuration, that will be merged with the local one.
 
 [source,js]
@@ -305,7 +358,7 @@ import { Client } from '@elastic/elasticsearch'
 [discrete]
 ===== Allow the client name to be a symbol https://github.com/elastic/elasticsearch-js/pull/1254[#1254]
 
-It was possible in plain JavaScript, but not in TypeScript, now you can do it in 
+It was possible in plain JavaScript, but not in TypeScript, now you can do it in
 TypeScript as well.
 
 [source,js]
@@ -325,17 +378,17 @@ Only `Record<string, any>` was allowed. Now `string` is allowed as well.
 [discrete]
 ===== Fixed type definitions https://github.com/elastic/elasticsearch-js/pull/1263[#1263]
 
-* The `transport.request` defintion was incorrect, it was returning a 
+* The `transport.request` defintion was incorrect, it was returning a
   `Promise<T>` instead of `TransportRequestPromise<T>`.
-* The `refresh` parameter of most APIs was declared as 
-  `'true' | 'false' | 'wait_for'`, which was clunky. Now is 
+* The `refresh` parameter of most APIs was declared as
+  `'true' | 'false' | 'wait_for'`, which was clunky. Now is
   `'wait_for' | boolean`.
 
 [discrete]
 ===== Generate response type as boolean if the request is HEAD only https://github.com/elastic/elasticsearch-js/pull/1275[#1275]
 
-All HEAD request will have the body casted to a boolean value, `true` in case of 
-a 200 response, `false` in case of a 404 response. The type definitions were not 
+All HEAD request will have the body casted to a boolean value, `true` in case of
+a 200 response, `false` in case of a 404 response. The type definitions were not
 reflecting this behavior.
 
 [source,ts]
@@ -355,10 +408,10 @@ console.log(body) // either `true` or `false`
 [discrete]
 ===== Updated default http agent configuration https://github.com/elastic/elasticsearch-js/pull/1242[#1242]
 
-Added the scheduling: 'lifo' option to the default HTTP agent configuration to 
-avoid maximizing the open sockets against {es} and lowering the risk of 
-encountering socket timeouts. This feature is only available from Node v14.5+, 
-but it should be backported to v10 and v12 
+Added the scheduling: 'lifo' option to the default HTTP agent configuration to
+avoid maximizing the open sockets against {es} and lowering the risk of
+encountering socket timeouts. This feature is only available from Node v14.5+,
+but it should be backported to v10 and v12
 (https://github.com/nodejs/node/pull/33278[nodejs/node#33278]).
 
 [discrete]
@@ -366,12 +419,12 @@ but it should be backported to v10 and v12
 
 This pr introduce two changes which should not impact the surface API:
 
-* Refactored the `client.child` API to allocate fewer objects, this change 
-  improves memory consumption over time and improves the child creation 
+* Refactored the `client.child` API to allocate fewer objects, this change
+  improves memory consumption over time and improves the child creation
   performances by ~12%.
-* The client no longer inherits from the EventEmitter class, but instead has an 
-  internal event emitter and exposes only the API useful for the users, namely 
-  `emit, `on`, `once`, and `off`. The type definitions have been updated 
+* The client no longer inherits from the EventEmitter class, but instead has an
+  internal event emitter and exposes only the API useful for the users, namely
+  `emit, `on`, `once`, and `off`. The type definitions have been updated
   accordingly.
 
 [discrete]
@@ -388,10 +441,10 @@ You can find all the API changes https://www.elastic.co/guide/en/elasticsearch/r
 [discrete]
 =====  Added multi search helper https://github.com/elastic/elasticsearch-js/pull/1186[#1186]
 
-If you are sending search request at a high rate, this helper might be useful 
-for you. It will use the mutli search API under the hood to batch the requests 
-and improve the overall performances of your application. The `result` exposes a 
-`documents` property as well, which allows you to access directly the hits 
+If you are sending search request at a high rate, this helper might be useful
+for you. It will use the mutli search API under the hood to batch the requests
+and improve the overall performances of your application. The `result` exposes a
+`documents` property as well, which allows you to access directly the hits
 sources.
 
 [source,js]
@@ -423,10 +476,10 @@ m.search(
 [discrete]
 =====  Added timeout support in bulk and msearch helpers https://github.com/elastic/elasticsearch-js/pull/1206[#1206]
 
-If there is a slow producer, the bulk helper might send data with a very large 
-period of time, and if the process crashes for any reason, the data would be 
-lost. This pr introduces a `flushInterval` option in the bulk helper to avoid 
-this issue. By default, the bulk helper will flush the data automatically every 
+If there is a slow producer, the bulk helper might send data with a very large
+period of time, and if the process crashes for any reason, the data would be
+lost. This pr introduces a `flushInterval` option in the bulk helper to avoid
+this issue. By default, the bulk helper will flush the data automatically every
 30 seconds, unless the threshold has been reached before.
 
 [source,js]
@@ -436,8 +489,8 @@ const b = client.helpers.bulk({
 })
 ----
 
-The same problem might happen with the multi search helper, where the user is 
-not sending search requests fast enough. A `flushInterval` options has been 
+The same problem might happen with the multi search helper, where the user is
+not sending search requests fast enough. A `flushInterval` options has been
 added as well, with a default value of 500 milliseconds.
 
 [source,js]
@@ -453,16 +506,16 @@ const m = client.helpers.msearch({
 [discrete]
 =====  Use filter_path for improving the search helpers performances https://github.com/elastic/elasticsearch-js/pull/1199[#1199]
 
-From now on, all he search helpers will use the `filter_path` option 
-automatically when needed to retrieve only the hits source. This change will 
+From now on, all he search helpers will use the `filter_path` option
+automatically when needed to retrieve only the hits source. This change will
 result in less netwprk traffic and improved deserialization performances.
 
 [discrete]
 =====  Search helpers documents getter https://github.com/elastic/elasticsearch-js/pull/1186[#1186]
 
-Before this, the `documents` key that you can access in any search helper was 
-computed as soon as we got the search result from Elasticsearch. With this 
-change the `documents` key is now a getter, which makes this process lazy, 
+Before this, the `documents` key that you can access in any search helper was
+computed as soon as we got the search result from Elasticsearch. With this
+change the `documents` key is now a getter, which makes this process lazy,
 resulting in better performances and lower memory impact.
 
 [discrete]
@@ -474,8 +527,8 @@ resulting in better performances and lower memory impact.
 [discrete]
 ===== Disable client Helpers in Node.js < 10 - https://github.com/elastic/elasticsearch-js/pull/1194[#1194]
 
-The client helpers can't be used in Node.js < 10 because it needs a custom flag 
-to be able to use them. Given that not every provider allows the user to specify 
+The client helpers can't be used in Node.js < 10 because it needs a custom flag
+to be able to use them. Given that not every provider allows the user to specify
 custom Node.js flags, the Helpers has been disabled completely in Node.js < 10.
 
 [discrete]
@@ -493,16 +546,16 @@ will be no conflicts in case of the same header with different casing.
 [discrete]
 ===== Support for Elasticsearch `v7.7`.
 
-You can find all the API changes 
+You can find all the API changes
 https://www.elastic.co/guide/en/elasticsearch/reference/7.7/release-notes-7.7.0.html[here].
 
 [discrete]
 ===== Introduced client helpers - https://github.com/elastic/elasticsearch-js/pull/1107[#1107]
 
-From now on, the client comes with an handy collection of helpers to give you a 
+From now on, the client comes with an handy collection of helpers to give you a
 more comfortable experience with some APIs.
 
-CAUTION: The client helpers are experimental, and the API may change in the next 
+CAUTION: The client helpers are experimental, and the API may change in the next
 minor releases.
 
 The following helpers has been introduced:
@@ -515,16 +568,16 @@ The following helpers has been introduced:
 [discrete]
 ===== The `ConnectionPool.getConnection` now always returns a `Connection` - https://github.com/elastic/elasticsearch-js/pull/1127[#1127]
 
-What does this mean? It means that you will see less `NoLivingConnectionError`, 
-which now can only be caused if you set a selector/filter too strict. For 
-improving the debugging experience, the `NoLivingConnectionsError` error message 
+What does this mean? It means that you will see less `NoLivingConnectionError`,
+which now can only be caused if you set a selector/filter too strict. For
+improving the debugging experience, the `NoLivingConnectionsError` error message
 has been updated.
 
 [discrete]
 ===== Abortable promises - https://github.com/elastic/elasticsearch-js/pull/1141[#1141]
 
-From now on, it will be possible to abort a request generated with the 
-promise-styl API. If you abort a request generated from a promise, the promise 
+From now on, it will be possible to abort a request generated with the
+promise-styl API. If you abort a request generated from a promise, the promise
 will be rejected with a `RequestAbortedError`.
 
 
@@ -546,8 +599,8 @@ promise.abort()
 [discrete]
 ===== Major refactor of the Type Definitions - https://github.com/elastic/elasticsearch-js/pull/1119[#1119] https://github.com/elastic/elasticsearch-js/issues/1130[#1130] https://github.com/elastic/elasticsearch-js/pull/1132[#1132]
 
-Now every API makes better use of the generics and overloading, so you can (or 
-not, by default request/response bodies are `Record<string, any>`) define the 
+Now every API makes better use of the generics and overloading, so you can (or
+not, by default request/response bodies are `Record<string, any>`) define the
 request/response bodies in the generics.
 
 [source,ts]
@@ -560,10 +613,10 @@ client.search<SearchResponse>(...)
 client.search<SearchResponse, SearchBody>(...)
 ----
 
-This *should* not be a breaking change, as every generics defaults to `any`. It 
-might happen to some users that the code breaks, but our test didn't detect any 
-of it, probably because they were not robust enough. However, given the gigantic 
-improvement in the developer experience, we have decided to release this change 
+This *should* not be a breaking change, as every generics defaults to `any`. It
+might happen to some users that the code breaks, but our test didn't detect any
+of it, probably because they were not robust enough. However, given the gigantic
+improvement in the developer experience, we have decided to release this change
 in the 7.x line.
 
 [discrete]
@@ -572,35 +625,35 @@ in the 7.x line.
 [discrete]
 ===== The `ConnectionPool.update` method now cleans the `dead` list - https://github.com/elastic/elasticsearch-js/issues/1122[#1122] https://github.com/elastic/elasticsearch-js/pull/1127[#1127]
 
-It can happen in a situation where we are updating the connections list and 
-running sniff, leaving the `dead` list in a dirty state. Now the 
-`ConnectionPool.update` cleans up the `dead` list every time, which makes way 
+It can happen in a situation where we are updating the connections list and
+running sniff, leaving the `dead` list in a dirty state. Now the
+`ConnectionPool.update` cleans up the `dead` list every time, which makes way
 more sense given that all the new connections are alive.
 
 [discrete]
 ===== `ConnectionPoolmarkDead` should ignore connections that no longer exists - https://github.com/elastic/elasticsearch-js/pull/1159[#1159]
 
-It might happen that markDead is called just after a pool update, and in such 
-case, the client was adding the dead list a node that no longer exists, causing 
+It might happen that markDead is called just after a pool update, and in such
+case, the client was adding the dead list a node that no longer exists, causing
 unhandled exceptions later.
 
 [discrete]
 ===== Do not retry a request if the body is a stream - https://github.com/elastic/elasticsearch-js/pull/1143[#1143]
 
-The client should not retry if it's sending a stream body, because it should 
-store in memory a copy of the stream to be able to send it again, but since it 
-doesn't know in advance the size of the stream, it risks to take too much 
-memory. Furthermore, copying everytime the stream is very an expensive 
+The client should not retry if it's sending a stream body, because it should
+store in memory a copy of the stream to be able to send it again, but since it
+doesn't know in advance the size of the stream, it risks to take too much
+memory. Furthermore, copying everytime the stream is very an expensive
 operation.
 
 [discrete]
 ===== Return an error if the request has been aborted - https://github.com/elastic/elasticsearch-js/pull/1141[#1141]
 
-Until now, aborting a request was blocking the HTTP request, but never calling 
-the callback or resolving the promise to notify the user. This is a bug because 
-it could lead to dangerous memory leaks. From now on if the user calls the 
-`request.abort()` method, the callback style API will be called with a 
-`RequestAbortedError`, the promise will be rejected with `RequestAbortedError` 
+Until now, aborting a request was blocking the HTTP request, but never calling
+the callback or resolving the promise to notify the user. This is a bug because
+it could lead to dangerous memory leaks. From now on if the user calls the
+`request.abort()` method, the callback style API will be called with a
+`RequestAbortedError`, the promise will be rejected with `RequestAbortedError`
 as well.
 
 [discrete]
@@ -608,14 +661,14 @@ as well.
 
 **Fixes:**
 
-- Secure json parsing - 
+- Secure json parsing -
   https://github.com/elastic/elasticsearch-js/pull/1110[#1110]
-- ApiKey should take precedence over basic auth - 
+- ApiKey should take precedence over basic auth -
   https://github.com/elastic/elasticsearch-js/pull/1115[#1115]
 
 **Documentation:**
 
-- Fix typo in api reference - 
+- Fix typo in api reference -
   https://github.com/elastic/elasticsearch-js/pull/1109[#1109]
 
 [discrete]
@@ -628,22 +681,22 @@ Support for Elasticsearch `v7.6`.
 
 **Fixes:**
 
-- Skip compression in case of empty string body - 
+- Skip compression in case of empty string body -
   https://github.com/elastic/elasticsearch-js/pull/1080[#1080]
-- Fix typo in NoLivingConnectionsError - 
+- Fix typo in NoLivingConnectionsError -
   https://github.com/elastic/elasticsearch-js/pull/1045[#1045]
-- Change TransportRequestOptions.ignore to number[] - 
+- Change TransportRequestOptions.ignore to number[] -
   https://github.com/elastic/elasticsearch-js/pull/1053[#1053]
-- ClientOptions["cloud"] should have optional auth fields - 
+- ClientOptions["cloud"] should have optional auth fields -
   https://github.com/elastic/elasticsearch-js/pull/1032[#1032]
 
 **Documentation:**
 
-- Docs: Return super in example Transport subclass - 
+- Docs: Return super in example Transport subclass -
   https://github.com/elastic/elasticsearch-js/pull/980[#980]
-- Add examples to reference - 
+- Add examples to reference -
   https://github.com/elastic/elasticsearch-js/pull/1076[#1076]
-- Added new examples - 
+- Added new examples -
   https://github.com/elastic/elasticsearch-js/pull/1031[#1031]
 
 [discrete]
@@ -662,21 +715,21 @@ Support for Elasticsearch `v7.4`.
 
 **Fixes:**
 
-- Fix issue; node roles are defaulting to true when undefined is breaking usage 
-  of nodeFilter option - 
+- Fix issue; node roles are defaulting to true when undefined is breaking usage
+  of nodeFilter option -
   https://github.com/elastic/elasticsearch-js/pull/967[#967]
 
 **Documentation:**
 
-- Updated API reference doc - 
-  https://github.com/elastic/elasticsearch-js/pull/945[#945], 
+- Updated API reference doc -
+  https://github.com/elastic/elasticsearch-js/pull/945[#945],
   https://github.com/elastic/elasticsearch-js/pull/969[#969]
-- Fix inaccurate description sniffEndpoint - 
+- Fix inaccurate description sniffEndpoint -
   https://github.com/elastic/elasticsearch-js/pull/959[#959]
 
 **Internals:**
 
-- Update code generation 
+- Update code generation
   https://github.com/elastic/elasticsearch-js/pull/969[#969]
 
 [discrete]
@@ -686,26 +739,26 @@ Support for Elasticsearch `v7.3`.
 
 **Features:**
 
-- Added `auth` option - 
+- Added `auth` option -
   https://github.com/elastic/elasticsearch-js/pull/908[#908]
-- Added support for `ApiKey` authentication - 
+- Added support for `ApiKey` authentication -
   https://github.com/elastic/elasticsearch-js/pull/908[#908]
 
 **Fixes:**
 
-- fix(Typings): sniffInterval can also be boolean - 
+- fix(Typings): sniffInterval can also be boolean -
   https://github.com/elastic/elasticsearch-js/pull/914[#914]
 
 **Internals:**
 
-- Refactored connection pool - 
+- Refactored connection pool -
   https://github.com/elastic/elasticsearch-js/pull/913[#913]
 
 **Documentation:**
 
-- Better reference code examples - 
+- Better reference code examples -
   https://github.com/elastic/elasticsearch-js/pull/920[#920]
-- Improve README - 
+- Improve README -
   https://github.com/elastic/elasticsearch-js/pull/909[#909]
 
 [discrete]
@@ -715,7 +768,7 @@ Support for Elasticsearch `v7.2`
 
 **Fixes:**
 
-- Remove auth data from inspect and toJSON in connection class - 
+- Remove auth data from inspect and toJSON in connection class -
   https://github.com/elastic/elasticsearch-js/pull/887[#887]
 
 [discrete]
@@ -725,9 +778,9 @@ Support for Elasticsearch `v7.1`
 
 **Fixes:**
 
-- Support for non-friendly chars in url username and password - 
+- Support for non-friendly chars in url username and password -
   https://github.com/elastic/elasticsearch-js/pull/858[#858]
-- Patch deprecated parameters - 
+- Patch deprecated parameters -
   https://github.com/elastic/elasticsearch-js/pull/851[#851]
 
 [discrete]
@@ -735,17 +788,17 @@ Support for Elasticsearch `v7.1`
 
 **Fixes:**
 
-- Fix TypeScript export *(issue 
-  https://github.com/elastic/elasticsearch-js/pull/841[#841])* - 
+- Fix TypeScript export *(issue
+  https://github.com/elastic/elasticsearch-js/pull/841[#841])* -
   https://github.com/elastic/elasticsearch-js/pull/842[#842]
-- Fix http and https port handling *(issue 
-  https://github.com/elastic/elasticsearch-js/pull/843[#843])* - 
+- Fix http and https port handling *(issue
+  https://github.com/elastic/elasticsearch-js/pull/843[#843])* -
   https://github.com/elastic/elasticsearch-js/pull/845[#845]
-- Fix TypeScript definiton *(issue 
-  https://github.com/elastic/elasticsearch-js/pull/803[#803])* - 
+- Fix TypeScript definiton *(issue
+  https://github.com/elastic/elasticsearch-js/pull/803[#803])* -
   https://github.com/elastic/elasticsearch-js/pull/846[#846]
-- Added toJSON method to Connection class *(issue 
-  https://github.com/elastic/elasticsearch-js/pull/848[#848])* - 
+- Added toJSON method to Connection class *(issue
+  https://github.com/elastic/elasticsearch-js/pull/848[#848])* -
   https://github.com/elastic/elasticsearch-js/pull/849[#849]
 
 [discrete]
diff --git a/docs/connecting.asciidoc b/docs/connecting.asciidoc
index 536b6474..53920845 100644
--- a/docs/connecting.asciidoc
+++ b/docs/connecting.asciidoc
@@ -177,6 +177,29 @@ const client = new Client({
 })
 ----
 
+[discrete]
+[[auth-ca-fingerprint]]
+==== CA fingerprint
+
+You can configure the client to only trust certificates that are signed by a specific CA certificate ( CA certificate pinning ) by providing a `caFingerprint` option. This will verify that the fingerprint of the CA certificate that has signed the certificate of the server matches the supplied value.
+a `caFingerprint` option, which will verify the supplied certificate authority fingerprint.
+You must configure a SHA256 digest.
+
+[source,js]
+----
+const { Client } = require('@elastic/elasticsearch')
+const client = new Client({
+  node: 'https://example.com'
+  auth: { ... },
+  // the fingerprint (SHA256) of the CA certificate that is used to sign the certificate that the Elasticsearch node presents for TLS.
+  caFingerprint: '20:0D:CA:FA:76:...',
+  ssl: {
+    // might be required if it's a self-signed certificate
+    rejectUnauthorized: false
+  }
+})
+----
+
 [discrete]
 [[client-usage]]
 === Usage
diff --git a/docs/reference.asciidoc b/docs/reference.asciidoc
index 2b6ed7bb..dd30b4ef 100644
--- a/docs/reference.asciidoc
+++ b/docs/reference.asciidoc
@@ -1969,7 +1969,7 @@ link:{ref}/cluster-allocation-explain.html[Documentation] +
 |`boolean` - Return information about disk usage and shard sizes (default: false)
 
 |`body`
-|`object` - The index, shard, and primary flag to explain. Empty means 'explain the first unassigned shard'
+|`object` - The index, shard, and primary flag to explain. Empty means 'explain a randomly-chosen unassigned shard'
 
 |===
 
@@ -9248,6 +9248,67 @@ _Default:_ `5`
 
 |===
 
+[discrete]
+=== searchMvt
+*Stability:* experimental
+[source,ts]
+----
+client.searchMvt({
+  index: string | string[],
+  field: string,
+  zoom: integer,
+  x: integer,
+  y: integer,
+  exact_bounds: boolean,
+  extent: number,
+  grid_precision: number,
+  grid_type: 'grid' | 'point',
+  size: number,
+  body: object
+})
+----
+link:{ref}/search-vector-tile-api.html[Documentation] +
+[cols=2*]
+|===
+|`index`
+|`string \| string[]` - Comma-separated list of data streams, indices, or aliases to search
+
+|`field`
+|`string` - Field containing geospatial data to return
+
+|`zoom`
+|`integer` - Zoom level for the vector tile to search
+
+|`x`
+|`integer` - X coordinate for the vector tile to search
+
+|`y`
+|`integer` - Y coordinate for the vector tile to search
+
+|`exact_bounds` or `exactBounds`
+|`boolean` - If false, the meta layer's feature is the bounding box of the tile. If true, the meta layer's feature is a bounding box resulting from a `geo_bounds` aggregation.
+
+|`extent`
+|`number` - Size, in pixels, of a side of the vector tile. +
+_Default:_ `4096`
+
+|`grid_precision` or `gridPrecision`
+|`number` - Additional zoom levels available through the aggs layer. Accepts 0-8. +
+_Default:_ `8`
+
+|`grid_type` or `gridType`
+|`'grid' \| 'point'` - Determines the geometry type for features in the aggs layer. +
+_Default:_ `grid`
+
+|`size`
+|`number` - Maximum number of features to return in the hits layer. Accepts 0-10000. +
+_Default:_ `10000`
+
+|`body`
+|`object` - Search request body.
+
+|===
+
 [discrete]
 === searchShards
 
@@ -10865,7 +10926,7 @@ client.sql.clearCursor({
   body: object
 })
 ----
-link:{ref}/sql-pagination.html[Documentation] +
+link:{ref}/clear-sql-cursor-api.html[Documentation] +
 [cols=2*]
 |===
 |`body`
@@ -10952,7 +11013,7 @@ client.sql.query({
   body: object
 })
 ----
-link:{ref}/sql-rest-overview.html[Documentation] +
+link:{ref}/sql-search-api.html[Documentation] +
 {jsclient}/sql_query_examples.html[Code Example] +
 [cols=2*]
 |===
@@ -10973,7 +11034,7 @@ client.sql.translate({
   body: object
 })
 ----
-link:{ref}/sql-translate.html[Documentation] +
+link:{ref}/sql-translate-api.html[Documentation] +
 [cols=2*]
 |===
 |`body`
diff --git a/docs/transport.asciidoc b/docs/transport.asciidoc
index f4fc722c..308e7098 100644
--- a/docs/transport.asciidoc
+++ b/docs/transport.asciidoc
@@ -32,3 +32,10 @@ class MyTransport extends Transport {
 }
 ----
 
+==== Supported content types
+
+- `application/json`, in this case the transport will return a plain JavaScript object
+- `text/plain`, in this case the transport will return a plain string
+- `application/vnd.mapbox-vector-tile`, in this case the transport will return a Buffer
+- `application/vnd.elasticsearch+json`, in this case the transport will return a plain JavaScript object
+
diff --git a/index.d.ts b/index.d.ts
index 061fec76..3cd158f7 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -118,6 +118,7 @@ interface ClientOptions {
     password?: string;
   };
   disablePrototypePoisoningProtection?: boolean | 'proto' | 'constructor';
+  caFingerprint?: string;
 }
 
 declare class Client {
@@ -2104,6 +2105,14 @@ declare class Client {
   search<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(callback: callbackFn<TResponse, TContext>): TransportRequestCallback
   search<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(params: RequestParams.Search<TRequestBody>, callback: callbackFn<TResponse, TContext>): TransportRequestCallback
   search<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(params: RequestParams.Search<TRequestBody>, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>): TransportRequestCallback
+  search_mvt<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(params?: RequestParams.SearchMvt<TRequestBody>, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TResponse, TContext>>
+  search_mvt<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(callback: callbackFn<TResponse, TContext>): TransportRequestCallback
+  search_mvt<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(params: RequestParams.SearchMvt<TRequestBody>, callback: callbackFn<TResponse, TContext>): TransportRequestCallback
+  search_mvt<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(params: RequestParams.SearchMvt<TRequestBody>, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>): TransportRequestCallback
+  searchMvt<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(params?: RequestParams.SearchMvt<TRequestBody>, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TResponse, TContext>>
+  searchMvt<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(callback: callbackFn<TResponse, TContext>): TransportRequestCallback
+  searchMvt<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(params: RequestParams.SearchMvt<TRequestBody>, callback: callbackFn<TResponse, TContext>): TransportRequestCallback
+  searchMvt<TResponse = Record<string, any>, TRequestBody extends RequestBody = Record<string, any>, TContext = Context>(params: RequestParams.SearchMvt<TRequestBody>, options: TransportRequestOptions, callback: callbackFn<TResponse, TContext>): TransportRequestCallback
   search_shards<TResponse = Record<string, any>, TContext = Context>(params?: RequestParams.SearchShards, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TResponse, TContext>>
   search_shards<TResponse = Record<string, any>, TContext = Context>(callback: callbackFn<TResponse, TContext>): TransportRequestCallback
   search_shards<TResponse = Record<string, any>, TContext = Context>(params: RequestParams.SearchShards, callback: callbackFn<TResponse, TContext>): TransportRequestCallback
diff --git a/index.js b/index.js
index 60c44014..11b60a56 100644
--- a/index.js
+++ b/index.js
@@ -102,6 +102,7 @@ class Client extends ESAPI {
         suggestCompression: false,
         compression: false,
         ssl: null,
+        caFingerprint: null,
         agent: null,
         headers: {},
         nodeFilter: null,
@@ -116,6 +117,10 @@ class Client extends ESAPI {
         disablePrototypePoisoningProtection: false
       }, opts)
 
+    if (options.caFingerprint !== null && isHttpConnection(opts.node || opts.nodes)) {
+      throw new ConfigurationError('You can\'t configure the caFingerprint with a http connection')
+    }
+
     if (process.env.ELASTIC_CLIENT_APIVERSIONING === 'true') {
       options.headers = Object.assign({ accept: 'application/vnd.elasticsearch+json; compatible-with=7' }, options.headers)
     }
@@ -146,6 +151,7 @@ class Client extends ESAPI {
         Connection: options.Connection,
         auth: options.auth,
         emit: this[kEventEmitter].emit.bind(this[kEventEmitter]),
+        caFingerprint: options.caFingerprint,
         sniffEnabled: options.sniffInterval !== false ||
                       options.sniffOnStart !== false ||
                       options.sniffOnConnectionFault !== false
@@ -315,6 +321,14 @@ function getAuth (node) {
   }
 }
 
+function isHttpConnection (node) {
+  if (Array.isArray(node)) {
+    return node.some((n) => new URL(n).protocol === 'http:')
+  } else {
+    return new URL(node).protocol === 'http:'
+  }
+}
+
 const events = {
   RESPONSE: 'response',
   REQUEST: 'request',
diff --git a/lib/Connection.d.ts b/lib/Connection.d.ts
index 933a6a8e..6b5c6cb7 100644
--- a/lib/Connection.d.ts
+++ b/lib/Connection.d.ts
@@ -40,6 +40,7 @@ export interface ConnectionOptions {
   roles?: ConnectionRoles;
   auth?: BasicAuth | ApiKeyAuth;
   proxy?: string | URL;
+  caFingerprint?: string;
 }
 
 interface ConnectionRoles {
diff --git a/lib/Connection.js b/lib/Connection.js
index 6eda7c53..88a154ae 100644
--- a/lib/Connection.js
+++ b/lib/Connection.js
@@ -42,6 +42,7 @@ class Connection {
     this.headers = prepareHeaders(opts.headers, opts.auth)
     this.deadCount = 0
     this.resurrectTimeout = 0
+    this.caFingerprint = opts.caFingerprint
 
     this._openRequests = 0
     this._status = opts.status || Connection.statuses.ALIVE
@@ -123,10 +124,36 @@ class Connection {
       callback(new RequestAbortedError(), null)
     }
 
+    const onSocket = socket => {
+      /* istanbul ignore else */
+      if (!socket.isSessionReused()) {
+        socket.once('secureConnect', () => {
+          const issuerCertificate = getIssuerCertificate(socket)
+          /* istanbul ignore next */
+          if (issuerCertificate == null) {
+            onError(new Error('Invalid or malformed certificate'))
+            request.once('error', () => {}) // we need to catch the request aborted error
+            return request.abort()
+          }
+
+          // Check if fingerprint matches
+          /* istanbul ignore else */
+          if (this.caFingerprint !== issuerCertificate.fingerprint256) {
+            onError(new Error('Server certificate CA fingerprint does not match the value configured in caFingerprint'))
+            request.once('error', () => {}) // we need to catch the request aborted error
+            return request.abort()
+          }
+        })
+      }
+    }
+
     request.on('response', onResponse)
     request.on('timeout', onTimeout)
     request.on('error', onError)
     request.on('abort', onAbort)
+    if (this.caFingerprint != null) {
+      request.on('socket', onSocket)
+    }
 
     // Disables the Nagle algorithm
     request.setNoDelay(true)
@@ -152,6 +179,7 @@ class Connection {
       request.removeListener('timeout', onTimeout)
       request.removeListener('error', onError)
       request.removeListener('abort', onAbort)
+      request.removeListener('socket', onSocket)
       cleanedListeners = true
     }
   }
@@ -340,5 +368,25 @@ function prepareHeaders (headers = {}, auth) {
   return headers
 }
 
+function getIssuerCertificate (socket) {
+  let certificate = socket.getPeerCertificate(true)
+  while (certificate && Object.keys(certificate).length > 0) {
+    // invalid certificate
+    if (certificate.issuerCertificate == null) {
+      return null
+    }
+
+    // We have reached the root certificate.
+    // In case of self-signed certificates, `issuerCertificate` may be a circular reference.
+    if (certificate.fingerprint256 === certificate.issuerCertificate.fingerprint256) {
+      break
+    }
+
+    // continue the loop
+    certificate = certificate.issuerCertificate
+  }
+  return certificate
+}
+
 module.exports = Connection
-module.exports.internals = { prepareHeaders }
+module.exports.internals = { prepareHeaders, getIssuerCertificate }
diff --git a/lib/Transport.d.ts b/lib/Transport.d.ts
index 912dd96d..2313bf23 100644
--- a/lib/Transport.d.ts
+++ b/lib/Transport.d.ts
@@ -155,8 +155,8 @@ export default class Transport {
   _nextSniff: number;
   _isSniffing: boolean;
   constructor(opts: TransportOptions);
-  request(params: TransportRequestParams, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse>;
-  request(params: TransportRequestParams, options?: TransportRequestOptions, callback?: (err: ApiError, result: ApiResponse) => void): TransportRequestCallback;
+  request<TResponse = Record<string, any>, TContext = Context>(params: TransportRequestParams, options?: TransportRequestOptions): TransportRequestPromise<ApiResponse<TResponse, TContext>>;
+  request<TResponse = Record<string, any>, TContext = Context>(params: TransportRequestParams, options?: TransportRequestOptions, callback?: (err: ApiError, result: ApiResponse<TResponse, TContext>) => void): TransportRequestCallback;
   getConnection(opts: TransportGetConnectionOptions): Connection | null;
   sniff(opts?: TransportSniffOptions, callback?: (...args: any[]) => void): void;
 }
diff --git a/lib/Transport.js b/lib/Transport.js
index cd2d7584..3e6d9fd3 100644
--- a/lib/Transport.js
+++ b/lib/Transport.js
@@ -237,6 +237,7 @@ class Transport {
 
       const contentEncoding = (result.headers['content-encoding'] || '').toLowerCase()
       const isCompressed = contentEncoding.indexOf('gzip') > -1 || contentEncoding.indexOf('deflate') > -1
+      const isVectorTile = (result.headers['content-type'] || '').indexOf('application/vnd.mapbox-vector-tile') > -1
 
       /* istanbul ignore else */
       if (result.headers['content-length'] !== undefined) {
@@ -255,8 +256,9 @@ class Transport {
       }
       // if the response is compressed, we must handle it
       // as buffer for allowing decompression later
-      let payload = isCompressed ? [] : ''
-      const onData = isCompressed
+      // while if it's a vector tile, we should return it as buffer
+      let payload = isCompressed || isVectorTile ? [] : ''
+      const onData = isCompressed || isVectorTile
         ? chunk => { payload.push(chunk) }
         : chunk => { payload += chunk }
       const onEnd = err => {
@@ -272,7 +274,7 @@ class Transport {
         if (isCompressed) {
           unzip(Buffer.concat(payload), onBody)
         } else {
-          onBody(null, payload)
+          onBody(null, isVectorTile ? Buffer.concat(payload) : payload)
         }
       }
 
@@ -281,7 +283,7 @@ class Transport {
         onEnd(new Error('Response aborted while reading the body'))
       }
 
-      if (!isCompressed) {
+      if (!isCompressed && !isVectorTile) {
         response.setEncoding('utf8')
       }
 
@@ -297,7 +299,9 @@ class Transport {
         this.emit('response', err, result)
         return callback(err, result)
       }
-      if (Buffer.isBuffer(payload)) {
+
+      const isVectorTile = (result.headers['content-type'] || '').indexOf('application/vnd.mapbox-vector-tile') > -1
+      if (Buffer.isBuffer(payload) && !isVectorTile) {
         payload = payload.toString()
       }
       const isHead = params.method === 'HEAD'
diff --git a/lib/errors.js b/lib/errors.js
index 2ec9bc71..bc691c86 100644
--- a/lib/errors.js
+++ b/lib/errors.js
@@ -97,8 +97,10 @@ class ResponseError extends ElasticsearchClientError {
       } else {
         this.message = meta.body.error.type
       }
+    } else if (typeof meta.body === 'object' && meta.body != null) {
+      this.message = JSON.stringify(meta.body)
     } else {
-      this.message = 'Response Error'
+      this.message = meta.body || 'Response Error'
     }
     this.meta = meta
   }
diff --git a/lib/pool/BaseConnectionPool.js b/lib/pool/BaseConnectionPool.js
index 2b308115..80e80a31 100644
--- a/lib/pool/BaseConnectionPool.js
+++ b/lib/pool/BaseConnectionPool.js
@@ -36,6 +36,7 @@ class BaseConnectionPool {
     this._ssl = opts.ssl
     this._agent = opts.agent
     this._proxy = opts.proxy || null
+    this._caFingerprint = opts.caFingerprint || null
   }
 
   getConnection () {
@@ -72,6 +73,8 @@ class BaseConnectionPool {
     if (opts.agent == null) opts.agent = this._agent
     /* istanbul ignore else */
     if (opts.proxy == null) opts.proxy = this._proxy
+    /* istanbul ignore else */
+    if (opts.caFingerprint == null) opts.caFingerprint = this._caFingerprint
 
     const connection = new this.Connection(opts)
 
diff --git a/lib/pool/index.d.ts b/lib/pool/index.d.ts
index c1ebbdad..7b3f62f9 100644
--- a/lib/pool/index.d.ts
+++ b/lib/pool/index.d.ts
@@ -31,6 +31,7 @@ interface BaseConnectionPoolOptions {
   auth?: BasicAuth | ApiKeyAuth;
   emit: (event: string | symbol, ...args: any[]) => boolean;
   Connection: typeof Connection;
+  caFingerprint?: string;
 }
 
 interface ConnectionPoolOptions extends BaseConnectionPoolOptions {


Test patch:
diff --git a/test/acceptance/product-check.test.js b/test/acceptance/product-check.test.js
index e32908ae..30c50eaa 100644
--- a/test/acceptance/product-check.test.js
+++ b/test/acceptance/product-check.test.js
@@ -649,7 +649,7 @@ test('500 error', t => {
       }
     }
   }, (err, result) => {
-    t.equal(err.message, 'Response Error')
+    t.equal(err.message, '{"error":"kaboom"}')
 
     client.search({
       index: 'foo',
diff --git a/test/acceptance/sniff.test.js b/test/acceptance/sniff.test.js
index 5dfaa3f7..d18e8a2a 100644
--- a/test/acceptance/sniff.test.js
+++ b/test/acceptance/sniff.test.js
@@ -77,6 +77,7 @@ test('Should update the connection pool', t => {
           t.same(hosts[i], {
             url: new URL(nodes[id].url),
             id: id,
+            caFingerprint: null,
             roles: {
               master: true,
               data: true,
diff --git a/test/unit/client.test.js b/test/unit/client.test.js
index d9a26c11..cd6484ff 100644
--- a/test/unit/client.test.js
+++ b/test/unit/client.test.js
@@ -25,7 +25,9 @@ const buffer = require('buffer')
 const intoStream = require('into-stream')
 const { ConnectionPool, Transport, Connection, errors } = require('../../index')
 const { CloudConnectionPool } = require('../../lib/pool')
-const { Client, buildServer } = require('../utils')
+const { Client, buildServer, connection } = require('../utils')
+const { buildMockConnection } = connection
+
 let clientVersion = require('../../package.json').version
 if (clientVersion.includes('-')) {
   clientVersion = clientVersion.slice(0, clientVersion.indexOf('-')) + 'p'
@@ -1498,3 +1500,116 @@ test('Bearer auth', t => {
     })
   })
 })
+
+test('Check server fingerprint (success)', t => {
+  t.plan(1)
+
+  function handler (req, res) {
+    res.end('ok')
+  }
+
+  buildServer(handler, { secure: true }, ({ port, caFingerprint }, server) => {
+    const client = new Client({
+      node: `https://localhost:${port}`,
+      caFingerprint
+    })
+
+    client.info((err, res) => {
+      t.error(err)
+      server.stop()
+    })
+  })
+})
+
+test('Check server fingerprint (failure)', t => {
+  t.plan(2)
+
+  function handler (req, res) {
+    res.end('ok')
+  }
+
+  buildServer(handler, { secure: true }, ({ port }, server) => {
+    const client = new Client({
+      node: `https://localhost:${port}`,
+      caFingerprint: 'FO:OB:AR'
+    })
+
+    client.info((err, res) => {
+      t.ok(err instanceof errors.ConnectionError)
+      t.equal(err.message, 'Server certificate CA fingerprint does not match the value configured in caFingerprint')
+      server.stop()
+    })
+  })
+})
+
+test('caFingerprint can\'t be configured over http / 1', t => {
+  t.plan(2)
+
+  try {
+    new Client({ // eslint-disable-line
+      node: 'http://localhost:9200',
+      caFingerprint: 'FO:OB:AR'
+    })
+    t.fail('shuld throw')
+  } catch (err) {
+    t.ok(err instanceof errors.ConfigurationError)
+    t.equal(err.message, 'You can\'t configure the caFingerprint with a http connection')
+  }
+})
+
+test('caFingerprint can\'t be configured over http / 2', t => {
+  t.plan(2)
+
+  try {
+    new Client({ // eslint-disable-line
+      nodes: ['http://localhost:9200'],
+      caFingerprint: 'FO:OB:AR'
+    })
+    t.fail('should throw')
+  } catch (err) {
+    t.ok(err instanceof errors.ConfigurationError)
+    t.equal(err.message, 'You can\'t configure the caFingerprint with a http connection')
+  }
+})
+
+test('caFingerprint can\'t be configured over http / 3', t => {
+  t.plan(1)
+
+  try {
+    new Client({ // eslint-disable-line
+      nodes: ['https://localhost:9200'],
+      caFingerprint: 'FO:OB:AR'
+    })
+    t.pass('should not throw')
+  } catch (err) {
+    t.fail('shuld not throw')
+  }
+})
+
+test('Error body that is not a json', t => {
+  t.plan(5)
+
+  const MockConnection = buildMockConnection({
+    onRequest (params) {
+      return {
+        statusCode: 400,
+        body: '<html><body>error!</body></html>',
+        headers: { 'content-type': 'text/html' }
+      }
+    }
+  })
+
+  const client = new Client({
+    node: 'http://localhost:9200',
+    Connection: MockConnection,
+    maxRetries: 1
+  })
+
+  client.info((err, result) => {
+    t.ok(err instanceof errors.ResponseError)
+    t.equal(err.name, 'ResponseError')
+    t.equal(err.body, '<html><body>error!</body></html>')
+    t.equal(err.message, '<html><body>error!</body></html>')
+    t.equal(err.statusCode, 400)
+  })
+})
diff --git a/test/unit/connection.test.js b/test/unit/connection.test.js
index a951a9e6..5ba1c494 100644
--- a/test/unit/connection.test.js
+++ b/test/unit/connection.test.js
@@ -28,7 +28,8 @@ const hpagent = require('hpagent')
 const intoStream = require('into-stream')
 const { buildServer } = require('../utils')
 const Connection = require('../../lib/Connection')
-const { TimeoutError, ConfigurationError, RequestAbortedError } = require('../../lib/errors')
+const { TimeoutError, ConfigurationError, RequestAbortedError, ConnectionError } = require('../../lib/errors')
+const { getIssuerCertificate } = Connection.internals
 
 test('Basic (http)', t => {
   t.plan(4)
@@ -947,3 +948,139 @@ test('Abort with a slow body', t => {
 
   setImmediate(() => request.abort())
 })
+
+test('Check server fingerprint (success)', t => {
+  t.plan(2)
+
+  function handler (req, res) {
+    res.end('ok')
+  }
+
+  buildServer(handler, { secure: true }, ({ port, caFingerprint }, server) => {
+    const connection = new Connection({
+      url: new URL(`https://localhost:${port}`),
+      caFingerprint
+    })
+
+    connection.request({
+      path: '/hello',
+      method: 'GET'
+    }, (err, res) => {
+      t.error(err)
+
+      let payload = ''
+      res.setEncoding('utf8')
+      res.on('data', chunk => { payload += chunk })
+      res.on('error', err => t.fail(err))
+      res.on('end', () => {
+        t.equal(payload, 'ok')
+        server.stop()
+      })
+    })
+  })
+})
+
+test('Check server fingerprint (failure)', t => {
+  t.plan(2)
+
+  function handler (req, res) {
+    res.end('ok')
+  }
+
+  buildServer(handler, { secure: true }, ({ port }, server) => {
+    const connection = new Connection({
+      url: new URL(`https://localhost:${port}`),
+      caFingerprint: 'FO:OB:AR'
+    })
+
+    connection.request({
+      path: '/hello',
+      method: 'GET'
+    }, (err, res) => {
+      t.ok(err instanceof ConnectionError)
+      t.equal(err.message, 'Server certificate CA fingerprint does not match the value configured in caFingerprint')
+      server.stop()
+    })
+  })
+})
+
+test('getIssuerCertificate returns the root CA', t => {
+  t.plan(2)
+  const issuerCertificate = {
+    fingerprint256: 'BA:ZF:AZ',
+    subject: {
+      C: '1',
+      ST: '1',
+      L: '1',
+      O: '1',
+      OU: '1',
+      CN: '1'
+    },
+    issuer: {
+      C: '1',
+      ST: '1',
+      L: '1',
+      O: '1',
+      OU: '1',
+      CN: '1'
+    }
+  }
+  issuerCertificate.issuerCertificate = issuerCertificate
+
+  const socket = {
+    getPeerCertificate (bool) {
+      t.ok(bool)
+      return {
+        fingerprint256: 'FO:OB:AR',
+        subject: {
+          C: '1',
+          ST: '1',
+          L: '1',
+          O: '1',
+          OU: '1',
+          CN: '1'
+        },
+        issuer: {
+          C: '2',
+          ST: '2',
+          L: '2',
+          O: '2',
+          OU: '2',
+          CN: '2'
+        },
+        issuerCertificate
+      }
+    }
+  }
+  t.same(getIssuerCertificate(socket), issuerCertificate)
+})
+
+test('getIssuerCertificate detects invalid/malformed certificates', t => {
+  t.plan(2)
+  const socket = {
+    getPeerCertificate (bool) {
+      t.ok(bool)
+      return {
+        fingerprint256: 'FO:OB:AR',
+        subject: {
+          C: '1',
+          ST: '1',
+          L: '1',
+          O: '1',
+          OU: '1',
+          CN: '1'
+        },
+        issuer: {
+          C: '2',
+          ST: '2',
+          L: '2',
+          O: '2',
+          OU: '2',
+          CN: '2'
+        }
+        // missing issuerCertificate
+      }
+    }
+  }
+  t.equal(getIssuerCertificate(socket), null)
+})
diff --git a/test/unit/errors.test.js b/test/unit/errors.test.js
index 301ca110..b8db815d 100644
--- a/test/unit/errors.test.js
+++ b/test/unit/errors.test.js
@@ -197,3 +197,29 @@ test('ResponseError with meaningful message / 3', t => {
   t.equal(err.toString(), JSON.stringify(meta.body))
   t.end()
 })
+
+test('ResponseError with meaningful message when body is not json', t => {
+  const meta = {
+    statusCode: 400,
+    body: '<html><body>error!</body></html>',
+    headers: { 'content-type': 'text/html' }
+  }
+  const err = new errors.ResponseError(meta)
+  t.equal(err.name, 'ResponseError')
+  t.equal(err.message, '<html><body>error!</body></html>')
+  t.equal(err.toString(), JSON.stringify(meta.body))
+  t.end()
+})
+
+test('ResponseError with meaningful message when body is falsy', t => {
+  const meta = {
+    statusCode: 400,
+    body: '',
+    headers: { 'content-type': 'text/plain' }
+  }
+  const err = new errors.ResponseError(meta)
+  t.equal(err.name, 'ResponseError')
+  t.equal(err.message, 'Response Error')
+  t.equal(err.toString(), JSON.stringify(meta.body))
+  t.end()
+})
diff --git a/test/unit/transport.test.js b/test/unit/transport.test.js
index c617bc3a..e1a6aaa9 100644
--- a/test/unit/transport.test.js
+++ b/test/unit/transport.test.js
@@ -2689,3 +2689,76 @@ test('The callback with a sync error should be called in the next tick - ndjson'
   t.type(transportReturn.catch, 'function')
   t.type(transportReturn.abort, 'function')
 })
+
+test('Support mapbox vector tile', t => {
+  t.plan(2)
+  const mvtContent = 'GoMCCgRtZXRhEikSFAAAAQACAQMBBAAFAgYDBwAIBAkAGAMiDwkAgEAagEAAAP8//z8ADxoOX3NoYXJkcy5mYWlsZWQaD19zaGFyZHMuc2tpcHBlZBoSX3NoYXJkcy5zdWNjZXNzZnVsGg1fc2hhcmRzLnRvdGFsGhlhZ2dyZWdhdGlvbnMuX2NvdW50LmNvdW50GhdhZ2dyZWdhdGlvbnMuX2NvdW50LnN1bRoTaGl0cy50b3RhbC5yZWxhdGlvbhoQaGl0cy50b3RhbC52YWx1ZRoJdGltZWRfb3V0GgR0b29rIgIwACICMAIiCRkAAAAAAAAAACIECgJlcSICOAAogCB4Ag=='
+
+  function handler (req, res) {
+    res.setHeader('Content-Type', 'application/vnd.mapbox-vector-tile')
+    res.end(Buffer.from(mvtContent, 'base64'))
+  }
+
+  buildServer(handler, ({ port }, server) => {
+    const pool = new ConnectionPool({ Connection })
+    pool.addConnection(`http://localhost:${port}`)
+
+    const transport = new Transport({
+      emit: () => {},
+      connectionPool: pool,
+      serializer: new Serializer(),
+      maxRetries: 3,
+      requestTimeout: 30000,
+      sniffInterval: false,
+      sniffOnStart: false
+    })
+    skipProductCheck(transport)
+
+    transport.request({
+      method: 'GET',
+      path: '/hello'
+    }, (err, { body }) => {
+      t.error(err)
+      t.same(body.toString('base64'), Buffer.from(mvtContent, 'base64').toString('base64'))
+      server.stop()
+    })
+  })
+})
+
+test('Compressed mapbox vector tile', t => {
+  t.plan(2)
+  const mvtContent = 'GoMCCgRtZXRhEikSFAAAAQACAQMBBAAFAgYDBwAIBAkAGAMiDwkAgEAagEAAAP8//z8ADxoOX3NoYXJkcy5mYWlsZWQaD19zaGFyZHMuc2tpcHBlZBoSX3NoYXJkcy5zdWNjZXNzZnVsGg1fc2hhcmRzLnRvdGFsGhlhZ2dyZWdhdGlvbnMuX2NvdW50LmNvdW50GhdhZ2dyZWdhdGlvbnMuX2NvdW50LnN1bRoTaGl0cy50b3RhbC5yZWxhdGlvbhoQaGl0cy50b3RhbC52YWx1ZRoJdGltZWRfb3V0GgR0b29rIgIwACICMAIiCRkAAAAAAAAAACIECgJlcSICOAAogCB4Ag=='
+
+  function handler (req, res) {
+    const body = gzipSync(Buffer.from(mvtContent, 'base64'))
+    res.setHeader('Content-Type', 'application/vnd.mapbox-vector-tile')
+    res.setHeader('Content-Encoding', 'gzip')
+    res.setHeader('Content-Length', Buffer.byteLength(body))
+    res.end(body)
+  }
+
+  buildServer(handler, ({ port }, server) => {
+    const pool = new ConnectionPool({ Connection })
+    pool.addConnection(`http://localhost:${port}`)
+
+    const transport = new Transport({
+      emit: () => {},
+      connectionPool: pool,
+      serializer: new Serializer(),
+      maxRetries: 3,
+      requestTimeout: 30000,
+      sniffInterval: false,
+      sniffOnStart: false
+    })
+    skipProductCheck(transport)
+
+    transport.request({
+      method: 'GET',
+      path: '/hello'
+    }, (err, { body }) => {
+      t.error(err)
+      t.same(body.toString('base64'), Buffer.from(mvtContent, 'base64').toString('base64'))
+      server.stop()
+    })
+  })
+})
diff --git a/test/utils/buildServer.js b/test/utils/buildServer.js
index b47b2fec..ef907c05 100644
--- a/test/utils/buildServer.js
+++ b/test/utils/buildServer.js
@@ -19,6 +19,7 @@
 
 'use strict'
 
+const crypto = require('crypto')
 const debug = require('debug')('elasticsearch-test')
 const stoppable = require('stoppable')
 
@@ -35,6 +36,13 @@ const secureOpts = {
   cert: readFileSync(join(__dirname, '..', 'fixtures', 'https.cert'), 'utf8')
 }
 
+const caFingerprint = getFingerprint(secureOpts.cert
+  .split('\n')
+  .slice(1, -1)
+  .map(line => line.trim())
+  .join('')
+)
+
 let id = 0
 function buildServer (handler, opts, cb) {
   const serverId = id++
@@ -58,7 +66,7 @@ function buildServer (handler, opts, cb) {
       server.listen(0, () => {
         const port = server.address().port
         debug(`Server '${serverId}' booted on port ${port}`)
-        resolve([Object.assign({}, secureOpts, { port }), server])
+        resolve([Object.assign({}, secureOpts, { port, caFingerprint }), server])
       })
     })
   } else {
@@ -70,4 +78,11 @@ function buildServer (handler, opts, cb) {
   }
 }
 
+function getFingerprint (content, inputEncoding = 'base64', outputEncoding = 'hex') {
+  const shasum = crypto.createHash('sha256')
+  shasum.update(content, inputEncoding)
+  const res = shasum.digest(outputEncoding)
+  return res.toUpperCase().match(/.{1,2}/g).join(':')
+}
+
 module.exports = buildServer