Upgrade ES client to 9.0.0-alpha.4 (#213375)

## Summary

Upgrading the ES client to v9.0.0-alpha.4 to test the changes mentioned
in https://github.com/elastic/elasticsearch-js/issues/2584

This new version introduces some type changes, most notably, the
`FieldValue` is `string | number | boolean | null | undefined` instead
of `any`, leading to some new type checks to be implemented (like on
aggregation results `bucket.key`, `search_after`, and `sort` options).

On top of that, it adds the new behavior where unknown properties are
placed in the `body` (when the request has a body). If they must be in
as a query parameter, they should be placed under the `querystring`
option.

cc @JoshMock 

TODO:
- [x] Stabilize the type errors
- [x] Address all the query parameters that are now placed in the body
(by wrapping them inside the option `querystring: {}`)

I will address `// @ts-expect-error elasticsearch@9.0.0
https://github.com/elastic/elasticsearch-js/issues/2584` in a separate
PR to reduce noise.


Related https://github.com/elastic/kibana/pull/208776
This commit is contained in:
Alejandro Fernández Haro 2025-04-03 22:54:55 +02:00 committed by GitHub
parent 5d16e44e79
commit b5ad8bc00b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
58 changed files with 128 additions and 106 deletions

View file

@ -123,7 +123,7 @@
"@elastic/datemath": "5.0.3",
"@elastic/ebt": "^1.1.1",
"@elastic/ecs": "^8.11.5",
"@elastic/elasticsearch": "9.0.0-alpha.3",
"@elastic/elasticsearch": "9.0.0-alpha.4",
"@elastic/ems-client": "8.6.3",
"@elastic/eui": "101.0.1",
"@elastic/eui-theme-borealis": "0.1.0",

View file

@ -19,6 +19,7 @@ const omittedProps = [
'transport',
'serializer',
'helpers',
'acceptedParams',
] as Array<PublicKeys<Client>>;
export type DeeplyMockedApi<T> = {

View file

@ -159,7 +159,7 @@ export const performCreate = async <T>(
refresh,
document: raw._source,
...(overwrite && version ? decodeRequestVersion(version) : {}),
require_alias: true,
querystring: { require_alias: true },
};
const { body, statusCode, headers } =

View file

@ -194,8 +194,7 @@ export const executeUpdate = async <T>(
refresh,
document: rawUpsert._source,
...(version ? decodeRequestVersion(version) : {}),
// @ts-expect-error
require_alias: true,
querystring: { require_alias: true },
};
const {

View file

@ -1424,7 +1424,7 @@ describe('CsvGenerator', () => {
expect(mockEsClient.asCurrentUser.openPointInTime).toHaveBeenCalledWith(
{
ignore_unavailable: true,
ignore_throttled: false,
querystring: { ignore_throttled: false },
index: 'logstash-*',
keep_alive: '30s',
},

View file

@ -47,13 +47,13 @@ export class SearchCursorPit extends SearchCursor {
index: this.indexPatternTitle,
keep_alive: scroll.duration(taskInstanceFields),
ignore_unavailable: true,
// @ts-expect-error ignore_throttled is not in the type definition, but it is accepted by es
ignore_throttled: includeFrozen ? false : undefined, // "true" will cause deprecation warnings logged in ES
...(includeFrozen ? { querystring: { ignore_throttled: false } } : {}), // "true" will cause deprecation warnings logged in ES
},
{
signal: this.abortController.signal,
requestTimeout: scroll.duration(taskInstanceFields),
maxRetries: 0,
// @ts-expect-error not documented in the types. Is this still supported?
maxConcurrentShardRequests,
}
);

View file

@ -115,11 +115,12 @@ export function registerFavoritesUsageCollection({
[]) as estypes.AggregationsStringTermsBucket[];
typesBuckets.forEach((bucket) => {
favoritesUsage[bucket.key] = {
total: bucket.stats.sum,
total_users_spaces: bucket.stats.count,
avg_per_user_per_space: bucket.stats.avg,
max_per_user_per_space: bucket.stats.max,
const stats = bucket.stats as estypes.AggregationsStatsAggregate;
favoritesUsage[`${bucket.key}`] = {
total: stats.sum,
total_users_spaces: stats.count,
avg_per_user_per_space: stats.avg!,
max_per_user_per_space: stats.max!,
};
});

View file

@ -51,17 +51,19 @@ export const isValidFeatureId = (a: unknown): a is ValidFeatureId =>
* @param sortIds estypes.SortResults | undefined
* @returns SortResults
*/
export const getSafeSortIds = (sortIds: estypes.SortResults | null | undefined) => {
export const getSafeSortIds = (
sortIds: estypes.SortResults | null | undefined
): Array<string | number> | undefined => {
if (sortIds == null) {
return sortIds;
return sortIds as undefined;
}
return sortIds.map((sortId) => {
// haven't determined when we would receive a null value for a sort id
// but in case we do, default to sending the stringified Java max_int
if (sortId == null || sortId === '' || sortId >= Number.MAX_SAFE_INTEGER) {
if (sortId == null || sortId === '' || Number(sortId) >= Number.MAX_SAFE_INTEGER) {
return '9223372036854775807';
}
return sortId;
return sortId as string | number;
});
};

View file

@ -80,9 +80,10 @@ export async function getSavedObjectsCounts(
const nonExpectedTypes: string[] = [];
const perType = buckets.map((perTypeEntry) => {
if (perTypeEntry.key !== MISSING_TYPE_KEY && !soTypes.includes(perTypeEntry.key)) {
const key = perTypeEntry.key as string;
if (key !== MISSING_TYPE_KEY && !soTypes.includes(key)) {
// If the breakdown includes any SO types that are not expected, highlight them in the nonExpectedTypes list.
nonExpectedTypes.push(perTypeEntry.key);
nonExpectedTypes.push(key);
}
return { key: perTypeEntry.key, doc_count: perTypeEntry.doc_count };
@ -90,6 +91,7 @@ export async function getSavedObjectsCounts(
return {
total: body.total,
// @ts-expect-error `FieldValue` types now claim that bucket keys can be `null`
per_type: perType,
non_expected_types: nonExpectedTypes,
others: body.aggregations?.types?.sum_other_doc_count ?? 0,

View file

@ -314,7 +314,9 @@ describe('ES search strategy', () => {
expect(mockRollupSearchCaller).toHaveBeenCalledWith(
{
index: 'foo-程',
ignore_unavailable: true,
querystring: {
ignore_unavailable: true,
},
max_concurrent_shard_requests: undefined,
timeout: '100ms',
track_total_hits: true,

View file

@ -166,12 +166,20 @@ export const enhancedEsSearchStrategyProvider = (
throw new KbnSearchError(`"params.index" is required when performing a rollup search`, 400);
}
// eslint-disable-next-line @typescript-eslint/naming-convention
const { ignore_unavailable, preference, ...params } = {
...querystring,
...request.params,
index: request.params.index,
};
try {
const esResponse = await client.rollup.rollupSearch(
{
...querystring,
...request.params,
index: request.params.index,
...params,
// Not defined in the spec, and the client places it in the body.
// This workaround allows us to force it as a query parameter.
querystring: { ...params.querystring, ignore_unavailable, preference },
},
{
signal: options?.abortSignal,

View file

@ -38,7 +38,7 @@ export const getSavedObjectCounts = async ({
(body.aggregations?.types?.buckets as estypes.AggregationsStringTermsBucketKeys[]) || [];
const counts = buckets.reduce((memo, bucket) => {
memo[bucket.key] = bucket.doc_count;
memo[`${bucket.key}`] = bucket.doc_count;
return memo;
}, {} as Record<string, number>);

View file

@ -162,7 +162,6 @@ const indexWithLifecyclePhaseDefinition: Index = {
step_time_millis: 1544187776208,
phase_execution: {
policy: 'testy',
// @ts-expect-error ILM type is incorrect https://github.com/elastic/elasticsearch-specification/issues/2326
phase_definition: { min_age: '0s', actions: { rollover: { max_size: '1gb' } } },
version: 1,
modified_date_in_millis: 1544031699844,

View file

@ -83,7 +83,7 @@ export const IndexLifecycleSummary: FunctionComponent<Props> = ({
defaultMessage: 'Policy name',
}
),
description: ilm.policy,
description: ilm.policy!,
},
{
title: i18n.translate(
@ -153,7 +153,7 @@ export const IndexLifecycleSummary: FunctionComponent<Props> = ({
<EuiLink
color="primary"
href={getUrlForApp('management', {
path: `data/index_lifecycle_management/${getPolicyEditPath(ilm.policy)}`,
path: `data/index_lifecycle_management/${getPolicyEditPath(ilm.policy!)}`,
})}
target="_blank"
>

View file

@ -7,7 +7,7 @@
import _ from 'lodash';
import { elasticsearchServiceMock } from '@kbn/core/server/mocks';
import type * as estypes from '@elastic/elasticsearch/lib/api/types';
import type { estypes } from '@elastic/elasticsearch';
import fakeDeprecations from '../__fixtures__/fake_deprecations.json';
import * as healthIndicatorsMock from '../__fixtures__/health_indicators';
@ -126,7 +126,6 @@ describe('getESUpgradeStatus', () => {
],
},
data_streams: {},
// @ts-expect-error not in types yet
ilm_policies: {},
templates: {},
});
@ -148,7 +147,7 @@ describe('getESUpgradeStatus', () => {
...esMigrationsMock.getMockEsDeprecations(),
...esMigrationsMock.getMockMlSettingsDeprecations(),
};
// @ts-ignore missing property definitions in ES resolve_during_rolling_upgrade and _meta
// @ts-expect-error missing property definitions in ES resolve_during_rolling_upgrade and _meta
esClient.migration.deprecations.mockResponse(mockResponse);
const enabledUpgradeStatus = await getESUpgradeStatus(esClient, {
@ -217,7 +216,6 @@ describe('getESUpgradeStatus', () => {
message: 'Index created before 7.0',
url: 'https: //www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html',
details: 'This index was created using version: 6.8.13',
// @ts-ignore
resolve_during_rolling_upgrade: false,
_meta: {
reindex_required: true,
@ -228,7 +226,6 @@ describe('getESUpgradeStatus', () => {
message: 'Index created before 7.0',
url: 'https: //www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html',
details: 'This index was created using version: 6.8.13',
// @ts-ignore
resolve_during_rolling_upgrade: false,
_meta: {
reindex_required: true,
@ -238,7 +235,6 @@ describe('getESUpgradeStatus', () => {
ml_settings: [],
index_settings: {},
data_streams: {},
// @ts-expect-error not in types yet
ilm_policies: {},
templates: {},
});
@ -313,7 +309,6 @@ describe('getESUpgradeStatus', () => {
},
],
},
// @ts-expect-error not in types yet
ilm_policies: {},
templates: {},
});
@ -369,7 +364,6 @@ describe('getESUpgradeStatus', () => {
],
},
data_streams: {},
// @ts-expect-error not in types yet
ilm_policies: {},
templates: {},
});
@ -398,7 +392,6 @@ describe('getESUpgradeStatus', () => {
message: 'Index created before 7.0',
url: 'https: //www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html',
details: 'This index was created using version: 6.8.13',
// @ts-ignore
resolve_during_rolling_upgrade: false,
_meta: {
reindex_required: true,
@ -408,7 +401,6 @@ describe('getESUpgradeStatus', () => {
ml_settings: [],
index_settings: {},
data_streams: {},
// @ts-expect-error not in types yet
ilm_policies: {},
templates: {},
});
@ -417,7 +409,7 @@ describe('getESUpgradeStatus', () => {
cluster_name: 'mock',
indicators: {
disk: healthIndicatorsMock.diskIndicatorGreen,
// @ts-ignore
// @ts-expect-error
shards_capacity: healthIndicatorsMock.shardCapacityIndicatorRed,
},
});

View file

@ -324,7 +324,7 @@ function formatExecutionLogAggBucket(bucket: IExecutionUuidAggBucket): IExecutio
const connectorId = outcomeAndMessage?.kibana?.action?.id ?? '';
const timedOut = (bucket?.timeoutMessage?.doc_count ?? 0) > 0;
return {
id: bucket?.key ?? '',
id: bucket?.key ? `${bucket.key}` : '',
timestamp: bucket?.actionExecution?.executeStartTime.value_as_string ?? '',
duration_ms: durationUs / Millis2Nanos,
status,

View file

@ -530,7 +530,7 @@ function formatExecutionLogAggBucket(bucket: IExecutionUuidAggBucket): IExecutio
? outcomeMessageAndMaintenanceWindow.rule?.name ?? ''
: '';
return {
id: bucket?.key ?? '',
id: bucket?.key ? `${bucket.key}` : '', // `key` can be a number, this way we stringify it.
timestamp: bucket?.ruleExecution?.executeStartTime.value_as_string ?? '',
duration_ms: durationUs / Millis2Nanos,
status,

View file

@ -101,7 +101,7 @@ export const findGapsSearchAfter = async ({
return {
total: gapsResponse.total,
data: transformToGap(gapsResponse),
searchAfter: gapsResponse.search_after,
searchAfter: gapsResponse.search_after as SortResults[] | undefined,
pitId: gapsResponse.pit_id,
};
} catch (err) {

View file

@ -253,7 +253,7 @@ function getWrappedEqlSearchFn(opts: WrapEsClientOpts) {
requestTimeout ? ` and ${requestTimeout}ms requestTimeout` : ''
}`
);
const result = (await originalEqlSearch.call(opts.esClient, params, {
const result = (await originalEqlSearch.call(opts.esClient.eql, params, {
...searchOptions,
...(requestTimeout
? {

View file

@ -340,7 +340,7 @@ export function parseRuleTypeBucket(
alertsPercentilesByType: { p50: {}, p90: {}, p99: {} },
};
for (const bucket of buckets ?? []) {
const ruleType: string = replaceDotSymbols(bucket?.key) ?? '';
const ruleType: string = replaceDotSymbols(`${bucket?.key ?? ''}`);
const numExecutions: number = bucket?.doc_count ?? 0;
const avgExecutionTimeNanos = bucket?.avg_execution_time?.value ?? 0;
const avgEsSearchTimeMillis = bucket?.avg_es_search_duration?.value ?? 0;
@ -391,7 +391,7 @@ export function parseExecutionFailureByRuleType(
const executionFailuresWithRuleTypeBuckets: FlattenedExecutionFailureBucket[] = flatMap(
buckets ?? [],
(bucket) => {
const ruleType: string = replaceDotSymbols(bucket.key);
const ruleType: string = replaceDotSymbols(`${bucket.key}`);
/**
* Execution failure bucket format
@ -409,7 +409,7 @@ export function parseExecutionFailureByRuleType(
const executionFailuresBuckets = bucket?.execution_failures?.by_reason
?.buckets as AggregationsStringTermsBucketKeys[];
return (executionFailuresBuckets ?? []).map((b) => ({ ...b, ruleType }));
return (executionFailuresBuckets ?? []).map((b) => ({ ...b, key: `${b.key}`, ruleType }));
}
);
@ -548,7 +548,7 @@ export function parseExecutionCountAggregationResults(results: {
countTotalFailedExecutions: results?.execution_failures?.doc_count ?? 0,
countFailedExecutionsByReason: executionFailuresByReasonBuckets.reduce<Record<string, number>>(
(acc, bucket: AggregationsStringTermsBucketKeys) => {
const reason: string = bucket.key;
const reason: string = `${bucket.key}`;
acc[reason] = bucket.doc_count ?? 0;
return acc;
},

View file

@ -163,12 +163,14 @@ export function parseBucket(
> {
return (buckets ?? []).reduce(
(summary, bucket) => {
const status: string = bucket.key;
const status: string = `${bucket.key}`;
const taskTypeBuckets = bucket?.by_task_type?.buckets as AggregationsStringTermsBucketKeys[];
const byTaskType = (taskTypeBuckets ?? []).reduce<Record<string, number>>(
(acc, taskTypeBucket: AggregationsStringTermsBucketKeys) => {
const taskType: string = replaceDotSymbols(taskTypeBucket.key.replace('alerting:', ''));
const taskType: string = replaceDotSymbols(
`${taskTypeBucket.key}`.replace('alerting:', '')
);
acc[taskType] = taskTypeBucket.doc_count ?? 0;
return acc;
},

View file

@ -16,7 +16,7 @@ export function parseSimpleRuleTypeBucket(
) {
const buckets = ruleTypeBuckets as AggregationsStringTermsBucketKeys[];
return (buckets ?? []).reduce((acc, bucket: AggregationsStringTermsBucketKeys) => {
const ruleType: string = replaceDotSymbols(bucket.key);
const ruleType: string = replaceDotSymbols(`${bucket.key}`);
acc[ruleType] = bucket.doc_count ?? 0;
return acc;
}, {} as Record<string, number>);

View file

@ -5,14 +5,17 @@
* 2.0.
*/
import type { QueryDslBoolQuery } from '@elastic/elasticsearch/lib/api/types';
import type {
AggregationsCompositeAggregateKey,
QueryDslBoolQuery,
} from '@elastic/elasticsearch/lib/api/types';
import type { ElasticsearchClient } from '@kbn/core/server';
import { extractIndexNameFromBackingIndex } from '../../../common/utils';
import { DataStreamDocsStat } from '../../../common/api_types';
import { createDatasetQualityESClient } from '../../utils';
import { rangeQuery } from '../../utils/queries';
interface Dataset {
interface Dataset extends AggregationsCompositeAggregateKey {
dataset: string;
}

View file

@ -935,7 +935,7 @@ export function getQueryBodyWithAuthFilter(
};
}
function getNamespaceQuery(namespace?: string) {
function getNamespaceQuery(namespace?: string): estypes.QueryDslQueryContainer {
const defaultNamespaceQuery = {
bool: {
must_not: {
@ -948,7 +948,7 @@ function getNamespaceQuery(namespace?: string) {
const namedNamespaceQuery = {
term: {
'kibana.saved_objects.namespace': {
value: namespace,
value: namespace!,
},
},
};

View file

@ -175,7 +175,9 @@ export const generateEsApiResponseMock = <TBody extends Record<string, any>>(
body: undefined,
querystring: '',
},
options: {},
options: {
requestTimeout: 30_000,
},
id: 7160,
},
name: 'elasticsearch-js',

View file

@ -96,8 +96,7 @@ async function handleMlModelInstall({
{
model_id: mlModel.installationName,
defer_definition_decompression: true,
// @ts-expect-error timeout is not declared
timeout: '45s',
querystring: { timeout: '45s' },
body: mlModel.content,
},
{

View file

@ -221,7 +221,7 @@ export async function handleExperimentalDatastreamFeatureOptIn({
await esClient.indices.putIndexTemplate({
name: featureMapEntry.data_stream,
// @ts-expect-error
// @ts-expect-error elasticsearch@9.0.0 https://github.com/elastic/elasticsearch-js/issues/2584
body: indexTemplateBody,
_meta: {
has_experimental_data_stream_indexing_features: featureMapEntry.features.tsdb,

View file

@ -55,9 +55,7 @@ export function registerPutDataRetention({ router, lib: { handleEsError } }: Rou
const { headers } = await client.asCurrentUser.indices.putDataLifecycle(
{
name: dataStreams,
lifecycle: {
data_retention: dataRetention,
},
data_retention: dataRetention,
},
{ meta: true }
);

View file

@ -8,6 +8,7 @@
import { uniq } from 'lodash';
import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server';
import { AGENTS_INDEX, PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '@kbn/fleet-plugin/common';
import type { SortResults } from '@elastic/elasticsearch/lib/api/types';
import { OSQUERY_INTEGRATION_NAME } from '../../common';
import type { OsqueryAppContext } from './osquery_app_context_services';
@ -24,9 +25,9 @@ export const aggregateResults = async (
generator: (
page: number,
perPage: number,
searchAfter?: unknown[],
searchAfter?: SortResults,
pitId?: string
) => Promise<{ results: string[]; total: number; searchAfter?: unknown[] }>,
) => Promise<{ results: string[]; total: number; searchAfter?: SortResults }>,
esClient: ElasticsearchClient,
context: OsqueryAppContext
) => {
@ -41,7 +42,7 @@ export const aggregateResults = async (
index: AGENTS_INDEX,
keep_alive: '10m',
});
let currentSort: unknown[] | undefined;
let currentSort: SortResults | undefined;
// Refetch first page with PIT
const { results: pitInitialResults, searchAfter } = await generator(
1,
@ -111,7 +112,7 @@ export const parseAgentSelection = async (
if (allAgentsSelected) {
const kuery = kueryFragments.join(' and ');
const fetchedAgents = await aggregateResults(
async (page, perPage, searchAfter?: unknown[], pitId?: string) => {
async (page, perPage, searchAfter?: SortResults, pitId?: string) => {
const res = await agentService.listAgents({
...(searchAfter ? { searchAfter } : {}),
...(pitId ? { pitId } : {}),
@ -145,7 +146,7 @@ export const parseAgentSelection = async (
kueryFragments.push(`(${groupFragments.join(' or ')})`);
const kuery = kueryFragments.join(' and ');
const fetchedAgents = await aggregateResults(
async (page, perPage, searchAfter?: unknown[], pitId?: string) => {
async (page, perPage, searchAfter?: SortResults, pitId?: string) => {
const res = await agentService.listAgents({
...(searchAfter ? { searchAfter } : {}),
...(pitId ? { pitId } : {}),

View file

@ -520,7 +520,7 @@ export class AlertsClient {
query: object | string;
operation: WriteOperations.Update | ReadOperations.Find | ReadOperations.Get;
}) {
let lastSortIds;
let lastSortIds: Array<string | number> | undefined;
let hasSortIds = true;
const alertSpaceId = this.spaceId;
if (alertSpaceId == null) {

View file

@ -595,10 +595,10 @@ export const categorizeAggregations = (aggregationResponse?: ApiKeyAggregations)
: [];
typeBuckets.forEach((type) => {
typeFilters.push(type.key);
typeFilters.push(type.key as CategorizedApiKey['type']);
});
usernameBuckets.forEach((username) => {
usernameFilters.push(username.key);
usernameFilters.push(`${username.key}`);
});
const { namePrefixBased, metadataBased } = managed?.buckets || {};
if (

View file

@ -1580,7 +1580,7 @@ describe('Session index', () => {
index: aliasName,
document: sessionValue,
refresh: false,
require_alias: true,
querystring: { require_alias: true },
},
{ ignore: [404], meta: true }
);
@ -1591,7 +1591,7 @@ describe('Session index', () => {
index: aliasName,
document: sessionValue,
refresh: false,
require_alias: true,
querystring: { require_alias: true },
},
{ ignore: [], meta: true }
);
@ -1635,7 +1635,7 @@ describe('Session index', () => {
index: aliasName,
document: sessionValue,
refresh: false,
require_alias: true,
querystring: { require_alias: true },
},
{ meta: true, ignore: [404] }
);

View file

@ -10,7 +10,6 @@ import type {
AggregateName,
AggregationsMultiTermsAggregate,
BulkOperationContainer,
CreateRequest,
IndicesCreateRequest,
MsearchRequestItem,
SearchHit,
@ -786,8 +785,8 @@ export class SessionIndex {
index: this.aliasName,
document: sessionValueToStore,
refresh: false,
require_alias: true,
} as CreateRequest,
querystring: { require_alias: true },
},
{ meta: true, ignore: ignore404 ? [404] : [] }
);

View file

@ -183,6 +183,7 @@ export async function executor(core: CoreSetup, options: ExecutorOptions<EsQuery
if (!isGroupAgg) {
// update the timestamp based on the current search results
const firstValidTimefieldSort = getValidTimefieldSort(
// @ts-expect-error `sort` now depends on `FieldValue` that is too broad
result.hits.find((hit) => getValidTimefieldSort(hit.sort))?.sort
);
if (firstValidTimefieldSort) {

View file

@ -116,12 +116,12 @@ describe('InferenceConnector', () => {
rerank: [
{
index: 2,
score: 0.011597361,
relevance_score: 0.011597361,
text: 'leia',
},
{
index: 0,
score: 0.006338922,
relevance_score: 0.006338922,
text: 'luke',
},
],
@ -165,7 +165,9 @@ describe('InferenceConnector', () => {
},
{ asStream: false }
);
expect(response).toEqual(mockResponseRerank.rerank);
expect(response).toEqual(
mockResponseRerank.rerank.map(({ relevance_score: score, ...rest }) => ({ ...rest, score }))
);
});
});

View file

@ -269,7 +269,7 @@ export class InferenceConnector extends SubActionConnector<Config, Secrets> {
false,
signal
);
return response.rerank!;
return response.rerank!.map(({ relevance_score: score, ...rest }) => ({ score, ...rest }));
}
/**

View file

@ -112,9 +112,7 @@ export async function updateDataStreamsLifecycle({
() =>
esClient.indices.putDataLifecycle({
name: names,
lifecycle: {
data_retention: isDslLifecycle(lifecycle) ? lifecycle.dsl.data_retention : undefined,
},
data_retention: isDslLifecycle(lifecycle) ? lifecycle.dsl.data_retention : undefined,
}),
{ logger }
);

View file

@ -157,6 +157,7 @@ export class TaskManagerMetricsCollector implements ITaskEventEmitter<TaskLifecy
}) ?? {};
const byTaskType = ((aggregations.byTaskType.buckets as OverdueTaskAggBucket[]) ?? []).reduce(
(acc: Record<string, number>, bucket: OverdueTaskAggBucket) => {
// @ts-expect-error there's no way that buckets (array) matches `number`
acc[bucket.key] = bucket?.overdueByHistogram?.buckets ?? [];
return acc;
},

View file

@ -78,7 +78,7 @@ export class TaskOverdueMetricsAggregator implements ITaskMetricsAggregator<Task
for (const key of Object.keys(metric.numOverdueTasks)) {
const hist = new SimpleHistogram(HDR_HISTOGRAM_MAX, HDR_HISTOGRAM_BUCKET_SIZE);
(metric.numOverdueTasks[key] ?? []).forEach((bucket) => {
const overdueInSec = parseInt(bucket.key, 10);
const overdueInSec = parseInt(`${bucket.key}`, 10);
hist.record(overdueInSec, bucket.doc_count);
if (key === 'total') {

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
import type { FieldValue, QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
import type { SearchFilter } from './generate_search_schema';
export const createFilterClauses = ({
@ -22,7 +22,7 @@ export const createFilterClauses = ({
if (filter) {
if (filter.type === 'keyword' || filter.type === 'boolean') {
clauses.push({
term: { [field]: value },
term: { [field]: value as FieldValue },
});
}
// TODO: handle other field types, date mostly

View file

@ -24,6 +24,7 @@ export type ApmAlertsRequiredParams = ESSearchRequest & {
query?: estypes.QueryDslQueryContainer;
sort?: estypes.SortOptions[];
_source?: string[] | false;
search_after?: Array<string | number>;
};
export async function getApmAlertsClient({

View file

@ -18,6 +18,7 @@ type RequiredParams = ESSearchRequest & {
track_total_hits: boolean | number;
sort?: estypes.SortOptions[];
_source?: string[] | false;
search_after?: Array<string | number>;
};
export type InfraAlertsClient = Awaited<ReturnType<typeof getInfraAlertsClient>>;

View file

@ -30,6 +30,7 @@ export async function createAlertsClient({
sort?: SortOptions[];
size: number;
track_total_hits: boolean | number;
search_after?: Array<string | number>;
};
return {

View file

@ -32,6 +32,7 @@ export async function getAlertsClient({
track_total_hits: boolean | number;
sort?: estypes.SortOptions[];
_source?: string[] | false;
search_after?: Array<string | number>;
};
return {

View file

@ -56,7 +56,7 @@ export function termsQuery(
field: string,
...values: Array<string | boolean | undefined | number | null>
): QueryDslQueryContainer[] {
const filtered = reject(values, isUndefinedOrNull);
const filtered = reject(values, isUndefinedOrNull) as Array<NonNullable<(typeof values)[number]>>;
if (!filtered.length) {
return [];

View file

@ -6,6 +6,7 @@
*/
import { timeslicesBudgetingMethodSchema } from '@kbn/slo-schema';
import type { AggregationsCompositeAggregateKey } from '@elastic/elasticsearch/lib/api/types';
import { Duration, SLODefinition, toDurationUnit } from '../../../../domain/models';
import { getDelayInSecondsFromSLO } from '../../../../domain/services/get_delay_in_seconds_from_slo';
import { getLookbackDateRange } from '../../../../domain/services/get_lookback_date_range';
@ -17,7 +18,7 @@ type BurnRateWindowWithDuration = WindowSchema & {
shortDuration: Duration;
};
export interface EvaluationAfterKey {
export interface EvaluationAfterKey extends AggregationsCompositeAggregateKey {
instanceId: string;
}

View file

@ -6,12 +6,13 @@
*/
import { ElasticsearchClient, Logger } from '@kbn/core/server';
import type { AggregationsCompositeAggregateKey } from '@elastic/elasticsearch/lib/api/types';
import {
SUMMARY_DESTINATION_INDEX_PATTERN,
SUMMARY_TEMP_INDEX_NAME,
} from '../../../common/constants';
interface AggBucketKey {
interface AggBucketKey extends AggregationsCompositeAggregateKey {
spaceId: string;
id: string;
}

View file

@ -112,7 +112,11 @@ export class DefaultSummarySearchClient implements SummarySearchClient {
const finalTotal = total - (tempSummaryDocuments.length - tempSummaryDocumentsDeduped.length);
const paginationResults = isCursorPagination(pagination)
? { searchAfter: finalResults[finalResults.length - 1].sort, size: pagination.size }
? {
// `sort` has unknown as types
searchAfter: finalResults[finalResults.length - 1].sort as Array<string | number>,
size: pagination.size,
}
: pagination;
return {

View file

@ -56,7 +56,7 @@ export function termsQuery(
field: string,
...values: Array<string | boolean | undefined | number | null>
): QueryDslQueryContainer[] {
const filtered = reject(values, isUndefinedOrNull);
const filtered = reject(values, isUndefinedOrNull) as Array<NonNullable<(typeof values)[number]>>;
if (!filtered.length) {
return [];

View file

@ -221,12 +221,14 @@ export const searchFindingsHandler = (findings: CspFinding[]) =>
const hasRuleSectionQuerySearchTerm =
isArray(filter) &&
isArray(filter[0]?.bool?.should) &&
// @ts-expect-error FieldValue is now very broad (can be anything)
filter[0]?.bool?.should?.[0]?.term?.['rule.section']?.value !== undefined;
if (hasRuleSectionQuerySearchTerm) {
const filteredFindings = findings.filter((finding) => {
const termValue = (filter[0].bool?.should as estypes.QueryDslQueryContainer[])?.[0]?.term?.[
'rule.section'
// @ts-expect-error FieldValue is now very broad (can be anything)
]?.value;
return finding.rule.section === termValue;
});

View file

@ -379,7 +379,7 @@ const getAccountStatsBasedOnEnablesRule = async (
must_not: mutedRulesFilterQuery,
must: {
terms: {
'rule.benchmark.id': benchmarksWithMutedRules,
'rule.benchmark.id': benchmarksWithMutedRules as string[],
},
},
},

View file

@ -315,7 +315,7 @@ export const formatAggExecutionEventFromBucket = (
const backfill = getBackfill(bucket);
return {
execution_uuid: bucket?.key ?? '',
execution_uuid: bucket?.key ? `${bucket.key}` : '',
timestamp: bucket?.ruleExecution?.executeStartTime.value_as_string ?? '',
duration_ms: durationUs / ONE_MILLISECOND_AS_NANOSECONDS,
status: bucket?.ruleExecution?.outcomeAndMessage?.hits?.hits[0]?._source?.event?.outcome,

View file

@ -276,7 +276,7 @@ export const createThreatSignals = async ({
// this could happen when event has empty sort field
// https://github.com/elastic/kibana/issues/174573 (happens to IM rule only since it uses desc order for events search)
// when negative sort id used in subsequent request it fails, so when negative sort value found we don't do next request
const hasNegativeDateSort = sortIds?.some((val) => val < 0);
const hasNegativeDateSort = sortIds?.some((val) => Number(val) < 0);
if (hasNegativeDateSort) {
ruleExecutionLogger.debug(

View file

@ -203,7 +203,7 @@ export const searchAfterAndBulkCreateFactory = async ({
// this could happen when event has empty sort field
// https://github.com/elastic/kibana/issues/174573 (happens to IM rule only since it uses desc order for events search)
// when negative sort id used in subsequent request it fails, so when negative sort value found we don't do next request
const hasNegativeNumber = lastSortIds?.some((val) => val < 0);
const hasNegativeNumber = lastSortIds?.some((val) => Number(val) < 0);
if (lastSortIds != null && lastSortIds.length !== 0 && !hasNegativeNumber) {
sortIds = lastSortIds;
} else {

View file

@ -709,7 +709,7 @@ export const getSafeSortIds = (sortIds: estypes.SortResults | undefined) => {
return sortIds?.map((sortId) => {
// haven't determined when we would receive a null value for a sort id
// but in case we do, default to sending the stringified Java max_int
if (sortId == null || sortId === '' || sortId >= Number.MAX_SAFE_INTEGER) {
if (sortId == null || sortId === '' || Number(sortId) >= Number.MAX_SAFE_INTEGER) {
return '9223372036854775807';
}
return sortId;

View file

@ -318,13 +318,15 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient
const migrationsAgg = result.aggregations?.migrationIds as AggregationsStringTermsAggregate;
const buckets = (migrationsAgg?.buckets as AggregationsStringTermsBucket[]) ?? [];
return buckets.map((bucket) => ({
id: bucket.key,
id: `${bucket.key}`,
rules: {
total: bucket.doc_count,
...this.statusAggCounts(bucket.status),
...this.statusAggCounts(bucket.status as AggregationsStringTermsAggregate),
},
created_at: bucket.createdAt?.value_as_string,
last_updated_at: bucket.lastUpdatedAt?.value_as_string,
created_at: (bucket.createdAt as AggregationsMinAggregate | undefined)
?.value_as_string as string,
last_updated_at: (bucket.lastUpdatedAt as AggregationsMaxAggregate | undefined)
?.value_as_string as string,
}));
}

View file

@ -139,11 +139,7 @@ export default function ({ getService }) {
};
const { body } = await createJob(payload);
// expect(body.message).to.contain('unknown field [invalid]');
// elasticsearch@9.0.0 https://github.com/elastic/elasticsearch-js/issues/2584
// At the moment, the client places unknown fields as URL parameters, we are discussing changing that to use the body as a catch-all.
// This might revert the asssertion to the above.
expect(body.message).to.contain('contains unrecognized parameter: [invalid]');
expect(body.message).to.contain('unknown field [invalid]');
});
it('should list the newly created job', async () => {

View file

@ -2139,10 +2139,10 @@
"@elastic/transport" "^8.3.1"
tslib "^2.4.0"
"@elastic/elasticsearch@9.0.0-alpha.3":
version "9.0.0-alpha.3"
resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-9.0.0-alpha.3.tgz#7580ca3f984cef7c4a9ecda0c5853dfa4671996d"
integrity sha512-10ZJtFXij0TiDc+5WpDfHB+ckEeeEgo6ZwY4QjjNNEFSLZSx+gg7DBgQkddRYpjBe7VM6dBhY76NkRmgod7p9A==
"@elastic/elasticsearch@9.0.0-alpha.4":
version "9.0.0-alpha.4"
resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-9.0.0-alpha.4.tgz#747541e0bd93d2310d522c7d6bf21bec5872eacd"
integrity sha512-qGtiC3lWH//J4rTneaXU8vPpxQe8kPO57ZU94kMSttpyyDE+yvs0uh/tsOwKwQS9i5L37fGZG1I02x0Kf5HHfw==
dependencies:
"@elastic/transport" "9.0.0-alpha.1"
apache-arrow "^18.0.0"